From dd656d973d8441fa9abf09135820889a057d6d18 Mon Sep 17 00:00:00 2001 From: Vincent Koc Date: Tue, 4 Aug 2026 03:33:52 +0800 Subject: [PATCH] test(qa): cover Plugin SDK import topology (#118878) --- .../plugin-public-entrypoint-contracts.yaml | 10 +++++-- .../contracts/plugin-sdk-subpaths.test.ts | 26 ++++++++++++++----- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/qa/scenarios/plugins/plugin-public-entrypoint-contracts.yaml b/qa/scenarios/plugins/plugin-public-entrypoint-contracts.yaml index 5dd3d38629bc..cc2435916d26 100644 --- a/qa/scenarios/plugins/plugin-public-entrypoint-contracts.yaml +++ b/qa/scenarios/plugins/plugin-public-entrypoint-contracts.yaml @@ -6,9 +6,15 @@ scenario: category: plugins.authoring-and-packaging-plugins coverage: primary: + - plugins.root-sdk-entrypoint + - plugins.focused-sdk-imports - plugins.entrypoint-discovery - objective: Verify plugin authors can discover public SDK entrypoints and support status from the maintained catalog and documentation. + - plugins.migration-shims + objective: Verify plugin authors can discover and import the supported root, focused, and migration Plugin SDK entrypoints. successCriteria: + - The supported top-level contract resolves through `openclaw/plugin-sdk/core`. + - Focused Plugin SDK subpaths resolve through their published package exports. + - Deprecated public subpaths remain importable while plugin authors migrate. - Every public SDK catalog entry has a published package export. - Private-local SDK entries stay out of published package exports. - Deprecated entries remain public while their support status is maintained separately. @@ -25,4 +31,4 @@ scenario: execution: kind: vitest path: src/plugins/contracts/plugin-sdk-subpaths.test.ts - summary: Run the public SDK catalog, package export, and documentation classification contract. + summary: Run the Plugin SDK import topology, package export, and documentation classification contract. diff --git a/src/plugins/contracts/plugin-sdk-subpaths.test.ts b/src/plugins/contracts/plugin-sdk-subpaths.test.ts index 5cd97314c691..816bb26db3b2 100644 --- a/src/plugins/contracts/plugin-sdk-subpaths.test.ts +++ b/src/plugins/contracts/plugin-sdk-subpaths.test.ts @@ -1363,8 +1363,17 @@ describe("plugin-sdk subpath exports", () => { >(); }); - it("keeps runtime entry subpaths importable", async () => { + it("keeps the supported root SDK contract importable through core", async () => { const coreSdk = await importResolvedPluginSdkSubpath("openclaw/plugin-sdk/core"); + + expect(coreSdk.definePluginEntry).toBe(coreDirectSdk.definePluginEntry); + expect(coreSdk.optionalStringEnum).toBe(coreDirectSdk.optionalStringEnum); + expect(coreSdk.prepareMemorySystemPromptAddition).toBe( + coreDirectSdk.prepareMemorySystemPromptAddition, + ); + }); + + it("keeps focused SDK subpaths importable", async () => { const channelActionsSdk = await importResolvedPluginSdkSubpath( "openclaw/plugin-sdk/channel-actions", ); @@ -1383,11 +1392,7 @@ describe("plugin-sdk subpath exports", () => { representativeModules.push(await importResolvedPluginSdkSubpath(`openclaw/plugin-sdk/${id}`)); } - expect(coreSdk.definePluginEntry).toBe(pluginEntrySdk.definePluginEntry); - expect(coreSdk.optionalStringEnum).toBe(coreDirectSdk.optionalStringEnum); - expect(coreSdk.prepareMemorySystemPromptAddition).toBe( - coreDirectSdk.prepareMemorySystemPromptAddition, - ); + expect(pluginEntrySdk.definePluginEntry).toBe(coreDirectSdk.definePluginEntry); expect(channelActionsSdk.optionalStringEnum).toBe(channelActionsDirectSdk.optionalStringEnum); expect(channelActionsSdk.stringEnum).toBe(channelActionsDirectSdk.stringEnum); expectSourceMentions("error-runtime", [ @@ -1453,6 +1458,15 @@ describe("plugin-sdk subpath exports", () => { } }); + it("keeps deprecated public SDK shims importable during migrations", async () => { + expect(deprecatedPublicPluginSdkEntrypoints.length).toBeGreaterThan(0); + + for (const subpath of deprecatedPublicPluginSdkEntrypoints) { + const mod = await importResolvedPluginSdkSubpath(`openclaw/plugin-sdk/${subpath}`); + expect(typeof mod, `deprecated subpath ${subpath} should resolve`).toBe("object"); + } + }); + it("keeps repeated silent-token semantics visible through the reply-chunking subpath", async () => { const replyChunkingSdk = await importResolvedPluginSdkSubpath( "openclaw/plugin-sdk/reply-chunking",