Pruebas de complementos
Pruebas de complementos
Sección titulada «Pruebas de complementos»Referencia de utilidades de prueba, patrones y aplicación de reglas de lint para complementos de OpenClaw.
Utilidades de prueba
Sección titulada «Utilidades de prueba»Importar: openclaw/plugin-sdk/testing
La subruta de pruebas exporta un conjunto limitado de auxiliares para los autores de complementos:
import { installCommonResolveTargetErrorCases, shouldAckReaction, removeAckReactionAfterReply } from "openclaw/plugin-sdk/testing";Exportaciones disponibles
Sección titulada «Exportaciones disponibles»| Exportación | Propósito |
|---|---|
installCommonResolveTargetErrorCases | Casos de prueba compartidos para el manejo de errores de resolución de objetivos |
shouldAckReaction | Verificar si un canal debe añadir una reacción de acknowledgment |
removeAckReactionAfterReply | Eliminar la reacción de acknowledgment después de la entrega de la respuesta |
La subruta de pruebas también reexporta tipos útiles en los archivos de prueba:
import type { ChannelAccountSnapshot, ChannelGatewayContext, OpenClawConfig, PluginRuntime, RuntimeEnv, MockFn } from "openclaw/plugin-sdk/testing";Prueba de la resolución de objetivos
Sección titulada «Prueba de la resolución de objetivos»Usa installCommonResolveTargetErrorCases para añadir casos de error estándar para la
resolución de objetivos del canal:
import { describe } from "vitest";import { installCommonResolveTargetErrorCases } from "openclaw/plugin-sdk/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", () => { // ... });});Patrones de pruebas
Sección titulada «Patrones de pruebas»Prueba unitaria de un complemento de canal
Sección titulada «Prueba unitaria de un complemento de canal»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"); });});Prueba unitaria de un complemento de proveedor
Sección titulada «Prueba unitaria de un complemento de proveedor»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); });});Simulación del tiempo de ejecución del complemento
Sección titulada «Simulación del tiempo de ejecución del complemento»Para el código que usa createPluginRuntimeStore, simula el tiempo de ejecución en las pruebas:
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";import type { PluginRuntime } from "openclaw/plugin-sdk/runtime-store";
const store = createPluginRuntimeStore<PluginRuntime>("test runtime not set");
// In test setupconst mockRuntime = { agent: { resolveAgentDir: vi.fn().mockReturnValue("/tmp/agent"), // ... other mocks }, config: { loadConfig: vi.fn(), writeConfigFile: vi.fn(), }, // ... other namespaces} as unknown as PluginRuntime;
store.setRuntime(mockRuntime);
// After testsstore.clearRuntime();Pruebas con simulaciones por instancia
Sección titulada «Pruebas con simulaciones por instancia»Prefiera las simulaciones por instancia sobre la mutación del prototipo:
// Preferred: per-instance stubconst client = new MyChannelClient();client.sendMessage = vi.fn().mockResolvedValue({ id: "msg-1" });
// Avoid: prototype mutation// MyChannelClient.prototype.sendMessage = vi.fn();Pruebas de contrato (complementos en el repositorio)
Sección titulada «Pruebas de contrato (complementos en el repositorio)»Los complementos integrados tienen pruebas de contrato que verifican la propiedad del registro:
pnpm test -- src/plugins/contracts/Estas pruebas afirman:
- Qué complementos registran qué proveedores
- Qué complementos registran qué proveedores de voz
- Corrección de la forma del registro
- Cumplimiento del contrato de tiempo de ejecución
Ejecución de pruebas con ámbito
Sección titulada «Ejecución de pruebas con ámbito»Para un complemento específico:
pnpm test -- <bundled-plugin-root>/my-channel/Solo para pruebas de contrato:
pnpm test -- src/plugins/contracts/shape.contract.test.tspnpm test -- src/plugins/contracts/auth.contract.test.tspnpm test -- src/plugins/contracts/runtime.contract.test.tsAplicación de reglas de lint (complementos en el repositorio)
Sección titulada «Aplicación de reglas de lint (complementos en el repositorio)»Tres reglas son aplicadas por pnpm check para los complementos en el repositorio:
- Sin importaciones raíz monolíticas — se rechaza el barril raíz
openclaw/plugin-sdk - Sin importaciones directas de
src/— los complementos no pueden importar../../src/directamente - No hay autoimportaciones — los complementos no pueden importar su propia sub-ruta
plugin-sdk/<name>
Los complementos externos no están sujetos a estas reglas de linting, pero se recomienda seguir los mismos patrones.
Configuración de pruebas
Sección titulada «Configuración de pruebas»OpenClaw usa Vitest con umbrales de cobertura de V8. Para las pruebas de complementos:
# Run all testspnpm test
# Run specific plugin testspnpm test -- <bundled-plugin-root>/my-channel/src/channel.test.ts
# Run with a specific test name filterpnpm test -- <bundled-plugin-root>/my-channel/ -t "resolves account"
# Run with coveragepnpm test:coverageSi las ejecuciones locales causan presión de memoria:
OPENCLAW_TEST_PROFILE=low OPENCLAW_TEST_SERIAL_GATEWAY=1 pnpm testRelacionado
Sección titulada «Relacionado»- Descripción general del SDK — convenciones de importación
- Complementos de canal del SDK — interfaz del complemento de canal
- Complementos de proveedor del SDK — hooks del complemento de proveedor
- Creación de complementos — guía de introducción