메인 콘텐츠로 건너뛰기

Documentation Index

Fetch the complete documentation index at: https://docs.openclaw.ai/llms.txt

Use this file to discover all available pages before exploring further.

OpenClaw Plugin의 테스트 유틸리티, 패턴 및 린트 강제 적용에 대한 참조입니다.
테스트 예제를 찾고 있나요? 방법 가이드에는 실제 테스트 예제가 포함되어 있습니다: Channel Plugin 테스트Provider Plugin 테스트.

테스트 유틸리티

이 테스트 헬퍼 하위 경로는 OpenClaw 자체 번들 Plugin 테스트를 위한 리포지토리 로컬 소스 진입점입니다. 타사 Plugin을 위한 패키지 export가 아닙니다. Plugin API mock import: openclaw/plugin-sdk/plugin-test-api Agent runtime contract import: openclaw/plugin-sdk/agent-runtime-test-contracts Channel contract import: openclaw/plugin-sdk/channel-contract-testing Channel test helper import: openclaw/plugin-sdk/channel-test-helpers Channel target test import: openclaw/plugin-sdk/channel-target-testing Plugin contract import: openclaw/plugin-sdk/plugin-test-contracts Plugin runtime test import: openclaw/plugin-sdk/plugin-test-runtime Provider contract import: openclaw/plugin-sdk/provider-test-contracts Provider HTTP mock import: openclaw/plugin-sdk/provider-http-test-mocks Environment/network test import: openclaw/plugin-sdk/test-env Generic fixture import: openclaw/plugin-sdk/test-fixtures Node builtin mock import: openclaw/plugin-sdk/test-node-mocks 새 Plugin 테스트에는 아래의 집중된 하위 경로를 선호하세요. 광범위한 openclaw/plugin-sdk/testing 배럴은 레거시 호환성 전용입니다. 리포지토리 가드레일은 plugin-sdk/testingplugin-sdk/test-utils에서 새 실제 import를 거부합니다. 이 이름들은 호환성 기록 테스트를 위한 폐기 예정 호환성 표면으로만 남아 있습니다.
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";

사용 가능한 export

내보내기목적
createTestPluginApi직접 등록 단위 테스트용 최소 Plugin 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네이티브 에이전트 런타임 어댑터용 공유 폴백 분류 계약 픽스처입니다. 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디렉터리 목록 함수의 채널 디렉터리 ID를 검증합니다. plugin-sdk/channel-test-helpers에서 가져옵니다
assertBundledChannelEntries번들 채널 엔트리포인트가 예상 공개 계약을 노출하는지 검증합니다. plugin-sdk/channel-test-helpers에서 가져옵니다
formatEnvelopeTimestamp결정적 엔벌로프 타임스탬프를 포맷합니다. plugin-sdk/channel-test-helpers에서 가져옵니다
expectPairingReplyText채널 페어링 응답 텍스트를 검증하고 해당 코드를 추출합니다. plugin-sdk/channel-test-helpers에서 가져옵니다
describePluginRegistrationContractPlugin 등록 계약 검사를 설치합니다. plugin-sdk/plugin-test-contracts에서 가져옵니다
registerSingleProviderPlugin로더 스모크 테스트에서 하나의 제공자 Plugin을 등록합니다. plugin-sdk/plugin-test-runtime에서 가져옵니다
registerProviderPlugin하나의 Plugin에서 모든 제공자 종류를 캡처합니다. plugin-sdk/plugin-test-runtime에서 가져옵니다
registerProviderPlugins여러 Plugin에 걸쳐 제공자 등록을 캡처합니다. plugin-sdk/plugin-test-runtime에서 가져옵니다
requireRegisteredProvider제공자 컬렉션에 ID가 포함되어 있는지 검증합니다. plugin-sdk/plugin-test-runtime에서 가져옵니다
createRuntimeEnv목 처리된 CLI/Plugin 런타임 환경을 빌드합니다. plugin-sdk/plugin-test-runtime에서 가져옵니다
createPluginSetupWizardStatus채널 Plugins용 설정 상태 헬퍼를 빌드합니다. plugin-sdk/plugin-test-runtime에서 가져옵니다
describeOpenAIProviderRuntimeContract제공자 패밀리 런타임 계약 검사를 설치합니다. plugin-sdk/provider-test-contracts에서 가져옵니다
expectPassthroughReplayPolicy제공자 재생 정책이 제공자 소유 도구와 메타데이터를 그대로 전달하는지 검증합니다. plugin-sdk/provider-test-contracts에서 가져옵니다
runRealtimeSttLiveTest공유 오디오 픽스처로 라이브 실시간 음성-텍스트 변환 제공자 테스트를 실행합니다. plugin-sdk/provider-test-contracts에서 가져옵니다
normalizeTranscriptForMatch퍼지 검증 전에 라이브 트랜스크립트 출력을 정규화합니다. 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옵트인 제공자 HTTP/인증 Vitest 목에 접근합니다. plugin-sdk/provider-http-test-mocks에서 가져옵니다
installProviderHttpMockCleanup각 테스트 후 제공자 HTTP/인증 목을 재설정합니다. plugin-sdk/provider-http-test-mocks에서 가져옵니다
installCommonResolveTargetErrorCases대상 확인 오류 처리를 위한 공유 테스트 케이스입니다. plugin-sdk/channel-target-testing에서 가져옵니다
shouldAckReaction채널이 확인 반응을 추가해야 하는지 확인합니다. plugin-sdk/channel-feedback에서 가져옵니다
removeAckReactionAfterReply응답 전달 후 확인 반응을 제거합니다. plugin-sdk/channel-feedback에서 가져옵니다
createTestRegistry채널 Plugin 레지스트리 픽스처를 빌드합니다. plugin-sdk/plugin-test-runtime 또는 plugin-sdk/channel-test-helpers에서 가져옵니다
createEmptyPluginRegistry빈 Plugin 레지스트리 픽스처를 빌드합니다. plugin-sdk/plugin-test-runtime 또는 plugin-sdk/channel-test-helpers에서 가져옵니다
setActivePluginRegistryPlugin 런타임 테스트용 레지스트리 픽스처를 설치합니다. plugin-sdk/plugin-test-runtime 또는 plugin-sdk/channel-test-helpers에서 가져옵니다
createRequestCaptureJsonFetch미디어 헬퍼 테스트에서 JSON 가져오기 요청을 캡처합니다. plugin-sdk/test-env에서 가져옵니다
withServer일회용 로컬 HTTP 서버를 대상으로 테스트를 실행합니다. plugin-sdk/test-env에서 가져옵니다
createMockIncomingRequest최소 인바운드 HTTP 요청 객체를 빌드합니다. plugin-sdk/test-env에서 가져옵니다
withFetchPreconnect사전 연결 훅이 설치된 상태로 가져오기 테스트를 실행합니다. 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번들 Plugin 소스 또는 배포 픽스처 경로를 확인합니다. plugin-sdk/test-fixtures에서 가져옵니다
mockNodeBuiltinModule좁은 범위의 Node 내장 Vitest 목을 설치합니다. plugin-sdk/test-node-mocks에서 가져옵니다
createSandboxTestContext샌드박스 테스트 컨텍스트를 빌드합니다. plugin-sdk/test-fixtures에서 가져옵니다
writeSkillSkills 픽스처를 작성합니다. 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검증용 제공자 마법사 선택 ID를 빌드합니다
setProviderWizardProvidersResolverForTest격리된 테스트용 제공자 마법사 제공자를 주입합니다
createProviderUsageFetch제공자 사용량 가져오기 픽스처를 빌드합니다
useFrozenTime / useRealTime시간에 민감한 테스트를 위해 타이머를 고정하고 복원합니다. plugin-sdk/test-env에서 가져옵니다
createTestWizardPrompter모의 설정 마법사 프롬프터를 빌드합니다
createRuntimeTaskFlow격리된 런타임 task-flow 상태를 생성합니다
typedCases테이블 기반 테스트의 리터럴 타입을 보존합니다. plugin-sdk/test-fixtures에서 가져옵니다
번들 Plugin 계약 스위트도 테스트 전용 registry, manifest, public-artifact, runtime fixture 헬퍼를 위해 SDK 테스트 하위 경로를 사용합니다. 번들 OpenClaw 인벤토리에 의존하는 코어 전용 스위트는 src/plugins/contracts 아래에 둡니다. 새 확장 테스트는 넓은 plugin-sdk/testing 호환성 barrel, repo src/** 파일, repo test/helpers/* 브리지를 직접 가져오는 대신 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 같은 문서화된 집중 SDK 하위 경로에 둡니다.

타입

집중 테스트 하위 경로는 테스트 파일에서 유용한 타입도 다시 내보냅니다.
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 mock을 register(api)에 전달하는 단위 테스트는 OpenClaw의 로더 승인 게이트를 실행하지 않습니다. Plugin이 의존하는 각 등록 표면마다, 특히 hook과 memory 같은 독점 capability에는 로더 기반 smoke test를 하나 이상 추가하세요. 필수 메타데이터가 누락되었거나 Plugin이 소유하지 않은 capability API를 호출하면 실제 로더는 Plugin 등록에 실패합니다. 예를 들어 api.registerHook(...)에는 hook 이름이 필요하고, api.registerMemoryCapability(...)에는 Plugin manifest 또는 내보낸 엔트리가 kind: "memory"를 선언해야 합니다.

runtime config 접근 테스트

번들 채널 Plugin을 테스트할 때는 openclaw/plugin-sdk/channel-test-helpers의 공유 Plugin runtime mock을 선호하세요. deprecated된 runtime.config.loadConfig()runtime.config.writeConfigFile(...) mock은 기본적으로 throw하므로 테스트가 호환성 API의 새 사용을 잡아낼 수 있습니다. 테스트가 레거시 호환성 동작을 명시적으로 다루는 경우에만 해당 mock을 override하세요.

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

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

Plugin runtime mock 처리

createPluginRuntimeStore를 사용하는 코드의 경우 테스트에서 runtime을 mock 처리합니다.
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();

인스턴스별 stub으로 테스트

prototype 변경보다 인스턴스별 stub을 선호하세요.
// Preferred: per-instance stub
const client = new MyChannelClient();
client.sendMessage = vi.fn().mockResolvedValue({ id: "msg-1" });

// Avoid: prototype mutation
// MyChannelClient.prototype.sendMessage = vi.fn();

계약 테스트(repo 내부 Plugin)

번들 Plugin에는 등록 소유권을 검증하는 계약 테스트가 있습니다.
pnpm test -- src/plugins/contracts/
이 테스트들은 다음을 assert합니다.
  • 어떤 Plugin이 어떤 provider를 등록하는지
  • 어떤 Plugin이 어떤 speech provider를 등록하는지
  • 등록 형태의 정확성
  • runtime 계약 준수

범위 지정 테스트 실행

특정 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 강제(repo 내부 Plugin)

repo 내부 Plugin에는 pnpm check가 세 가지 규칙을 강제합니다.
  1. monolithic root import 금지openclaw/plugin-sdk root barrel은 거부됩니다
  2. 직접 src/ import 금지 — Plugin은 ../../src/를 직접 가져올 수 없습니다
  3. self-import 금지 — Plugin은 자신의 plugin-sdk/<name> 하위 경로를 가져올 수 없습니다
외부 Plugin에는 이 lint 규칙이 적용되지 않지만, 같은 패턴을 따르는 것을 권장합니다.

테스트 구성

OpenClaw는 V8 coverage threshold와 함께 Vitest를 사용합니다. 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

관련 문서