name: e2e on: push: branches: [master] paths: - ".github/workflows/e2e-tests.yml" - "backend/**" - "frontend/**" - "e2e/**" - "compose-e2e-test.yml" - "Dockerfile" pull_request: branches: [master] paths: - ".github/workflows/e2e-tests.yml" - "backend/**" - "frontend/**" - "e2e/**" - "compose-e2e-test.yml" - "Dockerfile" concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: # cheap gate: catches a compile break or a lint regression in the build-tagged suite # without paying for the docker build and the browser download vet: name: Vet timeout-minutes: 10 runs-on: ubuntu-latest permissions: contents: read steps: - name: Checkout uses: actions/checkout@v7 with: persist-credentials: false - name: Set up Go uses: actions/setup-go@v7 with: go-version-file: e2e/go.mod cache-dependency-path: e2e/go.sum - name: Vet run: cd e2e && go vet -tags=e2e ./... - name: Lint uses: golangci/golangci-lint-action@v9 with: version: v2.13.1 working-directory: e2e args: --build-tags=e2e --config ../backend/.golangci.yml tests: name: Tests needs: vet # generous against the docker build plus two go test invocations: a job cancelled on # timeout skips its own failure steps, so the run would end with neither logs nor traces timeout-minutes: 45 runs-on: ubuntu-latest permissions: contents: read steps: - name: Checkout uses: actions/checkout@v7 with: persist-credentials: false - name: Set up Go uses: actions/setup-go@v7 with: go-version-file: e2e/go.mod cache-dependency-path: e2e/go.sum # two directories: the driver (node plus the npm package) and the browser builds, # which include firefox and webkit for the rendering tests - name: Cache playwright driver and browsers uses: actions/cache@v6 with: path: | ~/.cache/ms-playwright ~/.cache/ms-playwright-go key: playwright-${{ hashFiles('e2e/go.sum') }} restore-keys: playwright- - name: Build & start the stack run: COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker compose -f compose-e2e-test.yml up -d --build --quiet-pull --wait - name: Install gotestsum run: go install gotest.tools/gotestsum@v1.13.0 # each rerun is its own `go test` process carrying the same timeout, so the ceiling is # 8m for the first attempt plus 4 x 8m of reruns, inside the job's 45. a job cancelled on # timeout skips its own upload steps, which is the one outcome worth designing against. # four failures covers one test failing across all three engines, counted as its three # subtests plus their parent; more than that is a regression and should not be rerun. # a browser suite has a flake floor no amount of care removes, and one flake failing the # build is what makes people stop trusting it. one rerun, not two: a rerun stops at the # first pass, so each further attempt only widens the window in which a real intermittent # regression is absorbed. what needed a rerun is written to a report and uploaded, since # a green job is a job nobody reads the log of - name: Run e2e # shared across the rerun so it exercises the same threads as the attempt that failed env: E2E_RUN_ID: ${{ github.run_id }}-${{ github.run_attempt }} run: | cd e2e && gotestsum \ --rerun-fails=1 \ --rerun-fails-max-failures=4 \ --rerun-fails-report=rerun-report.txt \ --packages=./... \ --format standard-verbose \ -- -tags=e2e -count 1 -timeout 8m - name: Server logs on failure if: failure() run: docker compose -f compose-e2e-test.yml logs --tail=200 - name: Upload browser traces and any rerun report if: always() uses: actions/upload-artifact@v7 with: name: playwright-traces path: | e2e/traces/ e2e/rerun-report.txt retention-days: 30 if-no-files-found: ignore