Made Open

Testing Guide

Made Open has 482 test files (*.test.ts + *.test.tsx under apps/hub, apps/web, and packages/*) across 11 pnpm workspace packages, using Vitest for all TypeScript projects. (Individual test-case counts are not independently tracked in this guide.)

Running Tests

# All tests across the monorepo
pnpm test

# Individual packages
pnpm -F @made-open/hub test
pnpm -F @made-open/web test
pnpm -F @made-open/shared test
pnpm -F @made-open/ai test
pnpm -F @made-open/sdk test
pnpm -F @made-open/plugin-sdk test

# With coverage (hub)
pnpm -F @made-open/hub test:coverage

# Watch mode (re-runs on file change)
pnpm -F @made-open/hub test:watch

Test Architecture

Framework

All TypeScript packages use Vitest with the node environment and globals: true. Configuration is in vitest.config.ts at each package root.

Coverage Thresholds

The hub enforces strict coverage thresholds:

MetricThreshold
Lines99%
Functions100%
Branches98%
Statements99%

Coverage provider: V8 (fast) with reporters: text, json, html, lcov. Defined in apps/hub/vitest.config.ts.

Unit Tests

Unit tests live alongside source files as *.test.ts. Common patterns:

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

// Mock external dependencies
vi.mock('../services/data/DataService.js', () => ({
  DataService: vi.fn().mockImplementation(() => ({
    query: vi.fn().mockResolvedValue([]),
    getById: vi.fn().mockResolvedValue(null),
  })),
}));

describe('MyService', () => {
  let service: MyService;

  beforeEach(() => {
    service = new MyService(/* mocked deps */);
  });

  it('should do the thing', async () => {
    const result = await service.doThing();
    expect(result).toBeDefined();
  });
});

Integration Tests

Integration tests use the TestHarness pattern in apps/hub/src/__tests__/integration/:

TestWhat It Exercises
health.integration.test.tsAPI health endpoint
contacts.integration.test.tsContact CRUD end-to-end
demo-flow.integration.test.tsFull MVP demo flow
agent.integration.test.tsAI agent queries
platform.integration.test.tsPlatform-wide integration
graphql.integration.test.tsGraphQL API

The TestHarness (apps/hub/src/__tests__/integration/TestHarness.ts) bootstraps a minimal hub instance with real service instances but mocked external connections (NATS, Meilisearch, Supabase).

Real-world integration tests (requiring Docker) live in __tests__/integration/realworld/ and are excluded from the default test run. Run them with:

pnpm -F @made-open/hub test:integration

Route Tests

Every route file has a corresponding test:

apps/hub/src/api/routes/
├── credentials.ts          # Route implementation
├── credentials.test.ts     # Route test
├── marketplace.ts
├── marketplace.test.ts
└── ... (77 route/test pairs out of 84 route files; `capture.ts` and `whatsappWebhook.ts` currently have no matching `.test.ts`)

Plugin Tests

Plugin tests validate sandbox behaviour:

apps/hub/plugins/channels/twilio/
├── index.ts                # Plugin implementation
├── plugin.json             # Manifest
└── twilio-channel.test.ts  # Tests

Mock Patterns

Common mocking approaches:

  • vi.mock() — Module-level mocks for service dependencies
  • vi.fn() — Individual function mocks with return value control
  • vi.spyOn() — Spy on existing methods without replacing
  • Inline mock factoriesvi.fn().mockImplementation(() => ({...})) for complex service interfaces

Test Organization by Package

PackageFocus
@made-open/hubServices, routes, plugins, integration
@made-open/webComponents, pages, hooks
@made-open/sharedTypes, schemas, validation
@made-open/aiRAG, routing, embeddings
@made-open/sdkClient methods, auth
@made-open/plugin-sdkSDK helpers, types

Per-package test-case counts are not tracked here. The file-level total across the monorepo is 482 (*.test.ts + *.test.tsx).

CI Expectations

All tests must pass before merging. The test suite runs in ~60 seconds on a modern machine. Coverage reports are generated in coverage/ directories at each package root.