agentsclimarketplace

Jest vitest

Skill aks-builds/quality-skills/skills/jest-vitest

When the user wants to design, implement, debug, or optimize Jest or Vitest unit / integration tests in JavaScript or TypeScript. Use when the user mentions "Jest," "Vitest," "describe/it/test," "expect," "jest.mock," "vi.mock," "vi.fn," "snapshot," "spyOn," "fake timers," "module mocks," "jest.config," "vitest.config," "test coverage," or "@swc/jest." For Node API integration testing see supertest. For Cypress component tests see cypress. For pytest see pytest. For Java unit testing see junit-testng.From its SKILL.md

Install
npx -y skills add aks-builds/quality-skills --skill jest-vitest

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

11.5 KB, as published. Nobody here has run it

Jest & Vitest

You are an expert in both Jest and Vitest — the dominant JS/TS unit test runners. Your goal is to help engineers structure tests, mock effectively, handle async correctly, manage time and randomness, and pick between the two tools when relevant. Don't fabricate matcher names, mock APIs, or config keys. When uncertain, point the reader to jestjs.io or vitest.dev.

Initial Assessment

Check .agents/qa-context.md (fallback: .claude/qa-context.md) before answering. Pay attention to:

  • Which runner? — Jest (mature, broad ecosystem, slower) or Vitest (faster, Vite-based, smaller ecosystem). Vitest is largely API-compatible with Jest, so most patterns transfer.
  • Module system — ESM vs CJS. Jest historically struggled with ESM; Vitest is ESM-native. Knowing the module setup avoids hours of debugging.
  • TS vs JS — TypeScript adds setup considerations (ts-jest, @swc/jest, Vitest's built-in support).
  • Framework on top — React (React Testing Library), Vue (Vue Test Utils), Svelte, Solid, plain Node. Test patterns are similar; rendering helpers differ.
  • Test scope — unit (pure functions), component (UI render + assertion), integration (multiple modules + mocked I/O), or hybrid.

If the file does not exist, ask: Jest or Vitest, ESM or CJS, TypeScript, UI framework if any, and intended scope.


Why one over the other

Pick Jest when…Pick Vitest when…
Existing Jest investmentGreenfield project on Vite
React Native (Jest is the default)ESM-native code
Need every Jest plugin under the sunCare about test runtime / DX
CI infrastructure already wired for JestVue / Svelte / Solid project using Vite
Module-mocking patterns very deeply setWant browser-mode tests via Vitest

If you're starting fresh and not React-Native-bound, Vitest is the modern default for most Node/web projects. If you're maintaining a large suite, the migration is workable but not free — most APIs match but mock semantics differ in edge cases.


Test anatomy

// math.test.ts — works in both Jest and Vitest (with the right import for Vitest)
// Jest: globals are auto-provided; Vitest: `import { describe, it, expect, vi } from 'vitest'` (or set globals: true)

describe('add', () => {
  it('adds two numbers', () => {
    expect(add(1, 2)).toBe(3);
  });

  it.each([
    [1, 1, 2],
    [0, 0, 0],
    [-1, 1, 0],
  ])('add(%i, %i) = %i', (a, b, expected) => {
    expect(add(a, b)).toBe(expected);
  });
});
BlockUse
describeGroup related tests.
it / testOne test. (it and test are identical.)
it.eachParametrized.
beforeAll / afterAllOnce per suite.
beforeEach / afterEachPer test.
it.skip / it.only / describe.skip / describe.onlySkip / focus.

Matchers

Most-used expect matchers:

MatcherUse
toBe(x)Strict equality (===).
toEqual(x)Deep equality.
toMatchObject(x)Partial deep equality (subset).
toStrictEqual(x)Like toEqual but checks undefined props and types.
toBeNull() / toBeUndefined() / toBeDefined()Specific values.
toBeTruthy() / toBeFalsy()Coerced.
toBeGreaterThan(n) / toBeLessThanOrEqual(n)Numeric.
toContain(x) / toContainEqual(x)Array / string membership.
toHaveLength(n)Array length.
toHaveProperty(path, value?)Object property by path.
toThrow(/regex/) / toThrowError(...)Function throws.
toMatch(/regex/)String regex.
toMatchSnapshot()Inline / external snapshot.

expect.any(Type), expect.objectContaining({...}), expect.stringMatching(/x/) produce asymmetric matchers usable inside toEqual / toMatchObject.


Async tests

Three valid forms; pick one per test:

// async/await — recommended
it('resolves', async () => {
  await expect(fetchUser('user-42')).resolves.toMatchObject({ id: 'user-42' });
});

it('rejects', async () => {
  await expect(fetchUser('nope')).rejects.toThrow(/not found/);
});

// done callback — legacy, error-prone, avoid

Don't mix done callbacks with async. If a test calls await and never returns the awaited promise, the test "passes" silently when the assertion fails — always return/await promise-returning expressions.


Mocking

Function mocks

const greet = vi.fn(() => 'hi');   // Vitest
const greet = jest.fn(() => 'hi'); // Jest

greet('alice');
expect(greet).toHaveBeenCalledWith('alice');
expect(greet).toHaveBeenCalledTimes(1);

greet.mockReturnValueOnce('once');
greet.mockResolvedValueOnce({ id: 'user-42' });
greet.mockImplementation((name) => `hi ${name}`);
greet.mockRestore();  // for spies created via spyOn

Module mocks

// Vitest
vi.mock('./api', () => ({
  fetchUser: vi.fn().mockResolvedValue({ id: 'user-42' }),
}));

// Jest
jest.mock('./api', () => ({
  fetchUser: jest.fn().mockResolvedValue({ id: 'user-42' }),
}));

Module mocks are hoisted to the top of the file before imports — calling them inline mid-test does not work. For partial mocks:

vi.mock('./api', async () => {
  const actual = await vi.importActual<typeof import('./api')>('./api');
  return { ...actual, fetchUser: vi.fn() };
});

Spies

const spy = vi.spyOn(console, 'log').mockImplementation(() => {});
// call code under test
expect(spy).toHaveBeenCalledWith('expected message');
spy.mockRestore();

Spies wrap an existing implementation, keep call records, and restore on mockRestore(). Prefer spies over vi.fn() when you want default behavior preserved.


Fake timers

beforeEach(() => { vi.useFakeTimers(); });        // Jest: jest.useFakeTimers()
afterEach(() => { vi.useRealTimers(); });

it('debounces', () => {
  const cb = vi.fn();
  const debounced = debounce(cb, 200);
  debounced();
  vi.advanceTimersByTime(199);
  expect(cb).not.toHaveBeenCalled();
  vi.advanceTimersByTime(1);
  expect(cb).toHaveBeenCalledTimes(1);
});

Don't setTimeout(() => done(), 200) to test debouncing. Fake timers make these tests deterministic and fast.


Snapshot tests

expect(renderToString(<Profile name="Jane" />)).toMatchSnapshot();
expect(parse('a + b')).toMatchInlineSnapshot(`Object {...}`);

Snapshots are great for stable serialized output (parser ASTs, generated code) and bad for anything that changes on every commit (timestamps, random IDs). Review snapshot diffs in code review like regular code — a passing-because-updated snapshot defeats the point.

Use sparingly. A snapshot that's longer than 30 lines or full of dynamic content is usually the wrong tool.


Coverage

# Vitest
vitest run --coverage

# Jest
jest --coverage

Coverage tools (V8 for Vitest by default, Istanbul for Jest) report line / branch / function / statement coverage. Don't gate on coverage percentage as if it's quality — high coverage with weak assertions is worse than low coverage with strong ones. Use coverage for gap-finding, not pass/fail.

Cross-reference the code-coverage skill for deeper context.


Configuration

Vitest (vitest.config.ts)

import { defineConfig } from 'vitest/config';

export default defineConfig({
  test: {
    globals: true,                     // skip the imports for describe/it/expect
    environment: 'jsdom',              // or 'node' / 'happy-dom' / 'edge-runtime'
    setupFiles: ['./test/setup.ts'],
    coverage: { provider: 'v8', reporter: ['text', 'html', 'lcov'] },
    include: ['src/**/*.{test,spec}.{ts,tsx}'],
  },
});

Jest (jest.config.ts)

export default {
  preset: 'ts-jest',                   // or '@swc/jest' transform
  testEnvironment: 'node',             // or 'jsdom'
  setupFilesAfterEach: ['<rootDir>/test/setup.ts'],
  coverageProvider: 'v8',
  collectCoverageFrom: ['src/**/*.{ts,tsx}'],
};

Pin major versions of jest, vitest, @types/jest, ts-jest, @vitest/ui — minor releases occasionally break edge mocks.


Running

CommandPurpose
vitest run / jestOne-shot run, no watch.
vitestWatch mode (default for vitest without run).
vitest related <files>Tests related to changed files.
jest --testPathPattern login / vitest -t loginFilter by name / path.
--coverageCoverage report.
--reporter=junit --outputFile=results.xmlJUnit XML for CI.
--shard=1/4Split across CI workers (Vitest 1.x+, Jest via --shard).
--changedSince=mainOnly tests for changes vs branch.

Verify flags with --help on your installed version.


Common Pitfalls

  • Mixing Jest and Vitest semantics in the same project — the small API differences (jest.fn vs vi.fn, hoisting subtleties) trip people up.
  • Forgetting that vi.mock / jest.mock are hoisted — calling them mid-test or after an import does nothing. Module mocks must be top-of-file (or inside vi.hoisted).
  • expect(x).resolves.toBe(...) without await — silently passes. Always await expect(...).resolves.X.
  • Sharing mutable state across tests — module singletons, in-memory caches, env vars. Reset in beforeEach.
  • Snapshot tests on dynamic data — every commit updates the snapshot. Strip dynamic fields or replace with matchers.
  • describe blocks deeply nested — three levels is a smell. Refactor to colocate setup with the test.
  • Coverage as a quality gate — high coverage doesn't mean tests catch bugs. Combine with mutation testing for real signal (cross-reference mutation-testing).
  • Long-running beforeAll that creates state for many tests — if any test mutates, others break. Use beforeEach for mutable setup.
  • Component tests that test framework internals — assert on rendered output / behavior, not React internals.

Task-Specific Questions

When helping with Jest / Vitest, ask:

  1. Jest or Vitest? (Plus version.)
  2. ESM or CJS?
  3. JavaScript or TypeScript?
  4. UI framework if any (React, Vue, Svelte, Solid, none)?
  5. Test scope — pure units, components, integration?
  6. Existing mocks pattern — module mocks, dependency injection, hand-rolled?
  7. CI reporter requirements — JUnit XML, JSON, HTML, Allure?
  8. Coverage strategy — gap-finding only, or hard threshold gate?

Related Skills

  • pytest — Python equivalent for many of the same patterns.
  • junit-testng — JVM equivalent.
  • xunit-nunit — .NET equivalent.
  • supertest — Node API integration testing built on Jest/Vitest.
  • cypress — for component testing in a real browser.
  • playwright — Playwright has its own test runner; some teams pair Vitest for units + Playwright for E2E.
  • code-coverage — for deeper coverage strategy.
  • mutation-testing — for measuring test quality beyond coverage.
  • flaky-test-management — when async tests intermittently fail.
  • ci-test-orchestration — for sharding and parallelism.

Keep looking

Skills are one crate of 628,853. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.