All skills

Use when writing unit/integration tests for Vite projects - provides Vitest configuration, test APIs, mocking patterns, and coverage setup

  • 6 files
  • 24.3 KB
  • MIT
  • Updated 8 months ago
  • GitHub

Use this Skill: https://skilld.dev/gh/onmax/claude-config/vitest

This session only. Nothing lands on disk.

referencesutilities.md

≈1.4k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Utilities

Expect API

import { expect } from 'vitest'

// Equality
expect(1 + 1).toBe(2)              // Strict ===
expect({ a: 1 }).toEqual({ a: 1 }) // Deep equality
expect({ a: 1 }).toStrictEqual({ a: 1 }) // Checks undefined props

// Truthiness
expect(true).toBeTruthy()
expect(false).toBeFalsy()
expect(null).toBeNull()
expect(undefined).toBeUndefined()
expect('value').toBeDefined()

// Numbers
expect(10).toBeGreaterThan(5)
expect(10).toBeGreaterThanOrEqual(10)
expect(5).toBeLessThan(10)
expect(0.1 + 0.2).toBeCloseTo(0.3, 5)

// Strings
expect('hello world').toMatch(/world/)
expect('hello').toContain('ell')

// Arrays
expect([1, 2, 3]).toContain(2)
expect([{ a: 1 }]).toContainEqual({ a: 1 })
expect([1, 2, 3]).toHaveLength(3)

// Objects
expect({ a: 1, b: 2 }).toHaveProperty('a')
expect({ a: 1, b: 2 }).toHaveProperty('a', 1)
expect({ a: { b: 1 } }).toHaveProperty('a.b', 1)
expect({ a: 1 }).toMatchObject({ a: 1 })

// Types
expect('string').toBeTypeOf('string')
expect(new Date()).toBeInstanceOf(Date)

// Negation
expect(1).not.toBe(2)

Error Assertions

// Sync - wrap in function
expect(() => throwError()).toThrow()
expect(() => throwError()).toThrow('message')
expect(() => throwError()).toThrow(/pattern/)
expect(() => throwError()).toThrow(CustomError)

// Async - use rejects
await expect(asyncThrow()).rejects.toThrow('error')

Promise Assertions

await expect(Promise.resolve(1)).resolves.toBe(1)
await expect(Promise.reject('error')).rejects.toBe('error')

Spy/Mock Assertions

const fn = vi.fn()
fn('arg1', 'arg2')
fn('arg3')

expect(fn).toHaveBeenCalled()
expect(fn).toHaveBeenCalledTimes(2)
expect(fn).toHaveBeenCalledWith('arg1', 'arg2')
expect(fn).toHaveBeenLastCalledWith('arg3')
expect(fn).toHaveBeenNthCalledWith(1, 'arg1', 'arg2')
expect(fn).toHaveReturned()
expect(fn).toHaveReturnedWith(value)

Asymmetric Matchers

expect({ id: 1, name: 'test' }).toEqual({
  id: expect.any(Number),
  name: expect.any(String),
})

expect({ a: 1, b: 2, c: 3 }).toEqual(expect.objectContaining({ a: 1 }))
expect([1, 2, 3, 4]).toEqual(expect.arrayContaining([1, 3]))
expect('hello world').toEqual(expect.stringContaining('world'))
expect('hello world').toEqual(expect.stringMatching(/world$/))
expect({ value: null }).toEqual({ value: expect.anything() })
expect([1, 2]).toEqual(expect.not.arrayContaining([3]))

Soft & Poll Assertions

// Continue after failure
expect.soft(1).toBe(2)  // Marks failed but continues
expect.soft(2).toBe(3)  // Also runs

// Retry until passes
await expect.poll(() => fetchStatus()).toBe('ready')
await expect.poll(
  () => document.querySelector('.element'),
  { interval: 100, timeout: 5000 }
).toBeTruthy()

Assertion Count

test('async assertions', async () => {
  expect.assertions(2)      // Exactly 2 must run
  expect.hasAssertions()    // At least 1 must run
})

Custom Matchers

expect.extend({
  toBeWithinRange(received, floor, ceiling) {
    const pass = received >= floor && received <= ceiling
    return {
      pass,
      message: () => `expected ${received} to be within ${floor} - ${ceiling}`,
    }
  },
})

test('custom', () => { expect(100).toBeWithinRange(90, 110) })

Snapshots

expect(data).toMatchSnapshot()
expect(data).toMatchInlineSnapshot(`{ "id": 1 }`)
await expect(result).toMatchFileSnapshot('./expected.json')
expect(() => { throw new Error('fail') }).toThrowErrorMatchingSnapshot()

// With hints
expect(header).toMatchSnapshot('header')

// Shape matching
expect(data).toMatchSnapshot({
  id: expect.any(Number),
  created: expect.any(Date),
})

Update snapshots: vitest -u or press u in watch mode.

Custom Serializers

expect.addSnapshotSerializer({
  test(val) { return val && typeof val.toJSON === 'function' },
  serialize(val, config, indentation, depth, refs, printer) {
    return printer(val.toJSON(), config, indentation, depth, refs)
  },
})

Coverage

vitest run --coverage
defineConfig({
  test: {
    coverage: {
      provider: 'v8',  // or 'istanbul'
      enabled: true,
      reporter: ['text', 'json', 'html'],
      include: ['src/**/*.{ts,tsx}'],
      exclude: ['node_modules/', 'tests/', '**/*.d.ts'],
      all: true,  // Report uncovered files
      thresholds: { lines: 80, functions: 80, branches: 80, statements: 80 },
    },
  },
})

Ignore code:

/* v8 ignore next -- @preserve */
function ignored() {}

/* istanbul ignore next -- @preserve */
function ignored() {}

Filtering

vitest user                      # Files containing "user"
vitest src/user.test.ts:25       # Specific line
vitest -t "login"                # Tests matching pattern
vitest --changed                 # Uncommitted changes
vitest --changed HEAD~1          # Since commit
vitest related src/utils.ts --run  # Tests importing file
vitest --tags db                 # By tag
test('db test', { tags: ['db', 'slow'] }, async () => {})

Concurrency

defineConfig({
  test: {
    fileParallelism: true,
    maxWorkers: 4,
    pool: 'threads',  // 'threads', 'forks', 'vmThreads'
    maxConcurrency: 5,  // Max concurrent tests per file
    isolate: true,
    sequence: {
      shuffle: true,
      seed: 12345,
      hooks: 'stack',
      concurrent: true,
    },
  },
})
describe.concurrent('parallel', () => {
  test('test 1', async ({ expect }) => {})
  test('test 2', async ({ expect }) => {})
})

describe.shuffle('random order', () => {})

Source: SKILL.md on GitHub

No third-party reports yet.

Signed by skilld at 6a37106. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 8 hours ago.

Activeupdated 8 months ago

README badge

README badge for onmax/claude-config/vitest