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

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:

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.

// 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, which wires Playwright’s browser management to Cucumber’s step execution.


# 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. 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:

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

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

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 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.

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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →