agentsclimarketplace

Vitest unit testing

Skill Perdolique/workflow/skills/vitest-unit-testing

Personalised workflow, tools, agents, skills and other stuff in one place

Install
npx -y skills add Perdolique/workflow --skill vitest-unit-testing

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

  • 0 stars0 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.

What its author says it does

Copied from the file, not written here

Write and maintain Vitest unit tests for TypeScript code. Use when the user needs unit coverage for utilities, services, or stores, or asks for Vitest-based tests with mocks, spies, and assertions.

The file declares its own license as Unlicense. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

6.6 KB, as published. Nobody here has run it

Unit testing with Vitest

This skill provides patterns and conventions for writing comprehensive unit tests in TypeScript projects using Vitest.

When to use this skill

  • Writing unit tests for TypeScript utilities, services, or API clients
  • Testing stores (Pinia, Zustand, etc.)
  • Testing API transforms and services
  • Adding test coverage to existing code
  • Debugging failing tests

Test file structure

Location and naming

  • Place tests in __tests__/ directory next to the file being tested
  • Name test files with .test.ts suffix matching the source file name
  • Example: config.ts__tests__/config.test.ts

Basic structure

import { describe, test, expect, vi, beforeAll, afterAll, beforeEach, afterEach } from 'vitest';
import { functionToTest } from '../module';

describe('Module name or function group', () => {
  describe(functionName, () => {
    test('should do something specific', () => {
      // Arrange
      const input = 'test';

      // Act
      const result = functionToTest(input);

      // Assert
      expect(result).toBe('expected');
    });
  });
});

Core testing patterns

AAA pattern (Arrange, Act, Assert)

Always structure tests with clear AAA sections:

test('should calculate total price correctly', () => {
  // Arrange
  const items = [
    { price: 100, quantity: 2 },
    { price: 50, quantity: 1 }
  ];

  // Act
  const total = calculateTotal(items);

  // Assert
  expect(total).toBe(250);
});

Parametrized tests with test.each

Use test.each for testing multiple scenarios:

describe(getBaseUrl, () => {
  test.each([
    ['production', 'prod', 'https://app.example.com'],
    ['staging', 'staging', 'https://staging.example.com'],
    ['development', 'dev', 'http://localhost:3000']
  ])('returns correct URL for environment %s', (_name, env, expected) => {
    vi.spyOn(envUtils, 'getEnvironment').mockReturnValue(env);

    const url = getBaseUrl();

    expect(url).toBe(expected);
  });
});

Lifecycle hooks

describe('Test suite', () => {
  beforeAll(() => {
    // Runs once before all tests
  });

  beforeEach(() => {
    // Runs before each test
  });

  afterEach(() => {
    // Runs after each test — restore mocks here
    vi.restoreAllMocks();
  });

  afterAll(() => {
    // Runs once after all tests
    vi.useRealTimers();
  });
});

Mocking

See references/mocking.md for the comprehensive mocking guide.

Quick reference

// Mock entire module
vi.mock(import('./utils/logging'), () => ({
  logException: vi.fn()
}));

// Spy on function
vi.spyOn(module, 'functionName').mockReturnValue('result');

// Spy on getter
vi.spyOn(window.location, 'hostname', 'get').mockReturnValue('test.com');

// Fake timers
vi.useFakeTimers();
vi.setSystemTime(new Date('2024-01-01'));
vi.advanceTimersByTimeAsync(1000); // Use async version for promise-based timers

// Cleanup
vi.restoreAllMocks();
vi.useRealTimers();

Best practices

Test naming

Use descriptive test names explaining expected behavior. Start with "should" or describe the outcome. Be specific about the scenario being tested.

// Good
test('should return empty array when no items match filter', () => {});
test('throws error when user ID is invalid', () => {});

// Bad
test('works correctly', () => {});
test('test filter', () => {});

Grouping tests

Use nested describe blocks for organization:

describe('UserService', () => {
  describe(getUser, () => {
    test('should fetch user by ID', () => {});
    test('should handle missing user', () => {});
  });

  describe(updateUser, () => {
    test('should update user data', () => {});
    test('should validate input before update', () => {});
  });
});

Test coverage

Always test:

  • Expected/happy path behavior
  • Error conditions
  • Edge cases (null, undefined, empty values)
  • Boundary conditions

Mock management

  • Always restore mocks after tests using afterEach or afterAll
  • Use vi.hoisted() for shared mocks referenced in module mocks
  • Be specific with mock return values relevant to the test
  • Only mock external dependencies, not the code under test

Assertions

Prefer specific matchers:

// Good — specific matchers
expect(result).toBe(true);
expect(array).toHaveLength(3);
expect(object).toStrictEqual({ id: 1, name: 'test' });
expect(fn).toHaveBeenCalledWith('expected-arg');
expect(fn).toHaveBeenCalledTimes(1);

// Less specific but sometimes necessary
expect(result).toBeTruthy();
expect(result).toBeFalsy();

Running tests

Always use the runTests tool instead of running tests manually in terminal. The tool automatically runs tests in non-interactive mode and provides structured output for validation.

If you must use terminal commands, use the CI/non-interactive mode of the project's test script (e.g., vitest run or the project's equivalent). Never use a command that starts interactive watch mode.

# ❌ NEVER use watch mode
npx vitest

# ✅ Use run mode for specific test files
npx vitest run src/utils/__tests__/config.test.ts

# Run with coverage
npx vitest run --coverage

# Run all tests in CI mode
npx vitest run

Check the project's package.json for available test scripts — many projects define shortcuts like test:unit, test:unit:ci, or similar.

Common pitfalls to avoid

  1. Don't forget to restore mocks — Always use afterEach or afterAll with vi.restoreAllMocks()
  2. Don't test implementation details — Test behavior, not internal workings
  3. Don't create interdependent tests — Each test should be independent
  4. Don't mock everything — Only mock external dependencies, not the code under test
  5. Don't write tests that pass without assertions — Every test needs at least one expect()
  6. Don't use real timers when testing time-dependent code — Use vi.useFakeTimers()

TypeScript considerations

  • Use // @ts-expect-error when intentionally passing invalid types to test error handling
  • Use vi.mocked() for type-safe access to mocked functions
  • Use satisfies for type-checked assertion payloads without losing literal types

Reference files

  • references/mocking.md — Comprehensive mocking guide covering module mocks, spying, time mocking, async mocks, cleanup, and mock assertions

Keep looking

Skills are one crate of 328,083. 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.