Skip to main content

Testing a Plugin

A plugin is held to the same testing bar as the core. Your tests live inside your plugin folder, run alongside the core's suites, and must follow the platform's assertion rules — which exist to make sure a passing test actually proves something.

The test types​

All plugin tests live under plugins/{slug}/tests/ — never outside it:

  • API tests (tests/api/*.test.ts) — Vitest suites exercising your routes against a real Postgres.
  • Integration tests (tests/integration/*.sh) — full-stack shell scripts exercising the UI → nginx → API → DB path.
  • Frontend tests (tests/fe/*.test.tsx) — Vitest suites for your React components.
  • Unit tests — for plugin logic testable in isolation.

Discovery is already configured: the core's Vitest and integration runners include plugins/*/tests/..., so your tests run in CI alongside core tests (plugin integration suites appear prefixed plugin:<slug>/).

Infrastructure you can rely on​

CI stands up Postgres with the core schema and all plugin migrations already applied before tests run, and the plugin loader has seeded your entity and statuses at API startup — so your real entity and its statuses are available in the test DB. Use them: plugin tests use the plugin's real entity (seeded by the loader), not the core's ensureTestEntity fixture, which is for core cascade tests only. Auth helpers for register/login come from the core test helpers.

The assertion rules (non-negotiable)​

The platform's test rules apply to you in full — they exist so tests fail when the code is broken:

  • No toBeDefined() / toBeTruthy() alone — always follow with a value, type, or format assertion.
  • Assert against known seed data, not just shapes; use exact counts, not loose ranges.
  • No assertions inside conditionals (they silently skip).
  • Scope frontend assertions to specific elements (element IDs / within()), not broad text matches.

Repeatable and clean​

Tests must be runnable repeatedly without tearing down the database — so use unique-per-run identifiers (append a run id / timestamp) and clean up after yourself. The default plugin provides a shared cleanup helper (tests/helpers.ts) that deletes from all its tables in the correct FK order; copy that pattern.

The short version: put your tests in your plugin folder, lean on the seeded real entity, and write assertions strong enough to fail when something's actually wrong. That's what keeps a green suite meaningful.