# Testing in Lobe Chat: Unit, Integration, and E2E Strategies Explained

> Explore Lobe Chat testing strategies. Learn about unit, integration, and end-to-end tests powered by Vitest, Playwright, and Cucumber for robust application development.

- Repository: [LobeHub/lobe-chat](https://github.com/lobehub/lobe-chat)
- Tags: how-to-guide
- Published: 2026-03-03

---

**Lobe Chat implements a comprehensive testing strategy using Vitest for unit and integration tests in a happy-dom environment, alongside Playwright and Cucumber for end-to-end browser automation.**

The lobehub/lobe-chat repository maintains a layered testing architecture that ensures code quality across utility functions, React components, and complete user workflows. This approach combines fast, deterministic unit tests with realistic browser-based verification to catch regressions before they reach production.

## Unit and Integration Testing with Vitest

### Configuration and Environment

All unit and integration tests run under **Vitest** configured in the root `vitest.config.mts` file. The setup uses **happy-dom** to provide a lightweight DOM implementation for React component testing without the overhead of launching a real browser. The configuration defines module path aliases, enables V8 coverage collection, and includes inline Vite plugins to resolve third-party packages such as `@lobehub/fluent-emoji`.

### Test Scope and Colocation

Tests are colocated with source code to maintain clear relationships between implementation and verification. You will find test files adjacent to their targets:

- Utility functions in `src/utils/*` (e.g., [`src/utils/unzipFile.test.ts`](https://github.com/lobehub/lobe-chat/blob/main/src/utils/unzipFile.test.ts))
- Service layer logic in `src/services/*` (e.g., [`src/services/message/server.test.ts`](https://github.com/lobehub/lobe-chat/blob/main/src/services/message/server.test.ts))
- React hooks and UI components in `src/features/*/__tests__/*.test.tsx`

This colocation strategy makes it obvious which modules lack test coverage and simplifies navigation during refactoring.

### Mocking Strategy

Vitest’s built-in `vi.mock` utility stubs external dependencies to keep tests fast and deterministic. The codebase heavily mocks network clients such as `@/libs/trpc/client` to isolate service layer tests from actual API calls.

```typescript
// Example from src/utils/unzipFile.test.ts
import { describe, expect, it } from 'vitest';
import { unzipFile } from './unzipFile';
import { zip } from 'fflate';

describe('unzipFile', () => {
  it('should extract files from a ZIP archive', async () => {
    const testFiles = {
      'test.txt': new TextEncoder().encode('Hello, World!'),
    };
    const zipped = await new Promise<Uint8Array>((resolve, reject) => {
      zip(testFiles, (e, d) => (e ? reject(e) : resolve(d)));
    });
    const zipFile = new File([new Uint8Array(zipped)], 'test.zip', {
      type: 'application/zip',
    });
    const extracted = await unzipFile(zipFile);
    expect(extracted).toHaveLength(1);
    expect(await extracted[0].text()).toBe('Hello, World!');
  });
});

```

## End-to-End Testing with Playwright and Cucumber

### BDD-Style Feature Files

The E2E suite lives in the `e2e/` directory and uses **Playwright** to drive real browsers (Chromium, Firefox, WebKit) while **Cucumber** provides behavior-driven development (BDD) syntax. Feature files describe user journeys in plain language, with step definitions in `e2e/src/steps/` mapping those descriptions to automation code.

Key configuration resides in [`e2e/cucumber.config.js`](https://github.com/lobehub/lobe-chat/blob/main/e2e/cucumber.config.js), which wires Playwright’s browser management to Cucumber’s step execution.

```gherkin

# Example from e2e/src/features/agent/message-ops.feature

Feature: Agent message operations
  Scenario: User sends a new message
    Given the user is authenticated
    When the user types "Hello" in the chat input
    And clicks the send button
    Then the message "Hello" should appear in the conversation

```

### Mock Server for Deterministic Tests

To avoid flakiness from external LLM APIs, the E2E suite includes a lightweight mock server in [`e2e/src/mocks/llm/index.ts`](https://github.com/lobehub/lobe-chat/blob/main/e2e/src/mocks/llm/index.ts). This server simulates LLM and community API responses, ensuring that UI tests verify interface behavior rather than external service availability.

## Test Execution Commands

The repository provides npm scripts to trigger specific test layers:

- **Run unit/integration tests**: `npm run test-app` or `pnpm test-app`
- **Run with coverage**: `npm run test-app:coverage` or `pnpm test-app:coverage`
- **Run E2E scenarios**: `npm run e2e` or `pnpm e2e`
- **Update snapshots**: `npm run test:update` or `pnpm test:update`

For targeted execution during development, run a single file with Vitest directly:

```bash
pnpm vitest run src/utils/unzipFile.test.ts

```

Or execute a specific E2E feature using Cucumber’s grep filter:

```bash
pnpm e2e --grep "agent conversation"

```

## Coverage and Quality Gates

Vitest’s built-in **V8 coverage collector** generates reports in `text`, `json`, `lcov`, and `text-summary` formats under the `coverage/app` directory. The configuration in `vitest.config.mts` explicitly excludes generated code, database migrations, and third-party packages from coverage metrics.

Beyond tests, the CI pipeline enforces `npm run lint` and `npm run type-check` to catch static errors before runtime testing begins.

## Continuous Integration

The GitHub Actions workflow runs the complete test matrix on every pull request. This includes the full Vitest suite with coverage threshold enforcement, followed by headless Playwright E2E tests against a locally bootstrapped dev server. The mock server automatically applies during E2E runs to maintain deterministic execution in the CI environment.

## Summary

- **Vitest** powers unit and integration tests using a **happy-dom** environment for fast React component validation.
- Tests are **colocated** with source code in `src/utils/`, `src/services/`, and `src/features/` directories.
- **Playwright and Cucumber** drive E2E tests from the `e2e/` folder using BDD feature files and step definitions.
- A **mock server** in `e2e/src/mocks/` eliminates external dependencies during browser testing.
- **V8 coverage** reporting and strict CI gates ensure quality benchmarks are met before merging.

## Frequently Asked Questions

### What test runner does Lobe Chat use for unit tests?

Lobe Chat uses **Vitest** as the primary test runner for all unit and integration tests. It is configured in `vitest.config.mts` to use the **happy-dom** environment, which provides browser-like DOM APIs without the performance cost of running an actual browser.

### How does Lobe Chat handle mocking in tests?

The codebase relies on Vitest’s `vi.mock` utility to stub modules like `@/libs/trpc/client` and external network calls. During E2E tests, a dedicated mock server in [`e2e/src/mocks/llm/index.ts`](https://github.com/lobehub/lobe-chat/blob/main/e2e/src/mocks/llm/index.ts) simulates LLM responses, allowing the UI to be tested deterministically regardless of external API status.

### Where are the E2E tests located in the repository?

All end-to-end tests reside in the `e2e/` directory at the repository root. This includes Cucumber feature files describing user stories (e.g., `e2e/src/features/agent/message-ops.feature`), step definition implementations in `e2e/src/steps/`, and the Playwright configuration in [`e2e/cucumber.config.js`](https://github.com/lobehub/lobe-chat/blob/main/e2e/cucumber.config.js).

### What coverage tools are configured in the project?

The project uses Vitest’s built-in **V8 coverage engine** configured to output multiple report formats including `text`, `json`, and `lcov` under `coverage/app`. The configuration excludes generated files and migrations to ensure metrics reflect meaningful code coverage.