From 09f2832670d24b9c92f14c61595d416fc2806059 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Fri, 27 Mar 2026 16:27:46 +0000 Subject: [PATCH] test: split contract seams from unit lane --- CONTRIBUTING.md | 1 + docs/help/testing.md | 14 ++++++++++++-- package.json | 4 ++-- vitest.config.ts | 1 + vitest.contracts.config.ts | 19 +++++++++++++++++++ vitest.unit-paths.mjs | 5 +++++ 6 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 vitest.contracts.config.ts diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e9e796aac60..f128b32c575 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -94,6 +94,7 @@ Welcome to the lobster tank! 🦞 - `pnpm test:extension --list` to see valid extension ids - If you changed shared plugin or channel surfaces, run `pnpm test:contracts` - For targeted shared-surface work, use `pnpm test:contracts:channels` or `pnpm test:contracts:plugins` + - These commands also cover the shared seam/smoke files that the default unit lane skips - If you changed broader runtime behavior, still run the relevant wider lanes (`pnpm test:extensions`, `pnpm test:channels`, or `pnpm test`) before asking for review - If you have access to Codex, run `codex review --base origin/main` locally before opening or updating your PR. Treat this as the current highest standard of AI review, even if GitHub Codex review also runs. - Do not submit refactor-only PRs unless a maintainer explicitly requested that refactor for an active fix or deliverable. diff --git a/docs/help/testing.md b/docs/help/testing.md index acada562f78..a1a66482c3c 100644 --- a/docs/help/testing.md +++ b/docs/help/testing.md @@ -538,7 +538,9 @@ Future evals should stay deterministic first: Contract tests verify that every registered plugin and channel conforms to its interface contract. They iterate over all discovered plugins and run a suite of -shape and behavior assertions. +shape and behavior assertions. The default `pnpm test` unit lane intentionally +skips these shared seam and smoke files; run the contract commands explicitly +when you touch shared channel or provider surfaces. ### Commands @@ -548,7 +550,9 @@ shape and behavior assertions. ### Channel contracts -Located in `src/channels/plugins/contracts/*.contract.test.ts`: +Located in `src/channels/plugins/contracts/*.contract.test.ts`, with shared +channel seam coverage in `src/channels/plugins/plugins-core.test.ts` and +`src/security/dm-policy-channel-smoke.test.ts`: - **plugin** - Basic plugin shape (id, name, capabilities) - **setup** - Setup wizard contract @@ -559,6 +563,12 @@ Located in `src/channels/plugins/contracts/*.contract.test.ts`: - **threading** - Thread ID handling - **directory** - Directory/roster API - **group-policy** - Group policy enforcement + +### Provider contracts + +Located in `src/plugins/contracts/*.contract.test.ts`, with shared provider +seam coverage in `src/tts/tts.test.ts`. + - **status** - Channel status probes - **registry** - Plugin registry shape diff --git a/package.json b/package.json index ff381327802..5eb85850cd1 100644 --- a/package.json +++ b/package.json @@ -790,8 +790,8 @@ "test:changed:max": "node scripts/test-parallel.mjs --profile max --changed origin/main", "test:channels": "node scripts/test-parallel.mjs --surface channels", "test:contracts": "pnpm test:contracts:channels && pnpm test:contracts:plugins", - "test:contracts:channels": "OPENCLAW_TEST_PROFILE=serial pnpm test -- src/channels/plugins/contracts", - "test:contracts:plugins": "OPENCLAW_TEST_PROFILE=serial pnpm test -- src/plugins/contracts", + "test:contracts:channels": "OPENCLAW_TEST_PROFILE=serial pnpm exec vitest run --config vitest.contracts.config.ts src/channels/plugins/contracts src/channels/plugins/plugins-core.test.ts src/security/dm-policy-channel-smoke.test.ts", + "test:contracts:plugins": "OPENCLAW_TEST_PROFILE=serial pnpm exec vitest run --config vitest.contracts.config.ts src/plugins/contracts src/tts/tts.test.ts", "test:coverage": "vitest run --config vitest.unit.config.ts --coverage", "test:coverage:changed": "vitest run --config vitest.unit.config.ts --coverage --changed origin/main", "test:docker:all": "pnpm test:docker:live-models && pnpm test:docker:live-gateway && pnpm test:docker:openwebui && pnpm test:docker:onboard && pnpm test:docker:gateway-network && pnpm test:docker:qr && pnpm test:docker:doctor-switch && pnpm test:docker:plugins && pnpm test:docker:cleanup", diff --git a/vitest.config.ts b/vitest.config.ts index 3339905a27e..572cb5bc057 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -58,6 +58,7 @@ export default defineConfig({ "vitest.channel-paths.mjs", "vitest.channels.config.ts", "vitest.config.ts", + "vitest.contracts.config.ts", "vitest.e2e.config.ts", "vitest.extensions.config.ts", "vitest.gateway.config.ts", diff --git a/vitest.contracts.config.ts b/vitest.contracts.config.ts new file mode 100644 index 00000000000..d84fa31bf94 --- /dev/null +++ b/vitest.contracts.config.ts @@ -0,0 +1,19 @@ +import { createScopedVitestConfig } from "./vitest.scoped-config.ts"; + +export function createContractsVitestConfig(env?: Record) { + return createScopedVitestConfig( + [ + "src/channels/plugins/contracts/**/*.test.ts", + "src/channels/plugins/plugins-core.test.ts", + "src/security/dm-policy-channel-smoke.test.ts", + "src/plugins/contracts/**/*.test.ts", + "src/tts/tts.test.ts", + ], + { + env, + passWithNoTests: true, + }, + ); +} + +export default createContractsVitestConfig(); diff --git a/vitest.unit-paths.mjs b/vitest.unit-paths.mjs index 93d6f5eeeb7..689cdf1ac1c 100644 --- a/vitest.unit-paths.mjs +++ b/vitest.unit-paths.mjs @@ -22,6 +22,11 @@ export const unitTestAdditionalExcludePatterns = [ "src/agents/**", "src/auto-reply/**", "src/commands/**", + "src/channels/plugins/contracts/**", + "src/plugins/contracts/**", + "src/channels/plugins/plugins-core.test.ts", + "src/security/dm-policy-channel-smoke.test.ts", + "src/tts/tts.test.ts", ]; const sharedBaseExcludePatterns = [