Skip to content

Commit bfb5e10

Browse files
Lykhoydaclaude
andauthored
fix(story-06): accept dismissed|not_occluded in Android keyboard-guard smoke (#387) (#496)
* fix(story-06): accept dismissed|not_occluded in the Android keyboard-guard smoke (#387) Run 28792678817: iOS went GREEN (warm-sim + ready-timeout fix worked), integrity green — Android failed only because the keyboard-guard returned 'not_occluded' instead of the pinned 'dismissed'. Which fires depends on the emulator keyboard geometry (bottom button center inside the IME frame vs at/below its edge), non-deterministic run-to-run. Both are valid non-blocked outcomes; accept either and reject only no_keyboard/off. The exact shouldDismiss predicate stays precisely unit-tested in KeyboardGuardTest.kt (Phase A). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(story-06): verify the guarded tap landed via fixture_bottom_count (#387) Codex P2 on #496: accepting not_occluded on ok:true alone doesn't prove the bottom button was tapped — a tap swallowed by the IME/nav area still reports ok:true. Read the observable fixture_bottom_count after the guarded press (dismissing a still-open keyboard first so the counter is in the tree) and assert it incremented to 1. This proves the tap landed in BOTH guard outcomes and catches the swallowed-tap false-pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 0e52fd5 commit bfb5e10

2 files changed

Lines changed: 44 additions & 3 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'rn-dev-agent-plugin': patch
3+
---
4+
5+
Android device-smoke keyboard-guard step: accept both non-blocked guard outcomes (`dismissed` and `not_occluded`) instead of pinning `dismissed`. Which one fires depends on the emulator's exact keyboard geometry (whether the bottom button's tap point lands inside the IME frame or at/below its edge), which varies run-to-run. The smoke now verifies the guard evaluated on-device and did not wrongly block the tap; the precise `shouldDismiss` predicate stays unit-tested in `KeyboardGuardTest.kt`.

scripts/cdp-bridge/test/smoke/device-smoke.ts

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -342,15 +342,51 @@ test(`Phase B golden set (${PLATFORM})`, { timeout: 900_000 }, async () => {
342342
} else {
343343
kb = record('keyboard-guard', await callTool(s, 'device_press', { ref: preFillBottomRef }));
344344
const guard = kb.envelope?.meta?.keyboardGuard;
345-
// no_keyboard = the soft IME never appeared (environment problem), not a
346-
// contract result — fail with the fix rather than let it masquerade.
345+
// The guard ran and the tap was NOT blocked-through the keyboard. Accept
346+
// both non-blocked outcomes: "dismissed" (tap point inside the IME frame →
347+
// dismiss then tap) and "not_occluded" (keyboard up but the point landed
348+
// at/below the frame edge — emulator keyboard geometry varies run-to-run,
349+
// so which one fires is not deterministic). The exact shouldDismiss
350+
// predicate is unit-tested precisely in Phase A's KeyboardGuardTest.kt;
351+
// here we only pin that the guard evaluated on-device and did not wrongly
352+
// block. Reject the environment-problem / disabled states.
347353
assert.notEqual(
348354
guard,
349355
'no_keyboard',
350356
'Soft keyboard never appeared — the emulator needs `adb shell settings put secure show_ime_with_hard_keyboard 1` (the nightly workflow sets it)',
351357
);
358+
assert.notEqual(guard, 'off', 'keyboard guard was disabled (RN_KEYBOARD_GUARD=0?)');
352359
assert.equal(kb.envelope?.ok, true, `keyboard-guard press failed: ${kb.text.slice(0, 500)}`);
353-
assert.equal(guard, 'dismissed', 'Android must dismiss the keyboard first');
360+
assert.ok(
361+
guard === 'dismissed' || guard === 'not_occluded',
362+
`expected keyboardGuard dismissed|not_occluded, got "${guard}": ${kb.text.slice(0, 300)}`,
363+
);
364+
// Prove the guarded tap actually LANDED on the button (a tap swallowed by
365+
// the IME/nav area still reports ok:true). Read the observable counter —
366+
// dismissing a still-open keyboard first so the bottom bar is in the tree
367+
// (a still-open keyboard means the counter is occluded, not absent).
368+
let postKb = record(
369+
'snapshot-post-kbguard',
370+
await callTool(s, 'device_snapshot', { action: 'snapshot' }),
371+
);
372+
if (!refFor(postKb.envelope, 'fixture_bottom_count')) {
373+
// device_back only runs when the counter is hidden → a keyboard is up,
374+
// so back dismisses the IME rather than navigating the app.
375+
record('dismiss-kb', await callTool(s, 'device_back', {}));
376+
postKb = record(
377+
'snapshot-post-back',
378+
await callTool(s, 'device_snapshot', { action: 'snapshot' }),
379+
);
380+
}
381+
const bottomCount = postKb.envelope?.data?.nodes?.find(
382+
(n: any) => n.identifier === 'fixture_bottom_count',
383+
);
384+
assert.ok(bottomCount, 'fixture_bottom_count must be visible after dismissing the keyboard');
385+
assert.match(
386+
bottomCount.label ?? '',
387+
/bottom taps: 1/,
388+
`guarded tap must increment the bottom counter (proves it landed, not swallowed): got "${bottomCount.label}"`,
389+
);
354390
}
355391

356392
const neg = record(

0 commit comments

Comments
 (0)