From 479d7ba2e843d5ea93979f2eed68f4d38d146c25 Mon Sep 17 00:00:00 2001 From: cirakg Date: Tue, 20 Oct 2026 18:36:54 +0200 Subject: test(settings): cover every form, symbology and Manage action; send the forms end to end in the UI flow 34 Monkey C tests (154 per device): validation messages, idempotency, the queue, the About scan, "Encrypt names" and the properties contract. The UI-test build fills in Add OTP, Add code and Manage like the phone; the flow checks the new TOTP (309 848 at the frozen time), decodes the Code 128 card and confirms the queued change to the locked entry with the PIN. Co-Authored-By: Claude Opus 5.5 --- tools/ui_flow.py | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 5 deletions(-) (limited to 'tools/ui_flow.py') diff --git a/tools/ui_flow.py b/tools/ui_flow.py index e54b530..edfc9a4 100644 --- a/tools/ui_flow.py +++ b/tools/ui_flow.py @@ -19,8 +19,13 @@ drawing each screen, so every step waits for the screen it expects instead of sleeping. Menus are native Menu2 views that print nothing; for those the script waits a fixed time. -The flow covers: the results of an Aegis import sent through the settings -form (the fixture sets the form, as the phone would), the list, a TOTP entry, a HOTP entry and its next code, the +The flow covers: the results of an Aegis import and of the Add OTP, Add +code and Manage entry forms, all sent through the settings (the fixture +sets the forms, as the phone would), the two entries those forms added (a +TOTP whose code the golden image shows, and a Code 128 card whose +screenshot must decode), the Manage form's change to the locked Bank entry +waiting for the PIN and confirmed from the menu (watches with buttons), the +list, a TOTP entry, a HOTP entry and its next code, the PIN screen, a wrong PIN, a correct PIN opening a locked entry, auto-lock closing it, the menu, the About screen (watches with buttons; touch-only menus have no focus to move), the lockout after 5 wrong PINs, and an EAN-13 @@ -49,6 +54,7 @@ import zxingcpp EXIT_OK, EXIT_DIFFERENT, EXIT_FLOW = 0, 1, 2 SCREEN_TIMEOUT_S = 20.0 AUTO_LOCK_TIMEOUT_S = 25.0 # the UI-test build locks after 10 s without input +AUTO_LOCK_IDLE_S = 13.0 # idle time after which that lock has surely happened IMPORT_TIMEOUT_S = 90.0 # the 100-entry fixture import runs on a timer after start-up IMPORT_MEMORY_BUDGET = 0.70 # README 18: peak memory at most 70 % of the watch-app memory MENU_SETTLE_S = 1.5 # Menu2 has no "shown" line @@ -66,6 +72,9 @@ MEMBER_QR = ( # source/app/Fixtures.mc: a version 6 QR PARCEL_DM = "PARCEL-FAKE-0042-7731" # source/app/Fixtures.mc: Data Matrix TICKET_PDF417 = "Boarding pass FAKE 0042 seat 12A" # source/app/Fixtures.mc: PDF417 RAIL_AZTEC = "RAIL-FAKE-0042 Zone 1-3" # source/app/Fixtures.mc: Aztec +LOCKER_CODE128 = "FAKE-0042" # source/app/Fixtures.mc: the Add code form's Code 128 card +# The Add OTP form's TOTP ("Hello!" demo key) at TestMode.NOW is 309848, next +# 489290 (RFC 6238 computed in Python); the golden image otp_form shows them. QR_TIMEOUT_S = 30.0 # the QR is encoded in timer steps the first time @@ -350,6 +359,30 @@ def flow_import(f: Flow) -> None: f.expect("list") +def flow_forms(f: Flow) -> None: + """The entries the Add code and Add OTP forms added end the list: the + list wraps, so UP from the first row reaches them.""" + f.prev() # the Code 128 card (added last) + f.act() + f.open_focused_row() + f.expect("code") + f.shot("code_form", expect_code=LOCKER_CODE128) + f.act() + f.back() + f.expect("list") + f.prev() # the TOTP from Add OTP + f.act() + f.open_focused_row() + f.expect("otp") + f.shot("otp_form") + f.act() + f.back() + f.expect("list") + f.next() + f.next() # back to the first row (GitHub) + time.sleep(SETTLE_S) + + def flow_entries(f: Flow) -> None: """The list, a TOTP entry, a HOTP entry and its next code.""" f.shot("list") @@ -403,9 +436,10 @@ def flow_menu(f: Flow) -> None: f.shot("menu") f.act() if f.sim.has("down"): - # Locked with a PIN: Change PIN, Reset PIN, Settings results, Entry - # IDs, Clock status, About. - for _ in range(5): + # Locked with a PIN and a phone change waiting: Phone changes, + # Change PIN, Reset PIN, Settings results, Entry IDs, Clock status, + # About. + for _ in range(6): f.next() time.sleep(MENU_SETTLE_S) f.act() @@ -419,6 +453,32 @@ def flow_menu(f: Flow) -> None: f.expect("list") +def flow_queue(f: Flow) -> None: + """The Manage form's edit of the locked Bank entry waits for the PIN: + menu, Phone changes, Confirm all, PIN, results. Touch-only + menus have no focus to select with, so those watches skip it.""" + if not f.sim.has("down"): + return + f.menu() + time.sleep(MENU_SETTLE_S) + f.select() # Phone changes (the first item while one waits) + time.sleep(MENU_SETTLE_S) + f.shot("queue") + f.act() + f.select() # Confirm all + f.expect("pin") + f.opened_pin_screen() + f.act() + f.enter_pin(FIXTURE_PIN) + f.expect("results") + f.shot("queue_results") + f.act() + f.back() + f.expect("list") + # The PIN unlocked the session; the lockout flow needs it locked again. + time.sleep(AUTO_LOCK_IDLE_S) + + def flow_lockout(f: Flow) -> None: """Five wrong PINs start the 30 s wait.""" f.act() @@ -471,9 +531,11 @@ def flow_code(f: Flow) -> None: def run_flow(f: Flow) -> None: """The scripted session; see the module docstring.""" flow_import(f) + flow_forms(f) flow_entries(f) flow_locked_entry(f) flow_menu(f) + flow_queue(f) flow_lockout(f) flow_code(f) -- cgit v1.2.3