A guide for writing, debugging, and maintaining Vitest tests while optimizing performance.

Install

mkdir -p .claude/skills/testing && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/973" && unzip -o skill.zip -d .claude/skills/testing && rm skill.zip

Installs to .claude/skills/testing

Activation

This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.

Vitest testing guide. Use when writing or updating tests, fixing failing tests, improving coverage, debugging test issues, or setting up mocks.
143 chars✓ has a “when” trigger
Intermediate

Key capabilities

  • →Create unit tests for models and repositories
  • →Configure mock objects using spyOn
  • →Implement integration tests with database handles
  • →Manage regression test suites for bug fixes
  • →Optimize test execution across different test suites

How it works

Guides the generation of test files and mock setups according to LobeHub architecture, ensuring isolation and proper database separation.

Inputs & outputs

You give it
Test requirement or code bug report
You get back
Passing test suite with regression protection

When to use testing

  • →Create unit tests for new repository models
  • →Debug failing Vitest test suites
  • →Configure mock objects using vi.spyOn
  • →Optimize test execution time

About this skill

LobeHub Testing Guide

Quick Reference

Commands:

# Run specific test file
bunx vitest run --silent='passed-only' '[file-path]'

# Database package (client-db, PGlite — default, skips BM25/pg_search)
cd packages/database && bunx vitest run --silent='passed-only' '[file]'

# Database package (server-db, Postgres — BM25/pgvector parity, what CI measures coverage in)
cd packages/database && TEST_SERVER_DB=1 bunx vitest run --silent='passed-only' '[file]'

Never run bun run test - it runs all 3000+ tests (~10 minutes).

Database models/repositories: every new file under packages/database/src/models/** or src/repositories/** ships with a sibling __tests__/<name>.test.ts in the same PR. Use the real DB via getTestDB() (integration style), guard BM25/full-text-search blocks with describe.skipIf(!isServerDB), and always test user-isolation. See references/db-model-test.md for setup, schema gotchas, and the client-vs-server-db split.

Test Categories

CategoryLocationConfig
Webappsrc/**/*.test.ts(x)vitest.config.ts
Packagespackages/*/**/*.test.tspackages/*/vitest.config.ts
Desktopapps/desktop/**/*.test.tsapps/desktop/vitest.config.ts

Core Principles

  1. Prefer vi.spyOn over vi.mock - More targeted, easier to maintain. The root Vitest configs do not restore mocks automatically; restore spies in test cleanup with vi.restoreAllMocks().
  2. Test behavior, not implementation details
  3. Regression tests for bug fixes - Include a regression test that fails without the fix and passes with it; write the failing test first when the failure is easy to reproduce. Skip pure style/CSS fixes (selector, hover, mask, spacing, color) when the only practical assertion would be source-string matching on the stylesheet — that is not a regression test worth shipping.
  4. No new component tests - Only update existing React component tests. Complex logic should be extracted into hooks and tested there instead

UI Library Mocks (@lobehub/ui/base-ui)

Default: do NOT mock @lobehub/ui/base-ui — render the real components. vitest.config.mts redirects the library's internal MotionProvider to a static stub (tests/mocks/lobehubUiMotionProvider.tsx), so base-ui components render in tests without the app-level ConfigProvider. Please wrap your app with <ConfigProvider> (or <MotionProvider>) in a test means that redirect is not in effect (e.g. a package-local vitest config) — do not fix it by hand-mocking every component.

When a test genuinely wants simplified DOM, compose the canonical stubs over the real module instead of writing a closed factory (closed factories break whenever the library migrates a component's import path):

vi.mock('@lobehub/ui/base-ui', async (importOriginal) => ({
  ...(await importOriginal<object>()),
  ...(await import('~base-ui-stubs')).baseUiStubs,
}));

~base-ui-stubs (tests/mocks/baseUiStubs.tsx) covers ActionIcon / Button / Text / Tag / Avatar / Alert / toast / confirmModal / createModal with standard aria semantics. A per-file factory is still fine when assertions need bespoke testid conventions — but keep it composed over importOriginal so unknown exports never go missing.

Detailed Guides

See references/ for specific testing scenarios:

  • Database Model testing: references/db-model-test.md
  • Electron IPC testing: references/electron-ipc-test.md
  • Zustand Store Action testing: references/zustand-store-action-test.md
  • Agent Runtime E2E testing: references/agent-runtime-e2e.md
  • Desktop Controller testing: references/desktop-controller-test.md

Fixing Failing Tests — Optimize or Delete?

When tests fail due to implementation changes (not bugs), evaluate before blindly fixing:

Keep & Fix (update test data/assertions)

  • Behavior tests: Tests that verify what the code does (output, side effects, user-visible behavior). Just update mock data formats or expected values.
    • Example: Tool data structure changed from { name } to { function: { name } } → update mock data
    • Example: Output format changed from Current date: YYYY-MM-DD to Current date: YYYY-MM-DD (TZ) → update expected string

Delete (over-specified, low value)

  • Param-forwarding tests: Tests that assert exact internal function call arguments (e.g., expect(internalFn).toHaveBeenCalledWith(expect.objectContaining({ exact params }))) — these break on every refactor and duplicate what behavior tests already cover.
  • Implementation-coupled tests: Tests that verify how the code works internally rather than what it produces. If a higher-level test already covers the same behavior, the low-level test adds maintenance cost without coverage gain.

Decision Checklist

  1. Does the test verify externally observable behavior (API response, DB write, rendered output)? → Keep
  2. Does the test only verify internal wiring (which function receives which params)? → Check if a behavior test already covers it. If yes → Delete
  3. Is the same behavior already tested at a higher integration level? → Delete the lower-level duplicate
  4. Would the test break again on the next routine refactor? → Consider raising to integration level or deleting

When Writing New Tests

  • Prefer integration-level assertions (verify final output) over white-box assertions (verify internal calls)
  • Use expect.objectContaining only for stable, public-facing contracts — not for internal param shapes that change with refactors
  • Mock at boundaries (DB, network, external services), not between internal modules

When not to use it

  • →For ad-hoc script-only testing
  • →When full integration with the database is explicitly not desired

Prerequisites

vitestbun

Limitations

  • →Cannot use full 3000+ test suite
  • →Requires internal project structure for database models
  • →Limited to Vitest framework

How it compares

It enforces strict testing patterns (spyOn over mock) and specific command-line usage to handle the large internal codebase size.

Compared to similar skills

testing side by side with the closest alternatives in the catalog.

SkillInstallsUpdatedSafetyDifficulty
testing (this skill)53moReviewIntermediate
chrome-devtools418moReviewIntermediate
obsidian-local-dev-loop32moReviewIntermediate
dependency-upgrade266moReviewIntermediate

Try saying

Example prompts that trigger this skill in your AI assistant.

drizzle

lobehub

Drizzle ORM schema and database guide. Use when working with database schemas (src/database/schemas/*), defining tables, creating migrations, or database model code. Triggers on Drizzle schema definition, database migrations, or ORM usage questions.

238873

zustand

lobehub

Zustand state management guide. Use when working with store code (src/store/**), implementing actions, managing state, or creating slices. Triggers on Zustand store development, state management questions, or action implementation.

113434

react

lobehub

React component development guide. Use when working with React components (.tsx files), creating UI, using @lobehub/ui components, implementing routing, or building frontend features. Triggers on React component creation, modification, layout implementation, or navigation tasks.

3480

typescript

lobehub

TypeScript code style and optimization guidelines. Use when writing TypeScript code (.ts, .tsx, .mts files), reviewing code quality, or implementing type-safe patterns. Triggers on TypeScript development, type safety questions, or code style discussions.

2877

project-overview

lobehub

Complete project architecture and structure guide. Use when exploring the codebase, understanding project organization, finding files, or needing comprehensive architectural context. Triggers on architecture questions, directory navigation, or project overview needs.

1548

linear

lobehub

Linear issue management guide. Use when working with Linear issues, creating issues, updating status, or adding comments. Triggers on Linear issue references (LOBE-xxx), issue tracking, or project management tasks. Requires Linear MCP tools to be available.

10117

You might also like

chrome-devtools

mrgoonie

Browser automation, debugging, and performance analysis using Puppeteer CLI scripts. Use for automating browsers, taking screenshots, analyzing performance, monitoring network traffic, web scraping, form automation, and JavaScript debugging.

41157

obsidian-local-dev-loop

jeremylongshore

Configure Obsidian plugin development with hot-reload and fast iteration. Use when setting up development workflow, configuring test vaults, or establishing a rapid development cycle. Trigger with phrases like "obsidian dev loop", "obsidian hot reload", "obsidian development workflow", "develop obsidian plugin".

328

dependency-upgrade

wshobson

Manage major dependency version upgrades with compatibility analysis, staged rollout, and comprehensive testing. Use when upgrading framework versions, updating major dependencies, or managing breaking changes in libraries.

26240

playwright-browser-automation

lackeyjb

Complete browser automation with Playwright. Auto-detects dev servers, writes clean test scripts to /tmp. Test pages, fill forms, take screenshots, check responsive design, validate UX, test login flows, check links, automate any browser task. Use when user wants to test websites, automate browser interactions, validate web functionality, or perform any browser-based testing.

29146

nestjs-expert

davila7

Nest.js framework expert specializing in module architecture, dependency injection, middleware, guards, interceptors, testing with Jest/Supertest, TypeORM/Mongoose integration, and Passport.js authentication. Use PROACTIVELY for any Nest.js application issues including architecture decisions, testing strategies, performance optimization, or debugging complex dependency injection problems. If a specialized expert is a better fit, I will recommend switching and stop.

3758

zod-4

prowler-cloud

Zod 4 schema validation patterns. Trigger: When creating or updating Zod v4 schemas for validation/parsing (forms, request payloads, adapters), including v3 -> v4 migration patterns.

1260

Search skills

Search the agent skills registry