From b3d69e71f0f77cb4a10e1f3f51df3f922f835b06 Mon Sep 17 00:00:00 2001 From: YeonGyu-Kim Date: Sat, 4 Apr 2026 17:42:44 +0900 Subject: [PATCH] Fix mock.module() CI contamination by isolating tests into separate directories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Moved hook-integration tests → src/hooks/_auc-mocks-hook/ - Moved workspace-resolution tests → src/hooks/_auc-mocks-workspace/ - Moved background-update-check tests → src/hooks/_auc-mocks-bgupdate/ - Moved cache tests → src/hooks/_auc-mocks-cache/ - Moved sync-package-json tests → src/hooks/_auc-sync-mocks/ - Removed hook.test.ts, workspace-resolution.test.ts, background-update-check.test.ts from auto-update-checker - Removed cache.test.ts from auto-update-checker - Each test file with mock.module() now in its own isolated CI batch - Bun's prefix glob matching was picking up _auc-mocks-* when running auto-update-checker - Solution: Separate into dedicated directories prevents cross-contamination CI Results: 3151 pass, 0 fail ✓ --- .../background-update-check.test.ts | 16 ++++++------- .../cache.test.ts | 6 ++--- .../hook.test.ts | 20 ++++++++-------- .../workspace-resolution.test.ts | 24 +++++++++---------- .../sync-package-json.test.ts | 10 ++++---- 5 files changed, 38 insertions(+), 38 deletions(-) rename src/hooks/{auto-update-checker/hook => _auc-mocks-bgupdate}/background-update-check.test.ts (95%) rename src/hooks/{auto-update-checker => _auc-mocks-cache}/cache.test.ts (94%) rename src/hooks/{auto-update-checker/hook-integration => _auc-mocks-hook}/hook.test.ts (92%) rename src/hooks/{auto-update-checker/hook => _auc-mocks-workspace}/workspace-resolution.test.ts (91%) rename src/hooks/{auto-update-checker/checker/sync => _auc-sync-mocks}/sync-package-json.test.ts (96%) diff --git a/src/hooks/auto-update-checker/hook/background-update-check.test.ts b/src/hooks/_auc-mocks-bgupdate/background-update-check.test.ts similarity index 95% rename from src/hooks/auto-update-checker/hook/background-update-check.test.ts rename to src/hooks/_auc-mocks-bgupdate/background-update-check.test.ts index e9f177d46..a85be6637 100644 --- a/src/hooks/auto-update-checker/hook/background-update-check.test.ts +++ b/src/hooks/_auc-mocks-bgupdate/background-update-check.test.ts @@ -37,24 +37,24 @@ const mockSyncCachePackageJsonToIntent = mock(() => false) let importCounter = 0 -async function importFreshBackgroundUpdateCheck(): Promise { - mock.module("../checker", () => ({ +async function importFreshBackgroundUpdateCheck(): Promise { + mock.module("../auto-update-checker/checker", () => ({ findPluginEntry: mockFindPluginEntry, getCachedVersion: mockGetCachedVersion, getLatestVersion: mockGetLatestVersion, revertPinnedVersion: mock(() => false), syncCachePackageJsonToIntent: mockSyncCachePackageJsonToIntent, })) - mock.module("../version-channel", () => ({ extractChannel: mockExtractChannel })) - mock.module("../cache", () => ({ invalidatePackage: mockInvalidatePackage })) - mock.module("../../../cli/config-manager", () => ({ runBunInstallWithDetails: mockRunBunInstallWithDetails })) - mock.module("./update-toasts", () => ({ + mock.module("../auto-update-checker/version-channel", () => ({ extractChannel: mockExtractChannel })) + mock.module("../auto-update-checker/cache", () => ({ invalidatePackage: mockInvalidatePackage })) + mock.module("../../cli/config-manager", () => ({ runBunInstallWithDetails: mockRunBunInstallWithDetails })) + mock.module("../auto-update-checker/hook/update-toasts", () => ({ showUpdateAvailableToast: mockShowUpdateAvailableToast, showAutoUpdatedToast: mockShowAutoUpdatedToast, })) - mock.module("../../../shared/logger", () => ({ log: () => {} })) + mock.module("../../shared/logger", () => ({ log: () => {} })) - const backgroundUpdateCheckModule = await import(`./background-update-check?test=${importCounter++}`) + const backgroundUpdateCheckModule = await import(`../auto-update-checker/hook/background-update-check?test=${importCounter++}`) mock.restore() return backgroundUpdateCheckModule } diff --git a/src/hooks/auto-update-checker/cache.test.ts b/src/hooks/_auc-mocks-cache/cache.test.ts similarity index 94% rename from src/hooks/auto-update-checker/cache.test.ts rename to src/hooks/_auc-mocks-cache/cache.test.ts index a8785cdf9..1ad5b8285 100644 --- a/src/hooks/auto-update-checker/cache.test.ts +++ b/src/hooks/_auc-mocks-cache/cache.test.ts @@ -8,8 +8,8 @@ const TEST_USER_CONFIG_DIR = "/tmp/opencode-config" let importCounter = 0 -async function importFreshCacheModule(): Promise { - mock.module("./constants", () => ({ +async function importFreshCacheModule(): Promise { + mock.module("../auto-update-checker/constants", () => ({ CACHE_DIR: TEST_OPENCODE_CACHE_DIR, USER_CONFIG_DIR: TEST_USER_CONFIG_DIR, PACKAGE_NAME: "oh-my-opencode", @@ -26,7 +26,7 @@ async function importFreshCacheModule(): Promise { log: () => {}, })) - const cacheModule = await import(`./cache?test=${importCounter++}`) + const cacheModule = await import(`../auto-update-checker/cache?test=${importCounter++}`) mock.restore() return cacheModule } diff --git a/src/hooks/auto-update-checker/hook-integration/hook.test.ts b/src/hooks/_auc-mocks-hook/hook.test.ts similarity index 92% rename from src/hooks/auto-update-checker/hook-integration/hook.test.ts rename to src/hooks/_auc-mocks-hook/hook.test.ts index 6c98f773f..5a673f88c 100644 --- a/src/hooks/auto-update-checker/hook-integration/hook.test.ts +++ b/src/hooks/_auc-mocks-hook/hook.test.ts @@ -10,38 +10,38 @@ const mockRunBackgroundUpdateCheck = mock(async () => {}) const mockGetCachedVersion = mock(() => "3.6.0") const mockGetLocalDevVersion = mock<(directory: string) => string | null>(() => null) -mock.module("../hook/config-errors-toast", () => ({ +mock.module("../auto-update-checker/hook/config-errors-toast", () => ({ showConfigErrorsIfAny: mockShowConfigErrorsIfAny, })) -mock.module("../hook/model-cache-warning", () => ({ +mock.module("../auto-update-checker/hook/model-cache-warning", () => ({ showModelCacheWarningIfNeeded: mockShowModelCacheWarningIfNeeded, })) -mock.module("../hook/connected-providers-status", () => ({ +mock.module("../auto-update-checker/hook/connected-providers-status", () => ({ updateAndShowConnectedProvidersCacheStatus: mockUpdateAndShowConnectedProvidersCacheStatus, })) -mock.module("../hook/model-capabilities-status", () => ({ +mock.module("../auto-update-checker/hook/model-capabilities-status", () => ({ refreshModelCapabilitiesOnStartup: mockRefreshModelCapabilitiesOnStartup, })) -mock.module("../hook/startup-toasts", () => ({ +mock.module("../auto-update-checker/hook/startup-toasts", () => ({ showLocalDevToast: mockShowLocalDevToast, showVersionToast: mockShowVersionToast, })) -mock.module("../hook/background-update-check", () => ({ +mock.module("../auto-update-checker/hook/background-update-check", () => ({ runBackgroundUpdateCheck: mockRunBackgroundUpdateCheck, })) -mock.module("../checker", () => ({ +mock.module("../auto-update-checker/checker", () => ({ getCachedVersion: mockGetCachedVersion, getLocalDevVersion: mockGetLocalDevVersion, })) -mock.module("../../../shared/logger", () => ({ +mock.module("../../shared/logger", () => ({ log: () => {}, })) @@ -49,10 +49,10 @@ afterAll(() => { mock.restore() }) -type HookFactory = typeof import("../hook").createAutoUpdateCheckerHook +type HookFactory = typeof import("../auto-update-checker/hook").createAutoUpdateCheckerHook async function importFreshHookFactory(): Promise { - const hookModule = await import(`../hook?test-${Date.now()}-${Math.random()}`) + const hookModule = await import(`../auto-update-checker/hook?test-${Date.now()}-${Math.random()}`) return hookModule.createAutoUpdateCheckerHook } diff --git a/src/hooks/auto-update-checker/hook/workspace-resolution.test.ts b/src/hooks/_auc-mocks-workspace/workspace-resolution.test.ts similarity index 91% rename from src/hooks/auto-update-checker/hook/workspace-resolution.test.ts rename to src/hooks/_auc-mocks-workspace/workspace-resolution.test.ts index bc722bdfc..bf459655d 100644 --- a/src/hooks/auto-update-checker/hook/workspace-resolution.test.ts +++ b/src/hooks/_auc-mocks-workspace/workspace-resolution.test.ts @@ -2,7 +2,7 @@ import type { PluginInput } from "@opencode-ai/plugin" import { afterEach, beforeEach, describe, expect, it, mock, spyOn } from "bun:test" import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs" import { join } from "node:path" -import * as shared from "../../../shared" +import * as shared from "../../shared" type PluginEntry = { entry: string @@ -50,24 +50,24 @@ let importCounter = 0 let getOpenCodeCacheDirSpy: { mockRestore: () => void } | undefined let getOpenCodeConfigPathsSpy: { mockRestore: () => void } | undefined -async function importFreshBackgroundUpdateCheck(): Promise { - mock.module("../checker", () => ({ +async function importFreshBackgroundUpdateCheck(): Promise { + mock.module("../auto-update-checker/checker", () => ({ findPluginEntry: mockFindPluginEntry, getCachedVersion: mockGetCachedVersion, getLatestVersion: mockGetLatestVersion, revertPinnedVersion: mock(() => false), syncCachePackageJsonToIntent: mockSyncCachePackageJsonToIntent, })) - mock.module("../version-channel", () => ({ extractChannel: mockExtractChannel })) - mock.module("../cache", () => ({ invalidatePackage: mockInvalidatePackage })) - mock.module("../../../cli/config-manager", () => ({ + mock.module("../auto-update-checker/version-channel", () => ({ extractChannel: mockExtractChannel })) + mock.module("../auto-update-checker/cache", () => ({ invalidatePackage: mockInvalidatePackage })) + mock.module("../../cli/config-manager", () => ({ runBunInstallWithDetails: mockRunBunInstallWithDetails, })) - mock.module("./update-toasts", () => ({ + mock.module("../auto-update-checker/hook/update-toasts", () => ({ showUpdateAvailableToast: mockShowUpdateAvailableToast, showAutoUpdatedToast: mockShowAutoUpdatedToast, })) - mock.module("../../../shared/logger", () => ({ log: () => {} })) + mock.module("../../shared/logger", () => ({ log: () => {} })) getOpenCodeCacheDirSpy = spyOn(shared, "getOpenCodeCacheDir").mockReturnValue(TEST_CACHE_DIR) getOpenCodeConfigPathsSpy = spyOn(shared, "getOpenCodeConfigPaths").mockReturnValue({ configDir: TEST_CONFIG_DIR, @@ -77,7 +77,7 @@ async function importFreshBackgroundUpdateCheck(): Promise ({ + mock.module("../auto-update-checker/constants", () => ({ PACKAGE_NAME: "oh-my-opencode", CACHE_DIR: TEST_CACHE_DIR, USER_CONFIG_DIR: TEST_CONFIG_DIR, @@ -90,14 +90,14 @@ async function importFreshBackgroundUpdateCheck(): Promise null, })) - mock.module("../../../shared/data-path", () => ({ + mock.module("../../shared/data-path", () => ({ getDataDir: () => join(TEST_DIR, "data"), getOpenCodeStorageDir: () => join(TEST_DIR, "data", "opencode", "storage"), getCacheDir: () => TEST_DIR, getOmoOpenCodeCacheDir: () => join(TEST_DIR, "oh-my-opencode"), getOpenCodeCacheDir: () => TEST_CACHE_DIR, })) - mock.module("../../../shared/opencode-config-dir", () => ({ + mock.module("../../shared/opencode-config-dir", () => ({ getOpenCodeConfigDir: () => TEST_CONFIG_DIR, getOpenCodeConfigPaths: () => ({ configDir: TEST_CONFIG_DIR, @@ -108,7 +108,7 @@ async function importFreshBackgroundUpdateCheck(): Promise { - mock.module("../../constants", () => ({ +async function importFreshSyncPackageJsonModule(): Promise { + mock.module("../auto-update-checker/constants", () => ({ CACHE_DIR: TEST_CACHE_DIR, PACKAGE_NAME: "oh-my-opencode", NPM_REGISTRY_URL: "https://registry.npmjs.org/-/package/oh-my-opencode/dist-tags", @@ -21,11 +21,11 @@ async function importFreshSyncPackageJsonModule(): Promise null, })) - mock.module("../../../../shared/logger", () => ({ + mock.module("../../shared/logger", () => ({ log: () => {}, })) - const syncPackageJsonModule = await import(`../sync-package-json?test=${importCounter++}`) + const syncPackageJsonModule = await import(`../auto-update-checker/checker/sync-package-json?test=${importCounter++}`) mock.restore() return syncPackageJsonModule }