From 2d770d45bd28097e6a64c6e7669637ec8fc2ed1d Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 2 Jun 2026 01:01:17 +0000 Subject: [PATCH 01/40] Attempt to fix UI coverage --- .github/workflows/qc_checks.yaml | 1 + src/frontend/playwright.config.ts | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml index 78d979af3b6f..4520c36c5cbf 100644 --- a/.github/workflows/qc_checks.yaml +++ b/.github/workflows/qc_checks.yaml @@ -754,6 +754,7 @@ jobs: token: ${{ secrets.CODECOV_TOKEN }} slug: inventree/InvenTree flags: web + files: src/frontend/coverage/lcov.info - name: Upload bundler info env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/src/frontend/playwright.config.ts b/src/frontend/playwright.config.ts index 6cc8bf43f4d5..112c535c2fd9 100644 --- a/src/frontend/playwright.config.ts +++ b/src/frontend/playwright.config.ts @@ -26,9 +26,7 @@ const MAX_RETRIES: number = 3; * - WORKERS = 1 (to avoid conflicts with HMR) */ -const BASE_URL: string = IS_CI - ? 'http://localhost:8000' - : 'http://localhost:5173'; +const BASE_URL: string = 'http://localhost:5173'; console.log('Running Playwright Tests:'); console.log('- Base URL:', BASE_URL); From 9fc4036d95a3476faca1c967264118efcdd9c58f Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 2 Jun 2026 05:25:20 +0000 Subject: [PATCH 02/40] Update CI workflows: - use test sharding - Only upload coverage on master --- .github/workflows/qc_checks.yaml | 55 +++++++++++++++++++++++++++---- src/frontend/playwright.config.ts | 2 +- 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml index 4520c36c5cbf..9f45448fb4d5 100644 --- a/.github/workflows/qc_checks.yaml +++ b/.github/workflows/qc_checks.yaml @@ -665,11 +665,15 @@ jobs: invoke migrate web_ui: - name: Tests - Web UI + name: Tests - Web UI [${{ matrix.shard }}/4] runs-on: ubuntu-24.04 - timeout-minutes: 60 + timeout-minutes: 40 needs: ["code-style", "paths-filter"] if: needs.paths-filter.outputs.frontend == 'true' || needs.paths-filter.outputs.force == 'true' + strategy: + fail-fast: false + matrix: + shard: [1, 2, 3, 4] services: postgres: image: postgres:17 @@ -738,17 +742,54 @@ jobs: cp ./tests/fixtures/playwright_custom_logo.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_logo.png cp ./tests/fixtures/playwright_custom_splash.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_splash.png invoke static - env INVENTREE_CUSTOM_SPLASH="img/playwright_custom_splash.png" INVENTREE_CUSTOM_LOGO="img/playwright_custom_logo.png" npx nyc playwright test --project=customization - npx nyc playwright test --project=chromium --project=firefox + if [ "${{ matrix.shard }}" == "1" ]; then + env INVENTREE_CUSTOM_SPLASH="img/playwright_custom_splash.png" INVENTREE_CUSTOM_LOGO="img/playwright_custom_logo.png" npx nyc playwright test --project=customization + fi + npx nyc playwright test --project=chromium --project=firefox --shard=${{ matrix.shard }}/4 - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 if: ${{ !cancelled() && steps.tests.outcome == 'failure' }} with: - name: playwright-report + name: playwright-report-${{ matrix.shard }} path: src/frontend/playwright-report/ retention-days: 14 + - name: Upload nyc output + if: ${{ !cancelled() }} + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 + with: + name: nyc-output-${{ matrix.shard }} + path: src/frontend/.nyc_output/ + retention-days: 1 + + web_ui_coverage: + name: Coverage - Web UI + runs-on: ubuntu-24.04 + needs: ["web_ui", "paths-filter"] + if: >- + !cancelled() && + (needs.paths-filter.outputs.frontend == 'true' || needs.paths-filter.outputs.force == 'true') + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6.0.2 + with: + persist-credentials: false + - name: Environment Setup + uses: ./.github/actions/setup + with: + npm: true + - name: Install frontend dependencies + run: cd src/frontend && yarn install + - name: Download nyc outputs + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # pin@v8.0.1 + with: + pattern: nyc-output-* + path: src/frontend/.nyc_output + merge-multiple: true - name: Report coverage - run: cd src/frontend && npx nyc report --report-dir ./coverage --temp-dir .nyc_output --reporter=lcov --exclude-after-remap false + run: | + cd src/frontend + npx nyc report --report-dir ./coverage --temp-dir .nyc_output --reporter=lcov --reporter=text-summary --exclude-after-remap false >> "$GITHUB_STEP_SUMMARY" - name: Upload coverage reports to Codecov + if: github.ref == 'refs/heads/master' uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # pin@v6.0.1 with: token: ${{ secrets.CODECOV_TOKEN }} @@ -756,11 +797,11 @@ jobs: flags: web files: src/frontend/coverage/lcov.info - name: Upload bundler info + if: github.ref == 'refs/heads/master' env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} run: | cd src/frontend - yarn install yarn run build web_ui_build: diff --git a/src/frontend/playwright.config.ts b/src/frontend/playwright.config.ts index 112c535c2fd9..a312f50625e4 100644 --- a/src/frontend/playwright.config.ts +++ b/src/frontend/playwright.config.ts @@ -4,7 +4,7 @@ import { defineConfig, devices } from '@playwright/test'; const IS_CI = !!process.env.CI; const MAX_WORKERS: number = 3; -const MAX_RETRIES: number = 3; +const MAX_RETRIES: number = 2; /* We optionally spin-up services based on the testing mode: * From 30ee59e8d2685fe1225abc6425470bde799fdb89 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 2 Jun 2026 05:39:29 +0000 Subject: [PATCH 03/40] Restore line --- .github/workflows/qc_checks.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml index 9f45448fb4d5..45bba0a9b423 100644 --- a/.github/workflows/qc_checks.yaml +++ b/.github/workflows/qc_checks.yaml @@ -802,6 +802,7 @@ jobs: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} run: | cd src/frontend + yarn install yarn run build web_ui_build: From a430c95228d5b26cdbbf536eeea2553bebfae1b4 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 2 Jun 2026 06:06:55 +0000 Subject: [PATCH 04/40] Simplify test --- src/frontend/tests/pui_login.spec.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/frontend/tests/pui_login.spec.ts b/src/frontend/tests/pui_login.spec.ts index 3fe8f50279ad..9876a88e24ff 100644 --- a/src/frontend/tests/pui_login.spec.ts +++ b/src/frontend/tests/pui_login.spec.ts @@ -13,7 +13,8 @@ test('Login - Failures', async ({ page }) => { await page.getByRole('button', { name: 'Log In' }).click(); await page.getByText('Login failed', { exact: true }).waitFor(); await page.getByText('Check your input and try again').first().waitFor(); - await page.locator('#login').getByRole('button').click(); + + await page.reload(); }; // Navigate to the 'login' page From 93e35fec6218261c930c80801b887ee77e0575b3 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 2 Jun 2026 06:30:03 +0000 Subject: [PATCH 05/40] Simplify test matrix --- .github/workflows/qc_checks.yaml | 3 --- src/frontend/playwright.config.ts | 17 +++++------------ .../tests/customization/customization.spec.ts | 7 ++++++- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml index 45bba0a9b423..d5fdf4391fd6 100644 --- a/.github/workflows/qc_checks.yaml +++ b/.github/workflows/qc_checks.yaml @@ -742,9 +742,6 @@ jobs: cp ./tests/fixtures/playwright_custom_logo.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_logo.png cp ./tests/fixtures/playwright_custom_splash.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_splash.png invoke static - if [ "${{ matrix.shard }}" == "1" ]; then - env INVENTREE_CUSTOM_SPLASH="img/playwright_custom_splash.png" INVENTREE_CUSTOM_LOGO="img/playwright_custom_logo.png" npx nyc playwright test --project=customization - fi npx nyc playwright test --project=chromium --project=firefox --shard=${{ matrix.shard }}/4 - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 if: ${{ !cancelled() && steps.tests.outcome == 'failure' }} diff --git a/src/frontend/playwright.config.ts b/src/frontend/playwright.config.ts index a312f50625e4..e824e56bef4b 100644 --- a/src/frontend/playwright.config.ts +++ b/src/frontend/playwright.config.ts @@ -46,22 +46,13 @@ export default defineConfig({ name: 'chromium', use: { ...devices['Desktop Chrome'] - }, - testIgnore: /customization/ // Ignore all tests in the "customization" folder for this project + } }, { name: 'firefox', use: { ...devices['Desktop Firefox'] - }, - testIgnore: /customization/ // Ignore all tests in the "customization" folder for this project - }, - { - name: 'customization', - use: { - ...devices['Desktop Firefox'] - }, - testIgnore: /pui_.*\.spec\.ts/ // Ignore all "pui_*.spec.ts" tests for this project + } } ], @@ -101,7 +92,9 @@ export default defineConfig({ INVENTREE_DEBUG: 'True', INVENTREE_LOG_LEVEL: 'INFO', INVENTREE_PLUGINS_ENABLED: 'True', - INVENTREE_PLUGINS_MANDATORY: 'samplelocate' + INVENTREE_PLUGINS_MANDATORY: 'samplelocate', + INVENTREE_CUSTOM_SPLASH: 'img/playwright_custom_splash.png', + INVENTREE_CUSTOM_LOGO: 'img/playwright_custom_logo.png' } } ], diff --git a/src/frontend/tests/customization/customization.spec.ts b/src/frontend/tests/customization/customization.spec.ts index 9b792131ba9e..11e805457cee 100644 --- a/src/frontend/tests/customization/customization.spec.ts +++ b/src/frontend/tests/customization/customization.spec.ts @@ -5,7 +5,12 @@ import { navigate } from '../helpers'; * Tests for user interface customization functionality. * * Note: The correct environment variables must be set for these tests to work correctly. See "playwright.config.ts" for details. - * These tests are designed to run in CI environments where specific environment variables are set to enable custom logos and splash screens. The tests verify that these customizations are correctly applied in the user interface. + * These tests are designed to run in CI environments where specific environment variables are set to enable custom logos and splash screens. + * The tests verify that these customizations are correctly applied in the user interface. + * + * If you are running these tests locally, ensure that you have the appropriate environment variables set to enable the customizations. + * You may need to modify the "webServer" configuration in "playwright.config.ts" to include the necessary environment variables for local testing. + * */ test('Customization - Splash', async ({ page }) => { From 023f46340b9ad75b43659486a9d9205b89e92530 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 2 Jun 2026 07:26:26 +0000 Subject: [PATCH 06/40] Fix env vars --- src/frontend/playwright.config.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/frontend/playwright.config.ts b/src/frontend/playwright.config.ts index e824e56bef4b..3aadf7dfb21a 100644 --- a/src/frontend/playwright.config.ts +++ b/src/frontend/playwright.config.ts @@ -78,7 +78,9 @@ export default defineConfig({ INVENTREE_CORS_ORIGIN_ALLOW_ALL: 'True', INVENTREE_COOKIE_SAMESITE: 'False', INVENTREE_LOGIN_ATTEMPTS: '100', - INVENTREE_PLUGINS_MANDATORY: 'samplelocate' + INVENTREE_PLUGINS_MANDATORY: 'samplelocate', + INVENTREE_CUSTOM_SPLASH: 'img/playwright_custom_splash.png', + INVENTREE_CUSTOM_LOGO: 'img/playwright_custom_logo.png' }, url: 'http://localhost:8000/api/', reuseExistingServer: IS_CI, @@ -92,9 +94,7 @@ export default defineConfig({ INVENTREE_DEBUG: 'True', INVENTREE_LOG_LEVEL: 'INFO', INVENTREE_PLUGINS_ENABLED: 'True', - INVENTREE_PLUGINS_MANDATORY: 'samplelocate', - INVENTREE_CUSTOM_SPLASH: 'img/playwright_custom_splash.png', - INVENTREE_CUSTOM_LOGO: 'img/playwright_custom_logo.png' + INVENTREE_PLUGINS_MANDATORY: 'samplelocate' } } ], From 32ebb4780cff79ed478c22b41cae1868412d36fc Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 2 Jun 2026 08:15:08 +0000 Subject: [PATCH 07/40] Adjust matrix --- .github/workflows/qc_checks.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml index d5fdf4391fd6..62f7ebc8a0fe 100644 --- a/.github/workflows/qc_checks.yaml +++ b/.github/workflows/qc_checks.yaml @@ -665,7 +665,7 @@ jobs: invoke migrate web_ui: - name: Tests - Web UI [${{ matrix.shard }}/4] + name: Tests - Web UI [${{ matrix.browser }} - ${{ matrix.shard }}/3] runs-on: ubuntu-24.04 timeout-minutes: 40 needs: ["code-style", "paths-filter"] @@ -673,7 +673,8 @@ jobs: strategy: fail-fast: false matrix: - shard: [1, 2, 3, 4] + shard: [1, 2, 3] + browser: [chromium, firefox] services: postgres: image: postgres:17 @@ -742,7 +743,7 @@ jobs: cp ./tests/fixtures/playwright_custom_logo.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_logo.png cp ./tests/fixtures/playwright_custom_splash.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_splash.png invoke static - npx nyc playwright test --project=chromium --project=firefox --shard=${{ matrix.shard }}/4 + npx nyc playwright test --project=${{ matrix.browser }} --shard=${{ matrix.shard }}/3 - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 if: ${{ !cancelled() && steps.tests.outcome == 'failure' }} with: From ad1aae83251ab668a5168f4dcc7aba99cd557778 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 2 Jun 2026 08:15:32 +0000 Subject: [PATCH 08/40] Adjust output names --- .github/workflows/qc_checks.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml index 62f7ebc8a0fe..7ccce7b6dab6 100644 --- a/.github/workflows/qc_checks.yaml +++ b/.github/workflows/qc_checks.yaml @@ -747,14 +747,14 @@ jobs: - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 if: ${{ !cancelled() && steps.tests.outcome == 'failure' }} with: - name: playwright-report-${{ matrix.shard }} + name: playwright-report-${{ matrix.browser }}-${{ matrix.shard }} path: src/frontend/playwright-report/ retention-days: 14 - name: Upload nyc output if: ${{ !cancelled() }} uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 with: - name: nyc-output-${{ matrix.shard }} + name: nyc-output-${{ matrix.browser }}-${{ matrix.shard }} path: src/frontend/.nyc_output/ retention-days: 1 From 6657294585e18dc7406a1864305e35afa160fbae Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 2 Jun 2026 08:58:16 +0000 Subject: [PATCH 09/40] Fix paths --- .github/workflows/qc_checks.yaml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml index 7ccce7b6dab6..733c851f0ca5 100644 --- a/.github/workflows/qc_checks.yaml +++ b/.github/workflows/qc_checks.yaml @@ -755,7 +755,7 @@ jobs: uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 with: name: nyc-output-${{ matrix.browser }}-${{ matrix.shard }} - path: src/frontend/.nyc_output/ + path: src/frontend/coverage retention-days: 1 web_ui_coverage: @@ -780,11 +780,12 @@ jobs: uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # pin@v8.0.1 with: pattern: nyc-output-* - path: src/frontend/.nyc_output + path: src/frontend/coverage merge-multiple: true - name: Report coverage run: | cd src/frontend + mkdir -p .nyc_output npx nyc report --report-dir ./coverage --temp-dir .nyc_output --reporter=lcov --reporter=text-summary --exclude-after-remap false >> "$GITHUB_STEP_SUMMARY" - name: Upload coverage reports to Codecov if: github.ref == 'refs/heads/master' From b7a66ef3eb1748f4485409de8953ddd252b1a533 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 2 Jun 2026 11:39:09 +0000 Subject: [PATCH 10/40] Simplify qc_checks --- .github/workflows/qc_checks.yaml | 50 +++++++------------------------- 1 file changed, 10 insertions(+), 40 deletions(-) diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml index 733c851f0ca5..0fa19fe097c0 100644 --- a/.github/workflows/qc_checks.yaml +++ b/.github/workflows/qc_checks.yaml @@ -665,15 +665,13 @@ jobs: invoke migrate web_ui: - name: Tests - Web UI [${{ matrix.browser }} - ${{ matrix.shard }}/3] + name: Tests - Web UI [${{ matrix.browser }}] runs-on: ubuntu-24.04 timeout-minutes: 40 needs: ["code-style", "paths-filter"] if: needs.paths-filter.outputs.frontend == 'true' || needs.paths-filter.outputs.force == 'true' strategy: - fail-fast: false matrix: - shard: [1, 2, 3] browser: [chromium, firefox] services: postgres: @@ -743,52 +741,25 @@ jobs: cp ./tests/fixtures/playwright_custom_logo.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_logo.png cp ./tests/fixtures/playwright_custom_splash.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_splash.png invoke static - npx nyc playwright test --project=${{ matrix.browser }} --shard=${{ matrix.shard }}/3 + if [ "${{ matrix.browser }}" == "chromium" ]; then + npx nyc playwright test --project=chromium + else + npx playwright test --project=firefox + fi - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 if: ${{ !cancelled() && steps.tests.outcome == 'failure' }} with: - name: playwright-report-${{ matrix.browser }}-${{ matrix.shard }} + name: playwright-report path: src/frontend/playwright-report/ retention-days: 14 - - name: Upload nyc output - if: ${{ !cancelled() }} - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 - with: - name: nyc-output-${{ matrix.browser }}-${{ matrix.shard }} - path: src/frontend/coverage - retention-days: 1 - - web_ui_coverage: - name: Coverage - Web UI - runs-on: ubuntu-24.04 - needs: ["web_ui", "paths-filter"] - if: >- - !cancelled() && - (needs.paths-filter.outputs.frontend == 'true' || needs.paths-filter.outputs.force == 'true') - - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6.0.2 - with: - persist-credentials: false - - name: Environment Setup - uses: ./.github/actions/setup - with: - npm: true - - name: Install frontend dependencies - run: cd src/frontend && yarn install - - name: Download nyc outputs - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # pin@v8.0.1 - with: - pattern: nyc-output-* - path: src/frontend/coverage - merge-multiple: true - name: Report coverage + if: ${{ !cancelled() && matrix.browser == 'chromium' }} run: | cd src/frontend mkdir -p .nyc_output npx nyc report --report-dir ./coverage --temp-dir .nyc_output --reporter=lcov --reporter=text-summary --exclude-after-remap false >> "$GITHUB_STEP_SUMMARY" - name: Upload coverage reports to Codecov - if: github.ref == 'refs/heads/master' + if: ${{ !cancelled() && matrix.browser == 'chromium' && github.ref == 'refs/heads/master' }} uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # pin@v6.0.1 with: token: ${{ secrets.CODECOV_TOKEN }} @@ -796,12 +767,11 @@ jobs: flags: web files: src/frontend/coverage/lcov.info - name: Upload bundler info - if: github.ref == 'refs/heads/master' + if: ${{ !cancelled() && matrix.browser == 'chromium' && github.ref == 'refs/heads/master' }} env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} run: | cd src/frontend - yarn install yarn run build web_ui_build: From 64a72a72fe4c09ddd5a9dd632eaceb7205cc91aa Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 2 Jun 2026 11:42:37 +0000 Subject: [PATCH 11/40] Revert missing line --- .github/workflows/qc_checks.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml index 0fa19fe097c0..70c43afa44ea 100644 --- a/.github/workflows/qc_checks.yaml +++ b/.github/workflows/qc_checks.yaml @@ -772,6 +772,7 @@ jobs: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} run: | cd src/frontend + yarn install yarn run build web_ui_build: From b9a8ced96d5c8e2865923f14f1f87bd8cb101683 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 3 Jun 2026 00:50:17 +0000 Subject: [PATCH 12/40] Simplify coverage calls --- .github/workflows/qc_checks.yaml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml index 70c43afa44ea..f736d19dd5a7 100644 --- a/.github/workflows/qc_checks.yaml +++ b/.github/workflows/qc_checks.yaml @@ -741,11 +741,7 @@ jobs: cp ./tests/fixtures/playwright_custom_logo.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_logo.png cp ./tests/fixtures/playwright_custom_splash.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_splash.png invoke static - if [ "${{ matrix.browser }}" == "chromium" ]; then - npx nyc playwright test --project=chromium - else - npx playwright test --project=firefox - fi + npx nyc playwright test --project=${{ matrix.browser }} - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 if: ${{ !cancelled() && steps.tests.outcome == 'failure' }} with: @@ -757,7 +753,7 @@ jobs: run: | cd src/frontend mkdir -p .nyc_output - npx nyc report --report-dir ./coverage --temp-dir .nyc_output --reporter=lcov --reporter=text-summary --exclude-after-remap false >> "$GITHUB_STEP_SUMMARY" + npx nyc report --report-dir ./coverage --temp-dir .nyc_output --reporter=lcov --reporter=text-summary --exclude-after-remap false | tee -a "$GITHUB_STEP_SUMMARY" - name: Upload coverage reports to Codecov if: ${{ !cancelled() && matrix.browser == 'chromium' && github.ref == 'refs/heads/master' }} uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # pin@v6.0.1 From 5ca3d5b0f71025806989c21e553ff0209c940eba Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 3 Jun 2026 01:44:11 +0000 Subject: [PATCH 13/40] Run firefox test against port 8000 --- .github/workflows/qc_checks.yaml | 6 +++++- src/frontend/playwright.config.ts | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml index f736d19dd5a7..8554b44ee390 100644 --- a/.github/workflows/qc_checks.yaml +++ b/.github/workflows/qc_checks.yaml @@ -741,7 +741,11 @@ jobs: cp ./tests/fixtures/playwright_custom_logo.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_logo.png cp ./tests/fixtures/playwright_custom_splash.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_splash.png invoke static - npx nyc playwright test --project=${{ matrix.browser }} + if [ "${{ matrix.browser }}" == "chromium" ]; then + npx nyc playwright test --project=chromium + else + PLAYWRIGHT_BASE_URL=http://localhost:8000 npx nyc playwright test --project=firefox + fi - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 if: ${{ !cancelled() && steps.tests.outcome == 'failure' }} with: diff --git a/src/frontend/playwright.config.ts b/src/frontend/playwright.config.ts index 3aadf7dfb21a..a01f12d0b68e 100644 --- a/src/frontend/playwright.config.ts +++ b/src/frontend/playwright.config.ts @@ -26,7 +26,8 @@ const MAX_RETRIES: number = 2; * - WORKERS = 1 (to avoid conflicts with HMR) */ -const BASE_URL: string = 'http://localhost:5173'; +const BASE_URL: string = + process.env.PLAYWRIGHT_BASE_URL || 'http://localhost:5173'; console.log('Running Playwright Tests:'); console.log('- Base URL:', BASE_URL); From cc9d82bedaf136d821efd0e3cbf7919b907cc1c2 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 3 Jun 2026 01:50:15 +0000 Subject: [PATCH 14/40] Fix VITE_COVERAGE env var --- .github/workflows/qc_checks.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml index 8554b44ee390..de774d24e452 100644 --- a/.github/workflows/qc_checks.yaml +++ b/.github/workflows/qc_checks.yaml @@ -697,7 +697,7 @@ jobs: INVENTREE_DB_PASSWORD: inventree_password INVENTREE_DEBUG: true INVENTREE_PLUGINS_ENABLED: false - VITE_COVERAGE_BUILD: true + VITE_COVERAGE: true steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6.0.2 From 3900262d6cc59e8e49d392504cc3aea27ce2a5a2 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 3 Jun 2026 02:17:51 +0000 Subject: [PATCH 15/40] Capture browser name in report output --- .github/workflows/qc_checks.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml index de774d24e452..85608975d32f 100644 --- a/.github/workflows/qc_checks.yaml +++ b/.github/workflows/qc_checks.yaml @@ -749,7 +749,7 @@ jobs: - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 if: ${{ !cancelled() && steps.tests.outcome == 'failure' }} with: - name: playwright-report + name: playwright-report-${{ matrix.browser }} path: src/frontend/playwright-report/ retention-days: 14 - name: Report coverage From cc36fe91f55e9b3f781a3d688b3c604049165004 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 3 Jun 2026 02:25:19 +0000 Subject: [PATCH 16/40] Increase timeout again --- .github/workflows/qc_checks.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml index 85608975d32f..bbac334131b7 100644 --- a/.github/workflows/qc_checks.yaml +++ b/.github/workflows/qc_checks.yaml @@ -667,7 +667,7 @@ jobs: web_ui: name: Tests - Web UI [${{ matrix.browser }}] runs-on: ubuntu-24.04 - timeout-minutes: 40 + timeout-minutes: 60 needs: ["code-style", "paths-filter"] if: needs.paths-filter.outputs.frontend == 'true' || needs.paths-filter.outputs.force == 'true' strategy: From ac7f6c2876dc64af78809436ffdbc66985b085f5 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 3 Jun 2026 02:58:33 +0000 Subject: [PATCH 17/40] Enhanced feedback from playwright startup --- src/frontend/playwright.config.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/frontend/playwright.config.ts b/src/frontend/playwright.config.ts index a01f12d0b68e..9de7b356aa06 100644 --- a/src/frontend/playwright.config.ts +++ b/src/frontend/playwright.config.ts @@ -3,9 +3,6 @@ import { defineConfig, devices } from '@playwright/test'; // Detect if running in CI const IS_CI = !!process.env.CI; -const MAX_WORKERS: number = 3; -const MAX_RETRIES: number = 2; - /* We optionally spin-up services based on the testing mode: * * Local Development: @@ -29,16 +26,22 @@ const MAX_RETRIES: number = 2; const BASE_URL: string = process.env.PLAYWRIGHT_BASE_URL || 'http://localhost:5173'; +// If running in "production" mode, we can use multiple workers to speed up the tests +const MAX_WORKERS: number = BASE_URL.endsWith('8000') ? 3 : 1; +const MAX_RETRIES: number = IS_CI ? 2 : 5; + console.log('Running Playwright Tests:'); console.log('- Base URL:', BASE_URL); +console.log('- Max Workers:', MAX_WORKERS); +console.log('- Max Retries:', MAX_RETRIES); export default defineConfig({ testDir: './tests', fullyParallel: false, timeout: 90000, forbidOnly: !!IS_CI, - retries: IS_CI ? MAX_RETRIES : 0, - workers: IS_CI ? MAX_WORKERS : 1, + retries: MAX_RETRIES, + workers: MAX_WORKERS, reporter: IS_CI ? [['html', { open: 'never' }], ['github']] : 'list', /* Configure projects for major browsers */ From 7b27b048fce2163840ebf639e72ce6b846de1bf6 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 3 Jun 2026 03:20:11 +0000 Subject: [PATCH 18/40] Split UI checks into separate file --- .github/workflows/frontend.yaml | 320 +++++++++++++++++++++++++++++++ .github/workflows/qc_checks.yaml | 140 -------------- 2 files changed, 320 insertions(+), 140 deletions(-) create mode 100644 .github/workflows/frontend.yaml diff --git a/.github/workflows/frontend.yaml b/.github/workflows/frontend.yaml new file mode 100644 index 000000000000..3a5a2e2c2784 --- /dev/null +++ b/.github/workflows/frontend.yaml @@ -0,0 +1,320 @@ +# Playwright testing for frontend code +# Runs the following tests: +# - Playwright tests in Firefox (against compiled frontend code) +# - Playwright tests in Chromium (coverage enabled, against vite frontend code) +# - Build frontend code and upload as artifact + +name: Frontend + +on: + push: + branches-ignore: ["l10*"] + pull_request: + branches-ignore: ["l10*"] + +env: + python_version: 3.11 + node_version: 24 + # The OS version must be set per job + server_start_sleep: 60 + + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + INVENTREE_DB_ENGINE: sqlite3 + INVENTREE_DB_NAME: inventree + INVENTREE_MEDIA_ROOT: /home/runner/work/InvenTree/test_inventree_media + INVENTREE_STATIC_ROOT: /home/runner/work/InvenTree/test_inventree_static + INVENTREE_BACKUP_DIR: /home/runner/work/InvenTree/test_inventree_backup + INVENTREE_SITE_URL: http://localhost:8000 + INVENTREE_DEBUG: true + +permissions: + contents: read + +jobs: + paths-filter: + name: Filter + runs-on: ubuntu-latest + + outputs: + server: ${{ steps.filter.outputs.server }} + migrations: ${{ steps.filter.outputs.migrations }} + frontend: ${{ steps.filter.outputs.frontend }} + api: ${{ steps.filter.outputs.api }} + force: ${{ steps.force.outputs.force }} + cicd: ${{ steps.filter.outputs.cicd }} + requirements: ${{ steps.filter.outputs.requirements }} + runner-perf: ${{ steps.runner-perf.outputs.runner }} + performance: ${{ steps.performance.outputs.force-performance }} + submit-performance: ${{ steps.runner-perf.outputs.submit-performance }} + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6.0.2 + with: + persist-credentials: false + - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # pin@v4.0.1 + id: filter + with: + filters: | + server: + - 'src/backend/InvenTree/**' + - 'src/backend/requirements.txt' + - 'src/backend/requirements-dev.txt' + migrations: + - '**/test_migrations.py' + - '**/migrations/**' + - '.github/workflows**' + - 'src/backend/requirements.txt' + api: + - 'src/backend/InvenTree/InvenTree/api_version.py' + frontend: + - 'src/frontend/**' + cicd: + - '.github/workflows/**' + requirements: + - 'src/backend/requirements.txt' + - 'src/backend/requirements-dev.txt' + - 'docs/requirements.txt' + - 'contrib/dev_reqs/requirements.txt' + - name: Is CI being forced? + run: echo "force=true" >> $GITHUB_OUTPUT + id: force + if: | + contains(github.event.pull_request.labels.*.name, 'dependency') || + contains(github.event.pull_request.labels.*.name, 'full-run') + - name: Is performance testing being forced? + run: echo "force-performance=true" >> $GITHUB_OUTPUT + id: performance + if: | + contains(github.event.pull_request.labels.*.name, 'performance-run') + - name: Which runner to use? + env: + GITHUB_REF: ${{ github.ref }} + PERFORMANCE: ${{ steps.performance.outputs.force-performance }} + id: runner-perf + # decide if we are running in inventree/inventree -> use codspeed-macro runner else ubuntu-24.04 + run: | + is_main_push=false + if [[ '${{ github.event_name }}' == 'push' && "$GITHUB_REF" == 'refs/heads/master' ]]; then + is_main_push=true + fi + if [[ '${{ github.repository }}' == 'inventree/InvenTree' && ( "$is_main_push" == 'true' || "$PERFORMANCE" == 'true' ) ]]; then + echo "runner=codspeed-macro" >> "$GITHUB_OUTPUT" + echo "submit-performance=true" >> "$GITHUB_OUTPUT" + else + echo "runner=ubuntu-24.04" >> "$GITHUB_OUTPUT" + echo "submit-performance=false" >> "$GITHUB_OUTPUT" + fi + + firefox: + name: Tests - Firefox + runs-on: ubuntu-24.04 + timeout-minutes: 60 + needs: ["code-style", "paths-filter"] + if: needs.paths-filter.outputs.frontend == 'true' || needs.paths-filter.outputs.force == 'true' + services: + postgres: + image: postgres:17 + env: + POSTGRES_DB: inventree + POSTGRES_USER: inventree_user + POSTGRES_PASSWORD: inventree_password + ports: + - 5432:5432 + options: >- + --health-cmd "pg_isready -U testuser" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + env: + INVENTREE_DB_ENGINE: postgresql + INVENTREE_DB_NAME: inventree + INVENTREE_DB_HOST: "127.0.0.1" + INVENTREE_DB_PORT: 5432 + INVENTREE_DB_USER: inventree_user + INVENTREE_DB_PASSWORD: inventree_password + INVENTREE_DEBUG: true + INVENTREE_PLUGINS_ENABLED: false + VITE_COVERAGE: true + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6.0.2 + with: + persist-credentials: false + - name: Environment Setup + uses: ./.github/actions/setup + with: + npm: true + install: true + update: true + apt-dependency: gettext postgresql-client libpq-dev + pip-dependency: psycopg2 + - name: Set up test data + run: | + invoke dev.setup-test -iv + invoke int.rebuild-thumbnails + - name: Install dependencies + run: invoke int.frontend-compile --extract + - name: Cache Playwright browsers + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # pin@v4.3.0 + id: playwright-cache + with: + path: ~/.cache/ms-playwright + key: ${{ runner.os }}-playwright-${{ hashFiles('src/frontend/yarn.lock') }} + - name: Install Playwright browsers + if: steps.playwright-cache.outputs.cache-hit != 'true' + run: cd src/frontend && npx playwright install --with-deps + - name: Install Playwright OS dependencies + if: steps.playwright-cache.outputs.cache-hit == 'true' + run: cd src/frontend && npx playwright install-deps + - name: Install Sample Plugin + run: | + pip install -U inventree-plugin-creator + create-inventree-plugin --default + cd MyCustomPlugin && pip install -e . && cd frontend && npm install && npm run translate && npm run build + - name: Run Playwright tests + id: tests + run: | + cd src/frontend + cp ./tests/fixtures/playwright_custom_logo.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_logo.png + cp ./tests/fixtures/playwright_custom_splash.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_splash.png + invoke static + PLAYWRIGHT_BASE_URL=http://localhost:8000 npx playwright test --project=firefox + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 + if: ${{ !cancelled() && steps.tests.outcome == 'failure' }} + with: + name: playwright-report-firefox + path: src/frontend/playwright-report/ + retention-days: 14 + + chromium: + name: Tests - Chromium + runs-on: ubuntu-24.04 + timeout-minutes: 60 + needs: ["code-style", "paths-filter"] + if: needs.paths-filter.outputs.frontend == 'true' || needs.paths-filter.outputs.force == 'true' + services: + postgres: + image: postgres:17 + env: + POSTGRES_DB: inventree + POSTGRES_USER: inventree_user + POSTGRES_PASSWORD: inventree_password + ports: + - 5432:5432 + options: >- + --health-cmd "pg_isready -U testuser" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + env: + INVENTREE_DB_ENGINE: postgresql + INVENTREE_DB_NAME: inventree + INVENTREE_DB_HOST: "127.0.0.1" + INVENTREE_DB_PORT: 5432 + INVENTREE_DB_USER: inventree_user + INVENTREE_DB_PASSWORD: inventree_password + INVENTREE_DEBUG: true + INVENTREE_PLUGINS_ENABLED: false + VITE_COVERAGE: true + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6.0.2 + with: + persist-credentials: false + - name: Environment Setup + uses: ./.github/actions/setup + with: + npm: true + install: true + update: true + apt-dependency: gettext postgresql-client libpq-dev + pip-dependency: psycopg2 + - name: Set up test data + run: | + invoke dev.setup-test -iv + invoke int.rebuild-thumbnails + - name: Install dependencies + run: invoke int.frontend-compile --extract + - name: Cache Playwright browsers + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # pin@v4.3.0 + id: playwright-cache + with: + path: ~/.cache/ms-playwright + key: ${{ runner.os }}-playwright-${{ hashFiles('src/frontend/yarn.lock') }} + - name: Install Playwright browsers + if: steps.playwright-cache.outputs.cache-hit != 'true' + run: cd src/frontend && npx playwright install --with-deps + - name: Install Playwright OS dependencies + if: steps.playwright-cache.outputs.cache-hit == 'true' + run: cd src/frontend && npx playwright install-deps + - name: Install Sample Plugin + run: | + pip install -U inventree-plugin-creator + create-inventree-plugin --default + cd MyCustomPlugin && pip install -e . && cd frontend && npm install && npm run translate && npm run build + - name: Run Playwright tests + id: tests + run: | + cd src/frontend + cp ./tests/fixtures/playwright_custom_logo.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_logo.png + cp ./tests/fixtures/playwright_custom_splash.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_splash.png + npx nyc playwright test --project=chromium + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 + if: ${{ !cancelled() && steps.tests.outcome == 'failure' }} + with: + name: playwright-report-chromium + path: src/frontend/playwright-report/ + retention-days: 14 + - name: Report coverage + if: ${{ !cancelled() }} + run: | + cd src/frontend + mkdir -p .nyc_output + npx nyc report --report-dir ./coverage --temp-dir .nyc_output --reporter=lcov --reporter=text-summary --exclude-after-remap false | tee -a "$GITHUB_STEP_SUMMARY" + - name: Upload coverage reports to Codecov + if: ${{ !cancelled() && github.ref == 'refs/heads/master' }} + uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # pin@v6.0.1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + slug: inventree/InvenTree + flags: web + files: src/frontend/coverage/lcov.info + - name: Upload bundler info + if: ${{ !cancelled() && github.ref == 'refs/heads/master' }} + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + run: | + cd src/frontend + yarn install + yarn run build + + build: + name: Build Frontend + runs-on: ubuntu-24.04 + timeout-minutes: 60 + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6.0.2 + with: + persist-credentials: false + - name: Environment Setup + uses: ./.github/actions/setup + with: + npm: true + - name: Install dependencies + run: cd src/frontend && yarn install + - name: Build frontend + run: cd src/frontend && yarn run compile && yarn run lib && yarn run build + - name: Write version file - SHA + run: cd src/backend/InvenTree/web/static/web/.vite && echo "$GITHUB_SHA" > sha.txt + - name: Zip frontend + run: | + cd src/backend/InvenTree/web/static + zip -r frontend-build.zip web/ web/.vite + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 + with: + name: frontend-build + path: src/backend/InvenTree/web/static/web + include-hidden-files: true diff --git a/.github/workflows/qc_checks.yaml b/.github/workflows/qc_checks.yaml index bbac334131b7..bcc71469e676 100644 --- a/.github/workflows/qc_checks.yaml +++ b/.github/workflows/qc_checks.yaml @@ -664,146 +664,6 @@ jobs: chmod +rw /home/runner/work/InvenTree/db.sqlite3 invoke migrate - web_ui: - name: Tests - Web UI [${{ matrix.browser }}] - runs-on: ubuntu-24.04 - timeout-minutes: 60 - needs: ["code-style", "paths-filter"] - if: needs.paths-filter.outputs.frontend == 'true' || needs.paths-filter.outputs.force == 'true' - strategy: - matrix: - browser: [chromium, firefox] - services: - postgres: - image: postgres:17 - env: - POSTGRES_DB: inventree - POSTGRES_USER: inventree_user - POSTGRES_PASSWORD: inventree_password - ports: - - 5432:5432 - options: >- - --health-cmd "pg_isready -U testuser" - --health-interval 10s - --health-timeout 5s - --health-retries 5 - - env: - INVENTREE_DB_ENGINE: postgresql - INVENTREE_DB_NAME: inventree - INVENTREE_DB_HOST: "127.0.0.1" - INVENTREE_DB_PORT: 5432 - INVENTREE_DB_USER: inventree_user - INVENTREE_DB_PASSWORD: inventree_password - INVENTREE_DEBUG: true - INVENTREE_PLUGINS_ENABLED: false - VITE_COVERAGE: true - - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6.0.2 - with: - persist-credentials: false - - name: Environment Setup - uses: ./.github/actions/setup - with: - npm: true - install: true - update: true - apt-dependency: gettext postgresql-client libpq-dev - pip-dependency: psycopg2 - - name: Set up test data - run: | - invoke dev.setup-test -iv - invoke int.rebuild-thumbnails - - name: Install dependencies - run: invoke int.frontend-compile --extract - - name: Cache Playwright browsers - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # pin@v4.3.0 - id: playwright-cache - with: - path: ~/.cache/ms-playwright - key: ${{ runner.os }}-playwright-${{ hashFiles('src/frontend/yarn.lock') }} - - name: Install Playwright browsers - if: steps.playwright-cache.outputs.cache-hit != 'true' - run: cd src/frontend && npx playwright install --with-deps - - name: Install Playwright OS dependencies - if: steps.playwright-cache.outputs.cache-hit == 'true' - run: cd src/frontend && npx playwright install-deps - - name: Install Sample Plugin - run: | - pip install -U inventree-plugin-creator - create-inventree-plugin --default - cd MyCustomPlugin && pip install -e . && cd frontend && npm install && npm run translate && npm run build - - name: Run Playwright tests - id: tests - run: | - cd src/frontend - cp ./tests/fixtures/playwright_custom_logo.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_logo.png - cp ./tests/fixtures/playwright_custom_splash.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_splash.png - invoke static - if [ "${{ matrix.browser }}" == "chromium" ]; then - npx nyc playwright test --project=chromium - else - PLAYWRIGHT_BASE_URL=http://localhost:8000 npx nyc playwright test --project=firefox - fi - - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 - if: ${{ !cancelled() && steps.tests.outcome == 'failure' }} - with: - name: playwright-report-${{ matrix.browser }} - path: src/frontend/playwright-report/ - retention-days: 14 - - name: Report coverage - if: ${{ !cancelled() && matrix.browser == 'chromium' }} - run: | - cd src/frontend - mkdir -p .nyc_output - npx nyc report --report-dir ./coverage --temp-dir .nyc_output --reporter=lcov --reporter=text-summary --exclude-after-remap false | tee -a "$GITHUB_STEP_SUMMARY" - - name: Upload coverage reports to Codecov - if: ${{ !cancelled() && matrix.browser == 'chromium' && github.ref == 'refs/heads/master' }} - uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # pin@v6.0.1 - with: - token: ${{ secrets.CODECOV_TOKEN }} - slug: inventree/InvenTree - flags: web - files: src/frontend/coverage/lcov.info - - name: Upload bundler info - if: ${{ !cancelled() && matrix.browser == 'chromium' && github.ref == 'refs/heads/master' }} - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - run: | - cd src/frontend - yarn install - yarn run build - - web_ui_build: - name: Build - Web UI - runs-on: ubuntu-24.04 - timeout-minutes: 60 - - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6.0.2 - with: - persist-credentials: false - - name: Environment Setup - uses: ./.github/actions/setup - with: - npm: true - - name: Install dependencies - run: cd src/frontend && yarn install - - name: Build frontend - run: cd src/frontend && yarn run compile && yarn run lib && yarn run build - - name: Write version file - SHA - run: cd src/backend/InvenTree/web/static/web/.vite && echo "$GITHUB_SHA" > sha.txt - - name: Zip frontend - run: | - cd src/backend/InvenTree/web/static - zip -r frontend-build.zip web/ web/.vite - - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 - with: - name: frontend-build - path: src/backend/InvenTree/web/static/web - include-hidden-files: true - zizmor: name: Security [Zizmor] runs-on: ubuntu-24.04 From c080d5796473c2e1d3a975f84b530f7e41aa6ab8 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 3 Jun 2026 03:25:32 +0000 Subject: [PATCH 19/40] Fix workflow deps --- .github/workflows/frontend.yaml | 62 ++++++++++++++++----------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/.github/workflows/frontend.yaml b/.github/workflows/frontend.yaml index 3a5a2e2c2784..d678043f2859 100644 --- a/.github/workflows/frontend.yaml +++ b/.github/workflows/frontend.yaml @@ -105,11 +105,40 @@ jobs: echo "submit-performance=false" >> "$GITHUB_OUTPUT" fi + build: + name: Build Frontend + runs-on: ubuntu-24.04 + timeout-minutes: 60 + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6.0.2 + with: + persist-credentials: false + - name: Environment Setup + uses: ./.github/actions/setup + with: + npm: true + - name: Install dependencies + run: cd src/frontend && yarn install + - name: Build frontend + run: cd src/frontend && yarn run compile && yarn run lib && yarn run build + - name: Write version file - SHA + run: cd src/backend/InvenTree/web/static/web/.vite && echo "$GITHUB_SHA" > sha.txt + - name: Zip frontend + run: | + cd src/backend/InvenTree/web/static + zip -r frontend-build.zip web/ web/.vite + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 + with: + name: frontend-build + path: src/backend/InvenTree/web/static/web + include-hidden-files: true + firefox: name: Tests - Firefox runs-on: ubuntu-24.04 timeout-minutes: 60 - needs: ["code-style", "paths-filter"] + needs: ["build", "paths-filter"] if: needs.paths-filter.outputs.frontend == 'true' || needs.paths-filter.outputs.force == 'true' services: postgres: @@ -191,7 +220,7 @@ jobs: name: Tests - Chromium runs-on: ubuntu-24.04 timeout-minutes: 60 - needs: ["code-style", "paths-filter"] + needs: ["build", "paths-filter"] if: needs.paths-filter.outputs.frontend == 'true' || needs.paths-filter.outputs.force == 'true' services: postgres: @@ -289,32 +318,3 @@ jobs: cd src/frontend yarn install yarn run build - - build: - name: Build Frontend - runs-on: ubuntu-24.04 - timeout-minutes: 60 - - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6.0.2 - with: - persist-credentials: false - - name: Environment Setup - uses: ./.github/actions/setup - with: - npm: true - - name: Install dependencies - run: cd src/frontend && yarn install - - name: Build frontend - run: cd src/frontend && yarn run compile && yarn run lib && yarn run build - - name: Write version file - SHA - run: cd src/backend/InvenTree/web/static/web/.vite && echo "$GITHUB_SHA" > sha.txt - - name: Zip frontend - run: | - cd src/backend/InvenTree/web/static - zip -r frontend-build.zip web/ web/.vite - - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 - with: - name: frontend-build - path: src/backend/InvenTree/web/static/web - include-hidden-files: true From 2f0ad21dab1876b982593a7e4d32b66b3c3496ff Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 3 Jun 2026 05:29:18 +0000 Subject: [PATCH 20/40] Shard chromium build --- .github/workflows/frontend.yaml | 141 +++++++++++++++++++++++--------- 1 file changed, 102 insertions(+), 39 deletions(-) diff --git a/.github/workflows/frontend.yaml b/.github/workflows/frontend.yaml index d678043f2859..5af40a0ec1d6 100644 --- a/.github/workflows/frontend.yaml +++ b/.github/workflows/frontend.yaml @@ -19,13 +19,18 @@ env: server_start_sleep: 60 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - INVENTREE_DB_ENGINE: sqlite3 + INVENTREE_DB_ENGINE: postgresql INVENTREE_DB_NAME: inventree + INVENTREE_DB_HOST: "127.0.0.1" + INVENTREE_DB_PORT: 5432 + INVENTREE_DB_USER: inventree_user + INVENTREE_DB_PASSWORD: inventree_password + INVENTREE_DEBUG: true + INVENTREE_PLUGINS_ENABLED: false INVENTREE_MEDIA_ROOT: /home/runner/work/InvenTree/test_inventree_media INVENTREE_STATIC_ROOT: /home/runner/work/InvenTree/test_inventree_static INVENTREE_BACKUP_DIR: /home/runner/work/InvenTree/test_inventree_backup INVENTREE_SITE_URL: http://localhost:8000 - INVENTREE_DEBUG: true permissions: contents: read @@ -106,7 +111,7 @@ jobs: fi build: - name: Build Frontend + name: Build runs-on: ubuntu-24.04 timeout-minutes: 60 @@ -135,7 +140,7 @@ jobs: include-hidden-files: true firefox: - name: Tests - Firefox + name: Tests [Firefox] runs-on: ubuntu-24.04 timeout-minutes: 60 needs: ["build", "paths-filter"] @@ -156,15 +161,7 @@ jobs: --health-retries 5 env: - INVENTREE_DB_ENGINE: postgresql - INVENTREE_DB_NAME: inventree - INVENTREE_DB_HOST: "127.0.0.1" - INVENTREE_DB_PORT: 5432 - INVENTREE_DB_USER: inventree_user - INVENTREE_DB_PASSWORD: inventree_password - INVENTREE_DEBUG: true - INVENTREE_PLUGINS_ENABLED: false - VITE_COVERAGE: true + VITE_COVERAGE: false steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6.0.2 @@ -217,11 +214,15 @@ jobs: retention-days: 14 chromium: - name: Tests - Chromium + name: Tests [Chromium ${{ matrix.shard }} / 4] runs-on: ubuntu-24.04 timeout-minutes: 60 needs: ["build", "paths-filter"] if: needs.paths-filter.outputs.frontend == 'true' || needs.paths-filter.outputs.force == 'true' + strategy: + fail-fast: false + matrix: + shard: [1, 2, 3, 4] services: postgres: image: postgres:17 @@ -238,14 +239,7 @@ jobs: --health-retries 5 env: - INVENTREE_DB_ENGINE: postgresql - INVENTREE_DB_NAME: inventree - INVENTREE_DB_HOST: "127.0.0.1" - INVENTREE_DB_PORT: 5432 - INVENTREE_DB_USER: inventree_user - INVENTREE_DB_PASSWORD: inventree_password - INVENTREE_DEBUG: true - INVENTREE_PLUGINS_ENABLED: false + COVERAGE: true VITE_COVERAGE: true steps: @@ -283,25 +277,93 @@ jobs: pip install -U inventree-plugin-creator create-inventree-plugin --default cd MyCustomPlugin && pip install -e . && cd frontend && npm install && npm run translate && npm run build - - name: Run Playwright tests + - name: Playwright [${{ matrix.shard }} / 4] id: tests run: | cd src/frontend cp ./tests/fixtures/playwright_custom_logo.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_logo.png cp ./tests/fixtures/playwright_custom_splash.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_splash.png - npx nyc playwright test --project=chromium - - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 + npx nyc playwright test --project=chromium --shard=${{ matrix.shard }}/4 + - name: Upload Blob Report [${{ matrix.shard }} / 4] + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 + id: blob-upload + if: always() + with: + name: blob-report-${{ matrix.shard }} + path: blob-report/ + retention-days: 1 + - name: Upload Coverage Artifact [${{ matrix.shard }} / 4] + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 + id: coverage-upload + if: always() + with: + name: coverage-${{ matrix.shard }} + path: .nyc_output/ + retention-days: 1 + - name: Playwright Report [${{ matrix.shard }} / 4] + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 if: ${{ !cancelled() && steps.tests.outcome == 'failure' }} with: name: playwright-report-chromium path: src/frontend/playwright-report/ - retention-days: 14 - - name: Report coverage - if: ${{ !cancelled() }} + retention-days: 7 + + # Recombine the coverage reports from the 4 shards, and upload to Codecov + coverage: + name: Merge coverage reports and upload to Codecov + runs-on: ubuntu-latest + needs: chromium + timeout-minutes: 30 + if: always() + + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6.0.2 + with: + persist-credentials: false + + - name: Environment Setup + uses: ./.github/actions/setup + with: + npm: true + install: false + update: false + + - name: Download Blob Reports + uses: actions/download-artifact@v8 + with: + pattern: blob-report-* + path: all-blob-reports/ + merge-multiple: true + + - name: Merge Playwright reports + run: npx playwright merge-reports --reporter html ./all-blob-reports + + - name: Upload Merged HTML Report + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 + with: + name: playwright-report + path: playwright-report/ + retention-days: 7 + + - name: Download Coverage Artifacts + uses: actions/download-artifact@v8 + with: + pattern: coverage-* + path: all-coverage/ + merge-multiple: true + + - name: Merge Coverage Reports run: | - cd src/frontend mkdir -p .nyc_output - npx nyc report --report-dir ./coverage --temp-dir .nyc_output --reporter=lcov --reporter=text-summary --exclude-after-remap false | tee -a "$GITHUB_STEP_SUMMARY" + cp all-coverage/*.json .nyc_output/ 2>/dev/null || true + npx nyc merge .nyc_output merged-coverage.json + npx nyc report \ + --tempdir .nyc_output \ + --reporter=lcov \ + --reporter=text-summary \ + --report-dir ./coverage \ + - name: Upload coverage reports to Codecov if: ${{ !cancelled() && github.ref == 'refs/heads/master' }} uses: codecov/codecov-action@e79a6962e0d4c0c17b229090214935d2e33f8354 # pin@v6.0.1 @@ -309,12 +371,13 @@ jobs: token: ${{ secrets.CODECOV_TOKEN }} slug: inventree/InvenTree flags: web - files: src/frontend/coverage/lcov.info - - name: Upload bundler info - if: ${{ !cancelled() && github.ref == 'refs/heads/master' }} - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - run: | - cd src/frontend - yarn install - yarn run build + files: ./coverage/lcov.info + + # - name: Upload bundler info + # if: ${{ !cancelled() && github.ref == 'refs/heads/master' }} + # env: + # CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + # run: | + # cd src/frontend + # yarn install + # yarn run build From f0c7a8a74597b13ee13cd67e63fd7382b61cbbf1 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 3 Jun 2026 05:31:33 +0000 Subject: [PATCH 21/40] Adjust reporter type --- src/frontend/playwright.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/playwright.config.ts b/src/frontend/playwright.config.ts index 9de7b356aa06..16971b138e0f 100644 --- a/src/frontend/playwright.config.ts +++ b/src/frontend/playwright.config.ts @@ -42,7 +42,7 @@ export default defineConfig({ forbidOnly: !!IS_CI, retries: MAX_RETRIES, workers: MAX_WORKERS, - reporter: IS_CI ? [['html', { open: 'never' }], ['github']] : 'list', + reporter: IS_CI ? [['blob'], ['github']] : [['html']], /* Configure projects for major browsers */ projects: [ From 731ca186f3093003327c4dd02e62027f3bec5375 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Wed, 3 Jun 2026 05:40:19 +0000 Subject: [PATCH 22/40] Reduce uncessesary build steps --- .github/actions/setup/action.yaml | 2 +- .github/workflows/frontend.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/setup/action.yaml b/.github/actions/setup/action.yaml index 3c7526de7168..f312390970a3 100644 --- a/.github/actions/setup/action.yaml +++ b/.github/actions/setup/action.yaml @@ -106,7 +106,7 @@ runs: - name: Run invoke update if: ${{ inputs.update == 'true' }} shell: bash - run: invoke update --skip-backup --skip-static + run: invoke update --skip-backup --skip-static --no-frontend - name: Collect static files if: ${{ inputs.static == 'true' }} shell: bash diff --git a/.github/workflows/frontend.yaml b/.github/workflows/frontend.yaml index 5af40a0ec1d6..a9f7fd63c692 100644 --- a/.github/workflows/frontend.yaml +++ b/.github/workflows/frontend.yaml @@ -259,7 +259,7 @@ jobs: invoke dev.setup-test -iv invoke int.rebuild-thumbnails - name: Install dependencies - run: invoke int.frontend-compile --extract + run: invoke int.frontend-install - name: Cache Playwright browsers uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # pin@v4.3.0 id: playwright-cache From 31c1ba4777f54d8f15babfd38fdab7ba798d8d35 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 4 Jun 2026 08:34:49 +0000 Subject: [PATCH 23/40] Tweak paths filter --- .github/workflows/frontend.yaml | 50 +-------------------------------- 1 file changed, 1 insertion(+), 49 deletions(-) diff --git a/.github/workflows/frontend.yaml b/.github/workflows/frontend.yaml index a9f7fd63c692..3dc1b070d133 100644 --- a/.github/workflows/frontend.yaml +++ b/.github/workflows/frontend.yaml @@ -41,16 +41,8 @@ jobs: runs-on: ubuntu-latest outputs: - server: ${{ steps.filter.outputs.server }} - migrations: ${{ steps.filter.outputs.migrations }} frontend: ${{ steps.filter.outputs.frontend }} - api: ${{ steps.filter.outputs.api }} force: ${{ steps.force.outputs.force }} - cicd: ${{ steps.filter.outputs.cicd }} - requirements: ${{ steps.filter.outputs.requirements }} - runner-perf: ${{ steps.runner-perf.outputs.runner }} - performance: ${{ steps.performance.outputs.force-performance }} - submit-performance: ${{ steps.runner-perf.outputs.submit-performance }} steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # pin@v6.0.2 @@ -60,55 +52,15 @@ jobs: id: filter with: filters: | - server: - - 'src/backend/InvenTree/**' - - 'src/backend/requirements.txt' - - 'src/backend/requirements-dev.txt' - migrations: - - '**/test_migrations.py' - - '**/migrations/**' - - '.github/workflows**' - - 'src/backend/requirements.txt' - api: - - 'src/backend/InvenTree/InvenTree/api_version.py' frontend: - 'src/frontend/**' - cicd: - - '.github/workflows/**' - requirements: - - 'src/backend/requirements.txt' - - 'src/backend/requirements-dev.txt' - - 'docs/requirements.txt' - - 'contrib/dev_reqs/requirements.txt' - name: Is CI being forced? run: echo "force=true" >> $GITHUB_OUTPUT id: force if: | contains(github.event.pull_request.labels.*.name, 'dependency') || contains(github.event.pull_request.labels.*.name, 'full-run') - - name: Is performance testing being forced? - run: echo "force-performance=true" >> $GITHUB_OUTPUT - id: performance - if: | - contains(github.event.pull_request.labels.*.name, 'performance-run') - - name: Which runner to use? - env: - GITHUB_REF: ${{ github.ref }} - PERFORMANCE: ${{ steps.performance.outputs.force-performance }} - id: runner-perf - # decide if we are running in inventree/inventree -> use codspeed-macro runner else ubuntu-24.04 - run: | - is_main_push=false - if [[ '${{ github.event_name }}' == 'push' && "$GITHUB_REF" == 'refs/heads/master' ]]; then - is_main_push=true - fi - if [[ '${{ github.repository }}' == 'inventree/InvenTree' && ( "$is_main_push" == 'true' || "$PERFORMANCE" == 'true' ) ]]; then - echo "runner=codspeed-macro" >> "$GITHUB_OUTPUT" - echo "submit-performance=true" >> "$GITHUB_OUTPUT" - else - echo "runner=ubuntu-24.04" >> "$GITHUB_OUTPUT" - echo "submit-performance=false" >> "$GITHUB_OUTPUT" - fi + build: name: Build From 695d4519230245eb980f49177283968fc970cb07 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 4 Jun 2026 08:38:40 +0000 Subject: [PATCH 24/40] Reduce retries --- src/frontend/playwright.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/playwright.config.ts b/src/frontend/playwright.config.ts index 16971b138e0f..f423d24a8014 100644 --- a/src/frontend/playwright.config.ts +++ b/src/frontend/playwright.config.ts @@ -28,7 +28,7 @@ const BASE_URL: string = // If running in "production" mode, we can use multiple workers to speed up the tests const MAX_WORKERS: number = BASE_URL.endsWith('8000') ? 3 : 1; -const MAX_RETRIES: number = IS_CI ? 2 : 5; +const MAX_RETRIES: number = IS_CI ? 1 : 2; console.log('Running Playwright Tests:'); console.log('- Base URL:', BASE_URL); From 8fb68257a872bc855d321f50bd32010690f09555 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 4 Jun 2026 08:59:12 +0000 Subject: [PATCH 25/40] Also generate HTML reports --- src/frontend/playwright.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/playwright.config.ts b/src/frontend/playwright.config.ts index f423d24a8014..d868ec932442 100644 --- a/src/frontend/playwright.config.ts +++ b/src/frontend/playwright.config.ts @@ -42,7 +42,7 @@ export default defineConfig({ forbidOnly: !!IS_CI, retries: MAX_RETRIES, workers: MAX_WORKERS, - reporter: IS_CI ? [['blob'], ['github']] : [['html']], + reporter: IS_CI ? [['html'], ['blob'], ['github']] : [['html']], /* Configure projects for major browsers */ projects: [ From f5f46f847346d64b16f9d0a7b4cb17aa22304066 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 4 Jun 2026 09:44:10 +0000 Subject: [PATCH 26/40] Tweak reporter output --- .github/workflows/frontend.yaml | 4 ++-- src/frontend/playwright.config.ts | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/frontend.yaml b/.github/workflows/frontend.yaml index 3dc1b070d133..d2d3383e2522 100644 --- a/.github/workflows/frontend.yaml +++ b/.github/workflows/frontend.yaml @@ -211,7 +211,7 @@ jobs: invoke dev.setup-test -iv invoke int.rebuild-thumbnails - name: Install dependencies - run: invoke int.frontend-install + run: invoke int.frontend-compile --extract - name: Cache Playwright browsers uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # pin@v4.3.0 id: playwright-cache @@ -256,7 +256,7 @@ jobs: uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 if: ${{ !cancelled() && steps.tests.outcome == 'failure' }} with: - name: playwright-report-chromium + name: playwright-report-chromium-${{ matrix.shard }} path: src/frontend/playwright-report/ retention-days: 7 diff --git a/src/frontend/playwright.config.ts b/src/frontend/playwright.config.ts index d868ec932442..6ef25534388c 100644 --- a/src/frontend/playwright.config.ts +++ b/src/frontend/playwright.config.ts @@ -42,7 +42,9 @@ export default defineConfig({ forbidOnly: !!IS_CI, retries: MAX_RETRIES, workers: MAX_WORKERS, - reporter: IS_CI ? [['html'], ['blob'], ['github']] : [['html']], + reporter: IS_CI + ? [['html', { open: 'never' }], ['blob'], ['github']] + : 'list', /* Configure projects for major browsers */ projects: [ From 8bffbc60951c323d6762faf64c3c20f70cdcdabb Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 4 Jun 2026 11:25:48 +0000 Subject: [PATCH 27/40] Fix custom splash URLs --- .github/workflows/frontend.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/frontend.yaml b/.github/workflows/frontend.yaml index d2d3383e2522..0e57097ffa2d 100644 --- a/.github/workflows/frontend.yaml +++ b/.github/workflows/frontend.yaml @@ -157,7 +157,7 @@ jobs: cp ./tests/fixtures/playwright_custom_logo.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_logo.png cp ./tests/fixtures/playwright_custom_splash.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_splash.png invoke static - PLAYWRIGHT_BASE_URL=http://localhost:8000 npx playwright test --project=firefox + env PLAYWRIGHT_BASE_URL=http://localhost:8000 npx playwright test --project=firefox - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 if: ${{ !cancelled() && steps.tests.outcome == 'failure' }} with: @@ -235,7 +235,7 @@ jobs: cd src/frontend cp ./tests/fixtures/playwright_custom_logo.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_logo.png cp ./tests/fixtures/playwright_custom_splash.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_splash.png - npx nyc playwright test --project=chromium --shard=${{ matrix.shard }}/4 + env INVENTREE_CUSTOM_SPLASH="img/playwright_custom_splash.png" INVENTREE_CUSTOM_LOGO="img/playwright_custom_logo.png"npx nyc playwright test --project=chromium --shard=${{ matrix.shard }}/4 - name: Upload Blob Report [${{ matrix.shard }} / 4] uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 id: blob-upload From 2070f537a1a417184d6bc6a76472e2031c7e9845 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 4 Jun 2026 11:27:36 +0000 Subject: [PATCH 28/40] Fix envs for customization tests --- .github/workflows/frontend.yaml | 6 ++---- src/frontend/playwright.config.ts | 3 ++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/frontend.yaml b/.github/workflows/frontend.yaml index 0e57097ffa2d..7b3aa7369054 100644 --- a/.github/workflows/frontend.yaml +++ b/.github/workflows/frontend.yaml @@ -157,7 +157,7 @@ jobs: cp ./tests/fixtures/playwright_custom_logo.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_logo.png cp ./tests/fixtures/playwright_custom_splash.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_splash.png invoke static - env PLAYWRIGHT_BASE_URL=http://localhost:8000 npx playwright test --project=firefox + env INVENTREE_CUSTOM_SPLASH="img/playwright_custom_splash.png" INVENTREE_CUSTOM_LOGO="img/playwright_custom_logo.png" PLAYWRIGHT_BASE_URL=http://localhost:8000 npx playwright test --project=firefox - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 if: ${{ !cancelled() && steps.tests.outcome == 'failure' }} with: @@ -233,9 +233,7 @@ jobs: id: tests run: | cd src/frontend - cp ./tests/fixtures/playwright_custom_logo.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_logo.png - cp ./tests/fixtures/playwright_custom_splash.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_splash.png - env INVENTREE_CUSTOM_SPLASH="img/playwright_custom_splash.png" INVENTREE_CUSTOM_LOGO="img/playwright_custom_logo.png"npx nyc playwright test --project=chromium --shard=${{ matrix.shard }}/4 + npx nyc playwright test --project=chromium --shard=${{ matrix.shard }}/4 - name: Upload Blob Report [${{ matrix.shard }} / 4] uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 id: blob-upload diff --git a/src/frontend/playwright.config.ts b/src/frontend/playwright.config.ts index 6ef25534388c..a3f2a0fa1b27 100644 --- a/src/frontend/playwright.config.ts +++ b/src/frontend/playwright.config.ts @@ -52,7 +52,8 @@ export default defineConfig({ name: 'chromium', use: { ...devices['Desktop Chrome'] - } + }, + testIgnore: /customization/ // Ignore all tests in the "customization" folder for this project }, { name: 'firefox', From a190b8fe537bc15825392dadc3fcf3c9ac50bb22 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 4 Jun 2026 12:10:24 +0000 Subject: [PATCH 29/40] Shard the firefox runner too --- .github/workflows/frontend.yaml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/frontend.yaml b/.github/workflows/frontend.yaml index 7b3aa7369054..889afd4c0bd2 100644 --- a/.github/workflows/frontend.yaml +++ b/.github/workflows/frontend.yaml @@ -92,11 +92,15 @@ jobs: include-hidden-files: true firefox: - name: Tests [Firefox] + name: Tests [Firefox ${{ matrix.shard }} / 2] runs-on: ubuntu-24.04 timeout-minutes: 60 needs: ["build", "paths-filter"] if: needs.paths-filter.outputs.frontend == 'true' || needs.paths-filter.outputs.force == 'true' + strategy: + fail-fast: false + matrix: + shard: [1, 2] services: postgres: image: postgres:17 @@ -157,11 +161,11 @@ jobs: cp ./tests/fixtures/playwright_custom_logo.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_logo.png cp ./tests/fixtures/playwright_custom_splash.png ../backend/InvenTree/InvenTree/static/img/playwright_custom_splash.png invoke static - env INVENTREE_CUSTOM_SPLASH="img/playwright_custom_splash.png" INVENTREE_CUSTOM_LOGO="img/playwright_custom_logo.png" PLAYWRIGHT_BASE_URL=http://localhost:8000 npx playwright test --project=firefox + env INVENTREE_CUSTOM_SPLASH="img/playwright_custom_splash.png" INVENTREE_CUSTOM_LOGO="img/playwright_custom_logo.png" PLAYWRIGHT_BASE_URL=http://localhost:8000 npx playwright test --project=firefox --shard=${{ matrix.shard }}/2 - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 if: ${{ !cancelled() && steps.tests.outcome == 'failure' }} with: - name: playwright-report-firefox + name: playwright-report-firefox-${{ matrix.shard }} path: src/frontend/playwright-report/ retention-days: 14 @@ -240,7 +244,7 @@ jobs: if: always() with: name: blob-report-${{ matrix.shard }} - path: blob-report/ + path: src/frontend/blob-report/ retention-days: 1 - name: Upload Coverage Artifact [${{ matrix.shard }} / 4] uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 @@ -248,7 +252,7 @@ jobs: if: always() with: name: coverage-${{ matrix.shard }} - path: .nyc_output/ + path: src/frontend/.nyc_output/ retention-days: 1 - name: Playwright Report [${{ matrix.shard }} / 4] uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 From c891574d67020aaca6dc08e5b355ba5bbbaff51a Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 4 Jun 2026 12:10:58 +0000 Subject: [PATCH 30/40] Ignore customization tests for firefox too --- src/frontend/playwright.config.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/frontend/playwright.config.ts b/src/frontend/playwright.config.ts index a3f2a0fa1b27..31ba4a4f6886 100644 --- a/src/frontend/playwright.config.ts +++ b/src/frontend/playwright.config.ts @@ -59,7 +59,8 @@ export default defineConfig({ name: 'firefox', use: { ...devices['Desktop Firefox'] - } + }, + testIgnore: /customization/ // Ignore all tests in the "customization" folder for this project } ], From a81eeff89143c5fddcc4ffb5a4668f49b745dd7f Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 4 Jun 2026 12:11:51 +0000 Subject: [PATCH 31/40] Don't upload if tests fail --- .github/workflows/frontend.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/frontend.yaml b/.github/workflows/frontend.yaml index 889afd4c0bd2..4b1f239a25f2 100644 --- a/.github/workflows/frontend.yaml +++ b/.github/workflows/frontend.yaml @@ -241,7 +241,7 @@ jobs: - name: Upload Blob Report [${{ matrix.shard }} / 4] uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 id: blob-upload - if: always() + if: ${{ !cancelled() && steps.tests.outcome == 'failure' }} with: name: blob-report-${{ matrix.shard }} path: src/frontend/blob-report/ @@ -249,7 +249,7 @@ jobs: - name: Upload Coverage Artifact [${{ matrix.shard }} / 4] uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 id: coverage-upload - if: always() + if: ${{ !cancelled() && steps.tests.outcome == 'failure' }} with: name: coverage-${{ matrix.shard }} path: src/frontend/.nyc_output/ From 6f63fe85f31f1c402ca6c4b48f709a6ac36ca6e0 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 4 Jun 2026 12:47:14 +0000 Subject: [PATCH 32/40] Fix triggers --- .github/workflows/frontend.yaml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/frontend.yaml b/.github/workflows/frontend.yaml index 4b1f239a25f2..14820ae0e4d7 100644 --- a/.github/workflows/frontend.yaml +++ b/.github/workflows/frontend.yaml @@ -238,10 +238,17 @@ jobs: run: | cd src/frontend npx nyc playwright test --project=chromium --shard=${{ matrix.shard }}/4 + - name: Playwright Report [${{ matrix.shard }} / 4] + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 + if: ${{ !cancelled() && steps.tests.outcome == 'failure' }} + with: + name: playwright-report-chromium-${{ matrix.shard }} + path: src/frontend/playwright-report/ + retention-days: 7 - name: Upload Blob Report [${{ matrix.shard }} / 4] uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 id: blob-upload - if: ${{ !cancelled() && steps.tests.outcome == 'failure' }} + if: ${{ !cancelled() && steps.tests.outcome != 'failure' }} with: name: blob-report-${{ matrix.shard }} path: src/frontend/blob-report/ @@ -249,18 +256,11 @@ jobs: - name: Upload Coverage Artifact [${{ matrix.shard }} / 4] uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 id: coverage-upload - if: ${{ !cancelled() && steps.tests.outcome == 'failure' }} + if: ${{ !cancelled() && steps.tests.outcome != 'failure' }} with: name: coverage-${{ matrix.shard }} path: src/frontend/.nyc_output/ retention-days: 1 - - name: Playwright Report [${{ matrix.shard }} / 4] - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 - if: ${{ !cancelled() && steps.tests.outcome == 'failure' }} - with: - name: playwright-report-chromium-${{ matrix.shard }} - path: src/frontend/playwright-report/ - retention-days: 7 # Recombine the coverage reports from the 4 shards, and upload to Codecov coverage: From 171f5628a25d213c54e032fc8c133daeab1115cc Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 4 Jun 2026 13:17:08 +0000 Subject: [PATCH 33/40] Remove merged test coverage --- .github/workflows/frontend.yaml | 34 --------------------------------- 1 file changed, 34 deletions(-) diff --git a/.github/workflows/frontend.yaml b/.github/workflows/frontend.yaml index 14820ae0e4d7..69519c7be125 100644 --- a/.github/workflows/frontend.yaml +++ b/.github/workflows/frontend.yaml @@ -245,14 +245,6 @@ jobs: name: playwright-report-chromium-${{ matrix.shard }} path: src/frontend/playwright-report/ retention-days: 7 - - name: Upload Blob Report [${{ matrix.shard }} / 4] - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 - id: blob-upload - if: ${{ !cancelled() && steps.tests.outcome != 'failure' }} - with: - name: blob-report-${{ matrix.shard }} - path: src/frontend/blob-report/ - retention-days: 1 - name: Upload Coverage Artifact [${{ matrix.shard }} / 4] uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 id: coverage-upload @@ -283,23 +275,6 @@ jobs: install: false update: false - - name: Download Blob Reports - uses: actions/download-artifact@v8 - with: - pattern: blob-report-* - path: all-blob-reports/ - merge-multiple: true - - - name: Merge Playwright reports - run: npx playwright merge-reports --reporter html ./all-blob-reports - - - name: Upload Merged HTML Report - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 - with: - name: playwright-report - path: playwright-report/ - retention-days: 7 - - name: Download Coverage Artifacts uses: actions/download-artifact@v8 with: @@ -326,12 +301,3 @@ jobs: slug: inventree/InvenTree flags: web files: ./coverage/lcov.info - - # - name: Upload bundler info - # if: ${{ !cancelled() && github.ref == 'refs/heads/master' }} - # env: - # CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - # run: | - # cd src/frontend - # yarn install - # yarn run build From ecf3bb04df8a2f86a0fedb4c4e9aa7dbce07b63e Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 4 Jun 2026 13:19:10 +0000 Subject: [PATCH 34/40] Pin download action --- .github/workflows/frontend.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/frontend.yaml b/.github/workflows/frontend.yaml index 69519c7be125..7ea3733f3ddf 100644 --- a/.github/workflows/frontend.yaml +++ b/.github/workflows/frontend.yaml @@ -276,7 +276,7 @@ jobs: update: false - name: Download Coverage Artifacts - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # pin@v8.0.1 with: pattern: coverage-* path: all-coverage/ From abbb938aaaefb445816946173404789850339516 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 4 Jun 2026 13:22:26 +0000 Subject: [PATCH 35/40] Error if no artifact files found --- .github/workflows/frontend.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/frontend.yaml b/.github/workflows/frontend.yaml index 7ea3733f3ddf..63fcbe993ffa 100644 --- a/.github/workflows/frontend.yaml +++ b/.github/workflows/frontend.yaml @@ -244,6 +244,7 @@ jobs: with: name: playwright-report-chromium-${{ matrix.shard }} path: src/frontend/playwright-report/ + if-no-files-found: error retention-days: 7 - name: Upload Coverage Artifact [${{ matrix.shard }} / 4] uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # pin@v7.0.1 @@ -252,6 +253,7 @@ jobs: with: name: coverage-${{ matrix.shard }} path: src/frontend/.nyc_output/ + if-no-files-found: error retention-days: 1 # Recombine the coverage reports from the 4 shards, and upload to Codecov From dab1b227c2da4443366d605a07b9b68fdcb4aca9 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 4 Jun 2026 14:02:54 +0000 Subject: [PATCH 36/40] Update ignore dirs --- src/frontend/vite.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/vite.config.ts b/src/frontend/vite.config.ts index 627a1ade6e1b..2aa813204ea4 100644 --- a/src/frontend/vite.config.ts +++ b/src/frontend/vite.config.ts @@ -47,7 +47,7 @@ export default defineConfig(({ command, mode }) => { }), istanbul({ include: ['src/*', 'lib/*'], - exclude: ['node_modules', 'test/'], + exclude: ['node_modules/', 'playwright/', 'tests/'], extension: ['.js', '.ts', '.tsx'], requireEnv: true }), From db48bf7eaef730e07ebc5f27c0ff446aa1cdbb7e Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 5 Jun 2026 12:32:59 +0000 Subject: [PATCH 37/40] Adjust baseFixtures --- src/frontend/tests/baseFixtures.ts | 64 +++++++++++++++---- .../tests/customization/customization.spec.ts | 2 +- src/frontend/tests/pages/pui_return.spec.ts | 2 +- src/frontend/tests/pui_exporting.spec.ts | 2 +- src/frontend/tests/pui_forms.spec.ts | 4 +- src/frontend/tests/pui_importing.spec.ts | 2 +- src/frontend/tests/pui_machines.spec.ts | 2 +- src/frontend/tests/pui_permissions.spec.ts | 2 +- src/frontend/tests/pui_plugins.spec.ts | 2 +- 9 files changed, 59 insertions(+), 23 deletions(-) diff --git a/src/frontend/tests/baseFixtures.ts b/src/frontend/tests/baseFixtures.ts index 66bd83600885..032c21584746 100644 --- a/src/frontend/tests/baseFixtures.ts +++ b/src/frontend/tests/baseFixtures.ts @@ -2,7 +2,7 @@ import * as crypto from 'node:crypto'; import * as fs from 'node:fs'; import os from 'node:os'; import * as path from 'node:path'; -import { test as baseTest } from '@playwright/test'; +import { type BrowserContext, test as baseTest } from '@playwright/test'; const istanbulCLIOutput = path.join(process.cwd(), '.nyc_output'); const platform = os.platform(); @@ -19,16 +19,16 @@ export function generateUUID(): string { return crypto.randomBytes(16).toString('hex'); } -export const test = baseTest.extend({ - context: async ({ context }, use) => { - await context.addInitScript(() => - window.addEventListener('beforeunload', () => - (window as any).collectIstanbulCoverage( - JSON.stringify((window as any).__coverage__) - ) +async function setupCoverageCollection(context: BrowserContext) { + await context.addInitScript(() => + window.addEventListener('beforeunload', () => + (window as any).collectIstanbulCoverage?.( + JSON.stringify((window as any).__coverage__) ) - ); - await fs.promises.mkdir(istanbulCLIOutput, { recursive: true }); + ) + ); + await fs.promises.mkdir(istanbulCLIOutput, { recursive: true }); + try { await context.exposeFunction( 'collectIstanbulCoverage', (coverageJSON: string) => { @@ -42,18 +42,54 @@ export const test = baseTest.extend({ ); } ); - await use(context); - for (const page of context.pages()) { + } catch { + // already exposed on this context (e.g. called twice for same context) + } +} + +async function collectCoverageFromContext(context: BrowserContext) { + for (const page of context.pages()) { + try { await page.evaluate(() => - (window as any).collectIstanbulCoverage( + (window as any).collectIstanbulCoverage?.( JSON.stringify((window as any).__coverage__) ) ); + } catch { + // page may already be closed } + } +} + +export const test = baseTest.extend<{}, {}>({ + // Wrap browser.newPage so contexts created via doCachedLogin also get coverage + browser: [ + async ({ browser }, use) => { + const origNewPage = browser.newPage.bind(browser); + (browser as any).newPage = async ( + options?: Parameters[0] + ) => { + const page = await origNewPage(options); + await setupCoverageCollection(page.context()); + return page; + }; + await use(browser); + for (const context of browser.contexts()) { + await collectCoverageFromContext(context); + } + }, + { scope: 'worker' } + ], + + context: async ({ context }, use) => { + await setupCoverageCollection(context); + await use(context); + await collectCoverageFromContext(context); }, + // Ensure no errors are thrown in the console page: async ({ page }, use) => { - const messages = []; + const messages: any[] = []; page.on('console', (msg) => { const url = msg.location().url; if ( diff --git a/src/frontend/tests/customization/customization.spec.ts b/src/frontend/tests/customization/customization.spec.ts index 11e805457cee..74e9f36e8536 100644 --- a/src/frontend/tests/customization/customization.spec.ts +++ b/src/frontend/tests/customization/customization.spec.ts @@ -1,4 +1,4 @@ -import test, { expect } from '@playwright/test'; +import { expect, test } from '../baseFixtures'; import { navigate } from '../helpers'; /** diff --git a/src/frontend/tests/pages/pui_return.spec.ts b/src/frontend/tests/pages/pui_return.spec.ts index 96962d057423..5ffd09aadac0 100644 --- a/src/frontend/tests/pages/pui_return.spec.ts +++ b/src/frontend/tests/pages/pui_return.spec.ts @@ -1,4 +1,4 @@ -import test from '@playwright/test'; +import { test } from '../baseFixtures'; import { loadTab } from '../helpers'; import { doCachedLogin } from '../login'; diff --git a/src/frontend/tests/pui_exporting.spec.ts b/src/frontend/tests/pui_exporting.spec.ts index acf9a3834555..dc3237056005 100644 --- a/src/frontend/tests/pui_exporting.spec.ts +++ b/src/frontend/tests/pui_exporting.spec.ts @@ -1,4 +1,4 @@ -import test from '@playwright/test'; +import { test } from './baseFixtures'; import { stevenuser } from './defaults'; import { globalSearch, loadTab, navigate } from './helpers'; import { doCachedLogin } from './login'; diff --git a/src/frontend/tests/pui_forms.spec.ts b/src/frontend/tests/pui_forms.spec.ts index a812d42f05b6..38f48099c89b 100644 --- a/src/frontend/tests/pui_forms.spec.ts +++ b/src/frontend/tests/pui_forms.spec.ts @@ -1,6 +1,6 @@ -/** Unit tests for form validation, rendering, etc */ -import { expect, test } from 'playwright/test'; import { createApi } from './api'; +/** Unit tests for form validation, rendering, etc */ +import { expect, test } from './baseFixtures'; import { stevenuser } from './defaults'; import { navigate } from './helpers'; import { doCachedLogin } from './login'; diff --git a/src/frontend/tests/pui_importing.spec.ts b/src/frontend/tests/pui_importing.spec.ts index abd34cb20147..b7d5f6406150 100644 --- a/src/frontend/tests/pui_importing.spec.ts +++ b/src/frontend/tests/pui_importing.spec.ts @@ -1,4 +1,4 @@ -import test from '@playwright/test'; +import { test } from './baseFixtures'; import { stevenuser } from './defaults'; import { doCachedLogin } from './login'; diff --git a/src/frontend/tests/pui_machines.spec.ts b/src/frontend/tests/pui_machines.spec.ts index 0d5987b2ab9c..f24da371a5cc 100644 --- a/src/frontend/tests/pui_machines.spec.ts +++ b/src/frontend/tests/pui_machines.spec.ts @@ -1,4 +1,4 @@ -import test from 'playwright/test'; +import { test } from './baseFixtures'; import { adminuser } from './defaults'; import { clickOnRowMenu, navigate } from './helpers'; import { doCachedLogin } from './login'; diff --git a/src/frontend/tests/pui_permissions.spec.ts b/src/frontend/tests/pui_permissions.spec.ts index f554606d853e..9abc356cb141 100644 --- a/src/frontend/tests/pui_permissions.spec.ts +++ b/src/frontend/tests/pui_permissions.spec.ts @@ -2,7 +2,7 @@ * Tests for UI permissions checks */ -import test from '@playwright/test'; +import { test } from './baseFixtures'; import { adminuser, readeruser } from './defaults'; import { clickOnRowMenu, loadTab } from './helpers'; import { doCachedLogin } from './login'; diff --git a/src/frontend/tests/pui_plugins.spec.ts b/src/frontend/tests/pui_plugins.spec.ts index a4bc753303d6..e4adb8df2f29 100644 --- a/src/frontend/tests/pui_plugins.spec.ts +++ b/src/frontend/tests/pui_plugins.spec.ts @@ -1,4 +1,4 @@ -import test from 'playwright/test'; +import { test } from './baseFixtures'; import { adminuser } from './defaults.js'; import { From 5acce2d832940e13545e7652132e993ce472a552 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 5 Jun 2026 13:08:23 +0000 Subject: [PATCH 38/40] Fix for teardown in baseFixtures.ts --- src/frontend/tests/baseFixtures.ts | 42 ++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/src/frontend/tests/baseFixtures.ts b/src/frontend/tests/baseFixtures.ts index 032c21584746..18072d624991 100644 --- a/src/frontend/tests/baseFixtures.ts +++ b/src/frontend/tests/baseFixtures.ts @@ -48,17 +48,27 @@ async function setupCoverageCollection(context: BrowserContext) { } async function collectCoverageFromContext(context: BrowserContext) { - for (const page of context.pages()) { - try { - await page.evaluate(() => - (window as any).collectIstanbulCoverage?.( - JSON.stringify((window as any).__coverage__) - ) - ); - } catch { - // page may already be closed - } - } + await Promise.allSettled( + context.pages().map(async (page) => { + try { + await Promise.race([ + page.evaluate(() => + (window as any).collectIstanbulCoverage?.( + JSON.stringify((window as any).__coverage__) + ) + ), + new Promise((_, reject) => + setTimeout( + () => reject(new Error('Coverage collection timeout')), + 2000 + ) + ) + ]); + } catch { + // page may already be closed or script execution can be blocked during teardown + } + }) + ); } export const test = baseTest.extend<{}, {}>({ @@ -73,9 +83,13 @@ export const test = baseTest.extend<{}, {}>({ await setupCoverageCollection(page.context()); return page; }; - await use(browser); - for (const context of browser.contexts()) { - await collectCoverageFromContext(context); + try { + await use(browser); + } finally { + (browser as any).newPage = origNewPage; + for (const context of browser.contexts()) { + await collectCoverageFromContext(context); + } } }, { scope: 'worker' } From 516968d793f3abe1545658de528f887a251456c5 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 5 Jun 2026 13:28:15 +0000 Subject: [PATCH 39/40] Fix path for coverage files --- src/frontend/tests/baseFixtures.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/frontend/tests/baseFixtures.ts b/src/frontend/tests/baseFixtures.ts index 18072d624991..c834566f3f88 100644 --- a/src/frontend/tests/baseFixtures.ts +++ b/src/frontend/tests/baseFixtures.ts @@ -2,9 +2,14 @@ import * as crypto from 'node:crypto'; import * as fs from 'node:fs'; import os from 'node:os'; import * as path from 'node:path'; +import { fileURLToPath } from 'node:url'; import { type BrowserContext, test as baseTest } from '@playwright/test'; -const istanbulCLIOutput = path.join(process.cwd(), '.nyc_output'); +const frontendDir = path.resolve( + path.dirname(fileURLToPath(import.meta.url)), + '..' +); +const istanbulCLIOutput = path.join(frontendDir, '.nyc_output'); const platform = os.platform(); let systemKeyVar: string; if (platform === 'darwin') { From 8726d387a808a793a812c588cf9518823d9e071a Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Fri, 5 Jun 2026 14:11:58 +0000 Subject: [PATCH 40/40] include hidden files --- .github/workflows/frontend.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/frontend.yaml b/.github/workflows/frontend.yaml index 63fcbe993ffa..25fcfd61076d 100644 --- a/.github/workflows/frontend.yaml +++ b/.github/workflows/frontend.yaml @@ -254,6 +254,7 @@ jobs: name: coverage-${{ matrix.shard }} path: src/frontend/.nyc_output/ if-no-files-found: error + include-hidden-files: true retention-days: 1 # Recombine the coverage reports from the 4 shards, and upload to Codecov