home / skills / lobehub / lobe-chat / testing

testing skill

/.agents/skills/testing

This skill helps you write and debug Vitest tests in TypeScript, improve coverage, and follow best practices for reliable testing.

npx playbooks add skill lobehub/lobe-chat --skill testing

Review the files below or copy the command above to add this skill to your agents.

Files (6)
SKILL.md
2.7 KB
---
name: testing
description: Testing guide using Vitest. Use when writing tests (.test.ts, .test.tsx), fixing failing tests, improving test coverage, or debugging test issues. Triggers on test creation, test debugging, mock setup, or test-related questions.
---

# LobeChat Testing Guide

## Quick Reference

**Commands:**
```bash
# Run specific test file
bunx vitest run --silent='passed-only' '[file-path]'

# Database package (client)
cd packages/database && bunx vitest run --silent='passed-only' '[file]'

# Database package (server)
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).

## Test Categories

| Category | Location | Config |
|----------|----------|--------|
| Webapp | `src/**/*.test.ts(x)` | `vitest.config.ts` |
| Packages | `packages/*/**/*.test.ts` | `packages/*/vitest.config.ts` |
| Desktop | `apps/desktop/**/*.test.ts` | `apps/desktop/vitest.config.ts` |

## Core Principles

1. **Prefer `vi.spyOn` over `vi.mock`** - More targeted, easier to maintain
2. **Tests must pass type check** - Run `bun run type-check` after writing tests
3. **After 1-2 failed fix attempts, stop and ask for help**
4. **Test behavior, not implementation details**

## Basic Test Structure

```typescript
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';

beforeEach(() => {
  vi.clearAllMocks();
});

afterEach(() => {
  vi.restoreAllMocks();
});

describe('ModuleName', () => {
  describe('functionName', () => {
    it('should handle normal case', () => {
      // Arrange → Act → Assert
    });
  });
});
```

## Mock Patterns

```typescript
// ✅ Spy on direct dependencies
vi.spyOn(messageService, 'createMessage').mockResolvedValue('id');

// ✅ Use vi.stubGlobal for browser APIs
vi.stubGlobal('Image', mockImage);
vi.spyOn(URL, 'createObjectURL').mockReturnValue('blob:mock');

// ❌ Avoid mocking entire modules globally
vi.mock('@/services/chat'); // Too broad
```

## 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`

## Common Issues

1. **Module pollution**: Use `vi.resetModules()` when tests fail mysteriously
2. **Mock not working**: Check setup position and use `vi.clearAllMocks()` in beforeEach
3. **Test data pollution**: Clean database state in beforeEach/afterEach
4. **Async issues**: Wrap state changes in `act()` for React hooks

Overview

This skill is a practical Vitest testing guide for TypeScript projects. It helps you write, run, and debug unit and integration tests, with patterns for mocks, spies, and test file organization. Use it to speed up test creation, fix failing tests, and improve coverage across web, package, and desktop codebases.

How this skill works

The skill inspects test files, proposed test code, and test failures to suggest fixes and improvements. It recommends targeted mocking with vi.spyOn, global stubs for browser APIs, and commands to run specific tests to avoid running the entire suite. It also points to reference patterns for database, Electron, Zustand, and agent runtime testing.

When to use it

  • Writing new .test.ts or .test.tsx files
  • Debugging failing tests or mysterious test pollution
  • Setting up or fixing mocks and spies
  • Improving test coverage and type-checking tests
  • Running targeted tests without executing the whole suite

Best practices

  • Prefer vi.spyOn over vi.mock for focused, maintainable mocks
  • Clear and restore mocks each test: vi.clearAllMocks() and vi.restoreAllMocks()
  • Keep tests type-safe — run the project type-check after changes
  • Avoid global module mocks; stub browser globals with vi.stubGlobal when needed
  • When stuck after 1–2 attempts, stop and ask a teammate to avoid cascading errors

Example use cases

  • Run a single test file: bunx vitest run --silent='passed-only' '[file-path]' to save time
  • Test database models in packages with package-specific commands and TEST_SERVER_DB when needed
  • Mock Image or URL APIs with vi.stubGlobal and vi.spyOn for browser behavior
  • Fix async React hook tests by wrapping updates in act() and checking for state cleanup
  • Resolve module pollution by calling vi.resetModules() in affected test suites

FAQ

How do I run just one failing test quickly?

Run bunx vitest run --silent='passed-only' '[file-path]' or cd into the package and run the file to avoid running the full suite.

When should I use vi.resetModules()?

Use vi.resetModules() when tests fail mysteriously due to module state or cross-test pollution to force module re-initialization.

Should I mock entire modules globally?

No. Avoid broad vi.mock calls. Prefer vi.spyOn on specific methods or vi.stubGlobal for browser globals to keep tests predictable.