Skip to content

ValentinGurkov/vitest-react-compiler-missing-coverage-repro

Repository files navigation

Minimal repo for reproducing incorrect coverage when the React Compiler is used

Install dependencies with pnpm. The test script will also install Chromium binaries to run Playwright with!

The button we are going to test is a simple one:

export const Button = () => {
    return <button>Click me</button>;
};

As well as its' test:

import { page } from '@vitest/browser/context';
import { Button } from '@repo/components/ui/button.js';
import { describe, expect, it} from 'vitest';
import { render } from 'vitest-browser-react';

describe(Button, () => {
    it('renders with default variants', async () => {
        render(<Button />);

        const button = page.getByRole('button', { name: 'Click me' });

        await expect.element(button).toBeInTheDocument();
    });
});

1. Coverage with the React compiler

Run

pnpm test:coverage

Observe the coverage report:

   ✓ Button > renders with default variants 9ms

 Test Files  1 passed (1)
      Tests  1 passed (1)
   Start at  20:34:46
   Duration  632ms (transform 0ms, setup 133ms, collect 28ms, tests 9ms, environment 0ms, prepare 93ms)

 % Coverage report from v8
------------|---------|----------|---------|---------|-------------------
File        | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
------------|---------|----------|---------|---------|-------------------
All files   |     100 |       50 |     100 |     100 |                   
 button.tsx |     100 |       50 |     100 |     100 | 2                 
------------|---------|----------|---------|---------|-------------------

The component has no branching logic while the report shows are the are missing some. I believe I've managed to set up the vitest configuration to also log the transformed component and we have:

import { jsxDEV } from "react/jsx-dev-runtime";
import { c as _c } from "react/compiler-runtime";
export const Button = () => {
  const $ = _c(1);
  let t0;
  if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
    t0 = /* @__PURE__ */ jsxDEV("button", { children: "Click me" }, void 0, false, {
      fileName: "/Users/<my-user>/Projects/vitest-react-compiler-coverage/src/components/ui/button.tsx",
      lineNumber: 6,
      columnNumber: 10
    }, this);
    $[0] = t0;
  } else {
    t0 = $[0];
  }
  return t0;
};

So there appears to be a condition related to memoization? I don't know if we can ever test for it though.

1. Coverage without the React compiler

First edit the react plugin configuration vitest.config.ts to not use the react compiler:

- react({
-     babel: {
-         plugins: [
-             ["babel-plugin-react-compiler", {}]
-         ],
-     },
- }),
+ react(),

Run

pnpm test:coverage

Observe the coverage report:

✓ Button > renders with default variants 10ms

 Test Files  1 passed (1)
      Tests  1 passed (1)
   Start at  20:36:42
   Duration  490ms (transform 0ms, setup 36ms, collect 6ms, tests 10ms, environment 0ms, prepare 92ms)

 % Coverage report from v8
------------|---------|----------|---------|---------|-------------------
File        | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
------------|---------|----------|---------|---------|-------------------
All files   |     100 |      100 |     100 |     100 |                   
 button.tsx |     100 |      100 |     100 |     100 |                   
------------|---------|----------|---------|---------|-------------------

The code coverage is 100% as expected. The output code also has no conditions:

import { jsxDEV } from "react/jsx-dev-runtime";
export const Button = () => {
  return /* @__PURE__ */ jsxDEV("button", { children: "Click me" }, void 0, false, {
    fileName: "/Users/<my-user>/Projects/vitest-react-compiler-coverage/src/components/ui/button.tsx",
    lineNumber: 2,
    columnNumber: 12
  }, this);
};

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published