From f2243354c5ca11ce85f37d8117df47974b450554 Mon Sep 17 00:00:00 2001 From: "developerz-ai[bot]" <286432749+developerz-ai[bot]@users.noreply.github.com> Date: Tue, 22 Sep 2026 06:59:03 +0000 Subject: [PATCH] test(android): assert clear:true yields the empty-field keyevent sequence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The act `clear: true` path (act.ts:272-287) composes type('', '') → pressKey('Control+a') → pressKey('Delete') → type(text) on the bound Adapter. The existing test (act.test.ts:746-770) covers this against a generic fake, so it never confirms the actual adb argv the android adapter emits. The android adapter's pressKey('Control+a') becomes `input keycombination KEYCODE_CTRL_LEFT KEYCODE_A` (commands.ts:268-278) and pressKey('Delete') becomes `input keyevent KEYCODE_FORWARD_DEL` (commands.ts:254-262 alias) — the keyevent sequence that actually empties the field on the device. Add a behavior test in android-adapter.behavior.test.ts that drives the real AndroidAdapter through the four contract calls and asserts the adb argv sequence on the FakeAdb transport, in order. No change to android-adapter.ts. If the test ever fails, the failure is the finding — fixing the keyevent sequence is a separate follow-up. Dz-Task-Id: tsk_e45e4686c9e4c17eed6556c282bb98d1 --- .../android/android-adapter.behavior.test.ts | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/adapters/android/android-adapter.behavior.test.ts b/src/adapters/android/android-adapter.behavior.test.ts index bcb73e2..28361c2 100644 --- a/src/adapters/android/android-adapter.behavior.test.ts +++ b/src/adapters/android/android-adapter.behavior.test.ts @@ -161,6 +161,42 @@ describe('AndroidAdapter.pressKey', () => { }); }); +describe('AndroidAdapter act `clear: true` flow', () => { + // Drives the real AndroidAdapter through the sequence the act `clear: true` belt + // action emits: focus (tap), select-all chord, delete, then type the new text. + // Asserts the **exact** adb argv shape (FakeAdb.calls) — including the + // `input keycombination KEYCODE_CTRL_LEFT KEYCODE_A` chord and the + // `input keyevent KEYCODE_FORWARD_DEL` delete. If the adapter ever swaps + // the keyevent sequence the assertions fail verbatim; fixing that is a + // follow-up, not something this test should silently paper over. + test('type("", "") → pressKey("Control+a") → pressKey("Delete") → type("hello") emits the expected argv order', async () => { + const node = makeNode({ bounds: { x: 0, y: 0, width: 200, height: 60 } }); + const { adapter, adb } = makeAdapter({ nodes: [node] }); + + await adapter.type('Save', ''); + await adapter.pressKey('Control+a'); + await adapter.pressKey('Delete'); + await adapter.type('Save', 'hello'); + + // Slice down to the `input` argv the adapter hands the device shell, then + // strip the `input` prefix so the assertion reads as the belt sees it. + const ops = adb.calls + .filter((c) => c.method === 'shell' && c.args[0] === 'input') + .map((c) => c.args.slice(1)); + expect(ops).toEqual([ + // adapter.type('Save', '') → focus tap, no text call. + ['tap', '100', '30'], + // adapter.pressKey('Control+a') → select-all chord (Android 11+ keycombination). + ['keycombination', 'KEYCODE_CTRL_LEFT', 'KEYCODE_A'], + // adapter.pressKey('Delete') → forward-delete keyevent. + ['keyevent', 'KEYCODE_FORWARD_DEL'], + // adapter.type('Save', 'hello') → re-focus tap, then type the new text. + ['tap', '100', '30'], + ['text', 'hello'], + ]); + }); +}); + describe('AndroidAdapter.scroll', () => { test('down scroll → swipe shell call', async () => { const { adapter, adb } = makeAdapter();