Skip to main content
Reference for test utilities, patterns, and lint enforcement for OpenClaw plugins.
Looking for test examples? The how-to guides include worked test examples: Channel plugin tests and Provider plugin tests.

Test utilities

These subpaths are repo-local source entrypoints for OpenClaw’s own bundled plugin tests. They are not published package.json exports for third-party plugins, and they may import Vitest or other repo-only test dependencies.
Use these focused subpaths for bundled plugin tests. The former openclaw/plugin-sdk/testing barrel was repo-local, excluded from shipped packages, and has been removed. The legacy openclaw/plugin-sdk/test-utils alias remains repo-local; pnpm run lint:plugins:no-extension-test-core-imports (scripts/check-no-extension-test-core-imports.ts) rejects new extension-test imports of that alias.

Available exports

Bundled-plugin contract suites also use these SDK testing subpaths for test-only registry, manifest, public-artifact, and runtime fixture helpers. Core-only suites that depend on bundled OpenClaw inventory stay under src/plugins/contracts instead.

Types

Focused testing subpaths also re-export types useful in test files:

Testing target resolution

Use installCommonResolveTargetErrorCases to add standard error cases for channel target resolution:

Testing patterns

Testing registration contracts

Unit tests that pass a hand-written api mock to register(api) do not exercise OpenClaw’s loader acceptance gates. Add at least one loader-backed smoke test for each registration surface your plugin depends on, especially hooks and exclusive capabilities such as memory. The real loader fails plugin registration when required metadata is missing or a plugin calls a capability API it does not own. For example, api.registerHook(...) requires a hook name, and api.registerMemoryCapability(...) requires the plugin manifest or exported entry to declare kind: "memory".

Testing runtime config access

Prefer the shared plugin runtime mock from openclaw/plugin-sdk/plugin-test-runtime. Its runtime.config.loadConfig() and runtime.config.writeConfigFile(...) mocks throw by default so tests catch new usage of deprecated compatibility APIs. Override those mocks only when the test is explicitly covering legacy compatibility behavior.

Unit testing a channel plugin

Unit testing a provider plugin

Mocking the plugin runtime

For code that uses createPluginRuntimeStore, mock the runtime in tests:

Testing with per-instance stubs

Prefer per-instance stubs over prototype mutation:

Contract tests (in-repo plugins)

Bundled plugins have contract tests that verify registration ownership:
These tests assert:
  • Which plugins register which providers
  • Which plugins register which speech providers
  • Registration shape correctness
  • Runtime contract compliance

Running scoped tests

For a specific plugin:
For contract tests only:

Lint enforcement (in-repo plugins)

scripts/run-additional-boundary-checks.mjs runs a set of lint:plugins:* import-boundary checks in CI; each can also be run standalone locally: External plugins are not subject to these lint rules, but following the same patterns is recommended.

Test configuration

OpenClaw uses Vitest 4 with informational V8 coverage reporting. For plugin tests:
If local runs cause memory pressure: