CI Integration
In the other ddakit bases, the last operational seat is distribution. e2e-base has no app to ship, so CI integration takes that seat. implement-ci-workflow reads ci and targets from e2e-suite-config.json and generates .github/workflows/e2e.yml. If ci.provider is none, nothing is generated. Only the jobs for tracks present in targets go in; absent tracks get no job.
web sharding and the blob merge
Section titled “web sharding and the blob merge”Tests split into several shards and run in parallel, and once each shard uploads a blob report, a separate job merges them into one.
jobs: web: strategy: fail-fast: false matrix: { shardIndex: [1,2,3,4], shardTotal: [4] } runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: 20, cache: npm } - run: npm ci - run: npx playwright install --with-deps # not cached - run: npx playwright test --project=chromium --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} - uses: actions/upload-artifact@v4 if: always() with: { name: blob-report-${{ matrix.shardIndex }}, path: blob-report, retention-days: 1 } merge-reports: needs: [web] if: always() runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: 20, cache: npm } - run: npm ci - uses: actions/download-artifact@v4 with: { path: all-blob-reports, pattern: blob-report-* } - run: npx playwright merge-reports --reporter html ./all-blob-reports - uses: actions/upload-artifact@v4 with: { name: html-report, path: playwright-report, retention-days: 14 }With fail-fast: false, one broken shard does not stop the rest from running to the end. Each shard’s blob is kept for one day, and the merged HTML report for 14.
Why the browser binary is not cached
Section titled “Why the browser binary is not cached”Every job runs npx playwright install --with-deps. Caching looks faster, but when the Playwright version bumps, the cached binary and the version drift apart, and the OS-level dependencies --with-deps installs are not captured in the cache, so things break when the runner image changes. Installing every time is what stays clear of the forbidden pattern (§5).
electron OS matrix, xvfb on Linux only
Section titled “electron OS matrix, xvfb on Linux only”electron runs on three OSes. Only the Linux runner lacks a display, so it gets wrapped in xvfb-run; mac and windows run as is.
electron: strategy: { fail-fast: false, matrix: { os: [ubuntu-latest, windows-latest, macos-latest] } } runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: { node-version: 20, cache: npm } - run: npm ci - run: npx playwright install --with-deps - name: e2e (Linux) if: runner.os == 'Linux' run: xvfb-run --auto-servernum -- npx playwright test --project=electron - name: e2e (mac/win) if: runner.os != 'Linux' run: npx playwright test --project=electronA runner.os branch runs a different command for Linux only, inside the same job. That electron is single-instance and so the config is workers: 1 was covered in tracks.
mobile emulator, simctl, cloud
Section titled “mobile emulator, simctl, cloud”Android brings up an emulator with reactivecircus/android-emulator-runner. KVM has to be enabled for acceleration, and AVD caching cuts boot time.
mobile-android: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Enable KVM run: | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules sudo udevadm control --reload-rules && sudo udevadm trigger --name-match=kvm - uses: reactivecircus/android-emulator-runner@v2 with: { api-level: 30, arch: x86_64, force-avd-creation: false, script: maestro test tests/mobile/flows } # or detox testiOS brings up a simulator with xcrun simctl on a macos-latest runner. For a release gate that needs real-device verification or parallel scale-out, use Maestro Cloud (mobile-dev-inc/action-maestro-cloud) or a device farm. The cloud farm’s api-key and project-id go in only through ${{ secrets.* }}.
Safety guards
Section titled “Safety guards”Secrets pass only through ${{ secrets.* }} and real keys are never hardcoded (S2). Watch that tokens and PII do not get captured in artifacts (S4). The SUT the workflow env points at is staging or dedicated test only, and production is banned (S6).
updates comes next. /update-from-base, which safely pulls new skills and hooks into a fork when the base ships them, and /adopt, which lays the pattern onto an app repo that already has some e2e.