Vai al contenuto principale

Test dei plugin

Riferimento per utility di test, pattern e applicazione del lint per i plugin OpenClaw.
Cerchi esempi di test? Le guide how-to includono esempi pratici di test: Test dei plugin di canale e Test dei plugin provider.

Utility di test

Import: openclaw/plugin-sdk/testing Il sottopercorso di test esporta un insieme ristretto di helper per gli autori di plugin:
import {
  installCommonResolveTargetErrorCases,
  shouldAckReaction,
  removeAckReactionAfterReply,
} from "openclaw/plugin-sdk/testing";

Export disponibili

ExportScopo
installCommonResolveTargetErrorCasesCasi di test condivisi per la gestione degli errori di risoluzione del target
shouldAckReactionControlla se un canale deve aggiungere una reazione di ack
removeAckReactionAfterReplyRimuove la reazione di ack dopo la consegna della risposta

Tipi

Il sottopercorso di test riesporta anche tipi utili nei file di test:
import type {
  ChannelAccountSnapshot,
  ChannelGatewayContext,
  OpenClawConfig,
  PluginRuntime,
  RuntimeEnv,
  MockFn,
} from "openclaw/plugin-sdk/testing";

Testare la risoluzione del target

Usa installCommonResolveTargetErrorCases per aggiungere casi di errore standard per la risoluzione del target del canale:
import { describe } from "vitest";
import { installCommonResolveTargetErrorCases } from "openclaw/plugin-sdk/testing";

describe("risoluzione del target my-channel", () => {
  installCommonResolveTargetErrorCases({
    resolveTarget: ({ to, mode, allowFrom }) => {
      // Logica di risoluzione del target del tuo canale
      return myChannelResolveTarget({ to, mode, allowFrom });
    },
    implicitAllowFrom: ["user1", "user2"],
  });

  // Aggiungi casi di test specifici del canale
  it("dovrebbe risolvere i target @username", () => {
    // ...
  });
});

Pattern di test

Test unitario di un plugin di canale

import { describe, it, expect, vi } from "vitest";

describe("plugin my-channel", () => {
  it("dovrebbe risolvere l'account dalla configurazione", () => {
    const cfg = {
      channels: {
        "my-channel": {
          token: "test-token",
          allowFrom: ["user1"],
        },
      },
    };

    const account = myPlugin.setup.resolveAccount(cfg, undefined);
    expect(account.token).toBe("test-token");
  });

  it("dovrebbe ispezionare l'account senza materializzare i segreti", () => {
    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");
    // Nessun valore del token esposto
    expect(inspection).not.toHaveProperty("token");
  });
});

Test unitario di un plugin provider

import { describe, it, expect } from "vitest";

describe("plugin my-provider", () => {
  it("dovrebbe risolvere modelli dinamici", () => {
    const model = myProvider.resolveDynamicModel({
      modelId: "custom-model-v2",
      // ... contesto
    });

    expect(model.id).toBe("custom-model-v2");
    expect(model.provider).toBe("my-provider");
    expect(model.api).toBe("openai-completions");
  });

  it("dovrebbe restituire il catalogo quando è disponibile una chiave API", async () => {
    const result = await myProvider.catalog.run({
      resolveProviderApiKey: () => ({ apiKey: "test-key" }),
      // ... contesto
    });

    expect(result?.provider?.models).toHaveLength(2);
  });
});

Mockare il runtime del plugin

Per il codice che usa createPluginRuntimeStore, effettua il mock del runtime nei test:
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");

// Nel setup del test
const mockRuntime = {
  agent: {
    resolveAgentDir: vi.fn().mockReturnValue("/tmp/agent"),
    // ... altri mock
  },
  config: {
    loadConfig: vi.fn(),
    writeConfigFile: vi.fn(),
  },
  // ... altri namespace
} as unknown as PluginRuntime;

store.setRuntime(mockRuntime);

// Dopo i test
store.clearRuntime();

Testare con stub per istanza

Preferisci stub per istanza invece della mutazione del prototype:
// Preferito: stub per istanza
const client = new MyChannelClient();
client.sendMessage = vi.fn().mockResolvedValue({ id: "msg-1" });

// Da evitare: mutazione del prototype
// MyChannelClient.prototype.sendMessage = vi.fn();

Test di contratto (plugin nel repository)

I plugin inclusi hanno test di contratto che verificano la proprietà della registrazione:
pnpm test -- src/plugins/contracts/
Questi test verificano:
  • Quali plugin registrano quali provider
  • Quali plugin registrano quali provider speech
  • Correttezza della forma di registrazione
  • Conformità del contratto runtime

Eseguire test mirati

Per un plugin specifico:
pnpm test -- <bundled-plugin-root>/my-channel/
Solo per i test di contratto:
pnpm test -- src/plugins/contracts/shape.contract.test.ts
pnpm test -- src/plugins/contracts/auth.contract.test.ts
pnpm test -- src/plugins/contracts/runtime.contract.test.ts

Applicazione del lint (plugin nel repository)

Tre regole sono applicate da pnpm check per i plugin nel repository:
  1. Nessun import monolitico dalla root — il barrel root openclaw/plugin-sdk viene rifiutato
  2. Nessun import diretto da src/ — i plugin non possono importare direttamente ../../src/
  3. Nessun self-import — i plugin non possono importare il proprio sottopercorso plugin-sdk/<name>
I plugin esterni non sono soggetti a queste regole di lint, ma è comunque consigliato seguire gli stessi pattern.

Configurazione dei test

OpenClaw usa Vitest con soglie di copertura V8. Per i test dei plugin:
# Esegui tutti i test
pnpm test

# Esegui test di plugin specifici
pnpm test -- <bundled-plugin-root>/my-channel/src/channel.test.ts

# Esegui con un filtro sul nome del test specifico
pnpm test -- <bundled-plugin-root>/my-channel/ -t "resolves account"

# Esegui con copertura
pnpm test:coverage
Se le esecuzioni locali causano pressione sulla memoria:
OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test

Correlati