Phase 3 e2e: macOS leg and embedded-server isolation #35
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: E2E | |
| on: | |
| push: | |
| branches: [master] | |
| pull_request: | |
| branches: [master] | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| e2e: | |
| name: 'Playwright (${{ matrix.os }})' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [ubuntu-latest, macos-latest] | |
| runs-on: ${{ matrix.os }} | |
| # Bound the job so a stuck Electron launch/close fails fast instead of | |
| # tying up a runner; this suite specifically guards shutdown hangs. | |
| timeout-minutes: 15 | |
| env: | |
| # Only Electron is launched here, never Playwright's bundled browsers, so | |
| # skip their download during yarn install (faster, fewer network flakes). | |
| PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1' | |
| steps: | |
| - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 | |
| - uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5 | |
| with: | |
| # Match the Node that the target Electron bundles (Electron 42 -> Node | |
| # 24); do not run ahead of it. Node 26 broke Electron's install tooling. | |
| node-version: '24.x' | |
| cache: 'yarn' | |
| - run: yarn install --frozen-lockfile | |
| # The electron postinstall (extract-zip) intermittently leaves dist without | |
| # the binary on CI runners (it happens on macOS too, not just Linux), so | |
| # launch fails with "Electron failed to install correctly". Run install.js | |
| # explicitly on every OS to fetch and extract the binary. | |
| - name: Install the Electron binary | |
| run: node node_modules/electron/install.js | |
| # On Linux, if extract-zip still dropped the binary, fall back to system | |
| # unzip (the zip is the linux-x64 build, binary at dist/electron). | |
| - name: Repair the Electron binary on Linux if needed | |
| if: matrix.os == 'ubuntu-latest' | |
| run: | | |
| set -euo pipefail | |
| if [ ! -x node_modules/electron/dist/electron ]; then | |
| echo "linux electron binary missing, repairing from the cached zip" | |
| zip=$(ls ~/.cache/electron/*/electron-*-linux-x64.zip | head -1) | |
| rm -rf node_modules/electron/dist | |
| mkdir -p node_modules/electron/dist | |
| unzip -q -o "$zip" -d node_modules/electron/dist | |
| printf 'electron' > node_modules/electron/path.txt | |
| else | |
| echo "linux electron binary present, no repair needed" | |
| fi | |
| test -x node_modules/electron/dist/electron | |
| # extract-zip drops the binary on macOS too. Re-extract the cached darwin | |
| # zip with ditto (preserves the Electron Framework symlinks that plain | |
| # unzip mangles) and point path.txt at the app binary. The echo reports | |
| # whether the repair actually fired, so the CI log shows the real state. | |
| - name: Repair the Electron binary on macOS if needed | |
| if: matrix.os == 'macos-latest' | |
| run: | | |
| set -euo pipefail | |
| bin="node_modules/electron/dist/Electron.app/Contents/MacOS/Electron" | |
| if [ ! -x "$bin" ]; then | |
| case "$(uname -m)" in | |
| arm64) az=arm64 ;; | |
| *) az=x64 ;; | |
| esac | |
| zip=$(ls ~/Library/Caches/electron/electron-*-darwin-$az.zip | head -1) | |
| echo "macos electron binary missing, repairing from $zip" | |
| rm -rf node_modules/electron/dist | |
| mkdir -p node_modules/electron/dist | |
| ditto -x -k "$zip" node_modules/electron/dist | |
| printf 'Electron.app/Contents/MacOS/Electron' > node_modules/electron/path.txt | |
| else | |
| echo "macos electron binary present, no repair needed" | |
| fi | |
| test -x "$bin" | |
| - run: yarn build | |
| # Electron needs system libraries; xvfb provides a display on the headless | |
| # runner. The app launches up to four windows, so a real display beats | |
| # --headless here. Both are Linux-only: macOS runners have a display and do | |
| # not use this apt-based dependency installer. | |
| - if: matrix.os == 'ubuntu-latest' | |
| run: npx playwright install-deps | |
| # A minimal Python env with jupyterlab so the env-backed tests run (a venv | |
| # + pip is lighter than a full conda env for a smoke). The seeded | |
| # app-data.json points the app at this interpreter. | |
| - name: Provision a Python env for the env-backed e2e | |
| run: | | |
| set -euo pipefail | |
| # Install the same jupyterlab the app bundles, read from the env spec so | |
| # this tracks a version bump instead of drifting. Fail loudly if the | |
| # pin format changes rather than silently installing latest. | |
| ver=$(awk '$1=="-" && $2=="jupyterlab" {print $3}' env_installer/jlab_server.yaml) | |
| [[ "$ver" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || { echo "unexpected jupyterlab pin '$ver' in jlab_server.yaml (want exact x.y.z)"; exit 1; } | |
| python3 -m venv "$RUNNER_TEMP/jlab-venv" | |
| "$RUNNER_TEMP/jlab-venv/bin/pip" install --quiet "jupyterlab==$ver" | |
| echo "JLAB_TEST_PYTHON_PATH=$RUNNER_TEMP/jlab-venv/bin/python" >> "$GITHUB_ENV" | |
| - name: Diagnose electron resolution on macOS | |
| if: matrix.os == 'macos-latest' | |
| run: | | |
| echo "--- path.txt (cat -A) ---"; cat -A node_modules/electron/path.txt; echo | |
| echo "--- dist/version ---"; cat node_modules/electron/dist/version; echo | |
| echo "--- dist top ---"; ls -la node_modules/electron/dist | head | |
| echo "--- binary ---"; ls -la "node_modules/electron/dist/Electron.app/Contents/MacOS/Electron" | |
| echo "--- require.resolve(electron) ---"; node -e "console.log(require.resolve('electron'))" | |
| echo "--- require(electron) ---"; node -e "console.log(require('electron'))" || echo "REQUIRE THREW" | |
| echo "--- all electron path.txt in tree ---"; find node_modules -name path.txt -path "*electron*" 2>/dev/null | |
| echo "--- playwright electron resolution ---"; node -e "const r=require('@playwright/test'); console.log('pw ok')" || echo "PW REQUIRE THREW" | |
| # xvfb is Linux-only; on macOS the runner has a real display, so run the | |
| # suite directly. Same yarn test:e2e command on both legs. | |
| - name: Run the e2e suite | |
| run: | | |
| if [ "$RUNNER_OS" = "Linux" ]; then | |
| xvfb-run -a yarn test:e2e | |
| else | |
| yarn test:e2e | |
| fi | |
| - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 | |
| if: ${{ !cancelled() }} | |
| with: | |
| name: playwright-report-${{ matrix.os }} | |
| path: | | |
| playwright-report/ | |
| test-results/ | |
| retention-days: 14 |