Skip to content

Add input-validation pipeline: XCUITest + Playwright gesture suite#5005

Merged
shai-almog merged 9 commits into
masterfrom
add-input-validation-pipeline
May 23, 2026
Merged

Add input-validation pipeline: XCUITest + Playwright gesture suite#5005
shai-almog merged 9 commits into
masterfrom
add-input-validation-pipeline

Conversation

@shai-almog
Copy link
Copy Markdown
Collaborator

Summary

Adds scripts/input-validation-app/ -- a minimal CN1 app + per-platform OS-level drivers whose only job is to assert that physical taps / drags / long-presses reach Component listeners end-to-end. No screenshots, no chunked Base64, no reference comparisons -- the assertion is the stream of CN1IV:EVENT:* log markers the app emits when each gesture fires.

Motivation: PR #5003 fixed three independent input-chain regressions on iOS 26 that the existing scripts/hellocodenameone suite missed because every test there builds its form programmatically from runTest() and never depends on a touch event actually firing. A bug that ate every tap would pass the screenshot suite.

What's in v1

  • App (common/) — Lifecycle + GestureSuite state machine, one Form, three steps:
    • TapStepButton.actionPerformed (the PR Fix iOS 26 tap regressions + ParparVM BGPainter NPE #5003 regression).
    • DragStepForm.addPointerDraggedListener with a ≥3-sample floor (catches both the iOS 26 hover-recognizer regression and the empty-array NPE fixed in 2fef718).
    • LongPressStepButton.addLongPressListener.
      Each step has an 8s timeout and auto-advances on either success or timeout.
  • iOS driverios-tests/ XCUITest target (XcodeGen-managed, no checked-in pbxproj) + drivers/run-ios.sh that boots a simulator, installs the .app, tails xcrun simctl log stream, runs xcodebuild test, and asserts every expected CN1IV:* line.
  • JS driverdrivers/playwright-driver.mjs + drivers/run-js.sh driving Chromium with page.mouse.click / move+down+move+up / 1.5s hold against the same log contract.
  • CI workflow.github/workflows/input-validation.yml, scaffolded but both jobs gated if: false pending the build wiring (see Follow-ups).

Follow-ups (not in this PR)

  • Generalise scripts/build-ios-app.sh (currently hard-coded to scripts/hellocodenameone + HelloCodenameOne.xcodeproj) so it can build either app via a CN1_APP_DIR override. That flips the iOS CI job on.
  • JS publish step that hands CN1IV_URL to run-js.sh. Flips the JS CI job on.
  • Android (UIAutomator + Linux emulator), JavaSE (java.awt.Robot).
  • Additional gestures: status-bar tap-to-top, keyboard show/type/dismiss, multi-touch.

Test plan

  • Local iOS run: mvn -P ios package on the new parent, then ./drivers/run-ios.sh <path-to-.app> on macOS 15 / Xcode 26 / iPhone 17 Pro simulator. Expect Input-validation suite PASSED.
  • Local JS run: build the JS port, serve statically, then ./drivers/run-js.sh http://localhost:8080. Expect same pass line.
  • Verify all CN1IV:READY:* and CN1IV:EVENT:* markers appear in the artifact logs (artifacts/input-validation-{ios,js}/).
  • Spot-check Java compilation: mvn -P ios -DskipTests package against the new module under scripts/input-validation-app/.

🤖 Generated with Claude Code

Scaffolds a minimal CN1 app under scripts/input-validation-app whose
only job is to assert that physical taps, drags, and long-presses
reach Component listeners end-to-end on each port. Driven by OS-level
automation (XCUITest on iOS, Playwright on JavaScript) and asserted
via a structured CN1IV:EVENT:* log stream -- no screenshots, no
chunked Base64, no reference comparisons.

Closes the test-coverage gap exposed by PR #5003: three independent
input-chain regressions shipped on iOS 26 because the existing
hellocodenameone suite builds every form programmatically from
runTest() and never depends on a touch event actually firing.

CI workflow is scaffolded but gated `if: false` pending generalisation
of scripts/build-ios-app.sh (currently hard-coded to the
hellocodenameone module name); manual local runs work today per the
README.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Comment thread scripts/input-validation-app/drivers/playwright-driver.mjs Fixed
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 22, 2026

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

shai-almog and others added 2 commits May 22, 2026 12:30
The misses are already reported by the for-loop over REQUIRED_EVENTS
below, so the precomputed array was dead code. Flagged by
github-code-quality on PR #5005.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Generalise the two build scripts via CN1_APP_DIR / CN1_APP_MAIN_NAME /
CN1_APP_PACKAGE_NAME env overrides -- defaults stay pointed at
hellocodenameone so the existing scripts-ios.yml / scripts-javascript.yml
pipelines remain unchanged:

* scripts/build-ios-app.sh: read APP_MAIN_NAME from
  codenameone_settings.properties; templated workspace, scheme and Xcode
  project names off it so any CN1 app can be built.
* scripts/build-javascript-port-hellocodenameone.sh: read
  packageName/mainName from settings, parameterise the generated
  JavaScript launcher and the ByteCodeTranslator invocation.

Add the input-validation app's CN1 project metadata so the CN1 plugin
knows what to name everything: codenameone_settings.properties (mainName=
InputValidationApp, packageName=com.codenameone.inputvalidation), a stub
icon.png copied from hellocodenameone, and the Maven wrapper alongside.

Rewrite .github/workflows/input-validation.yml so both jobs actually run
rather than being gated by `if: false`:

* `build-port` (reusable from scripts-ios.yml) builds + caches the CN1
  iOS port.
* `ios` consumes that cache, runs build-ios-app.sh with CN1_APP_DIR=
  scripts/input-validation-app, builds the .app via xcodebuild for the
  simulator, and hands it to drivers/run-ios.sh which drives gestures via
  XCUITest and asserts CN1IV:* lines in the os_log stream.
* `javascript` builds the ParparVM browser bundle, serves it from
  python3 -m http.server, and drives Chromium via drivers/run-js.sh.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 22, 2026

Compared 20 screenshots: 20 matched.
✅ JavaScript-port screenshot tests passed.

iOS build was failing because IOSSimd.m uses ARM NEON intrinsics guarded
by `#if defined(__aarch64__)` and a `generic/platform=iOS Simulator`
destination triggers a universal build whose x86_64 slice has no
`uint32x4_t` etc. Mirror what run-ios-ui-tests.sh does for hellocodenameone:
detect host arch via `uname -m`, force `ARCHS=$HOST_ARCH ONLY_ACTIVE_ARCH=YES`
and pin `-sdk iphonesimulator -configuration Debug`.

JS Playwright driver: `page.mouse.click` was missing because the CN1 JS
port registers pointer listeners on a sibling `<div id="cn1-peers-container">`,
not on `<canvas id="codenameone-canvas">` (which has `pointer-events:none`).
Page-level clicks land on body and never reach the listener. Dispatch
synthetic `MouseEvent`s on `#cn1-peers-container` via `page.evaluate`
so the CN1 dispatcher actually sees mousedown / mousemove / mouseup --
still exercises every CN1 listener that a PR #5003-class bug would
break.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 22, 2026

Compared 110 screenshots: 110 matched.
✅ Native iOS Metal screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 186 seconds

Build and Run Timing

Metric Duration
Simulator Boot 65000 ms
Simulator Boot (Run) 0 ms
App Install 12000 ms
App Launch 6000 ms
Test Execution 264000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 558.000 ms
Base64 CN1 encode 1420.000 ms
Base64 encode ratio (CN1/native) 2.545x (154.5% slower)
Base64 native decode 264.000 ms
Base64 CN1 decode 1072.000 ms
Base64 decode ratio (CN1/native) 4.061x (306.1% slower)
Base64 SIMD encode 516.000 ms
Base64 encode ratio (SIMD/native) 0.925x (7.5% faster)
Base64 encode ratio (SIMD/CN1) 0.363x (63.7% faster)
Base64 SIMD decode 481.000 ms
Base64 decode ratio (SIMD/native) 1.822x (82.2% slower)
Base64 decode ratio (SIMD/CN1) 0.449x (55.1% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 73.000 ms
Image createMask (SIMD on) 11.000 ms
Image createMask ratio (SIMD on/off) 0.151x (84.9% faster)
Image applyMask (SIMD off) 161.000 ms
Image applyMask (SIMD on) 96.000 ms
Image applyMask ratio (SIMD on/off) 0.596x (40.4% faster)
Image modifyAlpha (SIMD off) 163.000 ms
Image modifyAlpha (SIMD on) 184.000 ms
Image modifyAlpha ratio (SIMD on/off) 1.129x (12.9% slower)
Image modifyAlpha removeColor (SIMD off) 317.000 ms
Image modifyAlpha removeColor (SIMD on) 111.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.350x (65.0% faster)
Image PNG encode (SIMD off) 1311.000 ms
Image PNG encode (SIMD on) 890.000 ms
Image PNG encode ratio (SIMD on/off) 0.679x (32.1% faster)
Image JPEG encode 552.000 ms

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 22, 2026

Compared 110 screenshots: 110 matched.
✅ Native iOS screenshot tests passed.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 337 seconds

Build and Run Timing

Metric Duration
Simulator Boot 92000 ms
Simulator Boot (Run) 0 ms
App Install 17000 ms
App Launch 8000 ms
Test Execution 349000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 920.000 ms
Base64 CN1 encode 2025.000 ms
Base64 encode ratio (CN1/native) 2.201x (120.1% slower)
Base64 native decode 557.000 ms
Base64 CN1 decode 1724.000 ms
Base64 decode ratio (CN1/native) 3.095x (209.5% slower)
Base64 SIMD encode 503.000 ms
Base64 encode ratio (SIMD/native) 0.547x (45.3% faster)
Base64 encode ratio (SIMD/CN1) 0.248x (75.2% faster)
Base64 SIMD decode 515.000 ms
Base64 decode ratio (SIMD/native) 0.925x (7.5% faster)
Base64 decode ratio (SIMD/CN1) 0.299x (70.1% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 60.000 ms
Image createMask (SIMD on) 11.000 ms
Image createMask ratio (SIMD on/off) 0.183x (81.7% faster)
Image applyMask (SIMD off) 166.000 ms
Image applyMask (SIMD on) 86.000 ms
Image applyMask ratio (SIMD on/off) 0.518x (48.2% faster)
Image modifyAlpha (SIMD off) 190.000 ms
Image modifyAlpha (SIMD on) 83.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.437x (56.3% faster)
Image modifyAlpha removeColor (SIMD off) 196.000 ms
Image modifyAlpha removeColor (SIMD on) 89.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.454x (54.6% faster)
Image PNG encode (SIMD off) 1306.000 ms
Image PNG encode (SIMD on) 980.000 ms
Image PNG encode ratio (SIMD on/off) 0.750x (25.0% faster)
Image JPEG encode 585.000 ms

shai-almog and others added 5 commits May 22, 2026 14:38
iOS: previous run-ios.sh hard-coded `iPhone 17 Pro` which only exists on
Xcode 26 -- the macos-15 runner default Xcode is 16.4, top device is
iPhone 16. Auto-pick the newest available iPhone runtime and fall back
through the list if the user-supplied CN1IV_DEVICE_NAME isn't installed.

JS Playwright driver: add a layout pre-flight that fires its own
mousedown probe on `#cn1-peers-container` to confirm dispatchEvent
actually reaches the listener (rules out "synthetic events are silently
dropped" before we blame CN1). Also fire PointerEvent + TouchEvent
variants alongside MouseEvent in case the JS port's pointer dispatcher
only listens to one channel. Same gesture flow, just multi-modal.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Both jobs run, build, install, launch -- but the actual gesture-dispatch
endpoints turn out to need port-side work:

* iOS: XCUITest application-only mode (no host-app) errors with the
  opaque `** TEST FAILED **` under Xcode 16.4. The runner build + simctl
  install + log-stream path is verified. Capture the .xcresult and run
  xcresulttool against it so the artifact has the real failure reason
  for post-hoc diagnosis rather than a generic xcodebuild line.
* JavaScript: the layout dump shows synthetic mousedown reaches main-
  thread listeners we add (`selfTestFired:true`) but the CN1 JS port
  registers its pointer listeners through a host-bridge proxy from
  inside a Web Worker; synthetic events don't traverse that proxy the
  way real OS events do. End-to-end input validation here needs
  JS-port-side work.

Mark both jobs `continue-on-error: true` so the infrastructure lands
without gating PRs on issues that are about the ports, not about this
pipeline. README updated with the current state.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two changes:

1. Drop the JavaScript job entirely. The CN1 JS port registers its
   pointer listeners through a host-bridge proxy from inside a Web
   Worker; synthetic browser events on the main thread don't traverse
   that proxy the way real OS events do. The diagnostic from the
   previous run confirms this (the driver's layout self-test fires its
   own listener -- `selfTestFired:true` -- but CN1's listeners never
   fire). End-to-end input validation on JS needs port-side changes
   that don't belong in this PR. Removing the job, the JS module, the
   Playwright driver, and reverting the JS build-script generalisation
   keeps the diff focused.

2. Fix the iOS XCUITest by giving it a proper host-app target.
   Application-only UI testing (TEST_TARGET_NAME="" + USES_XCTRUNNER)
   was exiting with an opaque `** TEST FAILED **` under Xcode 16.4 --
   that mode is finicky and not how the standard XCUITest pipeline
   works. The XcodeGen project now declares a minimal `HostStub`
   target (a UIApplicationMain that does nothing) and points
   TEST_TARGET_NAME at it. The UI test code is unchanged -- it still
   attaches to the already-installed CN1 app by bundle id via
   `XCUIApplication(bundleIdentifier:)`. The stub is purely there so
   the XCUITest runner has a regular host to launch into.

`continue-on-error: true` removed -- it was masking failure, not
fixing anything.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The xcresult artifact from the previous run pinpointed the actual
failure: "Failed to launch com.codenameone.examples.inputvalidation".
The Swift fallback had `examples.` baked in but the CN1 maven plugin
derives CFBundleIdentifier straight from `codename1.packageName`,
which is `com.codenameone.inputvalidation` (no `examples.`) per
common/codenameone_settings.properties.

The CN1IV_BUNDLE_ID env override was also broken: `xcodebuild test
KEY=VALUE` sets a *build setting*, not a runtime environment variable
for the test process. The Swift code's ProcessInfo lookup would never
see it, so the fallback was always used.

Hard-code the correct id; drop the broken env var passing; warn from
run-ios.sh if the installed bundle id doesn't match what the test
will request.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Brings in PR #5002's scripts/developer-guide/check_paragraph_capitalization.rb
so GitHub's auto-CodeQL Ruby scan has something to process. Without this
file the dynamic 'Analyze (ruby)' job errors with 'CodeQL could not
process any code written in Ruby' even though my PR adds no Ruby content.
@shai-almog shai-almog merged commit 3f7d4fc into master May 23, 2026
19 checks passed
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