From 52150fb60b7bed467e57c6d6816eef7dfefb7d99 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sun, 5 Apr 2026 13:51:11 +0900 Subject: [PATCH] fix(test): use dynamic import in discovery tests to prevent mock.module leak from loader.test.ts When run-ci-tests.ts groups the claude-code-plugin-loader directory, loader.test.ts mocks ./discovery with name: 'demo'. This mock leaked into discovery.test.ts because both ran in the same process. Fix: dynamic import with cache-busting query string ensures each test gets a fresh module instance, immune to sibling test mocks. --- .../claude-code-plugin-loader/discovery.test.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/features/claude-code-plugin-loader/discovery.test.ts b/src/features/claude-code-plugin-loader/discovery.test.ts index ca939966a..6e3e1cd34 100644 --- a/src/features/claude-code-plugin-loader/discovery.test.ts +++ b/src/features/claude-code-plugin-loader/discovery.test.ts @@ -3,7 +3,10 @@ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs" import { tmpdir } from "node:os" import { join } from "node:path" -import { discoverInstalledPlugins } from "./discovery" +// NOTE: Do NOT import discoverInstalledPlugins at top level. +// loader.test.ts in the same directory mocks "./discovery" with name: "demo", +// and when run-ci-tests.ts groups this directory together, that mock leaks. +// Dynamic import inside each test avoids the contamination. const originalClaudePluginsHome = process.env.CLAUDE_PLUGINS_HOME const temporaryDirectories: string[] = [] @@ -38,7 +41,7 @@ describe("discoverInstalledPlugins", () => { } }) - it("preserves scoped package name from npm plugin keys", () => { + it("preserves scoped package name from npm plugin keys", async () => { //#given const pluginsHome = process.env.CLAUDE_PLUGINS_HOME as string const installPathBase = createTemporaryDirectory("omo-scoped-plugin-") @@ -66,6 +69,7 @@ describe("discoverInstalledPlugins", () => { ) //#when + const { discoverInstalledPlugins } = await import(`./discovery?t=${Date.now()}-1`) const discovered = discoverInstalledPlugins({ pluginsHomeOverride: pluginsHome, loadPluginManifestOverride: () => null, @@ -77,7 +81,7 @@ describe("discoverInstalledPlugins", () => { expect(discovered.plugins[0]?.name).toBe("@myorg/my-plugin") }) - it("derives package name from file URL plugin keys", () => { + it("derives package name from file URL plugin keys", async () => { //#given const pluginsHome = process.env.CLAUDE_PLUGINS_HOME as string const installPath = createTemporaryDirectory("omo-fileurl-plugin-") @@ -103,6 +107,7 @@ describe("discoverInstalledPlugins", () => { ) //#when + const { discoverInstalledPlugins } = await import(`./discovery?t=${Date.now()}-2`) const discovered = discoverInstalledPlugins({ pluginsHomeOverride: pluginsHome, loadPluginManifestOverride: () => null, @@ -114,7 +119,7 @@ describe("discoverInstalledPlugins", () => { expect(discovered.plugins[0]?.name).toBe("oh-my-opencode") }) - it("derives canonical package name from npm plugin keys", () => { + it("derives canonical package name from npm plugin keys", async () => { //#given const pluginsHome = process.env.CLAUDE_PLUGINS_HOME as string const installPath = createTemporaryDirectory("omo-npm-plugin-") @@ -140,6 +145,7 @@ describe("discoverInstalledPlugins", () => { ) //#when + const { discoverInstalledPlugins } = await import(`./discovery?t=${Date.now()}-3`) const discovered = discoverInstalledPlugins({ pluginsHomeOverride: pluginsHome, loadPluginManifestOverride: () => null,