# Testing Patterns in Open-SEO: How to Run the Test Suite with Vitest and Playwright

> Explore Open-SEO testing patterns using Vitest for unit/integration tests and Playwright for end-to-end tests. Learn to run the full test suite with simple npm commands.

- Repository: [Every App/open-seo](https://github.com/every-app/open-seo)
- Tags: how-to-guide
- Published: 2026-07-30

---

**Open-SEO uses Vitest for unit and integration tests located in `src/**/*.test.ts` files, and Playwright for end-to-end tests in the `e2e/` directory, with all commands available via npm scripts in [`package.json`](https://github.com/every-app/open-seo/blob/main/package.json).**

The open-source SEO platform Open-SEO relies on a layered testing strategy to ensure code quality across its TypeScript codebase. Understanding the **testing patterns** used in this repository helps contributors write reliable features and debug issues efficiently. This guide explains exactly how the test suite is organized and how to execute both Vitest and Playwright tests locally or in CI pipelines.

## Testing Architecture Overview

Open-SEO implements two complementary testing patterns that cover different levels of the application stack.

### Unit and Integration Tests with Vitest

The codebase uses **Vitest** as its primary unit testing framework. Test files follow the convention `src/**/*.test.ts`, such as [`src/shared/targetDetection.test.ts`](https://github.com/every-app/open-seo/blob/main/src/shared/targetDetection.test.ts). Each suite employs the standard Jest-compatible API using `describe`, `it`, and `expect` globals. Vitest is configured with `restoreMocks` and `clearMocks` enabled to ensure a clean state between every test execution.

### End-to-End Tests with Playwright

For full-stack validation, Open-SEO uses **Playwright** to run E2E tests against a real browser environment. Test specifications reside in the `e2e/` folder, including examples like [`e2e/keyword-research-navigation.spec.ts`](https://github.com/every-app/open-seo/blob/main/e2e/keyword-research-navigation.spec.ts). These tests exercise the complete application stack including both frontend and backend components running on a local dev server.

### Continuous Integration Configuration

The repository optimizes test execution for CI pipelines through dedicated reporter settings. The `test:ci` script runs Vitest with the minimal `dot` reporter to reduce log noise, while E2E tests run via the standard `test:e2e` script using Playwright's built-in reporting.

## Configuration Deep Dive

Understanding the configuration files reveals how the **testing patterns** are implemented technically.

### Vitest Configuration (vitest.config.ts)

In [`vitest.config.ts`](https://github.com/every-app/open-seo/blob/main/vitest.config.ts), the test environment targets Node.js with specific inclusion patterns and mock cleanup settings:

```typescript
// https://github.com/every-app/open-seo/blob/main/vitest.config.ts
export default defineConfig({
  plugins: [tsConfigPaths()],
  test: {
    environment: "node",
    include: ["src/**/*.test.ts"],
    restoreMocks: true,
    clearMocks: true,
  },
});

```

This configuration ensures that all files matching `src/**/*.test.ts` are discovered automatically, and test isolation is maintained through automatic mock resetting.

### Playwright Configuration (playwright.config.ts)

The [`playwright.config.ts`](https://github.com/every-app/open-seo/blob/main/playwright.config.ts) file defines the E2E test directory, timeouts, and automatic dev server management:

```typescript
// https://github.com/every-app/open-seo/blob/main/playwright.config.ts
export default defineConfig({
  testDir: "./e2e",
  timeout: 45_000,
  workers: 1,
  use: {
    baseURL: "http://localhost:3101",
    screenshot: "only-on-failure",
    trace: "retain-on-failure",
    video: "retain-on-failure",
  },
  webServer: {
    command:
      "NODE_OPTIONS= AUTH_MODE=local_noauth VITE_E2E_DOMAIN_FIXTURES=1 VITE_E2E_KEYWORD_FIXTURES=1 PORT=3101 pnpm exec vite dev --host 127.0.0.1 --strictPort",
    url: "http://localhost:3101",
    reuseExistingServer: false,
    timeout: 120_000,
  },
});

```

The `webServer` configuration automatically launches the application on `localhost:3101` before executing tests, ensuring consistent test environments without manual server startup.

## How to Run the Test Suite

All test execution commands are defined in [`package.json`](https://github.com/every-app/open-seo/blob/main/package.json) under the `scripts` section.

### Execute Unit and Integration Tests

To **run the test suite** for unit and integration tests, use the following npm scripts:

```bash

# Run all Vitest tests once

npm run test

# Start Vitest in watch mode for development

npm run test:watch

```

The `test:watch` command keeps the test runner active in your terminal, automatically re-running relevant tests whenever you modify source files.

### Execute E2E Tests

To execute the full Playwright end-to-end suite or specific test files:

```bash

# Run all E2E tests (spins up dev server automatically)

npm run test:e2e

# Run specific E2E test files

npm run test:e2e:domain
npm run test:e2e:keywords

```

The `test:e2e:domain` script targets [`e2e/domain-overview-filters.spec.ts`](https://github.com/every-app/open-seo/blob/main/e2e/domain-overview-filters.spec.ts), while `test:e2e:keywords` runs [`e2e/keyword-research-navigation.spec.ts`](https://github.com/every-app/open-seo/blob/main/e2e/keyword-research-navigation.spec.ts). There is also a performance-specific variant available via `test:e2e:domain:perf`.

### CI-Optimized Commands

When running in continuous integration environments, use these optimized commands:

```bash

# CI-optimized unit tests with minimal reporter

npm run test:ci

# E2E tests for CI pipelines

npm run test:e2e

```

The `test:ci` command executes `vitest run --reporter=dot`, which provides deterministic feedback without verbose output, while the E2E command runs Playwright with the configuration settings appropriate for automated environments.

## Summary

- **Open-SEO** employs a dual-layer testing strategy using **Vitest** for unit/integration tests and **Playwright** for end-to-end browser automation.
- Unit test files follow the `src/**/*.test.ts` pattern and are configured in [`vitest.config.ts`](https://github.com/every-app/open-seo/blob/main/vitest.config.ts) with automatic mock cleanup.
- E2E tests reside in the `e2e/` directory and are managed via [`playwright.config.ts`](https://github.com/every-app/open-seo/blob/main/playwright.config.ts), which automatically spawns a dev server on `localhost:3101`.
- Run the full **test suite** using `npm run test` for unit tests or `npm run test:e2e` for browser-based integration tests.
- Use `npm run test:ci` and `npm run test:e2e` in CI pipelines for optimized, deterministic execution.

## Frequently Asked Questions

### What testing framework does Open-SEO use for unit tests?

Open-SEO uses **Vitest** for all unit and integration testing. The configuration in [`vitest.config.ts`](https://github.com/every-app/open-seo/blob/main/vitest.config.ts) specifies a Node.js environment with `restoreMocks` and `clearMocks` enabled to ensure test isolation. Test files are co-located with source code using the `*.test.ts` naming convention.

### How do I run only specific end-to-end test files?

You can run specific E2E tests using the targeted npm scripts: `npm run test:e2e:domain` executes [`e2e/domain-overview-filters.spec.ts`](https://github.com/every-app/open-seo/blob/main/e2e/domain-overview-filters.spec.ts), while `npm run test:e2e:keywords` runs [`e2e/keyword-research-navigation.spec.ts`](https://github.com/every-app/open-seo/blob/main/e2e/keyword-research-navigation.spec.ts). Alternatively, use `npx playwright test` with a specific file path argument.

### What is the difference between `npm run test` and `npm run test:ci`?

The `npm run test` command executes Vitest once with the default reporter, suitable for local development feedback. The `npm run test:ci` command runs `vitest run --reporter=dot`, which uses a minimal dot reporter optimized for CI pipelines where verbose output is discouraged and exit codes matter for build status.

### Does Playwright require manual server startup before running E2E tests?

No, manual server startup is unnecessary. The [`playwright.config.ts`](https://github.com/every-app/open-seo/blob/main/playwright.config.ts) includes a `webServer` configuration that automatically launches the application on `localhost:3101` before test execution begins. The configuration waits for the server to be ready with a 120-second timeout, ensuring tests run against a properly initialized environment.