Phase 3 e2e: macOS leg and embedded-server isolation #44
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 produces a broken Electron.app on the macOS runner: the | |
| # launcher at Contents/MacOS/Electron is present but Contents/Frameworks/ | |
| # Electron Framework.framework is incomplete, so dyld fails with "Library | |
| # not loaded" at launch, and path.txt is never written either. Re-extract | |
| # the cached darwin zip with ditto, which reproduces a complete .app | |
| # (framework binary plus the Versions/Current symlinks plain unzip mangles) | |
| # locally, then write path.txt (its macOS value is constant) and verify | |
| # both the launcher and the framework binary are in place. | |
| - name: Repair the Electron install on macOS | |
| if: matrix.os == 'macos-latest' | |
| run: | | |
| set -euo pipefail | |
| # Ask @electron/get (electron's own download dep) for the cached zip, | |
| # fetching it if absent. It stores the zip under a content-hash subdir, | |
| # so globbing the cache root misses it; let the library resolve the path. | |
| zip=$(node -e "const {downloadArtifact}=require('@electron/get');const {version}=require('electron/package.json');downloadArtifact({version,artifactName:'electron',platform:'darwin',arch:process.arch}).then(p=>process.stdout.write(p)).catch(e=>{console.error(e);process.exit(1)})") | |
| echo "re-extracting electron 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 | |
| test -x "node_modules/electron/dist/Electron.app/Contents/MacOS/Electron" | |
| test -f "node_modules/electron/dist/Electron.app/Contents/Frameworks/Electron Framework.framework/Versions/A/Electron Framework" | |
| node -e "console.log('resolved electron:', require('electron'))" | |
| - 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" | |
| # 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 |