Skip to content
Latchkey

CI workflow (jo-inc/camofox-browser)

The CI workflow from jo-inc/camofox-browser, explained and optimized by Latchkey.

C

CI health: C - fair

Point runs-on at Latchkey and get run de-duplication, job timeouts, self-healing for flaky steps, and up to 58% lower cost, applied automatically.

Grade your own workflow free or run it on Latchkey →
Source: jo-inc/camofox-browser.github/workflows/ci.ymlLicense MITView source

What it does

This is the CI workflow from the jo-inc/camofox-browser repository, a real project running GitHub Actions. It is shown here with attribution under its MIT license.

Below, Latchkey shows a faster, safer version produced by its optimization engine.

The workflow

workflow (.yml)
name: CI

on:
  push:
    branches: [master]
  pull_request:
    branches: [master]

jobs:
  unit:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [24]
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: npm

      - name: Install dependencies
        run: npm ci

      - name: Build plugin (TypeScript → JS)
        run: npm run build

      - name: Run unit + plugin tests (Jest)
        run: |
          npm install --no-save jest-junit
          node --experimental-vm-modules node_modules/.bin/jest \
            --testPathPattern='tests/unit|plugins' \
            --testPathIgnorePatterns='security\.test|tabRecycling\.test|cookies\.test' \
            --forceExit
        env:
          CI: true

  e2e:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [24]
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: npm

      - name: Install dependencies
        run: |
          npm ci
          npm install --no-save jest-junit

      - name: Cache Playwright browsers
        id: playwright-cache
        uses: actions/cache@v4
        with:
          path: ~/.cache/ms-playwright
          key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}

      - name: Install browser
        if: steps.playwright-cache.outputs.cache-hit != 'true'
        run: npx playwright install --with-deps firefox

      - name: Install browser system deps (cache hit)
        if: steps.playwright-cache.outputs.cache-hit == 'true'
        run: npx playwright install-deps firefox

      - name: Run e2e + browser-dependent unit tests
        run: |
          xvfb-run --auto-servernum \
            node --experimental-vm-modules node_modules/.bin/jest \
              --config jest.config.e2e.cjs \
              --runInBand --forceExit
        env:
          CI: true

      - name: Run browser-dependent unit tests
        run: |
          xvfb-run --auto-servernum \
            node --experimental-vm-modules node_modules/.bin/jest \
              --testPathPattern='tests/unit/(security|tabRecycling|cookies)\.test' \
              --runInBand --forceExit
        env:
          CI: true

The same workflow, on Latchkey

Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.

name: CI
 
on:
  push:
    branches: [master]
  pull_request:
    branches: [master]
 
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true
 
jobs:
  unit:
    timeout-minutes: 30
    runs-on: latchkey-small
    strategy:
      matrix:
        node-version: [24]
    steps:
      - uses: actions/checkout@v4
 
      - name: Setup Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: npm
 
      - name: Install dependencies
        run: npm ci
 
      - name: Build plugin (TypeScript → JS)
        run: npm run build
 
      - name: Run unit + plugin tests (Jest)
        run: |
          npm install --no-save jest-junit
          node --experimental-vm-modules node_modules/.bin/jest \
            --testPathPattern='tests/unit|plugins' \
            --testPathIgnorePatterns='security\.test|tabRecycling\.test|cookies\.test' \
            --forceExit
        env:
          CI: true
 
  e2e:
    timeout-minutes: 30
    runs-on: latchkey-small
    strategy:
      matrix:
        node-version: [24]
    steps:
      - uses: actions/checkout@v4
 
      - name: Setup Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: npm
 
      - name: Install dependencies
        run: |
          npm ci
          npm install --no-save jest-junit
 
      - name: Cache Playwright browsers
        id: playwright-cache
        uses: actions/cache@v4
        with:
          path: ~/.cache/ms-playwright
          key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
 
      - name: Install browser
        if: steps.playwright-cache.outputs.cache-hit != 'true'
        run: npx playwright install --with-deps firefox
 
      - name: Install browser system deps (cache hit)
        if: steps.playwright-cache.outputs.cache-hit == 'true'
        run: npx playwright install-deps firefox
 
      - name: Run e2e + browser-dependent unit tests
        run: |
          xvfb-run --auto-servernum \
            node --experimental-vm-modules node_modules/.bin/jest \
              --config jest.config.e2e.cjs \
              --runInBand --forceExit
        env:
          CI: true
 
      - name: Run browser-dependent unit tests
        run: |
          xvfb-run --auto-servernum \
            node --experimental-vm-modules node_modules/.bin/jest \
              --testPathPattern='tests/unit/(security|tabRecycling|cookies)\.test' \
              --runInBand --forceExit
        env:
          CI: true
 

What changed

What Latchkey heals here

This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:

This workflow runs 2 jobs per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.

Actions used in this workflow