Repository navigation
JSON mapping: codecs, creators, generics, arrays and null semantics #10477
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Test JavaScript screenshot scripts | |
| on: | |
| # Manual dispatch: this PR's changed-file count exceeds GitHub's paths-filter | |
| # diff limit, so pull_request triggers stopped firing -- dispatch with | |
| # gh workflow run <file> --ref <branch> | |
| workflow_dispatch: | |
| inputs: | |
| port_status_browser_evidence: | |
| description: Run only the Port Status browser evidence matrix | |
| required: false | |
| default: false | |
| type: boolean | |
| schedule: | |
| - cron: '35 1 * * *' | |
| pull_request: | |
| paths: | |
| # The application these jobs build compiles a Unity project, from an | |
| # archive that unity-gallery-prebuilt.yml makes out of these. | |
| - 'scripts/unity-compat-samples/gallery/**' | |
| - 'maven/cil-translator/**' | |
| - 'maven/unity-compat/**' | |
| - 'maven/build-engine/src/main/java/com/codename1/maven/Unity*' | |
| - 'maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/*Unity*' | |
| - 'scripts/unity-gallery-prebuilt.sh' | |
| - '.github/workflows/unity-gallery-prebuilt.yml' | |
| - '.github/actions/unity-gallery-prebuilt/**' | |
| - 'scripts/ci/retry.sh' | |
| - '.github/workflows/scripts-javascript.yml' | |
| - 'scripts/run-javascript-browser-tests.sh' | |
| - 'scripts/run-javascript-screenshot-tests.sh' | |
| - 'scripts/run-javascript-headless-browser.mjs' | |
| - 'scripts/run-javascript-lifecycle-tests.mjs' | |
| - 'scripts/test-javascript-surface-replay.mjs' | |
| - 'scripts/test-javascript-weak-refs.mjs' | |
| - 'scripts/test-javascript-native-stub-bindings.mjs' | |
| - 'scripts/ci/tests/cn1ss-async-sink-test.sh' | |
| - 'scripts/ci/tests/Cn1ssAsyncSinkTest.java' | |
| - 'scripts/fidelity-app/common/src/main/java/com/codenameone/fidelity/Cn1ssAsyncSink.java' | |
| - 'scripts/test-javascript-vault-bridge.mjs' | |
| - 'scripts/test-javascript-composited-rendering.mjs' | |
| - 'scripts/javascript/composited-app/**' | |
| - 'vm/ByteCodeTranslator/src/javascript/browser_bridge.js' | |
| - 'scripts/run-javascript-lifecycle-tests.sh' | |
| - 'scripts/verify-javascript-lens-parity.mjs' | |
| - 'scripts/build-javascript-port-hellocodenameone.sh' | |
| - 'scripts/javascript_browser_harness.py' | |
| - 'scripts/javascript/screenshots/**' | |
| - 'scripts/lib/cn1ss.sh' | |
| - 'scripts/common/java/**' | |
| - 'scripts/hellocodenameone/**' | |
| - 'CodenameOne/src/**' | |
| - '!CodenameOne/src/**/*.md' | |
| - 'Ports/JavaScriptPort/**' | |
| - 'vm/**' | |
| - 'maven/**' | |
| - '!maven/core-unittests/**' | |
| - '!docs/**' | |
| # The screenshot transport is now a Codename One backend application, so the | |
| # two files that are ONLY exercised here have to trigger this leg: the | |
| # server itself and the script that launches it. | |
| # | |
| # Deliberately NOT the rest of vm/backend. The websocket protocol code is | |
| # covered by maven/backend's unit tests, by vm/tests against the translated | |
| # binary, and by the Autobahn conformance job -- all of which already | |
| # trigger on vm/**. Fanning every backend change out to the macOS and | |
| # emulator legs as well would buy nothing and cost a great deal: a change to | |
| # the ORM, the database layer or the HTTP parser cannot reach this | |
| # transport. | |
| - 'scripts/hellocodenameone/backend/**' | |
| push: | |
| branches: [ master ] | |
| paths: | |
| # The application these jobs build compiles a Unity project, from an | |
| # archive that unity-gallery-prebuilt.yml makes out of these. | |
| - 'scripts/unity-compat-samples/gallery/**' | |
| - 'maven/cil-translator/**' | |
| - 'maven/unity-compat/**' | |
| - 'maven/build-engine/src/main/java/com/codename1/maven/Unity*' | |
| - 'maven/codenameone-maven-plugin/src/main/java/com/codename1/maven/*Unity*' | |
| - 'scripts/unity-gallery-prebuilt.sh' | |
| - '.github/workflows/unity-gallery-prebuilt.yml' | |
| - '.github/actions/unity-gallery-prebuilt/**' | |
| - 'scripts/ci/retry.sh' | |
| - '.github/workflows/scripts-javascript.yml' | |
| - 'scripts/run-javascript-browser-tests.sh' | |
| - 'scripts/test-javascript-composited-rendering.mjs' | |
| - 'scripts/javascript/composited-app/**' | |
| - 'scripts/run-javascript-screenshot-tests.sh' | |
| - 'scripts/run-javascript-headless-browser.mjs' | |
| - 'scripts/run-javascript-lifecycle-tests.mjs' | |
| - 'scripts/test-javascript-surface-replay.mjs' | |
| - 'scripts/test-javascript-weak-refs.mjs' | |
| - 'scripts/test-javascript-native-stub-bindings.mjs' | |
| - 'scripts/ci/tests/cn1ss-async-sink-test.sh' | |
| - 'scripts/ci/tests/Cn1ssAsyncSinkTest.java' | |
| - 'scripts/fidelity-app/common/src/main/java/com/codenameone/fidelity/Cn1ssAsyncSink.java' | |
| - 'scripts/run-javascript-lifecycle-tests.sh' | |
| - 'scripts/verify-javascript-lens-parity.mjs' | |
| - 'scripts/build-javascript-port-hellocodenameone.sh' | |
| - 'scripts/javascript_browser_harness.py' | |
| - 'scripts/javascript/screenshots/**' | |
| - 'scripts/lib/cn1ss.sh' | |
| - 'scripts/common/java/**' | |
| - 'scripts/hellocodenameone/**' | |
| - 'CodenameOne/src/**' | |
| - '!CodenameOne/src/**/*.md' | |
| - 'Ports/JavaScriptPort/**' | |
| - 'vm/**' | |
| - 'maven/**' | |
| - '!maven/core-unittests/**' | |
| - '!docs/**' | |
| # The screenshot transport is now a Codename One backend application, so the | |
| # two files that are ONLY exercised here have to trigger this leg: the | |
| # server itself and the script that launches it. | |
| # | |
| # Deliberately NOT the rest of vm/backend. The websocket protocol code is | |
| # covered by maven/backend's unit tests, by vm/tests against the translated | |
| # binary, and by the Autobahn conformance job -- all of which already | |
| # trigger on vm/**. Fanning every backend change out to the macOS and | |
| # emulator legs as well would buy nothing and cost a great deal: a change to | |
| # the ORM, the database layer or the HTTP parser cannot reach this | |
| # transport. | |
| - 'scripts/hellocodenameone/backend/**' | |
| concurrency: | |
| # Only the latest revision needs validation. PR numbers keep forks isolated; | |
| # event names keep a manual/scheduled run from cancelling a push or PR run. | |
| group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| # The application has a Unity project in it. One Linux job compiles it and | |
| # hands the result to the jobs below as an artifact; none of them installs | |
| # the .NET SDK or builds the Unity modules. | |
| unity-gallery: | |
| if: ${{ !inputs.port_status_browser_evidence }} | |
| uses: ./.github/workflows/unity-gallery-prebuilt.yml | |
| javascript-screenshots: | |
| needs: unity-gallery | |
| if: ${{ !inputs.port_status_browser_evidence }} | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| issues: write | |
| runs-on: ubuntu-24.04 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.CN1SS_GH_TOKEN }} | |
| # The device runner reports logical test failures through CN1SS log | |
| # markers, not through the build or the screenshot comparison. Make the | |
| # normalized report authoritative so a failing or never-run compliance | |
| # test cannot leave this workflow green and then be published from master. | |
| CN1SS_FAIL_ON_TEST_PROBLEMS: '1' | |
| GH_TOKEN: ${{ secrets.CN1SS_GH_TOKEN }} | |
| ARTIFACTS_DIR: ${{ github.workspace }}/artifacts/javascript-ui-tests | |
| # CN1_JS_TIMEOUT_SECONDS guards the per-suite SUITE:FINISHED wait. | |
| # Bumped from 720s to 1200s after merging master's #4875 chunk-emit | |
| # fix and removing the ``jsChunkDrop`` skip block in port.js: with | |
| # the previously-silent graphics / chart / kotlin / mainscreen / | |
| # transition tests now actually rendering and emitting full PNG | |
| # streams instead of being dropped, the 73-test suite walks at | |
| # ~10 s/test on shared GHA runners and lands 12-17 min wall-clock | |
| # depending on canvas-accumulation pressure later in the run. The | |
| # 720s budget was too tight: comparison-step runs succeed at 12-14 | |
| # min but SUITE:FINISHED-wait runs that race the bottom of the | |
| # suite were timing out before any tests could be diff'd. 1200s | |
| # absorbs the variance without re-introducing the | |
| # silently-dropped-test workaround. | |
| # 1800 -> 2400: un-skipping the StickyHeader (x3) + StatusBar grid | |
| # composites (now that WebSocket transport handles their large payloads) | |
| # adds wall-clock; 2400 absorbs the extra tests plus the cross-recovery | |
| # retry overhead. | |
| CN1_JS_TIMEOUT_SECONDS: "2400" | |
| CN1_JS_BROWSER_LIFETIME_SECONDS: "2340" | |
| CN1SS_SKIP_COVERAGE: "1" | |
| CN1SS_FAIL_ON_MISMATCH: "1" | |
| # Strict, matching the native ports. The "variable tail of dropped | |
| # screenshots" that previously forced a tolerance of 20 was the | |
| # canvas-accumulation root cause: browser_bridge.js retained every host | |
| # canvas forever, so by ~test 66 the main thread thrashed, capture | |
| # stalled and the suite re-dispatched. That leak is fixed (dead canvas | |
| # host-refs are now released on the worker GC signal), so the suite | |
| # delivers every screenshot deterministically -- a missing capture is a | |
| # real regression again. Keep at 0 like Android/JavaSE. Assertion failures | |
| # are separate from screenshot coverage and must never be tolerated here. | |
| CN1SS_ALLOWED_MISSING: "0" | |
| BROWSER_CMD: "node \"$GITHUB_WORKSPACE/scripts/run-javascript-headless-browser.mjs\"" | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Set TMPDIR | |
| run: echo "TMPDIR=${{ runner.temp }}" >> $GITHUB_ENV | |
| # Milliseconds, no browser and no bundle, so it runs before the build | |
| # rather than after a 20-minute suite. Guards the surface command replay: | |
| # one undrawable image source used to throw and take every op behind it | |
| # in that batch with it, which is what truncated graphics-draw-image-rect | |
| # intermittently. | |
| # | |
| # Deliberately ahead of "Set up Node 20": it uses only node: builtins | |
| # (fs/path/url/vm), so the runner image's preinstalled Node runs it, and | |
| # placing it here means a broken guard fails in seconds instead of after | |
| # the ParparVM build. | |
| - name: Surface command replay guards | |
| run: node scripts/test-javascript-surface-replay.mjs | |
| # Same placement rationale: node: builtins only, so it runs before the | |
| # ParparVM build and fails in seconds. Guards createSoftWeakRef / | |
| # extractHardRef in port.js -- the token has to be a real WeakRef, because | |
| # the WeakMap it used to be held its referent as the map VALUE, which is a | |
| # strong edge and made every "weak" cache in the framework unreclaimable. | |
| - name: Weak reference guards | |
| run: node scripts/test-javascript-weak-refs.mjs | |
| # A static interop factory (JSString.valueOf, Int32Array.create, ...) runs | |
| # its Java body -- `return null;` -- unless port.js binds it; an unbound | |
| # JSString.valueOf made every directory marker a delete. | |
| - name: Interop stub bindings | |
| run: node scripts/test-javascript-native-stub-bindings.mjs | |
| # Plain JVM, no build, so it also runs ahead of the ParparVM build. The | |
| # sink the Java-side captures ship through must redial after the test | |
| # server sheds its idle socket (close 1006): latching "failed" on that | |
| # close lost VideoIODecodedFrames with websocket-unavailable. | |
| - name: CN1SS async sink reconnect | |
| run: bash scripts/ci/tests/cn1ss-async-sink-test.sh | |
| - name: Cache codenameone-tools | |
| uses: actions/cache@v5 | |
| with: | |
| path: ${{ runner.temp }}/codenameone-tools | |
| key: ${{ runner.os }}-cn1-tools-${{ hashFiles('scripts/setup-workspace.sh') }} | |
| restore-keys: | | |
| ${{ runner.os }}-cn1-tools- | |
| - name: Set up Java 8 for ParparVM | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '8' | |
| cache: 'maven' | |
| # build.sh requires a JDK 8 BY NAME, and the Java 17 setup below replaces | |
| # JAVA_HOME -- so the value has to be captured while it is still correct. | |
| - name: Record JDK 8 for the native screenshot server | |
| run: echo "JDK_8_HOME=$JAVA_HOME" >> "$GITHUB_ENV" | |
| - name: Prepare Codename One binaries for Maven plugin | |
| run: | | |
| mkdir -p ~/.codenameone | |
| cp maven/UpdateCodenameOne.jar ~/.codenameone/ | |
| - name: Build ParparVM compiler bundle | |
| run: bash $GITHUB_WORKSPACE/scripts/ci/retry.sh mvn -B -f maven/pom.xml -pl parparvm -am -DskipTests -Dmaven.javadoc.skip=true package | |
| - name: Set up Java 17 | |
| uses: actions/setup-java@v5 | |
| with: | |
| distribution: 'temurin' | |
| java-version: '17' | |
| cache: 'maven' | |
| - name: Set up Node 20 | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: '20' | |
| - name: Verify JavaScript glass-tab lens parity | |
| run: node scripts/verify-javascript-lens-parity.mjs | |
| - name: Cache npm modules for scripts/ | |
| uses: actions/cache@v5 | |
| with: | |
| path: scripts/node_modules | |
| key: ${{ runner.os }}-scripts-npm-${{ hashFiles('scripts/package-lock.json') }} | |
| restore-keys: | | |
| ${{ runner.os }}-scripts-npm- | |
| - name: Cache Playwright browsers | |
| id: playwright-cache | |
| uses: actions/cache@v5 | |
| with: | |
| path: ~/.cache/ms-playwright | |
| key: ${{ runner.os }}-playwright-chromium-firefox-${{ hashFiles('scripts/package-lock.json') }} | |
| restore-keys: | | |
| ${{ runner.os }}-playwright- | |
| - name: Install Playwright Chromium | |
| run: | | |
| cd scripts | |
| npm ci | |
| # OS-level deps (apt packages) aren't cached so always install them. | |
| # Playwright shells out to apt for the OS-level deps, so the runner | |
| # image's third-party sources have to be pruned FIRST -- a broken | |
| # vendor mirror makes its apt-get fail as a whole and it reports | |
| # only "Failed to install browser dependencies". | |
| bash "$GITHUB_WORKSPACE/scripts/ci/apt-get-update.sh" | |
| npx playwright install-deps chromium firefox | |
| # Install the browser revisions selected by the committed lockfile; | |
| # a restored fallback cache may contain a different revision. | |
| npx playwright install chromium | |
| # Firefox for the composited rendering check below: issue #5910 was reported | |
| # from Firefox, and the two engines composite the canvas and the text layer | |
| # differently enough that one passing says little about the other. | |
| npx playwright install firefox | |
| # Placed here, before the workspace build, because it needs nothing from | |
| # it: the vault bridge is sliced straight out of browser_bridge.js and run | |
| # in a page. That also means a failure here is unambiguous -- it is the | |
| # bridge, not the bundle. | |
| # | |
| # This is the only coverage the WebAuthn PRF path has anywhere. It needs an | |
| # authenticator and a user, which no unit test can supply; Chrome's virtual | |
| # authenticator over the DevTools protocol supplies both. The Node test in | |
| # vm/tests covers the same bridge against a stub IndexedDB and cannot reach | |
| # any of the passkey code. | |
| - name: Vault bridge in a real browser (IndexedDB, Web Crypto, WebAuthn PRF) | |
| run: node scripts/test-javascript-vault-bridge.mjs | |
| # No virtual display for the Maven steps below: they only build, and the | |
| # css goal compiles theme.css headless. The browsers the tests drive are | |
| # launched headless by their own scripts. | |
| - name: Setup workspace | |
| run: ./scripts/setup-workspace.sh -q -DskipTests | |
| # After everything that fills the local Maven repository and before the | |
| # application is built; this job has no .NET SDK (see the action). | |
| - name: Unpack the Unity gallery prebuilt | |
| uses: ./.github/actions/unity-gallery-prebuilt | |
| - name: Build HelloCodenameOne JavaScript port bundle | |
| run: | | |
| # Use JAVA_HOME set by actions/setup-java for Java 17 | |
| # (JAVA_HOME_17_X64 is always available after setup-java@v4) | |
| export JAVA_HOME="${JAVA_HOME_17_X64}" | |
| export PATH="$JAVA_HOME/bin:$PATH" | |
| echo "Using JAVA_HOME=$JAVA_HOME" | |
| java -version | |
| SKIP_PARPARVM_BUILD=1 ./scripts/build-javascript-port-hellocodenameone.sh "${GITHUB_WORKSPACE}/artifacts/javascript-ui-tests/hellocodenameone-javascript-port.zip" | |
| # What the screenshot suite cannot see. Its capture reads the app's canvas back, which | |
| # suspends the DOM text layer, so it never looks at the page a browser shows -- and | |
| # issues #5910 (toolbar scrolled away, dialog over a blank page) and #5912 (a phone could | |
| # not scroll or tap) came back more than once while it stayed green. This builds the app | |
| # those issues were reported against through the Maven plugin, as a user's project is | |
| # built, and drives it with real wheel, mouse and touch input in Chromium and Firefox. | |
| - name: Composited rendering and input (Chromium, Firefox, phone emulation) | |
| run: | | |
| set -euo pipefail | |
| export JAVA_HOME="${JAVA_HOME_17_X64}" | |
| export PATH="$JAVA_HOME/bin:$PATH" | |
| (cd scripts/javascript/composited-app && mvn -B package -DskipTests \ | |
| -Dcodename1.platform=javascript -Dcodename1.buildTarget=local-javascript) | |
| bundle_dir="${RUNNER_TEMP}/composited-app" | |
| rm -rf "$bundle_dir" && mkdir -p "$bundle_dir" | |
| unzip -q scripts/javascript/composited-app/javascript/target/compositedapp-javascript-1.0-SNAPSHOT.zip -d "$bundle_dir" | |
| node scripts/test-javascript-composited-rendering.mjs "$bundle_dir" "${GITHUB_WORKSPACE}/artifacts/javascript-ui-tests/composited" | |
| - name: Locate JavaScript bundle | |
| id: locate_bundle | |
| run: | | |
| set -euo pipefail | |
| bundle="$(ls -1 \ | |
| artifacts/javascript-ui-tests/hellocodenameone-javascript-port.zip \ | |
| scripts/hellocodenameone/parparvm/target/hellocodenameone-javascript-port.zip \ | |
| 2>/dev/null | head -n1 || true)" | |
| if [ -z "$bundle" ]; then | |
| echo "Unable to locate HelloCodenameOne JavaScript-port bundle" >&2 | |
| exit 1 | |
| fi | |
| echo "bundle=$bundle" >> "$GITHUB_OUTPUT" | |
| # The standalone JavaScript lifecycle boot test was removed: it was | |
| # advisory (continue-on-error) but flaky on shared GHA runners -- when a | |
| # slow runner's cooperative scheduler stalled, the harness's page.evaluate | |
| # poll could hang indefinitely (past the 480s budget), wedging the whole | |
| # job. The screenshot suite below exercises the same boot path AND the | |
| # rendering, with its own per-suite timeout, so it is the single source of | |
| # truth. This keeps the workflow focused on the screenshot tests and fast. | |
| # THIS LEG RUNS THE TRANSLATED SCREENSHOT SERVER, and it is the only one | |
| # that does. Every other leg runs the same Java on a JVM, which covers the | |
| # protocol but not the arm that ships. This job is the right host for it: it | |
| # is Linux, where the native backend links; it already sets up the JDKs and | |
| # builds the ParparVM compiler above; it is a single job rather than a | |
| # matrix, so the binary is built once; and its client is the browser's own | |
| # WebSocket rather than one of ours, which makes it the only pairing of our | |
| # shipping server with a third-party RFC 6455 implementation. | |
| # | |
| # NOT with CN1_BACKEND_HTTPS=0, tempting as that is for avoiding these | |
| # packages: the build deletes cn1_backend_crypto.c in that mode, and a native | |
| # with no C symbol takes its Java method with it -- so Crypto.sha1 would | |
| # vanish and every handshake would compute the wrong accept value. | |
| - name: Install the native backend toolchain | |
| run: | | |
| bash "$GITHUB_WORKSPACE/scripts/ci/apt-get-update.sh" | |
| sudo apt-get install -y --no-install-recommends \ | |
| clang zlib1g-dev libcurl4-openssl-dev libssl-dev libnghttp2-dev | |
| - name: Run JavaScript screenshot browser tests | |
| env: | |
| # The translated binary, built by scripts/hellocodenameone/backend/server.sh | |
| # through the Maven plugin and self-checked by scripts/lib/cn1ss.sh before | |
| # the suite starts, so a broken one costs minutes rather than the whole | |
| # 40-minute timeout. | |
| CN1SS_WS_SERVER: native | |
| run: | | |
| mkdir -p "${ARTIFACTS_DIR}" | |
| ./scripts/run-javascript-browser-tests.sh "${{ steps.locate_bundle.outputs.bundle }}" "${GITHUB_WORKSPACE}/scripts/javascript/screenshots" | |
| - name: Upload JavaScript port status | |
| if: ${{ !cancelled() }} | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: port-status-javascript | |
| path: artifacts/javascript-ui-tests/port-status-javascript.json | |
| if-no-files-found: warn | |
| retention-days: 14 | |
| - name: Upload JavaScript screenshot artifacts | |
| if: ${{ !cancelled() }} | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: javascript-ui-tests | |
| path: artifacts/javascript-ui-tests | |
| if-no-files-found: warn | |
| retention-days: 14 | |
| port-status-browser-evidence: | |
| if: ${{ github.event_name == 'workflow_dispatch' && inputs.port_status_browser_evidence }} | |
| permissions: | |
| actions: write | |
| contents: write | |
| uses: ./.github/workflows/port-status-nightly.yml |