diff --git a/conformance/gates.sh b/conformance/gates.sh index 6e571f8..2cba52a 100755 --- a/conformance/gates.sh +++ b/conformance/gates.sh @@ -518,6 +518,8 @@ self_test() { "$(gate_no_doubled_text "${testdata}/g4-repeated-character" && echo PASS || echo FAIL)" assert "G4 doubled text caught from the recorded value" FAIL \ "$(gate_no_doubled_text "${testdata}/g4-recorded-text" && echo PASS || echo FAIL)" + assert "G4 input without a selector does not abort the gate" PASS \ + "$(gate_no_doubled_text "${testdata}/g4-selectorless-input" && echo PASS || echo FAIL)" assert "seeds default to one distinct value per run" "101 202 303 404 505" \ "$(select_seeds 5 "101 202 303 404 505" >/dev/null 2>&1 && echo "${seed_list[*]}")" diff --git a/conformance/testdata/g4-selectorless-input/exit_status b/conformance/testdata/g4-selectorless-input/exit_status new file mode 100644 index 0000000..c227083 --- /dev/null +++ b/conformance/testdata/g4-selectorless-input/exit_status @@ -0,0 +1 @@ +0 \ No newline at end of file diff --git a/conformance/testdata/g4-selectorless-input/output.log b/conformance/testdata/g4-selectorless-input/output.log new file mode 100644 index 0000000..ca891a9 --- /dev/null +++ b/conformance/testdata/g4-selectorless-input/output.log @@ -0,0 +1 @@ +run complete diff --git a/conformance/testdata/g4-selectorless-input/trace.jsonl b/conformance/testdata/g4-selectorless-input/trace.jsonl new file mode 100644 index 0000000..ee509ba --- /dev/null +++ b/conformance/testdata/g4-selectorless-input/trace.jsonl @@ -0,0 +1,3 @@ +{"step": 1, "timestamp": "2026-06-06T12:00:00.600000+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": ""}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": ""}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}, "next_action": {"kind": "InputText", "text": "[redacted]"}} +{"step": 2, "timestamp": "2026-06-06T12:00:01.200000+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": "demo@folio.app"}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": ""}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}, "next_action": {"kind": "InputText", "text": "[redacted]", "selector": "testTag:LoginScreen > testTag:LoginPassword"}} +{"step": 3, "timestamp": "2026-06-06T12:00:01.800000+05:30", "hierarchy": {"elements": [{"resourceId": "LoginScreen", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginScreen", "class": "android.view.View", "text": ""}}, {"resourceId": "LoginEmail", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginEmail", "class": "android.widget.EditText", "text": "demo@folio.app"}}, {"resourceId": "LoginPassword", "class": "android.widget.EditText", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginPassword", "class": "android.widget.EditText", "text": "ledger123"}}, {"resourceId": "LoginSubmit", "class": "android.view.View", "editable": true, "bounds": {"left": 34, "top": 87, "right": 286, "bottom": 135}, "attrs": {"resource-id": "LoginSubmit", "class": "android.view.View", "text": ""}}]}} diff --git a/conformance/testdata/generate.py b/conformance/testdata/generate.py index 4fdbdb5..b17a89c 100644 --- a/conformance/testdata/generate.py +++ b/conformance/testdata/generate.py @@ -152,6 +152,17 @@ write_run( ], ) +# G4: an action typed at coordinates names no field. The step carries nothing +# the gate can check, and it may not stop the gate checking the rest. +write_run( + "g4-selectorless-input", + [ + step(1, 600, login_screen("", ""), {"kind": "InputText", "text": REDACTED}), + step(2, 600, login_screen("demo@folio.app", ""), input_action("LoginPassword")), + step(3, 600, login_screen("demo@folio.app", "ledger123")), + ], +) + # G4: the same regression on a backend that records the typed value. The driver # appended the value twice to what the field already held, so the observed value # is not its own doubling and only the recorded text reveals it.