From 69987b01ecfddb54c13c088604a70cd0814032ef Mon Sep 17 00:00:00 2001 From: taroj1205 Date: Sun, 22 Jun 2025 17:49:28 +1200 Subject: [PATCH] perf(ci): optimize Playwright test execution with sharding and worker limits - Configure Playwright to use 50% workers in CI for better resource utilization - Limit CI browser testing to Firefox only for faster execution - Implement 4-way test sharding in GitHub Actions for parallel execution - Add comprehensive caching for Playwright browsers and artifacts - Set 10-minute timeout for Playwright test jobs - Maintain full browser coverage (Chrome, Firefox, Safari) for local development --- .github/workflows/ci-pipeline.yml | 130 +++++++++++++++++++++++++----- cspell.json | 2 +- playwright.config.ts | 63 ++++++--------- turbo.json | 1 - 4 files changed, 136 insertions(+), 60 deletions(-) diff --git a/.github/workflows/ci-pipeline.yml b/.github/workflows/ci-pipeline.yml index d6eec5a..abd8c4e 100644 --- a/.github/workflows/ci-pipeline.yml +++ b/.github/workflows/ci-pipeline.yml @@ -15,21 +15,21 @@ jobs: permissions: contents: read outputs: - exists: ${{ steps.filter.outputs.exists }} + exists: ${{ steps.filter.outputs.relevant }} steps: - uses: actions/checkout@v4 - name: Filter changes - uses: yumemi-inc/path-filter@v2 + uses: dorny/paths-filter@v3 id: filter with: - patterns: | - ** - !**.md - !.gitignore - !.gitattributes - !.vscode/** - !.env.example + filters: | + relevant: + !**.md + !.gitignore + !.gitattributes + !.vscode/** + !.env.example setup: name: Setup Dependencies @@ -50,6 +50,7 @@ jobs: lookup-only: true - name: Setup Node.js + if: steps.check-node-modules-cache.outputs.cache-hit != 'true' uses: actions/setup-node@v4 with: node-version: lts/* @@ -80,8 +81,6 @@ jobs: name: Test - check: spell name: Spell Check - - check: build - name: Build steps: - uses: actions/checkout@v4 @@ -119,22 +118,105 @@ jobs: - name: Run ${{ matrix.name }} run: pnpm exec turbo run ${{ matrix.check }} - playwright: - name: Playwright Tests + build: + name: Build needs: [check_changes, setup] if: ${{ needs.check_changes.outputs.exists == 'true' }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - with: - fetch-depth: 0 - name: Restore Turborepo Cache uses: actions/cache@v4 with: path: .turbo - key: ${{ runner.os }}-turbo-${{ github.sha }} - restore-keys: ${{ runner.os }}-turbo- + key: ${{ runner.os }}-turbo-build-${{ github.sha }} + restore-keys: ${{ runner.os }}-turbo-build- + + - name: Restore Astro Cache + uses: actions/cache@v4 + with: + path: | + .astro + node_modules/.astro + key: ${{ runner.os }}-astro-${{ hashFiles('**/pnpm-lock.yaml', 'src/**', 'public/**', 'astro.config.mjs') }} + restore-keys: | + ${{ runner.os }}-astro-${{ hashFiles('**/pnpm-lock.yaml') }}- + ${{ runner.os }}-astro- + + - name: Restore node_modules cache + id: cache + uses: actions/cache/restore@v4 + with: + path: | + node_modules + */node_modules + key: ${{ runner.os }}-node-modules-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: ${{ runner.os }}-node-modules- + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: lts/* + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + run_install: false + + - name: Install dependencies + if: steps.cache.outputs.cache-hit != 'true' + run: pnpm install --frozen-lockfile + + - name: Build project + run: pnpm exec turbo run build + + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: dist + path: dist/ + retention-days: 1 + + playwright: + name: Playwright Tests (Shard ${{ matrix.shard }}) + needs: [check_changes, setup, build] + if: ${{ needs.check_changes.outputs.exists == 'true' }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + shard: [1, 2, 3, 4] + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + name: dist + path: dist/ + + - name: Restore Turborepo Cache + uses: actions/cache@v4 + with: + path: .turbo + key: ${{ runner.os }}-turbo-playwright-shard-${{ matrix.shard }}-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-turbo-playwright-shard-${{ matrix.shard }}- + ${{ runner.os }}-turbo-playwright- + + - name: Restore Astro Cache + uses: actions/cache@v4 + with: + path: | + .astro + node_modules/.astro + key: ${{ runner.os }}-astro-${{ hashFiles('**/pnpm-lock.yaml', 'src/**', 'public/**', 'astro.config.mjs') }} + restore-keys: | + ${{ runner.os }}-astro-${{ hashFiles('**/pnpm-lock.yaml') }}- + ${{ runner.os }}-astro- - name: Restore node_modules cache id: cache @@ -170,13 +252,21 @@ jobs: - name: Install Playwright Browsers run: pnpm exec playwright install --with-deps - - name: Run Playwright Tests - run: pnpm exec turbo run test:playwright + - name: Run Playwright Tests (Shard ${{ matrix.shard }}/4) + run: pnpm exec turbo run test:playwright -- --shard=${{ matrix.shard }}/4 timeout-minutes: 10 + - name: Upload Playwright Report + uses: actions/upload-artifact@v4 + if: always() + with: + name: playwright-report-shard-${{ matrix.shard }} + path: playwright-report/ + retention-days: 7 + verify: name: Verify - needs: [check_changes, quality_checks, playwright] + needs: [check_changes, quality_checks, build, playwright] runs-on: ubuntu-latest if: always() outputs: diff --git a/cspell.json b/cspell.json index a507659..c96db93 100644 --- a/cspell.json +++ b/cspell.json @@ -18,6 +18,7 @@ "createdDefault", "createdDesc", "daniel", + "dorny", "ferrocyante", "flatpaks", "FMPEG", @@ -70,7 +71,6 @@ "workerd", "xmark", "XPCOM", - "yumemi", "zsync" ], "flagWords": [], diff --git a/playwright.config.ts b/playwright.config.ts index ee80e25..f30606c 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -17,9 +17,9 @@ export default defineConfig({ fullyParallel: true, forbidOnly: Boolean(process.env.CI), retries: process.env.CI ? 2 : 0, - /* Opt out of parallel tests on CI. */ - workers: process.env.CI ? 1 : undefined, - reporter: 'html', + /* Remove worker limitation in CI for better sharding performance */ + workers: process.env.CI ? '50%' : undefined, + reporter: process.env.CI ? [['github'], ['html']] : 'html', use: { baseURL: 'http://localhost:3000', trace: 'on-first-retry', @@ -27,45 +27,32 @@ export default defineConfig({ /* Configure projects for major browsers */ projects: [ - { - name: 'chromium', - use: { ...devices['Desktop Chrome'] }, - }, - - { - name: 'firefox', - use: { ...devices['Desktop Firefox'] }, - }, - - { - name: 'webkit', - use: { ...devices['Desktop Safari'] }, - }, - - /* Test against mobile viewports. */ - // { - // name: 'Mobile Chrome', - // use: { ...devices['Pixel 5'] }, - // }, - // { - // name: 'Mobile Safari', - // use: { ...devices['iPhone 12'] }, - // }, - - /* Test against branded browsers. */ - // { - // name: 'Microsoft Edge', - // use: { ...devices['Desktop Edge'], channel: 'msedge' }, - // }, - // { - // name: 'Google Chrome', - // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, - // }, + ...(process.env.CI + ? [ + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + ] + : [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + { + name: 'webkit', + use: { ...devices['Desktop Safari'] }, + }, + ]), ], /* Run your local dev server before starting the tests */ webServer: { - command: process.env.CI ? 'npm run start' : 'npm run dev', + command: process.env.CI ? 'pnpm run start' : 'pnpm run dev', url: 'http://localhost:3000', reuseExistingServer: !process.env.CI, }, diff --git a/turbo.json b/turbo.json index 643b153..fa8f070 100644 --- a/turbo.json +++ b/turbo.json @@ -32,7 +32,6 @@ }, "test:playwright": { "cache": true, - "dependsOn": ["build"], "inputs": ["**/*.{ts,tsx,js,jsx,astro}"], "outputs": ["playwright-report/**", "test-results/**"] }