Skip to content

[ACE-597] Maestro webview checkout regression suite#330

Open
shirly-chen-awx wants to merge 4 commits into
mainfrom
feat/ACE-597-maestro-webview-regression
Open

[ACE-597] Maestro webview checkout regression suite#330
shirly-chen-awx wants to merge 4 commits into
mainfrom
feat/ACE-597-maestro-webview-regression

Conversation

@shirly-chen-awx

@shirly-chen-awx shirly-chen-awx commented May 20, 2026

Copy link
Copy Markdown

Summary

Adds a regression suite under .maestro/WebViewCheckout/ that proves paymentacceptance-checkout-ui mounts and drives real payments correctly inside H5WebViewActivity (android.webkit.WebView).

  • flow_open_h5_webview.yaml — reusable Maestro flow: cold-launch sample app → H5 demo → load /shopping-cart in WebView.
  • test_webview_checkout_renders.yamlP0 (Maestro): asserts checkout-ui HPP mounts + Pay button (currency-formatted) visible + Google Pay tap-level smoke.
  • test_webview_card_3ds_success.shP1 (Maestro + adb): full card flow with test card 4012000300000088 (Y-Y-SUCCESS, OTP 1234) — PAN/Expiry/CVC entry → tokenization → DDC → 3DS challenge sheet → Submit → native success view with a real PaymentIntent.
  • README.md — design rationale, run instructions, iframe limitation + the adb shell input workaround, known bring-up issues.

JIRA: ACE-597.

Why P1 is a shell script, not a Maestro yaml

The original PR descoped card flow because Airwallex's card element renders PAN / Expiry / CVC in nested cross-origin iframes (PCI requirement). Investigation found:

iOS WKWebView Android WebView
Inner iframe EditText / AXTextField surfaced in a11y tree? ✅ Yes (iOS 18+) ✅ Yes
Maestro tapOn point focuses the inner field?
Maestro inputText triggers React onChange? ✅ Yes No — DOM value updates but React state stays empty, Pay stays disabled
adb shell input text (kernel-level InputConnection) triggers React onChange? (n/a) Yes — goes through IME pipeline

So iOS card flow is pure Maestro, and Android card flow is a shell script that:

  1. Uses Maestro for the navigation prologue (launch app → H5DemoActivity → tap Check out)
  2. Drops to adb shell input tap / adb shell input text for every iframe-internal interaction (PAN, Expiry, CVC, 3DS OTP, Submit)
  3. Re-dumps uiautomator between steps so coordinates stay correct as the form reflows around the soft keyboard

The same 3DS Challenge iframe (Cardinal Commerce) IS surfaced in Android's a11y tree, so the script can find the OTP input and Submit button by resource-id / text rather than by coordinate guessing.

Local test result

[card-flow] 0/8 Opening HPP via Maestro prologue
[card-flow] 1/8 Tap PAN field
[card-flow]   PAN center: (541, 1503)
[card-flow] 2/8 Tap Expiry + type 1155
...
[card-flow] 5/8 Wait for 3DS challenge to load
[card-flow]   3DS challenge visible after 2s
[card-flow] 6/8 Type OTP 1234 into challenge
[card-flow] 7/8 Tap Submit
[card-flow] 8/8 Wait for native success view
[card-flow]   Native success view visible after 2s

================ CARD FLOW PASS ================
  Test card:    4012000300000088
  3DS OTP:      1234
================================================

Real PaymentIntent generated: int_hkdmpt4f9hip47fh6au. Verification screenshots (card fields filled / 3DS challenge / native success) attached to ACE-597.

Test plan

  • maestro check-syntax clean on all yaml files
  • Shell script is set -euo pipefail, idempotent across re-runs (cold-launches the app)
  • test_webview_checkout_renders.yaml: 4/5 green on Pixel 6 / API 34 (1 transient network fail, fixed via timeout bump)
  • test_webview_card_3ds_success.sh: 2/2 green on Pixel 6 / API 34 (~210s, real PI generated)
  • iOS mirror ([APAM-602] Filter Google Pay for CIT recurring consent creation #277) — pure Maestro yaml, same scenarios
  • Reviewer: confirm Maestro CLI installation guidance in README matches your environment
  • Reviewer: confirm Android-specific adb workaround design (vs e.g. building a JS bridge into the sample app)

Notes for reviewer

  • .gitignore change ignores Maestro's takeScreenshot output webview_checkout_renders.png written to the repo root.
  • No changes to sample app source, no schema/codegen impact.
  • CI wiring is intentionally out of scope (manual_first per ticket); each test can be invoked from a one-liner job.
  • Pre-reqs to run P1 locally: emulator booted, sample app installed, adb + maestro in PATH. No API keys needed.

Adds a Maestro suite under `.maestro/WebViewCheckout/` that proves
paymentacceptance-checkout-ui mounts correctly inside H5WebViewActivity
(android.webkit.WebView). Locally green 4/5 runs on Pixel 6 / Android 34
emulator.

The card form / 3DS / digital wallet end-to-end paths are intentionally
out of scope here: Airwallex's card element renders inputs in nested
cross-origin iframes, which Android WebView's accessibility tree does
not surface — so Maestro cannot reach them. Those flows are covered by
paymentacceptance-fe-automation-test (Playwright) under mobile-chrome.
This suite owns the webview-specific risk: does checkout-ui mount and
initialize at all? Both READMEs explain the limitation and three
options for unblocking full card-flow automation in the future.

JIRA: https://airwallex.atlassian.net/browse/ACE-597
Co-authored-by: Cursor <cursoragent@cursor.com>
shirly-chen-awx and others added 3 commits May 20, 2026 11:44
Extends the P0 with a tap-level smoke test for the Google Pay button:
asserts the button is present, tappable, and that checkout-ui's onClick
handler runs without crashing the WebView (post-condition checks the
HPP element is still mounted afterwards).

Confirmed via `adb logcat` that the chromium console fires the
`button_name=google_pay` click analytics event, proving the
PaymentRequest bridge is wired. Native sheet doesn't open on this AVD
because `google_apis` system-image lacks Google Wallet — README docs
the `google_apis_playstore` setup to extend coverage to the native
sheet level.

Also bumps the `Order Information` extendedWaitUntil timeout from 60s
to 90s after observing Cloudflare CDN re-route through 3G/HSPA paths
with 75% packet loss on the emulator's cellular interface.

JIRA: https://airwallex.atlassian.net/browse/ACE-597
Co-authored-by: Cursor <cursoragent@cursor.com>
Investigated the native GPay sheet path empirically on both
google_apis and google_apis_playstore AVDs. Confirmed:
- canMakePayment() returns true in both
- checkout-ui's onClick handler fires the analytics event in both
- sheet only opens when (a) playstore AVD + (b) Google account
  signed in + (c) Google Wallet installed with a tokenized test
  card from developers.google.com/pay test-card-suite

None of those are reproducible on shared CI without baking a
custom AVD image with pre-seeded credentials, so the regression
stays at tap-level smoke. README now lists the exact 4-step
provisioning recipe + the 4-line yaml extension to assert sheet
appearance once PA stands up dedicated mobile CI hardware.

JIRA: https://airwallex.atlassian.net/browse/ACE-597
Co-authored-by: Cursor <cursoragent@cursor.com>
Android card flow runs the test card 4012000300000088 (Y-Y-SUCCESS, OTP
1234) end-to-end inside the native WebView -- PAN/Expiry/CVC entry ->
tokenization -> DDC -> 3DS challenge sheet -> Submit -> native success
view with a real PaymentIntent (int_hkdmpt4f9hip47fh6au).

Implemented as a shell script (test_webview_card_3ds_success.sh) rather
than a Maestro yaml, because Maestro's inputText action on Android
WebView updates the iframe DOM value but does NOT trigger React's
onChange event for inputs inside the PCI cross-origin iframes
(checkout.airwallex.com). The DOM looks filled but checkout-ui's
controlled-input state stays empty, so validation fails and Pay stays
disabled.

`adb shell input text` (raw kernel-level InputConnection events) routes
through the IME pipeline and does trigger onChange correctly, so the
script:

  1. Uses Maestro for the navigation prologue (launch app ->
     H5DemoActivity -> tap Check out).
  2. Drops to `adb shell input tap` / `adb shell input text` for every
     iframe-internal interaction (PAN/Expiry/CVC, 3DS OTP, Submit).
  3. Re-dumps `uiautomator` between steps so coordinates stay correct
     as the form reflows around the soft keyboard.

README updated with:
- coverage table flipped to ✅ for card / 3DS / native success rows
- new "Iframe limitation & the `adb shell input` workaround" section
  documenting the Maestro inputText limitation and the iOS/Android
  behaviour diff
- run instructions for the new P1 test
- timing + stability stats (2/2 green, ~210s wall time)

JIRA: ACE-597
Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant