Aller au contenu

Test de plugin

Référence pour les utilitaires de test, les modèles et l’application des règles de lint pour les plugins OpenClaw.

Ces sous-chemins d’aide aux tests sont des points d’entrée source locaux au dépôt pour les propres tests de plugins intégrés d’OpenClaw. Ils ne sont pas des exportations de package pour les plugins tiers.

Import du simulacre d’API de plugin : APIopenclaw/plugin-sdk/plugin-test-api

Import du contrat de runtime de l’agent : openclaw/plugin-sdk/agent-runtime-test-contracts

Import du contrat de canal : openclaw/plugin-sdk/channel-contract-testing

Import de l’aide aux tests de canal : openclaw/plugin-sdk/channel-test-helpers

Import du test de cible de canal : openclaw/plugin-sdk/channel-target-testing

Import du contrat de plugin : openclaw/plugin-sdk/plugin-test-contracts

Import du test de runtime de plugin : openclaw/plugin-sdk/plugin-test-runtime

Import du contrat de fournisseur : openclaw/plugin-sdk/provider-test-contracts

Import du simulacre HTTP de fournisseur : openclaw/plugin-sdk/provider-http-test-mocks

Import du test d’environnement/réseau : openclaw/plugin-sdk/test-env

Import de fixture générique : openclaw/plugin-sdk/test-fixtures

Import du simulacle intégré Node : openclaw/plugin-sdk/test-node-mocks

Privilégiez les sous-chemins ciblés ci-dessous pour les nouveaux tests de plugins. Le module général openclaw/plugin-sdk/testing n’est qu’une compatibilité héritée. Les garde-fous du dépôt rejettent les nouveaux imports réels de plugin-sdk/testing et plugin-sdk/test-utils ; ces noms ne demeurent que comme surfaces de compatibilité dépréciées pour les tests d’enregistrement de compatibilité.

import { shouldAckReaction, removeAckReactionAfterReply } from "openclaw/plugin-sdk/channel-feedback";
import { installCommonResolveTargetErrorCases } from "openclaw/plugin-sdk/channel-target-testing";
import { AUTH_PROFILE_RUNTIME_CONTRACT } from "openclaw/plugin-sdk/agent-runtime-test-contracts";
import { createTestPluginApi } from "openclaw/plugin-sdk/plugin-test-api";
import { expectChannelInboundContextContract } from "openclaw/plugin-sdk/channel-contract-testing";
import { createStartAccountContext } from "openclaw/plugin-sdk/channel-test-helpers";
import { describePluginRegistrationContract } from "openclaw/plugin-sdk/plugin-test-contracts";
import { registerSingleProviderPlugin } from "openclaw/plugin-sdk/plugin-test-runtime";
import { describeOpenAIProviderRuntimeContract } from "openclaw/plugin-sdk/provider-test-contracts";
import { getProviderHttpMocks } from "openclaw/plugin-sdk/provider-http-test-mocks";
import { withEnv, withFetchPreconnect, withServer } from "openclaw/plugin-sdk/test-env";
import { bundledPluginRoot, createCliRuntimeCapture, typedCases } from "openclaw/plugin-sdk/test-fixtures";
import { mockNodeBuiltinModule } from "openclaw/plugin-sdk/test-node-mocks";
ExportationObjectif
createTestPluginApiConstruit un simulacre minimal de l’API de plugin pour les tests unitaires d’enregistrement direct. Importer depuis APIplugin-sdk/plugin-test-api
AUTH_PROFILE_RUNTIME_CONTRACTFixture de contrat de profil d’authentification partagée pour les adaptateurs de runtime d’agent natif. Importer depuis plugin-sdk/agent-runtime-test-contracts
DELIVERY_NO_REPLY_RUNTIME_CONTRACTFixture de contrat de suppression de livraison partagée pour les adaptateurs de runtime d’agent natif. Importer depuis plugin-sdk/agent-runtime-test-contracts
OUTCOME_FALLBACK_RUNTIME_CONTRACTFixture de contrat de classification de repli partagée pour les adaptateurs de runtime d’agent natif. Importer depuis plugin-sdk/agent-runtime-test-contracts
createParameterFreeToolConstruit des fixtures de schéma d’outil dynamique pour les tests de contrat de runtime natif. Importer depuis plugin-sdk/agent-runtime-test-contracts
expectChannelInboundContextContractAssert channel inbound context shape. Import from plugin-sdk/channel-contract-testing
installChannelOutboundPayloadContractSuiteInstall channel outbound payload contract cases. Import from plugin-sdk/channel-contract-testing
createStartAccountContextBuild channel account lifecycle contexts. Import from plugin-sdk/channel-test-helpers
installChannelActionsContractSuiteInstall generic channel message-action contract cases. Import from plugin-sdk/channel-test-helpers
installChannelSetupContractSuiteInstall generic channel setup contract cases. Import from plugin-sdk/channel-test-helpers
installChannelStatusContractSuiteInstall generic channel status contract cases. Import from plugin-sdk/channel-test-helpers
expectDirectoryIdsAssert channel directory ids from a directory-list function. Import from plugin-sdk/channel-test-helpers
assertBundledChannelEntriesAssert bundled channel entrypoints expose the expected public contract. Import from plugin-sdk/channel-test-helpers
formatEnvelopeTimestampFormat deterministic envelope timestamps. Import from plugin-sdk/channel-test-helpers
expectPairingReplyTextAssert channel pairing reply text and extract its code. Import from plugin-sdk/channel-test-helpers
describePluginRegistrationContractInstall plugin registration contract checks. Import from plugin-sdk/plugin-test-contracts
registerSingleProviderPluginRegister one provider plugin in loader smoke tests. Import from plugin-sdk/plugin-test-runtime
registerProviderPluginCapture all provider kinds from one plugin. Import from plugin-sdk/plugin-test-runtime
registerProviderPluginsCapture provider registrations across multiple plugins. Import from plugin-sdk/plugin-test-runtime
requireRegisteredProviderAssert that a provider collection contains an id. Import from plugin-sdk/plugin-test-runtime
createRuntimeEnvBuild a mocked CLI/plugin runtime environment. Import from plugin-sdk/plugin-test-runtime
createPluginSetupWizardStatusBuild setup status helpers for channel plugins. Import from plugin-sdk/plugin-test-runtime
describeOpenAIProviderRuntimeContractInstaller les vérifications de contrat d’exécution pour la famille de providers. Importer depuis plugin-sdk/provider-test-contracts
expectPassthroughReplayPolicyAffirmer que les stratégies de relecture du provider traversent les outils et les métadonnées appartenant au provider. Importer depuis plugin-sdk/provider-test-contracts
runRealtimeSttLiveTestExécuter un test STT provider temps réel en direct avec des fixtures audio partagées. Importer depuis plugin-sdk/provider-test-contracts
normalizeTranscriptForMatchNormaliser la sortie de la transcription en direct avant les assertions floues. Importer depuis plugin-sdk/provider-test-contracts
expectExplicitVideoGenerationCapabilitiesAffirmer que les providers vidéo déclarent des capacités de mode de génération explicites. Importer depuis plugin-sdk/provider-test-contracts
expectExplicitMusicGenerationCapabilitiesAffirmer que les providers de musique déclarent des capacités de génération/édition explicites. Importer depuis plugin-sdk/provider-test-contracts
mockSuccessfulDashscopeVideoTaskInstaller une réponse de tâche vidéo compatible DashScope réussie. Importer depuis plugin-sdk/provider-test-contracts
getProviderHttpMocksAccéder aux mocks Vitest HTTP/auth opt-in du provider. Importer depuis plugin-sdk/provider-http-test-mocks
installProviderHttpMockCleanupRéinitialiser les mocks HTTP/auth du provider après chaque test. Importer depuis plugin-sdk/provider-http-test-mocks
installCommonResolveTargetErrorCasesCas de test partagés pour la gestion des erreurs de résolution de cible. Importer depuis plugin-sdk/channel-target-testing
shouldAckReactionVérifier si un channel doit ajouter une réaction d’accusé de réception. Importer depuis plugin-sdk/channel-feedback
removeAckReactionAfterReplySupprimer la réaction d’accusé de réception après la livraison de la réponse. Importer depuis plugin-sdk/channel-feedback
createTestRegistryConstruire une fixture de registre de plugins de channel. Importer depuis plugin-sdk/plugin-test-runtime ou plugin-sdk/channel-test-helpers
createEmptyPluginRegistryConstruire une fixture de registre de plugins vide. Importer depuis plugin-sdk/plugin-test-runtime ou plugin-sdk/channel-test-helpers
setActivePluginRegistryInstaller une fixture de registre pour les tests d’exécution de plugins. Importer depuis plugin-sdk/plugin-test-runtime ou plugin-sdk/channel-test-helpers
createRequestCaptureJsonFetchCapture JSON fetch requests in media helper tests. Import from plugin-sdk/test-env
withServerRun tests against a disposable local HTTP server. Import from plugin-sdk/test-env
createMockIncomingRequestBuild a minimal incoming HTTP request object. Import from plugin-sdk/test-env
withFetchPreconnectRun fetch tests with preconnect hooks installed. Import from plugin-sdk/test-env
withEnv / withEnvAsyncTemporarily patch environment variables. Import from plugin-sdk/test-env
createTempHomeEnv / withTempHome / withTempDirCreate isolated filesystem test fixtures. Import from plugin-sdk/test-env
createMockServerResponseCreate a minimal HTTP server response mock. Import from plugin-sdk/test-env
createCliRuntimeCaptureCapture CLI runtime output in tests. Import from plugin-sdk/test-fixtures
importFreshModuleImport an ESM module with a fresh query token to bypass module cache. Import from plugin-sdk/test-fixtures
bundledPluginRoot / bundledPluginFileResolve bundled plugin source or dist fixture paths. Import from plugin-sdk/test-fixtures
mockNodeBuiltinModuleInstall narrow Node builtin Vitest mocks. Import from plugin-sdk/test-node-mocks
createSandboxTestContextBuild sandbox test contexts. Import from plugin-sdk/test-fixtures
writeSkillWrite skill fixtures. Import from plugin-sdk/test-fixtures
makeAgentAssistantMessageBuild agent transcript message fixtures. Import from plugin-sdk/test-fixtures
peekSystemEvents / resetSystemEventsForTestInspect and reset system event fixtures. Import from plugin-sdk/test-fixtures
sanitizeTerminalTextSanitize terminal output for assertions. Import from plugin-sdk/test-fixtures
countLines / hasBalancedFencesAffirmer la forme de la sortie du chunking. Importer depuis plugin-sdk/test-fixtures
runProviderCatalogExécuter un hook de catalogue de fournisseur avec des dépendances de test
resolveProviderWizardOptionsRésoudre les choix de l’assistant de configuration du fournisseur dans les tests contractuels
resolveProviderModelPickerEntriesRésoudre les entrées du sélecteur de modèle du fournisseur dans les tests contractuels
buildProviderPluginMethodChoiceConstruire les identifiants des choix de l’assistant du fournisseur pour les assertions
setProviderWizardProvidersResolverForTestInjecter les fournisseurs de l’assistant du fournisseur pour des tests isolés
createProviderUsageFetchConstruire des fixtures de récupération d’utilisation du fournisseur
useFrozenTime / useRealTimeGeler et restaurer les minuteurs pour les tests sensibles au temps. Importer depuis plugin-sdk/test-env
createTestWizardPrompterConstruire un assistant de configuration de test simulé
createRuntimeTaskFlowCréer un état isolé du flux de tâches d’exécution
typedCasesPréserver les types littéraux pour les tests basés sur des tableaux. Importer depuis plugin-sdk/test-fixtures

Les suites de tests contractuels de plugins groupés utilisent également des sous-chemins de test du SDK pour les assistants de registre, de manifeste, d’artefact public et de fixture d’exécution réservés aux tests. Les suites exclusivement au cœur qui dépendent de l’inventaire OpenClaw groupé restent sous src/plugins/contracts. Gardez les nouveaux tests d’extension sur un sous-chemin SDK ciblé documenté tel que plugin-sdk/plugin-test-api, plugin-sdk/channel-contract-testing, plugin-sdk/agent-runtime-test-contracts, plugin-sdk/channel-test-helpers, plugin-sdk/plugin-test-contracts, plugin-sdk/plugin-test-runtime, plugin-sdk/provider-test-contracts, plugin-sdk/provider-http-test-mocks, plugin-sdk/test-env, ou plugin-sdk/test-fixtures plutôt que d’importer le baril de compatibilité large plugin-sdk/testing, les fichiers src/** du dépôt, ou les ponts test/helpers/* du dépôt directement.

Les sous-chemins de test ciblés réexportent également des types utiles dans les fichiers de test :

import type { ChannelAccountSnapshot, ChannelGatewayContext } from "openclaw/plugin-sdk/channel-contract";
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-contracts";
import type { MockFn, PluginRuntime, RuntimeEnv } from "openclaw/plugin-sdk/plugin-test-runtime";

Utilisez installCommonResolveTargetErrorCases pour ajouter des cas d’erreur standard pour la résolution de la cible du channel :

import { describe } from "vitest";
import { installCommonResolveTargetErrorCases } from "openclaw/plugin-sdk/channel-target-testing";
describe("my-channel target resolution", () => {
installCommonResolveTargetErrorCases({
resolveTarget: ({ to, mode, allowFrom }) => {
// Your channel's target resolution logic
return myChannelResolveTarget({ to, mode, allowFrom });
},
implicitAllowFrom: ["user1", "user2"],
});
// Add channel-specific test cases
it("should resolve @username targets", () => {
// ...
});
});

Les tests unitaires qui passent un api mock écrit à la main à register(api) n’exercent pas les barrières d’acceptation du chargeur d’OpenClaw. Ajoutez au moins un test de fumée (smoke test) soutenu par le chargeur pour chaque surface d’enregistrement dont dépend votre plugin, en particulier les hooks et les capacités exclusives telles que la mémoire.

Le vrai chargeur échoue l’enregistrement du plugin lorsque les métadonnées requises sont manquantes ou qu’un plugin appelle une API de capacité qu’il ne possède pas. Par exemple, api.registerHook(...) nécessite un nom de hook, et api.registerMemoryCapability(...) nécessite que le manifeste du plugin ou l’entrée exportée déclare kind: "memory".

Test de l’accès à la configuration d’exécution

Section intitulée « Test de l’accès à la configuration d’exécution »

Préférez le mock partagé du runtime de plugin à partir de openclaw/plugin-sdk/channel-test-helpers lors des tests des plugins channel regroupés. Ses mocks obsolètes runtime.config.loadConfig() et runtime.config.writeConfigFile(...) lancent des exceptions par défaut afin que les tests détectent toute nouvelle utilisation des API de compatibilité. Ne substituez ces mocks que lorsque le test couvre explicitement le comportement de compatibilité hérité.

import { describe, it, expect, vi } from "vitest";
describe("my-channel plugin", () => {
it("should resolve account from config", () => {
const cfg = {
channels: {
"my-channel": {
token: "test-token",
allowFrom: ["user1"],
},
},
};
const account = myPlugin.setup.resolveAccount(cfg, undefined);
expect(account.token).toBe("test-token");
});
it("should inspect account without materializing secrets", () => {
const cfg = {
channels: {
"my-channel": { token: "test-token" },
},
};
const inspection = myPlugin.setup.inspectAccount(cfg, undefined);
expect(inspection.configured).toBe(true);
expect(inspection.tokenStatus).toBe("available");
// No token value exposed
expect(inspection).not.toHaveProperty("token");
});
});
import { describe, it, expect } from "vitest";
describe("my-provider plugin", () => {
it("should resolve dynamic models", () => {
const model = myProvider.resolveDynamicModel({
modelId: "custom-model-v2",
// ... context
});
expect(model.id).toBe("custom-model-v2");
expect(model.provider).toBe("my-provider");
expect(model.api).toBe("openai-completions");
});
it("should return catalog when API key is available", async () => {
const result = await myProvider.catalog.run({
resolveProviderApiKey: () => ({ apiKey: "test-key" }),
// ... context
});
expect(result?.provider?.models).toHaveLength(2);
});
});

Pour le code qui utilise createPluginRuntimeStore, mockez le runtime dans les tests :

import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
import type { PluginRuntime } from "openclaw/plugin-sdk/runtime-store";
const store = createPluginRuntimeStore<PluginRuntime>({
pluginId: "test-plugin",
errorMessage: "test runtime not set",
});
// In test setup
const mockRuntime = {
agent: {
resolveAgentDir: vi.fn().mockReturnValue("/tmp/agent"),
// ... other mocks
},
config: {
current: vi.fn(() => ({}) as const),
mutateConfigFile: vi.fn(),
replaceConfigFile: vi.fn(),
},
// ... other namespaces
} as unknown as PluginRuntime;
store.setRuntime(mockRuntime);
// After tests
store.clearRuntime();

Préférez les stubs par instance à la mutation du prototype :

// Preferred: per-instance stub
const client = new MyChannelClient();
client.sendMessage = vi.fn().mockResolvedValue({ id: "msg-1" });
// Avoid: prototype mutation
// MyChannelClient.prototype.sendMessage = vi.fn();

Les plugins regroupés disposent de tests de contrat qui vérifient la propriété de l’enregistrement :

Fenêtre de terminal
pnpm test -- src/plugins/contracts/

Ces tests affirment :

  • Quels plugins enregistrent quels providers
  • Quels plugins enregistrent quels providers de synthèse vocale
  • Correction de la forme de l’enregistrement
  • Conformité du contrat d’exécution

Pour un plugin spécifique :

Fenêtre de terminal
pnpm test -- <bundled-plugin-root>/my-channel/

Pour les tests de contrat uniquement :

Fenêtre de terminal
pnpm test -- src/plugins/contracts/shape.contract.test.ts
pnpm test -- src/plugins/contracts/auth-choice.contract.test.ts
pnpm test -- src/plugins/contracts/runtime-seams.contract.test.ts

Application des règles de lint (plugins dans le dépôt)

Section intitulée « Application des règles de lint (plugins dans le dépôt) »

Trois règles sont appliquées par pnpm check pour les plugins dans le dépôt :

  1. Pas d’imports racine monolithiques — le barrel racine de openclaw/plugin-sdk est rejeté
  2. Pas d’imports directs src/ — les plugins ne peuvent pas importer ../../src/ directement
  3. Pas d’auto-imports — les plugins ne peuvent pas importer leur propre sous-chemin plugin-sdk/<name>

Les plugins externes ne sont pas soumis à ces règles de lint, mais il est recommandé de suivre les mêmes modèles.

OpenClaw utilise Vitest avec des seuils de couverture V8. Pour les tests de plugins :

Fenêtre de terminal
# Run all tests
pnpm test
# Run specific plugin tests
pnpm test -- <bundled-plugin-root>/my-channel/src/channel.test.ts
# Run with a specific test name filter
pnpm test -- <bundled-plugin-root>/my-channel/ -t "resolves account"
# Run with coverage
pnpm test:coverage

Si les exécutions locales provoquent une pression sur la mémoire :

Fenêtre de terminal
OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test