Skip to content

Vitest examples ​

These examples use Vitest throughout. Start with the Vitest guide for installation, your first scan and framework-specific limits. Each example shows a project's file layout; adjust its globs to your own suite. Scanning reads the source without running tests or starting a browser.

React with Vitest and Testing Library ​

trading-dashboard keeps its tests next to its React components, in *.test.tsx files. JSX is read like the rest of the code:

Excerpt: tsx
// src/components/OrderTicket.test.tsx
// TODO(TRD-731): the date picker for good-till-date orders is being rebuilt
it.skip('submits a good-till-date order', async () => {
  const user = userEvent.setup();
  render(<OrderTicket symbol="AAPL" lastPrice={187.5} buyingPower={25_000} onSubmit={vi.fn()} />);
  await user.click(screen.getByRole('button', { name: 'Good till date' }));
});

it.todo('shows the estimated commission');
sh
npx test-inventory "src/**/*.test.tsx" --framework vitest --output inventory.json
json
{
  "fullName": "OrderTicket > submits a good-till-date order",
  "relativeFilePath": "src/components/OrderTicket.test.tsx",
  "state": "skip",
  "comments": ["TODO(TRD-731): the date picker for good-till-date orders is being rebuilt"]
}
json
{
  "fullName": "OrderTicket > shows the estimated commission",
  "state": "todo",
  "bodyHash": null
}

Vue with Vitest and Vue Test Utils ​

watchlist-vue turns on Vitest's globals, so its specs use describe and it without importing them:

Excerpt: ts
// tests/unit/Watchlist.spec.ts
import { mount } from '@vue/test-utils';
import Watchlist from '../../src/components/Watchlist.vue';
// ...
describe('when the feed is delayed', () => {
  it('shows how many minutes the quotes are delayed', () => {
    const wrapper = mount(Watchlist, { props: { quotes, delayedMinutes: 15 } });
    expect(wrapper.get('[data-test="delay-banner"]').text()).toBe('Quotes are delayed by 15 minutes');
  });

  it.todo('greys out quotes older than the delay');
});
sh
npx test-inventory "tests/unit/**/*.spec.ts" --framework vitest --output inventory.json

A name that a file uses but never imports or declares is read as a Vitest global. The scan then looks for test.globals: true in the config the file uses, the outermost one in its folder or a folder above that runs it, or for vitest/globals in a tsconfig in those folders, and warns with globals-not-enabled when there is neither. Here vitest.config.ts turns them on:

json
{
  "fullName": "Watchlist > when the feed is delayed > greys out quotes older than the delay",
  "suitePath": ["Watchlist", "when the feed is delayed"],
  "state": "todo"
}

Vitest browser mode ​

chart-browser draws candlestick charts on a canvas and tests them in Chromium and WebKit with Vitest's browser mode. One test is skipped in WebKit:

Excerpt: ts
// src/candlestick-chart.test.ts
  // WebKit returns an empty blob for canvases larger than the device pixel ratio allows in headless mode.
  test.skipIf(server.browser === 'webkit')('exports the chart as a PNG', async () => {
sh
npx test-inventory "src/**/*.test.ts" --framework vitest --output inventory.json
json
{
  "fullName": "CandlestickChart > exports the chart as a PNG",
  "state": "skip",
  "isConditional": true,
  "condition": "server.browser === 'webkit'",
  "stateSource": "test"
}

The scan reads browser instances from the config and lists their names in each test's projects. Each declaration still has one record, even when the runner executes it in two browsers. This test's record includes:

json
{ "projects": ["chromium", "webkit"] }

In-source and type tests ​

strategy-engine keeps some tests next to the code they test, inside if (import.meta.vitest):

Excerpt: ts
// src/pnl/format.ts
if (import.meta.vitest) {
  const { describe, it, expect } = import.meta.vitest;

  describe('formatPnl', () => {
    it('adds a plus sign to gains', () => {
      expect(formatPnl(1234.5)).toBe('+$1,234.50');
    });

It also has type tests in *.test-d.ts files:

Excerpt: ts
// tests/orders/order.test-d.ts
describe('Order', () => {
  test('narrows to a limit order by its type', () => {
    const order = { symbol: 'AAPL', side: 'buy', type: 'limit', quantity: 10, limitPrice: 187.5 } as Order;
    if (order.type === 'limit') expectTypeOf(order).toEqualTypeOf<LimitOrder>();
  });

Scan the source files and the type test files along with the tests:

sh
npx test-inventory "tests/**/*.{test,test-d}.ts" "src/**/*.ts" --framework vitest --output inventory.json

The import.meta.vitest check is how in-source tests are written, so it does not count as a condition:

json
{
  "fullName": "formatPnl > adds a plus sign to gains",
  "relativeFilePath": "src/pnl/format.ts",
  "lineStart": 16,
  "state": "active",
  "isInCondition": false
}
json
{
  "fullName": "Order > narrows to a limit order by its type",
  "relativeFilePath": "tests/orders/order.test-d.ts",
  "isTypeTest": true
}

A Vitest monorepo ​

trading-monorepo has three packages, each with its own Vitest config, and a root config that lists them as projects. Scan them all from the root:

sh
npx test-inventory "packages/*/src/**/*.test.ts" --framework vitest --output inventory.json

Paths are relative to the root, so each record names its package:

json
{
  "fullName": "QuoteCache > returns the mid price of a fresh quote",
  "relativeFilePath": "packages/market-data/src/quote-cache.test.ts"
}

Only market-data turns on globals, in packages/market-data/vitest.config.ts. The scan finds that config from the package's test files, so it gives no globals-not-enabled warning:

json
{
  "fileCount": 3,
  "suiteCount": 3,
  "testCount": 8,
  "activeCount": 7,
  "todoCount": 1,
  "diagnosticCount": 0
}

To scan one package, pass it as the root: --root packages/risk. The framework version is read from node_modules in the root or a folder above it, so a package of a monorepo gets the version installed at the top.

Next ​

Documentation for test-inventory 0.10.1. Released under the MIT License.