diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c28457b1986..143717b3ea5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -161,7 +161,19 @@ jobs: - name: Install Playwright Chromium run: yarn --cwd frontend playwright install ${{ matrix.os == 'ubuntu-latest' && '--with-deps' || '' }} chromium - name: Run frontend browser-mode tests - run: yarn --cwd frontend ng run gui:test-browser + run: yarn --cwd frontend ng run gui:test-browser --coverage --coverage-reporters=lcovonly + - name: Upload frontend browser-mode coverage to Codecov + # These tests already exercise code the jsdom run cannot reach (Monaco, real + # pointer input); without this upload those lines are reported as uncovered. + # vitest.browser.config.ts writes to coverage-browser/ so this does not collide + # with the jsdom run's coverage/gui/lcov.info. + if: matrix.os == 'ubuntu-latest' && always() + uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: ./frontend/coverage-browser/**/lcov.info + flags: frontend + fail_ci_if_error: false - name: Upload frontend browser-mode test results to Codecov # vitest.browser.config.ts emits junit-browser.xml (distinct from # the unit-test report). Same `frontend` flag — Codecov merges diff --git a/frontend/.gitignore b/frontend/.gitignore index c3db340e81d..93858f17d66 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -10,6 +10,7 @@ # test coverage /coverage +/coverage-browser # vitest browser-mode snapshot baselines **/__screenshots__/ diff --git a/frontend/vitest.browser.config.ts b/frontend/vitest.browser.config.ts index 3fe2c410390..4baa234ded0 100644 --- a/frontend/vitest.browser.config.ts +++ b/frontend/vitest.browser.config.ts @@ -47,8 +47,14 @@ export default defineConfig({ // `require()` calls inside the CJS package crash on first import. // Explicit-include forces esbuild to pre-bundle it (alongside its // `base64-js` + `ieee754` transitive deps) into a browser-runnable ESM. + // + // `@vitest/coverage-v8/browser` is loaded dynamically by the coverage provider once + // `--coverage` is passed, and it is not in the import graph either, so it needs the same + // hint. Without it the run fails with "Failed to fetch dynamically imported module: + // /@id/@vitest/coverage-v8/browser" and no coverage is produced -- the tests still pass, + // which is why the gap went unnoticed. optimizeDeps: { - include: ["buffer"], + include: ["buffer", "@vitest/coverage-v8/browser"], }, test: { // Emit a JUnit-XML report alongside the default console reporter so @@ -56,6 +62,12 @@ export default defineConfig({ // flakies on main. Written to a distinct filename so the upload step // can disambiguate it from the unit-test report. reporters: ["default", ["junit", { outputFile: "junit-browser.xml" }]], + // Written to its own directory so it does not overwrite the jsdom run's + // coverage/gui/lcov.info. Codecov merges multiple uploads under one flag, so both + // records count and the lines these tests already exercise stop reading as uncovered. + coverage: { + reportsDirectory: "coverage-browser", + }, globals: true, // browser-buffer-polyfill must run FIRST: it puts Buffer/process on // globalThis before any test module loads, which is required for