Перейти до основного вмісту
Довідник із тестових утиліт, патернів і примусового застосування lint для Plugin OpenClaw.
Шукаєте приклади тестів? Практичні посібники містять опрацьовані приклади тестів: Тести Plugin каналу і Тести Plugin провайдера.

Тестові утиліти

Ці підшляхи тестових помічників є локальними для репозиторію вхідними точками вихідного коду для власних тестів bundled Plugin OpenClaw. Вони не є експортами пакета для сторонніх Plugin і можуть імпортувати Vitest або інші тестові залежності, доступні лише в репозиторії. Імпорт mock Plugin API: openclaw/plugin-sdk/plugin-test-api Імпорт контракту runtime агента: openclaw/plugin-sdk/agent-runtime-test-contracts Імпорт контракту каналу: openclaw/plugin-sdk/channel-contract-testing Імпорт тестового помічника каналу: openclaw/plugin-sdk/channel-test-helpers Імпорт тесту цілі каналу: openclaw/plugin-sdk/channel-target-testing Імпорт контракту Plugin: openclaw/plugin-sdk/plugin-test-contracts Імпорт тесту runtime Plugin: openclaw/plugin-sdk/plugin-test-runtime Імпорт контракту провайдера: openclaw/plugin-sdk/provider-test-contracts Імпорт HTTP mock провайдера: openclaw/plugin-sdk/provider-http-test-mocks Імпорт тесту середовища/мережі: openclaw/plugin-sdk/test-env Імпорт узагальненої фікстури: openclaw/plugin-sdk/test-fixtures Імпорт mock вбудованого модуля Node: openclaw/plugin-sdk/test-node-mocks У репозиторії OpenClaw для нових тестів bundled Plugin віддавайте перевагу наведеним нижче спеціалізованим підшляхам. Широкий barrel openclaw/plugin-sdk/testing призначений лише для legacy сумісності. Захисні правила репозиторію відхиляють нові реальні імпорти з plugin-sdk/testing і plugin-sdk/test-utils; ці назви залишаються лише як застарілі поверхні сумісності для тестів записів сумісності.
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";

Доступні експорти

ЕкспортПризначення
createTestPluginApiСтворює мінімальний мок API плагіна для модульних тестів прямої реєстрації. Імпортуйте з plugin-sdk/plugin-test-api
AUTH_PROFILE_RUNTIME_CONTRACTСпільна фікстура контракту профілю автентифікації для нативних адаптерів середовища виконання агента. Імпортуйте з plugin-sdk/agent-runtime-test-contracts
DELIVERY_NO_REPLY_RUNTIME_CONTRACTСпільна фікстура контракту пригнічення доставки для нативних адаптерів середовища виконання агента. Імпортуйте з plugin-sdk/agent-runtime-test-contracts
OUTCOME_FALLBACK_RUNTIME_CONTRACTСпільна фікстура контракту fallback-класифікації для нативних адаптерів середовища виконання агента. Імпортуйте з plugin-sdk/agent-runtime-test-contracts
createParameterFreeToolСтворює фікстури схем динамічних інструментів для тестів контракту нативного середовища виконання. Імпортуйте з plugin-sdk/agent-runtime-test-contracts
expectChannelInboundContextContractПеревіряє форму вхідного контексту каналу. Імпортуйте з plugin-sdk/channel-contract-testing
installChannelOutboundPayloadContractSuiteВстановлює набори випадків контракту вихідного корисного навантаження каналу. Імпортуйте з plugin-sdk/channel-contract-testing
createStartAccountContextСтворює контексти життєвого циклу облікового запису каналу. Імпортуйте з plugin-sdk/channel-test-helpers
installChannelActionsContractSuiteВстановлює загальні випадки контракту дій повідомлень каналу. Імпортуйте з plugin-sdk/channel-test-helpers
installChannelSetupContractSuiteВстановлює загальні випадки контракту налаштування каналу. Імпортуйте з plugin-sdk/channel-test-helpers
installChannelStatusContractSuiteВстановлює загальні випадки контракту статусу каналу. Імпортуйте з plugin-sdk/channel-test-helpers
expectDirectoryIdsПеревіряє ідентифікатори каталогів каналу з функції списку каталогів. Імпортуйте з plugin-sdk/channel-test-helpers
assertBundledChannelEntriesПеревіряє, що вбудовані точки входу каналу відкривають очікуваний публічний контракт. Імпортуйте з plugin-sdk/channel-test-helpers
formatEnvelopeTimestampФорматує детерміновані часові позначки конвертів. Імпортуйте з plugin-sdk/channel-test-helpers
expectPairingReplyTextПеревіряє текст відповіді сполучення каналу й витягує його код. Імпортуйте з plugin-sdk/channel-test-helpers
describePluginRegistrationContractВстановлює перевірки контракту реєстрації плагіна. Імпортуйте з plugin-sdk/plugin-test-contracts
registerSingleProviderPluginРеєструє один плагін провайдера в smoke-тестах завантажувача. Імпортуйте з plugin-sdk/plugin-test-runtime
registerProviderPluginЗахоплює всі типи провайдерів з одного плагіна. Імпортуйте з plugin-sdk/plugin-test-runtime
registerProviderPluginsЗахоплює реєстрації провайдерів у кількох плагінах. Імпортуйте з plugin-sdk/plugin-test-runtime
requireRegisteredProviderПеревіряє, що колекція провайдерів містить ідентифікатор. Імпортуйте з plugin-sdk/plugin-test-runtime
createRuntimeEnvСтворює моковане середовище виконання CLI/плагіна. Імпортуйте з plugin-sdk/plugin-test-runtime
createPluginRuntimeMockСтворює моковану поверхню середовища виконання плагіна. Імпортуйте з plugin-sdk/plugin-test-runtime
createPluginSetupWizardStatusСтворює помічники статусу налаштування для плагінів каналів. Імпортуйте з plugin-sdk/plugin-test-runtime
describeOpenAIProviderRuntimeContractВстановлює перевірки контракту середовища виконання сімейства провайдерів. Імпортуйте з plugin-sdk/provider-test-contracts
expectPassthroughReplayPolicyПеревіряє, що політики повторного відтворення провайдера пропускають інструменти й метадані, якими володіє провайдер. Імпортуйте з plugin-sdk/provider-test-contracts
runRealtimeSttLiveTestЗапускає live-тест провайдера realtime STT зі спільними аудіофікстурами. Імпортуйте з plugin-sdk/provider-test-contracts
normalizeTranscriptForMatchНормалізує вивід live-транскрипту перед нечіткими перевірками. Імпортуйте з plugin-sdk/provider-test-contracts
expectExplicitVideoGenerationCapabilitiesПеревіряє, що відеопровайдери оголошують явні можливості режиму генерації. Імпортуйте з plugin-sdk/provider-test-contracts
expectExplicitMusicGenerationCapabilitiesПеревіряє, що музичні провайдери оголошують явні можливості генерації/редагування. Імпортуйте з plugin-sdk/provider-test-contracts
mockSuccessfulDashscopeVideoTaskВстановлює успішну відповідь відеозавдання, сумісну з DashScope. Імпортуйте з plugin-sdk/provider-test-contracts
getProviderHttpMocksНадає доступ до opt-in HTTP/auth моків Vitest для провайдера. Імпортуйте з plugin-sdk/provider-http-test-mocks
installProviderHttpMockCleanupСкидає HTTP/auth моки провайдера після кожного тесту. Імпортуйте з plugin-sdk/provider-http-test-mocks
installCommonResolveTargetErrorCasesСпільні тестові випадки для обробки помилок розв’язання цілі. Імпортуйте з plugin-sdk/channel-target-testing
shouldAckReactionПеревіряє, чи канал має додати реакцію підтвердження. Імпортуйте з plugin-sdk/channel-feedback
removeAckReactionAfterReplyВидаляє реакцію підтвердження після доставки відповіді. Імпортуйте з plugin-sdk/channel-feedback
createTestRegistryСтворює фікстуру реєстру плагінів каналів. Імпортуйте з plugin-sdk/plugin-test-runtime або plugin-sdk/channel-test-helpers
createEmptyPluginRegistryСтворює фікстуру порожнього реєстру плагінів. Імпортуйте з plugin-sdk/plugin-test-runtime або plugin-sdk/channel-test-helpers
setActivePluginRegistryВстановлює фікстуру реєстру для тестів середовища виконання плагінів. Імпортуйте з plugin-sdk/plugin-test-runtime або plugin-sdk/channel-test-helpers
createRequestCaptureJsonFetchЗахоплює JSON-запити fetch у тестах медіапомічників. Імпортуйте з plugin-sdk/test-env
withServerЗапускає тести проти одноразового локального HTTP-сервера. Імпортуйте з plugin-sdk/test-env
createMockIncomingRequestСтворює мінімальний об’єкт вхідного HTTP-запиту. Імпортуйте з plugin-sdk/test-env
withFetchPreconnectЗапускає тести fetch зі встановленими хуками попереднього з’єднання. Імпортуйте з plugin-sdk/test-env
withEnv / withEnvAsyncТимчасово змінює змінні середовища. Імпортуйте з plugin-sdk/test-env
createTempHomeEnv / withTempHome / withTempDirСтворює ізольовані файлові тестові фікстури. Імпортуйте з plugin-sdk/test-env
createMockServerResponseСтворює мінімальний мок відповіді HTTP-сервера. Імпортуйте з plugin-sdk/test-env
createCliRuntimeCaptureЗахоплює вивід середовища виконання CLI у тестах. Імпортуйте з plugin-sdk/test-fixtures
importFreshModuleІмпортує ESM-модуль зі свіжим токеном запиту, щоб обійти кеш модулів. Імпортуйте з plugin-sdk/test-fixtures
bundledPluginRoot / bundledPluginFileРозв’язує шляхи до фікстур джерел або dist вбудованого плагіна. Імпортуйте з plugin-sdk/test-fixtures
mockNodeBuiltinModuleВстановлює вузькі моки вбудованих модулів Node для Vitest. Імпортуйте з plugin-sdk/test-node-mocks
createSandboxTestContextСтворює контексти тестів пісочниці. Імпортуйте з plugin-sdk/test-fixtures
writeSkillЗаписує фікстури Skills. Імпортуйте з plugin-sdk/test-fixtures
makeAgentAssistantMessageСтворює фікстури повідомлень транскрипту агента. Імпортуйте з plugin-sdk/test-fixtures
peekSystemEvents / resetSystemEventsForTestПереглядає та скидає фікстури системних подій. Імпортуйте з plugin-sdk/test-fixtures
sanitizeTerminalTextСанітизує вивід термінала для тверджень. Імпортуйте з plugin-sdk/test-fixtures
countLines / hasBalancedFencesПеревіряє форму виводу розбиття на фрагменти. Імпортуйте з plugin-sdk/test-fixtures
runProviderCatalogВиконує хук каталогу провайдера з тестовими залежностями
resolveProviderWizardOptionsРозв’язує варіанти майстра налаштування провайдера в тестах контракту
resolveProviderModelPickerEntriesРозв’язує записи вибору моделей провайдера в тестах контракту
buildProviderPluginMethodChoiceСтворює ідентифікатори вибору майстра провайдера для тверджень
setProviderWizardProvidersResolverForTestВпровадити провайдери майстра провайдера для ізольованих тестів
createProviderUsageFetchСтворити фікстури отримання даних про використання провайдера
useFrozenTime / useRealTimeЗаморозити й відновити таймери для тестів, чутливих до часу. Імпортуйте з plugin-sdk/test-env
createTestWizardPrompterСтворити імітований prompter майстра налаштування
createRuntimeTaskFlowСтворити ізольований стан TaskFlow середовища виконання
typedCasesЗберегти літеральні типи для табличних тестів. Імпортуйте з plugin-sdk/test-fixtures
Набори контрактних тестів для вбудованих Plugin-ів також використовують тестові підшляхи SDK для допоміжних засобів тестового реєстру, маніфесту, публічних артефактів і runtime fixture. Набори тестів лише для core, які залежать від інвентарю вбудованого OpenClaw, залишаються в src/plugins/contracts. Нові тести extension тримайте на задокументованому сфокусованому підшляху SDK, як-от 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 або plugin-sdk/test-fixtures, замість прямого імпорту широкого сумісного barrel-експорту plugin-sdk/testing, файлів репозиторію src/** або мостів репозиторію test/helpers/*.

Типи

Сфокусовані тестові підшляхи також реекспортують типи, корисні у тестових файлах:
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";

Тестування розв’язання цілі

Використовуйте installCommonResolveTargetErrorCases, щоб додати стандартні помилкові випадки для розв’язання цілі каналу:
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", () => {
    // ...
  });
});

Шаблони тестування

Тестування контрактів реєстрації

Модульні тести, які передають власноруч написаний мок api до register(api), не перевіряють acceptance gates завантажувача OpenClaw. Додайте принаймні один smoke-тест на основі завантажувача для кожної реєстраційної поверхні, від якої залежить ваш Plugin, особливо для hooks і ексклюзивних можливостей, як-от memory. Справжній завантажувач зупиняє реєстрацію Plugin-а, коли бракує обов’язкових метаданих або Plugin викликає API можливості, якою він не володіє. Наприклад, api.registerHook(...) вимагає назву hook, а api.registerMemoryCapability(...) вимагає, щоб маніфест Plugin-а або експортований entry оголошував kind: "memory".

Тестування доступу до runtime-конфігурації

Віддавайте перевагу спільному моку runtime Plugin-а з openclaw/plugin-sdk/plugin-test-runtime. Його застарілі моки runtime.config.loadConfig() і runtime.config.writeConfigFile(...) за замовчуванням викидають помилку, щоб тести ловили нове використання API сумісності. Перевизначайте ці моки лише тоді, коли тест явно покриває застарілу поведінку сумісності.

Модульне тестування Plugin-а каналу

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");
  });
});

Модульне тестування Plugin-а провайдера

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);
  });
});

Мок runtime Plugin-а

Для коду, який використовує createPluginRuntimeStore, мокуйте runtime у тестах:
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();

Тестування з per-instance stubs

Віддавайте перевагу per-instance stubs замість мутації 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();

Контрактні тести (Plugin-и в репозиторії)

Вбудовані Plugin-и мають контрактні тести, які перевіряють володіння реєстрацією:
pnpm test -- src/plugins/contracts/
Ці тести перевіряють:
  • Які Plugin-и реєструють яких провайдерів
  • Які Plugin-и реєструють яких провайдерів мовлення
  • Коректність форми реєстрації
  • Відповідність runtime-контракту

Запуск scoped tests

Для конкретного Plugin-а:
pnpm test -- <bundled-plugin-root>/my-channel/
Лише для контрактних тестів:
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

Примусове застосування lint (Plugin-и в репозиторії)

Для Plugin-ів у репозиторії pnpm check примусово застосовує три правила:
  1. Жодних монолітних root-імпортів — root barrel openclaw/plugin-sdk відхиляється
  2. Жодних прямих імпортів src/ — Plugin-и не можуть напряму імпортувати ../../src/
  3. Жодних self-imports — Plugin-и не можуть імпортувати власний підшлях plugin-sdk/<name>
Зовнішні Plugin-и не підпадають під ці правила lint, але рекомендується дотримуватися тих самих шаблонів.

Конфігурація тестів

OpenClaw використовує Vitest із порогами покриття V8. Для тестів Plugin-ів:
# 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
Якщо локальні запуски спричиняють тиск на пам’ять:
OPENCLAW_VITEST_MAX_WORKERS=1 pnpm test

Пов’язане