From d35ada2f5439eeb1a98f2fda7c9fed723ebc0686 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 28 Apr 2026 02:13:58 +0100 Subject: [PATCH] refactor: relocate channel contract helpers --- CHANGELOG.md | 1 + docs/plugins/sdk-testing.md | 15 ++++-------- docs/reference/test.md | 2 +- .../check-no-extension-test-core-imports.ts | 15 ++++++++++++ .../channel-catalog.contract.test.ts | 2 +- ...y.registry-backed-shard-a.contract.test.ts | 2 +- ...y.registry-backed-shard-b.contract.test.ts | 2 +- ...y.registry-backed-shard-c.contract.test.ts | 2 +- ...y.registry-backed-shard-d.contract.test.ts | 2 +- ...y.registry-backed-shard-e.contract.test.ts | 2 +- ...y.registry-backed-shard-f.contract.test.ts | 2 +- ...y.registry-backed-shard-g.contract.test.ts | 2 +- ...y.registry-backed-shard-h.contract.test.ts | 2 +- .../group-policy.fallback.contract.test.ts | 6 ++--- ...n.registry-backed-shard-a.contract.test.ts | 2 +- ...n.registry-backed-shard-b.contract.test.ts | 2 +- ...n.registry-backed-shard-c.contract.test.ts | 2 +- ...n.registry-backed-shard-d.contract.test.ts | 2 +- ...n.registry-backed-shard-e.contract.test.ts | 2 +- ...n.registry-backed-shard-f.contract.test.ts | 2 +- ...n.registry-backed-shard-g.contract.test.ts | 2 +- ...n.registry-backed-shard-h.contract.test.ts | 2 +- ...orize-config-write.policy.contract.test.ts | 2 +- ...rize-config-write.targets.contract.test.ts | 2 +- ...gins-core.catalog.entries.contract.test.ts | 2 +- ...lugins-core.catalog.paths.contract.test.ts | 2 +- .../contracts/registry.contract.test.ts | 2 +- ...n-binding.registry-backed.contract.test.ts | 4 ++-- ...y.registry-backed-shard-a.contract.test.ts | 2 +- ...y.registry-backed-shard-b.contract.test.ts | 2 +- ...y.registry-backed-shard-c.contract.test.ts | 2 +- ...y.registry-backed-shard-d.contract.test.ts | 2 +- ...y.registry-backed-shard-e.contract.test.ts | 2 +- ...y.registry-backed-shard-f.contract.test.ts | 2 +- ...y.registry-backed-shard-g.contract.test.ts | 2 +- ...y.registry-backed-shard-h.contract.test.ts | 2 +- .../plugins/contracts/test-helpers}/AGENTS.md | 17 +++++++------- .../plugins/contracts/test-helpers}/CLAUDE.md | 0 .../bundled-channel-plugin-loader.ts | 10 ++++---- .../test-helpers}/channel-catalog-contract.ts | 5 +--- .../channel-plugin-catalog-contract-suites.ts | 2 +- .../config-write-contract-suites.ts | 4 ++-- .../group-policy-contract-suites.ts | 2 +- .../test-helpers}/group-policy-contract.ts | 2 +- .../test-helpers}/imessage-test-plugin.ts | 2 +- .../test-helpers}/lazy-object-surface.ts | 0 .../contracts/test-helpers}/manifest.ts | 0 .../registry-backed-contract-shards.ts | 2 +- .../test-helpers}/registry-plugin.ts | 6 ++--- .../test-helpers}/registry-session-binding.ts | 14 +++++------ .../test-helpers}/runtime-artifacts.ts | 6 ++--- ...ession-binding-registry-backed-contract.ts | 9 +++----- .../surface-contract-registry.ts | 6 ++--- .../test-helpers}/surface-contract-suite.ts | 2 +- .../threading-directory-contract-suites.ts | 10 ++++---- ...g.registry-backed-shard-a.contract.test.ts | 2 +- ...g.registry-backed-shard-b.contract.test.ts | 2 +- ...g.registry-backed-shard-c.contract.test.ts | 2 +- ...g.registry-backed-shard-d.contract.test.ts | 2 +- ...g.registry-backed-shard-e.contract.test.ts | 2 +- ...g.registry-backed-shard-f.contract.test.ts | 2 +- ...g.registry-backed-shard-g.contract.test.ts | 2 +- ...g.registry-backed-shard-h.contract.test.ts | 2 +- test/extension-test-boundary.test.ts | 14 ++++++++--- test/helpers/channels/directory-ids.ts | 4 ---- .../channels/registry-contract-suites.ts | 7 ------ test/scripts/test-projects.test.ts | 23 +++++++++---------- 67 files changed, 133 insertions(+), 133 deletions(-) rename {test/helpers/channels => src/channels/plugins/contracts/test-helpers}/AGENTS.md (68%) rename {test/helpers/channels => src/channels/plugins/contracts/test-helpers}/CLAUDE.md (100%) rename {test/helpers/channels => src/channels/plugins/contracts/test-helpers}/bundled-channel-plugin-loader.ts (89%) rename {test/helpers/channels => src/channels/plugins/contracts/test-helpers}/channel-catalog-contract.ts (98%) rename {test/helpers/channels => src/channels/plugins/contracts/test-helpers}/channel-plugin-catalog-contract-suites.ts (99%) rename {test/helpers/channels => src/channels/plugins/contracts/test-helpers}/config-write-contract-suites.ts (97%) rename {test/helpers/channels => src/channels/plugins/contracts/test-helpers}/group-policy-contract-suites.ts (98%) rename {test/helpers/channels => src/channels/plugins/contracts/test-helpers}/group-policy-contract.ts (89%) rename {test/helpers/channels => src/channels/plugins/contracts/test-helpers}/imessage-test-plugin.ts (88%) rename {test/helpers/channels => src/channels/plugins/contracts/test-helpers}/lazy-object-surface.ts (100%) rename {test/helpers/channels => src/channels/plugins/contracts/test-helpers}/manifest.ts (100%) rename {test/helpers/channels => src/channels/plugins/contracts/test-helpers}/registry-backed-contract-shards.ts (97%) rename {test/helpers/channels => src/channels/plugins/contracts/test-helpers}/registry-plugin.ts (86%) rename {test/helpers/channels => src/channels/plugins/contracts/test-helpers}/registry-session-binding.ts (97%) rename {test/helpers/channels => src/channels/plugins/contracts/test-helpers}/runtime-artifacts.ts (87%) rename {test/helpers/channels => src/channels/plugins/contracts/test-helpers}/session-binding-registry-backed-contract.ts (92%) rename {test/helpers/channels => src/channels/plugins/contracts/test-helpers}/surface-contract-registry.ts (96%) rename {test/helpers/channels => src/channels/plugins/contracts/test-helpers}/surface-contract-suite.ts (98%) rename {test/helpers/channels => src/channels/plugins/contracts/test-helpers}/threading-directory-contract-suites.ts (95%) delete mode 100644 test/helpers/channels/directory-ids.ts delete mode 100644 test/helpers/channels/registry-contract-suites.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index aae96b15d48..6e2f52c8945 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ Docs: https://docs.openclaw.ai - Channels/QQBot: add full group chat support (history tracking, @-mention gating, activation modes, per-group config, FIFO message queue with deliver debounce), C2C `stream_messages` streaming with a `StreamingController` lifecycle manager, unified `sendMedia` with chunked upload for large files, and refactor the engine into pipeline stages, focused outbound submodules, builtin slash-command modules, and explicit DI ports via `createEngineAdapters()`. (#70624) Thanks @cxyhhhhh. - Gateway/runtime: reuse the current plugin metadata snapshot for provider discovery so repeated model-provider discovery avoids rebuilding plugin manifest metadata. Thanks @shakkernerd. - Gateway/startup: pass the plugin metadata snapshot from config validation into plugin bootstrap so startup reuses one manifest product instead of rebuilding plugin metadata. Thanks @shakkernerd. +- Plugin SDK/testing: move core-only channel contract fixtures under the channel contract test tree and retire the old `test/helpers/channels` bridge directory so plugin tests stay on focused SDK surfaces. Thanks @vincentkoc. - Plugin SDK/testing: promote bundled plugin/provider/channel contract helpers to focused SDK test subpaths and retire the repo-only `test/helpers/plugins` TypeScript bridge. Thanks @vincentkoc. - Plugin SDK/testing: expose generic channel action, setup, status, and directory contract helpers through `plugin-sdk/channel-test-helpers` so bundled extension tests no longer import repo-only channel helper bridges. Thanks @vincentkoc. - Plugin SDK/testing: add `plugin-sdk/channel-target-testing` for shared channel target-resolution cases, document channel reaction helpers on `plugin-sdk/channel-feedback`, and keep the old `plugin-sdk/test-utils` alias as compatibility-only. Thanks @vincentkoc. diff --git a/docs/plugins/sdk-testing.md b/docs/plugins/sdk-testing.md index 84ac207e35d..4009410c042 100644 --- a/docs/plugins/sdk-testing.md +++ b/docs/plugins/sdk-testing.md @@ -19,8 +19,6 @@ plugins. ## Test utilities -**Compatibility import:** `openclaw/plugin-sdk/testing` - **Plugin API mock import:** `openclaw/plugin-sdk/plugin-test-api` **Channel contract import:** `openclaw/plugin-sdk/channel-contract-testing` @@ -40,8 +38,7 @@ plugins. **Generic fixture import:** `openclaw/plugin-sdk/test-fixtures` Prefer the focused subpaths below for new plugin tests. The broad -`openclaw/plugin-sdk/testing` barrel remains for compatibility with older tests -and helpers that have not moved to a narrower documented surface yet. +`openclaw/plugin-sdk/testing` barrel is legacy compatibility only. ```typescript import { @@ -121,17 +118,15 @@ broad `plugin-sdk/testing` compatibility barrel, repo `src/**` files, or repo ### Types -The testing subpath also re-exports types useful in test files: +Focused testing subpaths also re-export types useful in test files: ```typescript import type { ChannelAccountSnapshot, ChannelGatewayContext, - OpenClawConfig, - PluginRuntime, - RuntimeEnv, - MockFn, -} from "openclaw/plugin-sdk/testing"; +} from "openclaw/plugin-sdk/channel-contract"; +import type { OpenClawConfig } from "openclaw/plugin-sdk/config-types"; +import type { MockFn, PluginRuntime, RuntimeEnv } from "openclaw/plugin-sdk/plugin-test-runtime"; ``` ## Testing target resolution diff --git a/docs/reference/test.md b/docs/reference/test.md index 78084f292d6..3efba097d27 100644 --- a/docs/reference/test.md +++ b/docs/reference/test.md @@ -18,7 +18,7 @@ title: "Tests" - Test wrapper runs end with a short `[test] passed|failed|skipped ... in ...` summary. Vitest's own duration line stays the per-shard detail. - Full, extension, and include-pattern shard runs update local timing data in `.artifacts/vitest-shard-timings.json`; later whole-config runs use those timings to balance slow and fast shards. Include-pattern CI shards append the shard name to the timing key, which keeps filtered shard timings visible without replacing whole-config timing data. Set `OPENCLAW_TEST_PROJECTS_TIMINGS=0` to ignore the local timing artifact. - Selected `plugin-sdk` and `commands` test files now route through dedicated light lanes that keep only `test/setup.ts`, leaving runtime-heavy cases on their existing lanes. -- Source files with sibling tests map to that sibling before falling back to wider directory globs. Helper edits under `test/helpers/channels`, `src/plugin-sdk/test-helpers`, and `src/plugins/contracts` use a local import graph to run importing tests instead of broad-running every shard when the dependency path is precise. +- Source files with sibling tests map to that sibling before falling back to wider directory globs. Helper edits under `src/channels/plugins/contracts/test-helpers`, `src/plugin-sdk/test-helpers`, and `src/plugins/contracts` use a local import graph to run importing tests instead of broad-running every shard when the dependency path is precise. - `auto-reply` now also splits into three dedicated configs (`core`, `top-level`, `reply`) so the reply harness does not dominate the lighter top-level status/token/helper tests. - Base Vitest config now defaults to `pool: "threads"` and `isolate: false`, with the shared non-isolated runner enabled across the repo configs. - `pnpm test:channels` runs `vitest.channels.config.ts`. diff --git a/scripts/check-no-extension-test-core-imports.ts b/scripts/check-no-extension-test-core-imports.ts index 03e3e9b8686..024fff89cc2 100644 --- a/scripts/check-no-extension-test-core-imports.ts +++ b/scripts/check-no-extension-test-core-imports.ts @@ -33,6 +33,10 @@ const FORBIDDEN_PATTERNS: Array<{ pattern: RegExp; hint: string }> = [ pattern: /["'](?:\.\.\/)+(?:test\/helpers\/channels\/)[^"']+["']/, hint: "Use openclaw/plugin-sdk/channel-test-helpers or another focused SDK test subpath instead of repo-only channel helper bridges.", }, + { + pattern: /["'](?:\.\.\/)+(?:src\/channels\/plugins\/contracts\/test-helpers\/)[^"']+["']/, + hint: "Use openclaw/plugin-sdk/channel-test-helpers or another focused SDK test subpath instead of core-only channel contract helpers.", + }, { pattern: /["'](?:\.\.\/)+(?:src\/test-utils\/)[^"']+["']/, hint: "Use a documented openclaw/plugin-sdk test subpath for public surfaces.", @@ -178,10 +182,21 @@ function collectRelativeCoreImportOffenders( function main() { const extensionsDir = path.join(process.cwd(), "extensions"); const pluginHelpersDir = path.join(process.cwd(), "test/helpers/plugins"); + const retiredChannelHelpersDir = path.join(process.cwd(), "test/helpers/channels"); const files = collectExtensionTestFiles(extensionsDir); const pluginHelperFiles = collectPluginHelperFiles(pluginHelpersDir); + const retiredChannelHelperFiles = fs.existsSync(retiredChannelHelpersDir) + ? collectFilesSync(retiredChannelHelpersDir, { includeFile: isCodeFile }) + : []; const offenders: Offender[] = []; + for (const file of retiredChannelHelperFiles) { + offenders.push({ + file, + hint: "Keep core channel contract helpers under src/channels/plugins/contracts/test-helpers and public plugin helpers under focused openclaw/plugin-sdk test subpaths.", + }); + } + for (const file of RETIRED_EXTENSION_TEST_HELPER_BRIDGE_FILES) { const filePath = path.join(process.cwd(), file); if (!fs.existsSync(filePath)) { diff --git a/src/channels/plugins/contracts/channel-catalog.contract.test.ts b/src/channels/plugins/contracts/channel-catalog.contract.test.ts index 9c393108162..42e9faa6844 100644 --- a/src/channels/plugins/contracts/channel-catalog.contract.test.ts +++ b/src/channels/plugins/contracts/channel-catalog.contract.test.ts @@ -2,7 +2,7 @@ import { describeBundledMetadataOnlyChannelCatalogContract, describeChannelCatalogEntryContract, describeOfficialFallbackChannelCatalogContract, -} from "../../../../test/helpers/channels/channel-catalog-contract.js"; +} from "./test-helpers/channel-catalog-contract.js"; describeChannelCatalogEntryContract({ channelId: "msteams", diff --git a/src/channels/plugins/contracts/directory.registry-backed-shard-a.contract.test.ts b/src/channels/plugins/contracts/directory.registry-backed-shard-a.contract.test.ts index 18bf28604d0..bfe8a1c3b85 100644 --- a/src/channels/plugins/contracts/directory.registry-backed-shard-a.contract.test.ts +++ b/src/channels/plugins/contracts/directory.registry-backed-shard-a.contract.test.ts @@ -1,3 +1,3 @@ -import { installDirectoryContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installDirectoryContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installDirectoryContractRegistryShard({ shardIndex: 0, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/directory.registry-backed-shard-b.contract.test.ts b/src/channels/plugins/contracts/directory.registry-backed-shard-b.contract.test.ts index 575e76d433a..0d822457f16 100644 --- a/src/channels/plugins/contracts/directory.registry-backed-shard-b.contract.test.ts +++ b/src/channels/plugins/contracts/directory.registry-backed-shard-b.contract.test.ts @@ -1,3 +1,3 @@ -import { installDirectoryContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installDirectoryContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installDirectoryContractRegistryShard({ shardIndex: 1, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/directory.registry-backed-shard-c.contract.test.ts b/src/channels/plugins/contracts/directory.registry-backed-shard-c.contract.test.ts index 3c715463846..a0833a0af9e 100644 --- a/src/channels/plugins/contracts/directory.registry-backed-shard-c.contract.test.ts +++ b/src/channels/plugins/contracts/directory.registry-backed-shard-c.contract.test.ts @@ -1,3 +1,3 @@ -import { installDirectoryContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installDirectoryContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installDirectoryContractRegistryShard({ shardIndex: 2, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/directory.registry-backed-shard-d.contract.test.ts b/src/channels/plugins/contracts/directory.registry-backed-shard-d.contract.test.ts index da83d6e2007..34c046a134c 100644 --- a/src/channels/plugins/contracts/directory.registry-backed-shard-d.contract.test.ts +++ b/src/channels/plugins/contracts/directory.registry-backed-shard-d.contract.test.ts @@ -1,3 +1,3 @@ -import { installDirectoryContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installDirectoryContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installDirectoryContractRegistryShard({ shardIndex: 3, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/directory.registry-backed-shard-e.contract.test.ts b/src/channels/plugins/contracts/directory.registry-backed-shard-e.contract.test.ts index 89c475756b4..aaaafa7ac77 100644 --- a/src/channels/plugins/contracts/directory.registry-backed-shard-e.contract.test.ts +++ b/src/channels/plugins/contracts/directory.registry-backed-shard-e.contract.test.ts @@ -1,3 +1,3 @@ -import { installDirectoryContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installDirectoryContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installDirectoryContractRegistryShard({ shardIndex: 4, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/directory.registry-backed-shard-f.contract.test.ts b/src/channels/plugins/contracts/directory.registry-backed-shard-f.contract.test.ts index 7c1ae4a43bd..05150c0adb3 100644 --- a/src/channels/plugins/contracts/directory.registry-backed-shard-f.contract.test.ts +++ b/src/channels/plugins/contracts/directory.registry-backed-shard-f.contract.test.ts @@ -1,3 +1,3 @@ -import { installDirectoryContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installDirectoryContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installDirectoryContractRegistryShard({ shardIndex: 5, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/directory.registry-backed-shard-g.contract.test.ts b/src/channels/plugins/contracts/directory.registry-backed-shard-g.contract.test.ts index eaeb2780d2e..56057ad6c23 100644 --- a/src/channels/plugins/contracts/directory.registry-backed-shard-g.contract.test.ts +++ b/src/channels/plugins/contracts/directory.registry-backed-shard-g.contract.test.ts @@ -1,3 +1,3 @@ -import { installDirectoryContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installDirectoryContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installDirectoryContractRegistryShard({ shardIndex: 6, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/directory.registry-backed-shard-h.contract.test.ts b/src/channels/plugins/contracts/directory.registry-backed-shard-h.contract.test.ts index 95685ceee1c..30c039a9c7d 100644 --- a/src/channels/plugins/contracts/directory.registry-backed-shard-h.contract.test.ts +++ b/src/channels/plugins/contracts/directory.registry-backed-shard-h.contract.test.ts @@ -1,3 +1,3 @@ -import { installDirectoryContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installDirectoryContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installDirectoryContractRegistryShard({ shardIndex: 7, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/group-policy.fallback.contract.test.ts b/src/channels/plugins/contracts/group-policy.fallback.contract.test.ts index 0ed18d5db9d..b548e1313d9 100644 --- a/src/channels/plugins/contracts/group-policy.fallback.contract.test.ts +++ b/src/channels/plugins/contracts/group-policy.fallback.contract.test.ts @@ -1,10 +1,10 @@ import { describe, expect, it } from "vitest"; -import { installChannelRuntimeGroupPolicyFallbackSuite } from "../../../../test/helpers/channels/group-policy-contract-suites.js"; +import { resolveOpenProviderRuntimeGroupPolicy } from "../../../config/runtime-group-policy.js"; +import { installChannelRuntimeGroupPolicyFallbackSuite } from "./test-helpers/group-policy-contract-suites.js"; import { resolveZaloRuntimeGroupPolicy, resolveWhatsAppRuntimeGroupPolicy, -} from "../../../../test/helpers/channels/group-policy-contract.js"; -import { resolveOpenProviderRuntimeGroupPolicy } from "../../../config/runtime-group-policy.js"; +} from "./test-helpers/group-policy-contract.js"; describe("channel runtime group policy fallback contract", () => { describe("slack", () => { diff --git a/src/channels/plugins/contracts/plugin.registry-backed-shard-a.contract.test.ts b/src/channels/plugins/contracts/plugin.registry-backed-shard-a.contract.test.ts index 66798b55eed..6ab92e7f35a 100644 --- a/src/channels/plugins/contracts/plugin.registry-backed-shard-a.contract.test.ts +++ b/src/channels/plugins/contracts/plugin.registry-backed-shard-a.contract.test.ts @@ -1,3 +1,3 @@ -import { installPluginContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installPluginContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installPluginContractRegistryShard({ shardIndex: 0, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/plugin.registry-backed-shard-b.contract.test.ts b/src/channels/plugins/contracts/plugin.registry-backed-shard-b.contract.test.ts index 5869af73677..b1b59602da0 100644 --- a/src/channels/plugins/contracts/plugin.registry-backed-shard-b.contract.test.ts +++ b/src/channels/plugins/contracts/plugin.registry-backed-shard-b.contract.test.ts @@ -1,3 +1,3 @@ -import { installPluginContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installPluginContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installPluginContractRegistryShard({ shardIndex: 1, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/plugin.registry-backed-shard-c.contract.test.ts b/src/channels/plugins/contracts/plugin.registry-backed-shard-c.contract.test.ts index 7db56b0c7c9..3776870b84a 100644 --- a/src/channels/plugins/contracts/plugin.registry-backed-shard-c.contract.test.ts +++ b/src/channels/plugins/contracts/plugin.registry-backed-shard-c.contract.test.ts @@ -1,3 +1,3 @@ -import { installPluginContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installPluginContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installPluginContractRegistryShard({ shardIndex: 2, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/plugin.registry-backed-shard-d.contract.test.ts b/src/channels/plugins/contracts/plugin.registry-backed-shard-d.contract.test.ts index ba2466a71ff..1b5b42cf60d 100644 --- a/src/channels/plugins/contracts/plugin.registry-backed-shard-d.contract.test.ts +++ b/src/channels/plugins/contracts/plugin.registry-backed-shard-d.contract.test.ts @@ -1,3 +1,3 @@ -import { installPluginContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installPluginContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installPluginContractRegistryShard({ shardIndex: 3, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/plugin.registry-backed-shard-e.contract.test.ts b/src/channels/plugins/contracts/plugin.registry-backed-shard-e.contract.test.ts index b1c8efbe8b9..22cbbbacead 100644 --- a/src/channels/plugins/contracts/plugin.registry-backed-shard-e.contract.test.ts +++ b/src/channels/plugins/contracts/plugin.registry-backed-shard-e.contract.test.ts @@ -1,3 +1,3 @@ -import { installPluginContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installPluginContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installPluginContractRegistryShard({ shardIndex: 4, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/plugin.registry-backed-shard-f.contract.test.ts b/src/channels/plugins/contracts/plugin.registry-backed-shard-f.contract.test.ts index 80c26ed8ccf..eb18289091b 100644 --- a/src/channels/plugins/contracts/plugin.registry-backed-shard-f.contract.test.ts +++ b/src/channels/plugins/contracts/plugin.registry-backed-shard-f.contract.test.ts @@ -1,3 +1,3 @@ -import { installPluginContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installPluginContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installPluginContractRegistryShard({ shardIndex: 5, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/plugin.registry-backed-shard-g.contract.test.ts b/src/channels/plugins/contracts/plugin.registry-backed-shard-g.contract.test.ts index cfd28555252..b6e121825bb 100644 --- a/src/channels/plugins/contracts/plugin.registry-backed-shard-g.contract.test.ts +++ b/src/channels/plugins/contracts/plugin.registry-backed-shard-g.contract.test.ts @@ -1,3 +1,3 @@ -import { installPluginContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installPluginContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installPluginContractRegistryShard({ shardIndex: 6, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/plugin.registry-backed-shard-h.contract.test.ts b/src/channels/plugins/contracts/plugin.registry-backed-shard-h.contract.test.ts index 7ee92b376be..20bcbb7cf11 100644 --- a/src/channels/plugins/contracts/plugin.registry-backed-shard-h.contract.test.ts +++ b/src/channels/plugins/contracts/plugin.registry-backed-shard-h.contract.test.ts @@ -1,3 +1,3 @@ -import { installPluginContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installPluginContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installPluginContractRegistryShard({ shardIndex: 7, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/plugins-core.authorize-config-write.policy.contract.test.ts b/src/channels/plugins/contracts/plugins-core.authorize-config-write.policy.contract.test.ts index 205eb110c9c..8d4d3f29bc6 100644 --- a/src/channels/plugins/contracts/plugins-core.authorize-config-write.policy.contract.test.ts +++ b/src/channels/plugins/contracts/plugins-core.authorize-config-write.policy.contract.test.ts @@ -1,3 +1,3 @@ -import { describeChannelConfigWritePolicyContract } from "../../../../test/helpers/channels/config-write-contract-suites.js"; +import { describeChannelConfigWritePolicyContract } from "./test-helpers/config-write-contract-suites.js"; describeChannelConfigWritePolicyContract(); diff --git a/src/channels/plugins/contracts/plugins-core.authorize-config-write.targets.contract.test.ts b/src/channels/plugins/contracts/plugins-core.authorize-config-write.targets.contract.test.ts index 2db7f9ae31f..abe2d0f7150 100644 --- a/src/channels/plugins/contracts/plugins-core.authorize-config-write.targets.contract.test.ts +++ b/src/channels/plugins/contracts/plugins-core.authorize-config-write.targets.contract.test.ts @@ -1,3 +1,3 @@ -import { describeChannelConfigWriteTargetContract } from "../../../../test/helpers/channels/config-write-contract-suites.js"; +import { describeChannelConfigWriteTargetContract } from "./test-helpers/config-write-contract-suites.js"; describeChannelConfigWriteTargetContract(); diff --git a/src/channels/plugins/contracts/plugins-core.catalog.entries.contract.test.ts b/src/channels/plugins/contracts/plugins-core.catalog.entries.contract.test.ts index 2e12116dfbc..79abd8c4fa0 100644 --- a/src/channels/plugins/contracts/plugins-core.catalog.entries.contract.test.ts +++ b/src/channels/plugins/contracts/plugins-core.catalog.entries.contract.test.ts @@ -1,3 +1,3 @@ -import { describeChannelPluginCatalogEntriesContract } from "../../../../test/helpers/channels/channel-plugin-catalog-contract-suites.js"; +import { describeChannelPluginCatalogEntriesContract } from "./test-helpers/channel-plugin-catalog-contract-suites.js"; describeChannelPluginCatalogEntriesContract(); diff --git a/src/channels/plugins/contracts/plugins-core.catalog.paths.contract.test.ts b/src/channels/plugins/contracts/plugins-core.catalog.paths.contract.test.ts index ae341862881..980ab06897e 100644 --- a/src/channels/plugins/contracts/plugins-core.catalog.paths.contract.test.ts +++ b/src/channels/plugins/contracts/plugins-core.catalog.paths.contract.test.ts @@ -1,3 +1,3 @@ -import { describeChannelPluginCatalogPathResolutionContract } from "../../../../test/helpers/channels/channel-plugin-catalog-contract-suites.js"; +import { describeChannelPluginCatalogPathResolutionContract } from "./test-helpers/channel-plugin-catalog-contract-suites.js"; describeChannelPluginCatalogPathResolutionContract(); diff --git a/src/channels/plugins/contracts/registry.contract.test.ts b/src/channels/plugins/contracts/registry.contract.test.ts index 77159c8f831..5acd8e1afee 100644 --- a/src/channels/plugins/contracts/registry.contract.test.ts +++ b/src/channels/plugins/contracts/registry.contract.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { sessionBindingContractChannelIds } from "../../../../test/helpers/channels/manifest.js"; +import { sessionBindingContractChannelIds } from "./test-helpers/manifest.js"; const discordSessionBindingAdapterChannels = ["discord"] as const; diff --git a/src/channels/plugins/contracts/session-binding.registry-backed.contract.test.ts b/src/channels/plugins/contracts/session-binding.registry-backed.contract.test.ts index d1714196f37..b6263638577 100644 --- a/src/channels/plugins/contracts/session-binding.registry-backed.contract.test.ts +++ b/src/channels/plugins/contracts/session-binding.registry-backed.contract.test.ts @@ -1,5 +1,5 @@ -import { getSessionBindingContractRegistry } from "../../../../test/helpers/channels/registry-session-binding.js"; -import { describeSessionBindingRegistryBackedContract } from "../../../../test/helpers/channels/session-binding-registry-backed-contract.js"; +import { getSessionBindingContractRegistry } from "./test-helpers/registry-session-binding.js"; +import { describeSessionBindingRegistryBackedContract } from "./test-helpers/session-binding-registry-backed-contract.js"; for (const entry of getSessionBindingContractRegistry()) { describeSessionBindingRegistryBackedContract(entry.id); diff --git a/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-a.contract.test.ts b/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-a.contract.test.ts index ca9e1f78d3e..3a46a2d7679 100644 --- a/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-a.contract.test.ts +++ b/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-a.contract.test.ts @@ -1,3 +1,3 @@ -import { installSurfaceContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installSurfaceContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installSurfaceContractRegistryShard({ shardIndex: 0, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-b.contract.test.ts b/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-b.contract.test.ts index d9435795433..3acd651fc8f 100644 --- a/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-b.contract.test.ts +++ b/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-b.contract.test.ts @@ -1,3 +1,3 @@ -import { installSurfaceContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installSurfaceContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installSurfaceContractRegistryShard({ shardIndex: 1, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-c.contract.test.ts b/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-c.contract.test.ts index bd85f3164b0..9e058e8c8d6 100644 --- a/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-c.contract.test.ts +++ b/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-c.contract.test.ts @@ -1,3 +1,3 @@ -import { installSurfaceContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installSurfaceContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installSurfaceContractRegistryShard({ shardIndex: 2, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-d.contract.test.ts b/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-d.contract.test.ts index c246c3d09d1..4e98a18cd48 100644 --- a/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-d.contract.test.ts +++ b/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-d.contract.test.ts @@ -1,3 +1,3 @@ -import { installSurfaceContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installSurfaceContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installSurfaceContractRegistryShard({ shardIndex: 3, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-e.contract.test.ts b/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-e.contract.test.ts index 66d94dd8c63..f7a2fcdec8c 100644 --- a/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-e.contract.test.ts +++ b/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-e.contract.test.ts @@ -1,3 +1,3 @@ -import { installSurfaceContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installSurfaceContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installSurfaceContractRegistryShard({ shardIndex: 4, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-f.contract.test.ts b/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-f.contract.test.ts index b08d8584ad1..72974ca2e3c 100644 --- a/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-f.contract.test.ts +++ b/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-f.contract.test.ts @@ -1,3 +1,3 @@ -import { installSurfaceContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installSurfaceContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installSurfaceContractRegistryShard({ shardIndex: 5, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-g.contract.test.ts b/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-g.contract.test.ts index 1ed4911bac1..6273954e8f6 100644 --- a/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-g.contract.test.ts +++ b/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-g.contract.test.ts @@ -1,3 +1,3 @@ -import { installSurfaceContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installSurfaceContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installSurfaceContractRegistryShard({ shardIndex: 6, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-h.contract.test.ts b/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-h.contract.test.ts index 6f7b38b42dd..8dcf921f7f4 100644 --- a/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-h.contract.test.ts +++ b/src/channels/plugins/contracts/surfaces-only.registry-backed-shard-h.contract.test.ts @@ -1,3 +1,3 @@ -import { installSurfaceContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installSurfaceContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installSurfaceContractRegistryShard({ shardIndex: 7, shardCount: 8 }); diff --git a/test/helpers/channels/AGENTS.md b/src/channels/plugins/contracts/test-helpers/AGENTS.md similarity index 68% rename from test/helpers/channels/AGENTS.md rename to src/channels/plugins/contracts/test-helpers/AGENTS.md index d1d4c2692f0..8519e770503 100644 --- a/test/helpers/channels/AGENTS.md +++ b/src/channels/plugins/contracts/test-helpers/AGENTS.md @@ -1,14 +1,13 @@ -# Test Helper Boundary +# Channel Contract Helper Boundary -This directory holds shared channel test helpers used by core and bundled plugin -tests. +This directory holds core-owned channel contract test helpers. -This file adds channel-specific rules on top of `test/helpers/AGENTS.md`. +This file adds channel-specific rules on top of `src/channels/AGENTS.md`. ## Bundled Plugin Imports -- Core test helpers in this directory must not hardcode repo-relative imports - into `extensions/**`. +- Core contract helpers in this directory must not hardcode repo-relative + imports into `extensions/**`. - When a helper needs a bundled plugin public/test surface, go through `src/test-utils/bundled-plugin-public-surface.ts`. - Prefer `loadBundledPluginTestApiSync(...)` for eager access to exported test @@ -28,7 +27,7 @@ This file adds channel-specific rules on top of `test/helpers/AGENTS.md`. ## Intent -- Keep shared test helpers aligned with the same public/plugin boundary that +- Keep core contract helpers aligned with the same public/plugin boundary that production code uses. -- Avoid drift where core test helpers start reaching into bundled plugin private - files by path because it is convenient in one test. +- Avoid drift where core contract helpers start reaching into bundled plugin + private files by path because it is convenient in one test. diff --git a/test/helpers/channels/CLAUDE.md b/src/channels/plugins/contracts/test-helpers/CLAUDE.md similarity index 100% rename from test/helpers/channels/CLAUDE.md rename to src/channels/plugins/contracts/test-helpers/CLAUDE.md diff --git a/test/helpers/channels/bundled-channel-plugin-loader.ts b/src/channels/plugins/contracts/test-helpers/bundled-channel-plugin-loader.ts similarity index 89% rename from test/helpers/channels/bundled-channel-plugin-loader.ts rename to src/channels/plugins/contracts/test-helpers/bundled-channel-plugin-loader.ts index 3b2382fa499..57243fefee5 100644 --- a/test/helpers/channels/bundled-channel-plugin-loader.ts +++ b/src/channels/plugins/contracts/test-helpers/bundled-channel-plugin-loader.ts @@ -1,14 +1,14 @@ -import { listBundledChannelPluginIds as listCatalogBundledChannelPluginIds } from "../../../src/channels/plugins/bundled-ids.js"; -import type { ChannelId } from "../../../src/channels/plugins/channel-id.types.js"; -import type { ChannelPlugin } from "../../../src/channels/plugins/types.js"; import { listChannelCatalogEntries, type PluginChannelCatalogEntry, -} from "../../../src/plugins/channel-catalog-registry.js"; +} from "../../../../plugins/channel-catalog-registry.js"; import { loadBundledPluginPublicSurface, loadBundledPluginPublicSurfaceSync, -} from "../../../src/test-utils/bundled-plugin-public-surface.js"; +} from "../../../../test-utils/bundled-plugin-public-surface.js"; +import { listBundledChannelPluginIds as listCatalogBundledChannelPluginIds } from "../../bundled-ids.js"; +import type { ChannelId } from "../../channel-id.types.js"; +import type { ChannelPlugin } from "../../types.js"; type ChannelPluginApiModule = Record; diff --git a/test/helpers/channels/channel-catalog-contract.ts b/src/channels/plugins/contracts/test-helpers/channel-catalog-contract.ts similarity index 98% rename from test/helpers/channels/channel-catalog-contract.ts rename to src/channels/plugins/contracts/test-helpers/channel-catalog-contract.ts index fce81fc4cc2..999d0922ef4 100644 --- a/test/helpers/channels/channel-catalog-contract.ts +++ b/src/channels/plugins/contracts/test-helpers/channel-catalog-contract.ts @@ -2,10 +2,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import { describe, expect, it } from "vitest"; -import { - getChannelPluginCatalogEntry, - listChannelPluginCatalogEntries, -} from "../../../src/channels/plugins/catalog.js"; +import { getChannelPluginCatalogEntry, listChannelPluginCatalogEntries } from "../../catalog.js"; type CatalogEntryMeta = { id: string; diff --git a/test/helpers/channels/channel-plugin-catalog-contract-suites.ts b/src/channels/plugins/contracts/test-helpers/channel-plugin-catalog-contract-suites.ts similarity index 99% rename from test/helpers/channels/channel-plugin-catalog-contract-suites.ts rename to src/channels/plugins/contracts/test-helpers/channel-plugin-catalog-contract-suites.ts index e31a31eb9f8..45b010b7d85 100644 --- a/test/helpers/channels/channel-plugin-catalog-contract-suites.ts +++ b/src/channels/plugins/contracts/test-helpers/channel-plugin-catalog-contract-suites.ts @@ -2,7 +2,7 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import { describe, expect, it } from "vitest"; -import { listChannelPluginCatalogEntries } from "../../../src/channels/plugins/catalog.js"; +import { listChannelPluginCatalogEntries } from "../../catalog.js"; function createCatalogEntry(params: { packageName: string; diff --git a/test/helpers/channels/config-write-contract-suites.ts b/src/channels/plugins/contracts/test-helpers/config-write-contract-suites.ts similarity index 97% rename from test/helpers/channels/config-write-contract-suites.ts rename to src/channels/plugins/contracts/test-helpers/config-write-contract-suites.ts index 2d85155f372..4d5e41833fa 100644 --- a/test/helpers/channels/config-write-contract-suites.ts +++ b/src/channels/plugins/contracts/test-helpers/config-write-contract-suites.ts @@ -1,12 +1,12 @@ import { describe, expect, it } from "vitest"; +import { INTERNAL_MESSAGE_CHANNEL } from "../../../../utils/message-channel.js"; import { authorizeConfigWrite, canBypassConfigWritePolicy, formatConfigWriteDeniedMessage, resolveExplicitConfigWriteTarget, resolveConfigWriteTargetFromPath, -} from "../../../src/channels/plugins/config-writes.js"; -import { INTERNAL_MESSAGE_CHANNEL } from "../../../src/utils/message-channel.js"; +} from "../../config-writes.js"; const demoOriginChannelId = "demo-origin"; const demoTargetChannelId = "demo-target"; diff --git a/test/helpers/channels/group-policy-contract-suites.ts b/src/channels/plugins/contracts/test-helpers/group-policy-contract-suites.ts similarity index 98% rename from test/helpers/channels/group-policy-contract-suites.ts rename to src/channels/plugins/contracts/test-helpers/group-policy-contract-suites.ts index 5bff04d4c76..00ecb12f70c 100644 --- a/test/helpers/channels/group-policy-contract-suites.ts +++ b/src/channels/plugins/contracts/test-helpers/group-policy-contract-suites.ts @@ -1,5 +1,5 @@ import { expect, it } from "vitest"; -import { resolveOpenProviderRuntimeGroupPolicy } from "../../../src/config/runtime-group-policy.js"; +import { resolveOpenProviderRuntimeGroupPolicy } from "../../../../config/runtime-group-policy.js"; type ResolvedGroupPolicy = ReturnType; diff --git a/test/helpers/channels/group-policy-contract.ts b/src/channels/plugins/contracts/test-helpers/group-policy-contract.ts similarity index 89% rename from test/helpers/channels/group-policy-contract.ts rename to src/channels/plugins/contracts/test-helpers/group-policy-contract.ts index bd9830de8d2..784e1de8110 100644 --- a/test/helpers/channels/group-policy-contract.ts +++ b/src/channels/plugins/contracts/test-helpers/group-policy-contract.ts @@ -1,4 +1,4 @@ -import { resolveOpenProviderRuntimeGroupPolicy } from "../../../src/config/runtime-group-policy.js"; +import { resolveOpenProviderRuntimeGroupPolicy } from "../../../../config/runtime-group-policy.js"; const resolveWhatsAppRuntimeGroupPolicy = resolveOpenProviderRuntimeGroupPolicy; const resolveZaloRuntimeGroupPolicy = resolveOpenProviderRuntimeGroupPolicy; diff --git a/test/helpers/channels/imessage-test-plugin.ts b/src/channels/plugins/contracts/test-helpers/imessage-test-plugin.ts similarity index 88% rename from test/helpers/channels/imessage-test-plugin.ts rename to src/channels/plugins/contracts/test-helpers/imessage-test-plugin.ts index 62861aefd40..658d7b90671 100644 --- a/test/helpers/channels/imessage-test-plugin.ts +++ b/src/channels/plugins/contracts/test-helpers/imessage-test-plugin.ts @@ -1,6 +1,6 @@ import type { ChannelOutboundAdapter } from "openclaw/plugin-sdk/channel-contract"; import type { ChannelPlugin } from "openclaw/plugin-sdk/channel-plugin-common"; -import { loadBundledPluginTestApiSync } from "../../../src/test-utils/bundled-plugin-public-surface.js"; +import { loadBundledPluginTestApiSync } from "../../../../test-utils/bundled-plugin-public-surface.js"; type CreateIMessageTestPlugin = (params?: { outbound?: ChannelOutboundAdapter }) => ChannelPlugin; diff --git a/test/helpers/channels/lazy-object-surface.ts b/src/channels/plugins/contracts/test-helpers/lazy-object-surface.ts similarity index 100% rename from test/helpers/channels/lazy-object-surface.ts rename to src/channels/plugins/contracts/test-helpers/lazy-object-surface.ts diff --git a/test/helpers/channels/manifest.ts b/src/channels/plugins/contracts/test-helpers/manifest.ts similarity index 100% rename from test/helpers/channels/manifest.ts rename to src/channels/plugins/contracts/test-helpers/manifest.ts diff --git a/test/helpers/channels/registry-backed-contract-shards.ts b/src/channels/plugins/contracts/test-helpers/registry-backed-contract-shards.ts similarity index 97% rename from test/helpers/channels/registry-backed-contract-shards.ts rename to src/channels/plugins/contracts/test-helpers/registry-backed-contract-shards.ts index c1f1008f30d..a51ba9db49f 100644 --- a/test/helpers/channels/registry-backed-contract-shards.ts +++ b/src/channels/plugins/contracts/test-helpers/registry-backed-contract-shards.ts @@ -1,7 +1,7 @@ +import { expectChannelPluginContract } from "openclaw/plugin-sdk/channel-test-helpers"; import { describe, it } from "vitest"; import { getBundledChannelPluginAsync } from "./bundled-channel-plugin-loader.js"; import { channelPluginSurfaceKeys } from "./manifest.js"; -import { expectChannelPluginContract } from "./registry-contract-suites.js"; import { getPluginContractRegistryShardRefs } from "./registry-plugin.js"; import { getDirectoryContractRegistryShardRefs, diff --git a/test/helpers/channels/registry-plugin.ts b/src/channels/plugins/contracts/test-helpers/registry-plugin.ts similarity index 86% rename from test/helpers/channels/registry-plugin.ts rename to src/channels/plugins/contracts/test-helpers/registry-plugin.ts index cc731af7649..901f181c534 100644 --- a/test/helpers/channels/registry-plugin.ts +++ b/src/channels/plugins/contracts/test-helpers/registry-plugin.ts @@ -1,6 +1,6 @@ -import type { ChannelId } from "../../../src/channels/plugins/channel-id.types.js"; -import { normalizeChannelMeta } from "../../../src/channels/plugins/meta-normalization.js"; -import type { ChannelPlugin } from "../../../src/channels/plugins/types.js"; +import type { ChannelId } from "../../channel-id.types.js"; +import { normalizeChannelMeta } from "../../meta-normalization.js"; +import type { ChannelPlugin } from "../../types.js"; import { getBundledChannelCatalogEntry, getBundledChannelPlugin, diff --git a/test/helpers/channels/registry-session-binding.ts b/src/channels/plugins/contracts/test-helpers/registry-session-binding.ts similarity index 97% rename from test/helpers/channels/registry-session-binding.ts rename to src/channels/plugins/contracts/test-helpers/registry-session-binding.ts index fb4b48a1d8c..3591a8deaad 100644 --- a/test/helpers/channels/registry-session-binding.ts +++ b/src/channels/plugins/contracts/test-helpers/registry-session-binding.ts @@ -2,22 +2,22 @@ import fs from "node:fs"; import os from "node:os"; import path from "node:path"; import { expect } from "vitest"; -import { createChannelConversationBindingManager } from "../../../src/channels/plugins/conversation-bindings.js"; -import type { ChannelPlugin } from "../../../src/channels/plugins/types.js"; -import type { OpenClawConfig } from "../../../src/config/config.js"; +import type { OpenClawConfig } from "../../../../config/config.js"; import { getSessionBindingService, type SessionBindingCapabilities, type SessionBindingRecord, -} from "../../../src/infra/outbound/session-binding-service.js"; -import { setActivePluginRegistry } from "../../../src/plugins/runtime.js"; -import { createTestRegistry } from "../../../src/test-utils/channel-plugins.js"; +} from "../../../../infra/outbound/session-binding-service.js"; +import { setActivePluginRegistry } from "../../../../plugins/runtime.js"; +import { createTestRegistry } from "../../../../test-utils/channel-plugins.js"; +import { createChannelConversationBindingManager } from "../../conversation-bindings.js"; +import type { ChannelPlugin } from "../../types.js"; import { sessionBindingContractChannelIds, type SessionBindingContractChannelId, } from "./manifest.js"; import { importBundledChannelContractArtifact } from "./runtime-artifacts.js"; -import "../../../src/channels/plugins/registry.js"; +import "../../registry.js"; type SessionBindingContractEntry = { id: string; diff --git a/test/helpers/channels/runtime-artifacts.ts b/src/channels/plugins/contracts/test-helpers/runtime-artifacts.ts similarity index 87% rename from test/helpers/channels/runtime-artifacts.ts rename to src/channels/plugins/contracts/test-helpers/runtime-artifacts.ts index 2de99325519..aa8ba9fcc1b 100644 --- a/test/helpers/channels/runtime-artifacts.ts +++ b/src/channels/plugins/contracts/test-helpers/runtime-artifacts.ts @@ -1,13 +1,13 @@ import fs from "node:fs"; import path from "node:path"; import { fileURLToPath, pathToFileURL } from "node:url"; -import { resolveBundledChannelWorkspacePath } from "../../../src/plugins/bundled-channel-runtime.js"; +import { resolveBundledChannelWorkspacePath } from "../../../../plugins/bundled-channel-runtime.js"; import { resolvePluginRuntimeModulePath, resolvePluginRuntimeRecord, -} from "../../../src/plugins/runtime/runtime-plugin-boundary.js"; +} from "../../../../plugins/runtime/runtime-plugin-boundary.js"; -const REPO_ROOT = fileURLToPath(new URL("../../../", import.meta.url)); +const REPO_ROOT = fileURLToPath(new URL("../../../../../", import.meta.url)); function resolveBundledChannelWorkspaceArtifactPath( pluginId: string, diff --git a/test/helpers/channels/session-binding-registry-backed-contract.ts b/src/channels/plugins/contracts/test-helpers/session-binding-registry-backed-contract.ts similarity index 92% rename from test/helpers/channels/session-binding-registry-backed-contract.ts rename to src/channels/plugins/contracts/test-helpers/session-binding-registry-backed-contract.ts index b667d8b61b0..503499b3575 100644 --- a/test/helpers/channels/session-binding-registry-backed-contract.ts +++ b/src/channels/plugins/contracts/test-helpers/session-binding-registry-backed-contract.ts @@ -1,14 +1,11 @@ import { afterEach, beforeEach, describe, expect, it } from "vitest"; -import { - clearRuntimeConfigSnapshot, - setRuntimeConfigSnapshot, -} from "../../../src/config/config.js"; +import { clearRuntimeConfigSnapshot, setRuntimeConfigSnapshot } from "../../../../config/config.js"; import { __testing as sessionBindingTesting, type SessionBindingCapabilities, type SessionBindingRecord, -} from "../../../src/infra/outbound/session-binding-service.js"; -import { resetPluginRuntimeStateForTest } from "../../../src/plugins/runtime.js"; +} from "../../../../infra/outbound/session-binding-service.js"; +import { resetPluginRuntimeStateForTest } from "../../../../plugins/runtime.js"; import { getSessionBindingContractRegistry } from "./registry-session-binding.js"; function resolveSessionBindingContractRuntimeConfig(id: string) { diff --git a/test/helpers/channels/surface-contract-registry.ts b/src/channels/plugins/contracts/test-helpers/surface-contract-registry.ts similarity index 96% rename from test/helpers/channels/surface-contract-registry.ts rename to src/channels/plugins/contracts/test-helpers/surface-contract-registry.ts index d79d9d3268d..535c2a3514c 100644 --- a/test/helpers/channels/surface-contract-registry.ts +++ b/src/channels/plugins/contracts/test-helpers/surface-contract-registry.ts @@ -1,6 +1,6 @@ -import type { ChannelId } from "../../../src/channels/plugins/channel-id.types.js"; -import type { ChannelPlugin } from "../../../src/channels/plugins/types.js"; -import type { OpenClawConfig } from "../../../src/config/config.js"; +import type { OpenClawConfig } from "../../../../config/config.js"; +import type { ChannelId } from "../../channel-id.types.js"; +import type { ChannelPlugin } from "../../types.js"; import { getBundledChannelPlugin, listBundledChannelPluginIds, diff --git a/test/helpers/channels/surface-contract-suite.ts b/src/channels/plugins/contracts/test-helpers/surface-contract-suite.ts similarity index 98% rename from test/helpers/channels/surface-contract-suite.ts rename to src/channels/plugins/contracts/test-helpers/surface-contract-suite.ts index 536a31895d5..02408eb80ad 100644 --- a/test/helpers/channels/surface-contract-suite.ts +++ b/src/channels/plugins/contracts/test-helpers/surface-contract-suite.ts @@ -1,5 +1,5 @@ import { expect, it } from "vitest"; -import type { ChannelPlugin } from "../../../src/channels/plugins/types.js"; +import type { ChannelPlugin } from "../../types.js"; export function installChannelSurfaceContractSuite(params: { plugin: Pick< diff --git a/test/helpers/channels/threading-directory-contract-suites.ts b/src/channels/plugins/contracts/test-helpers/threading-directory-contract-suites.ts similarity index 95% rename from test/helpers/channels/threading-directory-contract-suites.ts rename to src/channels/plugins/contracts/test-helpers/threading-directory-contract-suites.ts index 2d3cf6730c1..66bcc006787 100644 --- a/test/helpers/channels/threading-directory-contract-suites.ts +++ b/src/channels/plugins/contracts/test-helpers/threading-directory-contract-suites.ts @@ -1,13 +1,13 @@ import { expect, it } from "vitest"; +import type { OpenClawConfig } from "../../../../config/config.js"; +import type { RuntimeEnv } from "../../../../runtime.js"; import type { ChannelDirectoryEntry, ChannelFocusedBindingContext, ChannelReplyTransport, ChannelThreadingToolContext, -} from "../../../src/channels/plugins/types.core.js"; -import type { ChannelPlugin } from "../../../src/channels/plugins/types.js"; -import type { OpenClawConfig } from "../../../src/config/config.js"; -import type { RuntimeEnv } from "../../../src/runtime.js"; +} from "../../types.core.js"; +import type { ChannelPlugin } from "../../types.js"; let contractRuntime: RuntimeEnv | undefined; @@ -15,7 +15,7 @@ async function getDirectoryContractRuntime(): Promise { if (contractRuntime) { return contractRuntime; } - const { createNonExitingRuntime } = await import("../../../src/runtime.js"); + const { createNonExitingRuntime } = await import("../../../../runtime.js"); contractRuntime = createNonExitingRuntime(); return contractRuntime; } diff --git a/src/channels/plugins/contracts/threading.registry-backed-shard-a.contract.test.ts b/src/channels/plugins/contracts/threading.registry-backed-shard-a.contract.test.ts index f1de5ddc67d..5016e75c993 100644 --- a/src/channels/plugins/contracts/threading.registry-backed-shard-a.contract.test.ts +++ b/src/channels/plugins/contracts/threading.registry-backed-shard-a.contract.test.ts @@ -1,3 +1,3 @@ -import { installThreadingContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installThreadingContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installThreadingContractRegistryShard({ shardIndex: 0, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/threading.registry-backed-shard-b.contract.test.ts b/src/channels/plugins/contracts/threading.registry-backed-shard-b.contract.test.ts index 7648c866c8c..313f96da2f0 100644 --- a/src/channels/plugins/contracts/threading.registry-backed-shard-b.contract.test.ts +++ b/src/channels/plugins/contracts/threading.registry-backed-shard-b.contract.test.ts @@ -1,3 +1,3 @@ -import { installThreadingContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installThreadingContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installThreadingContractRegistryShard({ shardIndex: 1, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/threading.registry-backed-shard-c.contract.test.ts b/src/channels/plugins/contracts/threading.registry-backed-shard-c.contract.test.ts index 8f63743ade0..d453c0d010b 100644 --- a/src/channels/plugins/contracts/threading.registry-backed-shard-c.contract.test.ts +++ b/src/channels/plugins/contracts/threading.registry-backed-shard-c.contract.test.ts @@ -1,3 +1,3 @@ -import { installThreadingContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installThreadingContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installThreadingContractRegistryShard({ shardIndex: 2, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/threading.registry-backed-shard-d.contract.test.ts b/src/channels/plugins/contracts/threading.registry-backed-shard-d.contract.test.ts index 49307be4df2..69d026c432c 100644 --- a/src/channels/plugins/contracts/threading.registry-backed-shard-d.contract.test.ts +++ b/src/channels/plugins/contracts/threading.registry-backed-shard-d.contract.test.ts @@ -1,3 +1,3 @@ -import { installThreadingContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installThreadingContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installThreadingContractRegistryShard({ shardIndex: 3, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/threading.registry-backed-shard-e.contract.test.ts b/src/channels/plugins/contracts/threading.registry-backed-shard-e.contract.test.ts index 4fa944a7c9c..b1fa21d506c 100644 --- a/src/channels/plugins/contracts/threading.registry-backed-shard-e.contract.test.ts +++ b/src/channels/plugins/contracts/threading.registry-backed-shard-e.contract.test.ts @@ -1,3 +1,3 @@ -import { installThreadingContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installThreadingContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installThreadingContractRegistryShard({ shardIndex: 4, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/threading.registry-backed-shard-f.contract.test.ts b/src/channels/plugins/contracts/threading.registry-backed-shard-f.contract.test.ts index f59b1a0a5fa..52f26682447 100644 --- a/src/channels/plugins/contracts/threading.registry-backed-shard-f.contract.test.ts +++ b/src/channels/plugins/contracts/threading.registry-backed-shard-f.contract.test.ts @@ -1,3 +1,3 @@ -import { installThreadingContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installThreadingContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installThreadingContractRegistryShard({ shardIndex: 5, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/threading.registry-backed-shard-g.contract.test.ts b/src/channels/plugins/contracts/threading.registry-backed-shard-g.contract.test.ts index 8288ac3fe0b..6a7196a67dc 100644 --- a/src/channels/plugins/contracts/threading.registry-backed-shard-g.contract.test.ts +++ b/src/channels/plugins/contracts/threading.registry-backed-shard-g.contract.test.ts @@ -1,3 +1,3 @@ -import { installThreadingContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installThreadingContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installThreadingContractRegistryShard({ shardIndex: 6, shardCount: 8 }); diff --git a/src/channels/plugins/contracts/threading.registry-backed-shard-h.contract.test.ts b/src/channels/plugins/contracts/threading.registry-backed-shard-h.contract.test.ts index e3f14c87085..201df9c4b54 100644 --- a/src/channels/plugins/contracts/threading.registry-backed-shard-h.contract.test.ts +++ b/src/channels/plugins/contracts/threading.registry-backed-shard-h.contract.test.ts @@ -1,3 +1,3 @@ -import { installThreadingContractRegistryShard } from "../../../../test/helpers/channels/registry-backed-contract-shards.js"; +import { installThreadingContractRegistryShard } from "./test-helpers/registry-backed-contract-shards.js"; installThreadingContractRegistryShard({ shardIndex: 7, shardCount: 8 }); diff --git a/test/extension-test-boundary.test.ts b/test/extension-test-boundary.test.ts index 5aec30d84c3..d2a290203da 100644 --- a/test/extension-test-boundary.test.ts +++ b/test/extension-test-boundary.test.ts @@ -8,6 +8,7 @@ const repoRoot = path.resolve(import.meta.dirname, ".."); const ALLOWED_EXTENSION_PUBLIC_SURFACE_BASENAMES = new Set( GUARDED_EXTENSION_PUBLIC_SURFACE_BASENAMES, ); +const CHANNEL_CONTRACT_TEST_HELPERS_PREFIX = "src/channels/plugins/contracts/test-helpers/"; const ROOTDIR_BOUNDARY_CANARY_RE = /(^|\/)__rootdir_boundary_canary__\.(?:[cm]?ts|[cm]?js|tsx|jsx)$/u; @@ -151,7 +152,9 @@ describe("non-extension test boundaries", () => { }); it("keeps bundled plugin public-surface imports out of core source", () => { - const files = walkCode(path.join(repoRoot, "src")); + const files = walkCode(path.join(repoRoot, "src")).filter( + (file) => !file.startsWith(CHANNEL_CONTRACT_TEST_HELPERS_PREFIX), + ); const offenders = files.filter((file) => { const source = fs.readFileSync(path.join(repoRoot, file), "utf8"); @@ -167,6 +170,7 @@ describe("non-extension test boundaries", () => { ...walkCode(path.join(repoRoot, "test")), ] .filter((file) => !file.startsWith(BUNDLED_PLUGIN_PATH_PREFIX)) + .filter((file) => !file.startsWith(CHANNEL_CONTRACT_TEST_HELPERS_PREFIX)) .filter((file) => !file.startsWith("test/helpers/")) .filter((file) => file !== "test/extension-test-boundary.test.ts"); @@ -186,7 +190,10 @@ describe("non-extension test boundaries", () => { const offenders = files.filter((file) => { const source = fs.readFileSync(path.join(repoRoot, file), "utf8"); - return source.includes("test/helpers/channels/security-audit-contract.js"); + return ( + source.includes("test/helpers/channels/security-audit-contract.js") || + source.includes("src/channels/plugins/contracts/test-helpers/security-audit-contract.js") + ); }); expect(offenders).toEqual([]); @@ -197,7 +204,7 @@ describe("non-extension test boundaries", () => { const offenders = files.filter((file) => { const source = fs.readFileSync(path.join(repoRoot, file), "utf8"); - return source.includes("src/channels/plugins/contracts/test-helpers.js"); + return source.includes("src/channels/plugins/contracts/test-helpers/"); }); expect(offenders).toEqual([]); @@ -208,6 +215,7 @@ describe("non-extension test boundaries", () => { /["']openclaw\/plugin-sdk\/testing["']/u, /["']openclaw\/plugin-sdk\/test-utils["']/u, /["'](?:\.\.\/)+(?:test\/helpers\/channels\/)[^"']+["']/u, + /["'](?:\.\.\/)+(?:src\/channels\/plugins\/contracts\/test-helpers\/)[^"']+["']/u, /["'](?:\.\.\/)+(?:test\/helpers\/plugins\/)[^"']+["']/u, ]; const files = walkCode(path.join(repoRoot, "extensions")); diff --git a/test/helpers/channels/directory-ids.ts b/test/helpers/channels/directory-ids.ts deleted file mode 100644 index 12271f08343..00000000000 --- a/test/helpers/channels/directory-ids.ts +++ /dev/null @@ -1,4 +0,0 @@ -export { - expectDirectoryIds, - type DirectoryListFn, -} from "../../../src/plugin-sdk/test-helpers/directory-ids.js"; diff --git a/test/helpers/channels/registry-contract-suites.ts b/test/helpers/channels/registry-contract-suites.ts deleted file mode 100644 index 928717a4093..00000000000 --- a/test/helpers/channels/registry-contract-suites.ts +++ /dev/null @@ -1,7 +0,0 @@ -export { - expectChannelPluginContract, - installChannelActionsContractSuite, - installChannelPluginContractSuite, - installChannelSetupContractSuite, - installChannelStatusContractSuite, -} from "../../../src/plugin-sdk/test-helpers/channel-contract-suites.js"; diff --git a/test/scripts/test-projects.test.ts b/test/scripts/test-projects.test.ts index ece5f48ded2..cf6444fd3a7 100644 --- a/test/scripts/test-projects.test.ts +++ b/test/scripts/test-projects.test.ts @@ -225,7 +225,7 @@ describe("scripts/test-projects changed-target routing", () => { it("keeps shared test helpers cheap by default when no precise target exists", () => { expect( resolveChangedTargetArgs(["--changed", "origin/main"], process.cwd(), () => [ - "test/helpers/channels/plugin.ts", + "test/helpers/poll.ts", ]), ).toEqual([]); }); @@ -235,26 +235,25 @@ describe("scripts/test-projects changed-target routing", () => { resolveChangedTargetArgs( ["--changed", "origin/main"], process.cwd(), - () => ["test/helpers/channels/plugin.ts"], + () => ["test/helpers/poll.ts"], { env: { OPENCLAW_TEST_CHANGED_BROAD: "1" } }, ), ).toBeNull(); }); - it("routes channel helper edits through the tests that import them", () => { - expect(resolveChangedTestTargetPlan(["test/helpers/channels/directory-ids.ts"])).toEqual({ - mode: "targets", - targets: [ - "extensions/discord/src/directory-contract.test.ts", - "extensions/slack/src/directory-contract.test.ts", - "extensions/telegram/src/directory-contract.test.ts", - ], - }); + it("routes channel contract helper edits through the tests that import them", () => { + const plan = resolveChangedTestTargetPlan([ + "src/channels/plugins/contracts/test-helpers/manifest.ts", + ]); + + expect(plan.mode).toBe("targets"); + expect(plan.targets).toContain("src/channels/plugins/contracts/registry.contract.test.ts"); + expect(plan.targets).not.toContain("extensions/discord/src/directory-contract.test.ts"); }); it("routes channel contract helper edits through contract shards", () => { const plan = resolveChangedTestTargetPlan([ - "test/helpers/channels/registry-backed-contract-shards.ts", + "src/channels/plugins/contracts/test-helpers/registry-backed-contract-shards.ts", ]); expect(plan.mode).toBe("targets");