Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/actions/db-sync-server/action.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
name: Start db-sync server
description: >-
Check out logseq@feature/native-mobile-app, build the db-sync node adapter,
Check out the native-compatible Logseq revision, build the db-sync node adapter,
and start it on the given port (default 8787). The app e2e flows create sync
graphs against it. logseq/logseq is public, so no credential is needed.
inputs:
ref:
description: logseq/logseq ref to check out.
required: false
default: feature/native-mobile-app
# This revision includes the snapshot transaction cursor required by the
# shared native bootstrap protocol. The old feature branch omitted it.
default: a63da5cb7993302f8c58ccf42eaf0083b77cf42b
port:
description: Port the server binds.
required: false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import androidx.compose.ui.test.performTouchInput
import androidx.compose.ui.test.swipeRight
import androidx.compose.ui.unit.dp
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.logseq.app.runtime.logseqIconResolver
import dev.lui.LuiBackend
import dev.lui.LuiEvent
Expand Down Expand Up @@ -135,6 +136,55 @@ class AndroidNativeSurfacesTest {
ui.runOnIdle { assertEquals(listOf(LuiEvent.Dismiss(2)), events) }
}

private fun assertModalControlsExposeResourceIds(kind: String) {
render(kind)
ui.runOnIdle {
val ops = JSONArray()
listOf("text-field", "switch", "button").forEachIndexed { index, control ->
val id = index + 3
ops.put(op("create-node", "id" to id, "kind" to control))
.put(op("set-prop", "id" to id, "property" to "accessibility-identifier", "value" to "modal.$control"))
.put(op("set-prop", "id" to id, "property" to "text", "value" to control))
.put(op("insert-child", "parent" to 2, "child" to id, "index" to index))
}
apply(ops)
}
val automation = InstrumentationRegistry.getInstrumentation().uiAutomation
val originalInfo = automation.serviceInfo
automation.serviceInfo = android.accessibilityservice.AccessibilityServiceInfo().apply {
eventTypes = originalInfo.eventTypes
feedbackType = originalInfo.feedbackType
flags = originalInfo.flags or
android.accessibilityservice.AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS or
android.accessibilityservice.AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS
}
fun resourceIds(): Set<String> {
val pending = java.util.ArrayDeque<android.view.accessibility.AccessibilityNodeInfo>()
automation.windows.forEach { window -> window.root?.let { pending.add(it) } }
val ids = mutableSetOf<String>()
while (pending.isNotEmpty()) {
val node = pending.removeFirst()
node.viewIdResourceName?.let { ids.add(it) }
repeat(node.childCount) { index -> node.getChild(index)?.let { pending.add(it) } }
}
return ids
}
val expected = setOf("modal.text-field", "modal.switch", "modal.button")
try {
ui.waitUntil(5_000) { resourceIds().containsAll(expected) }
} finally {
automation.serviceInfo = originalInfo
}
}

@Test fun dialogControlsExposeResourceIdsInTheirOwnNativeWindow() {
assertModalControlsExposeResourceIds("dialog")
}

@Test fun sheetControlsExposeResourceIdsInTheirOwnNativeWindow() {
assertModalControlsExposeResourceIds("sheet")
}

@Test fun selectedListItemsExposeNativeSingleSelection() {
render("list-item", mapOf("text" to "Example", "selected" to true, "press-enabled" to true))
ui.onNodeWithText("Example").assertIsSelected().performClick()
Expand Down
2 changes: 1 addition & 1 deletion apple/Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apple/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ let package = Package(
.library(name: "LogseqModel", type: .dynamic, targets: ["LogseqModel"]),
],
dependencies: [
.package(url: "ssh://git@github.com/logseq/lui.git", revision: "db5cca5056a76775b2ce12d085c9eadde44cc42d"),
.package(url: "ssh://git@github.com/logseq/lui.git", revision: "52aae8634c9add1e0c11fecfdda102b3f3644b08"),
.package(url: "https://github.com/gonzalezreal/swiftui-math", from: "0.1.0"),
.package(url: "https://github.com/appstefan/highlightswift.git", from: "1.1.0")
],
Expand Down
2 changes: 1 addition & 1 deletion logseq.opam
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ pin-depends: [
["melange-transit-core.0.1.2" "git+https://github.com/logseq/melange-transit.git#main"]
["melange-transit-native.0.1.2" "git+https://github.com/logseq/melange-transit.git#main"]
["melange-transit-melange.0.1.2" "git+https://github.com/logseq/melange-transit.git#main"]
["lui.0.1.0" "git+ssh://git@github.com/logseq/lui.git#db5cca5056a76775b2ce12d085c9eadde44cc42d"]
["lui.0.1.0" "git+ssh://git@github.com/logseq/lui.git#52aae8634c9add1e0c11fecfdda102b3f3644b08"]
["drive.dev" "git+https://github.com/logseq/drive.git#dd735a65ed525d1c36db38ac8e8114aa81d314a1"]
["ocaml-signal.0.1.0" "git+https://github.com/logseq/ocaml-signal.git#02e18cdc5e0ad672aa223f638eaa3ba52fc9421e"]
["mldoc.dev" "git+https://github.com/logseq/mldoc.git#f11230c367964af2b575524d00779cfb1ffc7147"]
Expand Down
2 changes: 2 additions & 0 deletions scripts/test-android-e2e-runner.sh
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,8 @@ PATH="$mock_bin:$PATH" \
"$runner" connect >/dev/null
grep -Fxq -- '-s test-device reverse tcp:8787 tcp:8787' "$adb_args" \
|| die "Android E2E runner did not expose the host-local backend to the device"
grep -Eq 'run-as com\.logseq\.app cp .* shared_prefs/logseq\.xml$' "$adb_args" \
|| die "Android E2E server override did not use the app's SharedPreferences file"

PATH="$mock_bin:$PATH" \
ANDROID_SERIAL=test-device \
Expand Down
2 changes: 1 addition & 1 deletion scripts/test-android-e2e.sh
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ if [[ -n ${LOGSEQ_E2E_BASE_URL:-} ]]; then
'</map>' >"$preferences_file"
adb -s "$device" push "$preferences_file" "$remote_preferences" >/dev/null
adb -s "$device" shell run-as "$app_id" mkdir -p shared_prefs
adb -s "$device" shell run-as "$app_id" cp "$remote_preferences" shared_prefs/defaults.xml
adb -s "$device" shell run-as "$app_id" cp "$remote_preferences" shared_prefs/logseq.xml
adb -s "$device" shell rm -f "$remote_preferences"
fi

Expand Down
3 changes: 3 additions & 0 deletions tests/e2e/android-capture-search.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ appId: com.logseq.app
- assertVisible:
id: "screen.search"
- assertVisible: "Android E2E capture"
# Returning to search restores focus to its field. Back first dismisses the
# Android IME; close the keyboard explicitly before testing route dismissal.
- hideKeyboard
- pressKey: BACK
- assertVisible:
id: "button.composer.expand"
Expand Down
53 changes: 33 additions & 20 deletions tests/e2e/android-local-graph-setup.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +15,34 @@ appId: com.logseq.app
- tapOn: "Use without an account"
- extendedWaitUntil:
visible:
id: "signInFormUsername"
id: "signInFormUsername|screen.graph-picker|button.composer.expand"
timeout: 30000
- tapOn:
id: "signInFormUsername"
- inputText: ${USERNAME}
# A retained browser session can complete sign-in without the form.
- runFlow:
when:
visible: "Try out your stylus"
visible:
id: "signInFormUsername"
commands:
- tapOn: "Cancel"
- tapOn:
id: "signInFormPassword"
- inputText: ${PASSWORD}
- hideKeyboard
- extendedWaitUntil:
visible: "submit"
timeout: 10000
- tapOn: "submit"
- extendedWaitUntil:
visible:
id: "screen.graph-picker"
timeout: 60000
- tapOn:
id: "signInFormUsername"
- inputText: ${USERNAME}
- runFlow:
when:
visible: "Try out your stylus"
commands:
- tapOn: "Cancel"
- tapOn:
id: "signInFormPassword"
- inputText: ${PASSWORD}
- hideKeyboard
- extendedWaitUntil:
visible: "submit"
timeout: 10000
- tapOn: "submit"
- extendedWaitUntil:
visible:
id: "screen.graph-picker|button.composer.expand"
timeout: 60000
- runFlow:
when:
visible:
Expand All @@ -46,8 +52,15 @@ appId: com.logseq.app
id: "button.graph-add"
- extendedWaitUntil:
visible:
id: "field.graph-name"
# Login can finish opening the bootstrap graph after the picker
# was observed. Wait for either stable outcome of that transition.
id: "field.graph-name|button.composer.expand"
timeout: 30000
- runFlow:
when:
visible:
id: "field.graph-name"
commands:
- tapOn:
id: "field.graph-name"
- inputText: "android-e2e-smoke"
Expand All @@ -65,5 +78,5 @@ appId: com.logseq.app
timeout: 60000
- extendedWaitUntil:
visible:
id: "button.sidebar"
id: "button.composer.expand"
timeout: 60000
1 change: 1 addition & 0 deletions tests/e2e/android-search-navigation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ appId: com.logseq.app
- assertVisible:
id: "screen.search"
- assertVisible: "E2E Page Target 20260816"
- hideKeyboard
- pressKey: BACK
- assertVisible:
id: "button.search"
7 changes: 5 additions & 2 deletions tests/e2e/ios-capture-responsive.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@ appId: com.logseq.logseq
- assertVisible:
id: "button.composer.expand"
- tapOn:
id: "button.connection"
- tapOn: "Settings"
id: "button.sidebar"
- tapOn:
id: "button.sidebar.settings"
- assertVisible: "Sync server"
- assertVisible:
id: "field.base-url"
- tapOn:
id: "button.connection.cancel"
- tapOn:
id: "button.sidebar.dismiss"
- assertVisible:
id: "button.composer.expand"
- tapOn:
Expand Down
Loading