test(plugin-loader): isolate discovery name derivation

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
YeonGyu-Kim
2026-04-05 12:38:27 +09:00
parent 7243bfa483
commit 709706378b
3 changed files with 23 additions and 11 deletions
@@ -16,18 +16,17 @@ function createTemporaryDirectory(prefix: string): string {
describe("discoverInstalledPlugins", () => {
beforeEach(() => {
// Mock logger to avoid noise in test output and force process isolation in CI
mock.module("../../shared/logger", () => ({
log: () => {},
}))
const pluginsHome = createTemporaryDirectory("omo-claude-plugins-")
process.env.CLAUDE_PLUGINS_HOME = pluginsHome
})
afterEach(() => {
mock.restore()
if (originalClaudePluginsHome === undefined) {
delete process.env.CLAUDE_PLUGINS_HOME
} else {
@@ -42,7 +41,6 @@ describe("discoverInstalledPlugins", () => {
it("preserves scoped package name from npm plugin keys", () => {
//#given
const pluginsHome = process.env.CLAUDE_PLUGINS_HOME as string
// Use unique temp directory with scoped path to prevent cross-test contamination
const installPathBase = createTemporaryDirectory("omo-scoped-plugin-")
const installPath = join(installPathBase, "@myorg", "my-plugin")
mkdirSync(installPath, { recursive: true })
@@ -68,7 +66,10 @@ describe("discoverInstalledPlugins", () => {
)
//#when
const discovered = discoverInstalledPlugins({ pluginsHomeOverride: pluginsHome })
const discovered = discoverInstalledPlugins({
pluginsHomeOverride: pluginsHome,
loadPluginManifestOverride: () => null,
})
//#then
expect(discovered.errors).toHaveLength(0)
@@ -79,7 +80,6 @@ describe("discoverInstalledPlugins", () => {
it("derives package name from file URL plugin keys", () => {
//#given
const pluginsHome = process.env.CLAUDE_PLUGINS_HOME as string
// Use unique temp directory directly to prevent cross-test contamination
const installPath = createTemporaryDirectory("omo-fileurl-plugin-")
const databasePath = join(pluginsHome, "installed_plugins.json")
@@ -103,7 +103,10 @@ describe("discoverInstalledPlugins", () => {
)
//#when
const discovered = discoverInstalledPlugins({ pluginsHomeOverride: pluginsHome })
const discovered = discoverInstalledPlugins({
pluginsHomeOverride: pluginsHome,
loadPluginManifestOverride: () => null,
})
//#then
expect(discovered.errors).toHaveLength(0)
@@ -114,7 +117,6 @@ describe("discoverInstalledPlugins", () => {
it("derives canonical package name from npm plugin keys", () => {
//#given
const pluginsHome = process.env.CLAUDE_PLUGINS_HOME as string
// Use unique temp directory directly to prevent cross-test contamination
const installPath = createTemporaryDirectory("omo-npm-plugin-")
const databasePath = join(pluginsHome, "installed_plugins.json")
@@ -138,7 +140,10 @@ describe("discoverInstalledPlugins", () => {
)
//#when
const discovered = discoverInstalledPlugins({ pluginsHomeOverride: pluginsHome })
const discovered = discoverInstalledPlugins({
pluginsHomeOverride: pluginsHome,
loadPluginManifestOverride: () => null,
})
//#then
expect(discovered.errors).toHaveLength(0)
@@ -64,7 +64,7 @@ function loadClaudeSettings(): ClaudeSettings | null {
}
}
function loadPluginManifest(installPath: string): PluginManifest | null {
export function loadPluginManifest(installPath: string): PluginManifest | null {
const manifestPath = join(installPath, ".claude-plugin", "plugin.json")
if (!existsSync(manifestPath)) {
return null
@@ -176,6 +176,7 @@ export function discoverInstalledPlugins(options?: PluginLoaderOptions): PluginL
const settingsEnabledPlugins = settings?.enabledPlugins
const overrideEnabledPlugins = options?.enabledPluginsOverride
const pluginManifestLoader = options?.loadPluginManifestOverride ?? loadPluginManifest
for (const [pluginKey, installation] of extractPluginEntries(db)) {
if (!installation) continue
@@ -196,7 +197,7 @@ export function discoverInstalledPlugins(options?: PluginLoaderOptions): PluginL
continue
}
const manifest = loadPluginManifest(installPath)
const manifest = pluginManifestLoader(installPath)
const pluginName = manifest?.name || derivePluginNameFromKey(pluginKey)
const loadedPlugin: LoadedPlugin = {
@@ -227,6 +227,12 @@ export interface PluginLoaderOptions {
*/
pluginsHomeOverride?: string
/**
* Override plugin manifest loading for testing.
* Return null to force plugin name derivation from the plugin key.
*/
loadPluginManifestOverride?: (installPath: string) => PluginManifest | null
/**
* Override enabled plugins from oh-my-opencode config.
* Key format: "pluginName@marketplace" (e.g., "shell-scripting@claude-code-workflows")