Merge pull request #2841 from code-yeongyu/fix/model-fallback-test-isolation
fix(tests): resolve 5 cross-file test isolation failures
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
import { afterEach, describe, expect, it } from "bun:test"
|
||||
import { mkdirSync, mkdtempSync, realpathSync, rmSync, symlinkSync, writeFileSync } from "node:fs"
|
||||
import { mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from "node:fs"
|
||||
import { tmpdir } from "node:os"
|
||||
import { dirname, join } from "node:path"
|
||||
|
||||
import { PACKAGE_NAME } from "../constants"
|
||||
import { resolveSymlink } from "../../../shared/file-utils"
|
||||
|
||||
const systemLoadedVersionModulePath = "./system-loaded-version?system-loaded-version-test"
|
||||
|
||||
@@ -125,7 +126,7 @@ describe("system loaded version", () => {
|
||||
const loadedVersion = getLoadedPluginVersion()
|
||||
|
||||
//#then
|
||||
expect(loadedVersion.cacheDir).toBe(realpathSync(symlinkConfigDir))
|
||||
expect(loadedVersion.cacheDir).toBe(resolveSymlink(symlinkConfigDir))
|
||||
expect(loadedVersion.expectedVersion).toBe("4.5.6")
|
||||
expect(loadedVersion.loadedVersion).toBe("4.5.6")
|
||||
})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { existsSync, readFileSync, realpathSync } from "node:fs"
|
||||
import { existsSync, readFileSync } from "node:fs"
|
||||
import { homedir } from "node:os"
|
||||
import { join } from "node:path"
|
||||
|
||||
import { resolveSymlink } from "../../../shared/file-utils"
|
||||
import { getLatestVersion } from "../../../hooks/auto-update-checker/checker"
|
||||
import { extractChannel } from "../../../hooks/auto-update-checker"
|
||||
import { PACKAGE_NAME } from "../constants"
|
||||
@@ -38,12 +38,7 @@ function resolveOpenCodeCacheDir(): string {
|
||||
|
||||
function resolveExistingDir(dirPath: string): string {
|
||||
if (!existsSync(dirPath)) return dirPath
|
||||
|
||||
try {
|
||||
return realpathSync(dirPath)
|
||||
} catch {
|
||||
return dirPath
|
||||
}
|
||||
return resolveSymlink(dirPath)
|
||||
}
|
||||
|
||||
function readPackageJson(filePath: string): PackageJsonShape | null {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, test, expect, mock, beforeEach } from "bun:test"
|
||||
import { afterAll, beforeEach, describe, expect, mock, test } from "bun:test"
|
||||
|
||||
mock.module("../../shared", () => ({
|
||||
log: mock(() => {}),
|
||||
@@ -82,6 +82,10 @@ function createDefaultArgs(taskOverrides: Partial<BackgroundTask> = {}) {
|
||||
}
|
||||
|
||||
describe("tryFallbackRetry", () => {
|
||||
afterAll(() => {
|
||||
mock.restore()
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
;(shouldRetryError as any).mockImplementation(() => true)
|
||||
;(selectFallbackProvider as any).mockImplementation((providers: string[]) => providers[0])
|
||||
@@ -274,8 +278,8 @@ describe("tryFallbackRetry", () => {
|
||||
|
||||
describe("#given disconnected fallback providers with connected preferred provider", () => {
|
||||
test("keeps fallback entry and selects connected preferred provider", () => {
|
||||
;(readProviderModelsCache as any).mockReturnValue({ connected: ["provider-a"] })
|
||||
;(selectFallbackProvider as any).mockImplementation(
|
||||
;(readProviderModelsCache as any).mockReturnValueOnce({ connected: ["provider-a"] })
|
||||
;(selectFallbackProvider as any).mockImplementationOnce(
|
||||
(_providers: string[], preferredProviderID?: string) => preferredProviderID ?? "provider-b",
|
||||
)
|
||||
|
||||
|
||||
@@ -3,6 +3,24 @@ const { beforeEach, describe, expect, mock, test } = require("bun:test")
|
||||
|
||||
const readConnectedProvidersCacheMock = mock(() => null)
|
||||
const readProviderModelsCacheMock = mock(() => null)
|
||||
const selectFallbackProviderMock = mock((providers: string[], preferredProviderID?: string) => {
|
||||
const connectedProviders = readConnectedProvidersCacheMock()
|
||||
if (connectedProviders) {
|
||||
const connectedSet = new Set(connectedProviders.map((provider: string) => provider.toLowerCase()))
|
||||
|
||||
for (const provider of providers) {
|
||||
if (connectedSet.has(provider.toLowerCase())) {
|
||||
return provider
|
||||
}
|
||||
}
|
||||
|
||||
if (preferredProviderID && connectedSet.has(preferredProviderID.toLowerCase())) {
|
||||
return preferredProviderID
|
||||
}
|
||||
}
|
||||
|
||||
return providers[0] || preferredProviderID || "opencode"
|
||||
})
|
||||
const transformModelForProviderMock = mock((provider: string, model: string) => {
|
||||
if (provider === "github-copilot") {
|
||||
return model
|
||||
@@ -31,6 +49,10 @@ mock.module("../../shared/provider-model-id-transform", () => ({
|
||||
transformModelForProvider: transformModelForProviderMock,
|
||||
}))
|
||||
|
||||
mock.module("../../shared/model-error-classifier", () => ({
|
||||
selectFallbackProvider: selectFallbackProviderMock,
|
||||
}))
|
||||
|
||||
import {
|
||||
clearPendingModelFallback,
|
||||
createModelFallbackHook,
|
||||
@@ -44,6 +66,7 @@ describe("model fallback hook", () => {
|
||||
readProviderModelsCacheMock.mockReturnValue(null)
|
||||
readConnectedProvidersCacheMock.mockClear()
|
||||
readProviderModelsCacheMock.mockClear()
|
||||
selectFallbackProviderMock.mockClear()
|
||||
|
||||
clearPendingModelFallback("ses_model_fallback_main")
|
||||
clearPendingModelFallback("ses_model_fallback_ghcp")
|
||||
|
||||
@@ -274,3 +274,13 @@ export function createModelFallbackHook(args?: { toast?: FallbackToast; onApplie
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets all module-global state for testing.
|
||||
* Clears pending fallbacks, toast keys, and session chains.
|
||||
*/
|
||||
export function _resetForTesting(): void {
|
||||
pendingModelFallbacks.clear()
|
||||
lastToastKey.clear()
|
||||
sessionFallbackChains.clear()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, test, expect, beforeEach, afterEach } from "bun:test"
|
||||
import { homedir } from "node:os"
|
||||
import { join, resolve } from "node:path"
|
||||
import { join, resolve, win32 } from "node:path"
|
||||
import {
|
||||
getOpenCodeConfigDir,
|
||||
getOpenCodeConfigPaths,
|
||||
@@ -241,9 +241,10 @@ describe("opencode-config-dir", () => {
|
||||
// when getOpenCodeConfigDir is called with binary="opencode-desktop"
|
||||
const result = getOpenCodeConfigDir({ binary: "opencode-desktop", version: "1.0.200", checkExisting: false })
|
||||
|
||||
// then returns %APPDATA%/ai.opencode.desktop
|
||||
expect(result).toBe(join("C:\\Users\\TestUser\\AppData\\Roaming", TAURI_APP_IDENTIFIER))
|
||||
// then returns %APPDATA%/ai.opencode.desktop using Windows path semantics
|
||||
expect(result).toBe(win32.join("C:\\Users\\TestUser\\AppData\\Roaming", TAURI_APP_IDENTIFIER))
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
describe("dev build detection", () => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { existsSync, realpathSync } from "node:fs"
|
||||
import { homedir } from "node:os"
|
||||
import { join, resolve } from "node:path"
|
||||
import { join, resolve, win32 } from "node:path"
|
||||
|
||||
import type {
|
||||
OpenCodeBinaryType,
|
||||
@@ -31,7 +31,7 @@ function getTauriConfigDir(identifier: string): string {
|
||||
|
||||
case "win32": {
|
||||
const appData = process.env.APPDATA || join(homedir(), "AppData", "Roaming")
|
||||
return join(appData, identifier)
|
||||
return win32.join(appData, identifier)
|
||||
}
|
||||
|
||||
case "linux":
|
||||
@@ -71,7 +71,10 @@ export function getOpenCodeConfigDir(options: OpenCodeConfigDirOptions): string
|
||||
}
|
||||
|
||||
const identifier = isDevBuild(version) ? TAURI_APP_IDENTIFIER_DEV : TAURI_APP_IDENTIFIER
|
||||
const tauriDir = resolveConfigPath(getTauriConfigDir(identifier))
|
||||
const tauriDirBase = getTauriConfigDir(identifier)
|
||||
const tauriDir = process.platform === "win32"
|
||||
? (win32.isAbsolute(tauriDirBase) ? win32.normalize(tauriDirBase) : win32.resolve(tauriDirBase))
|
||||
: resolveConfigPath(tauriDirBase)
|
||||
|
||||
if (checkExisting) {
|
||||
const legacyDir = getCliConfigDir()
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { beforeEach } from "bun:test"
|
||||
import { _resetForTesting } from "./src/features/claude-code-session-state/state"
|
||||
import { _resetForTesting as resetClaudeSessionState } from "./src/features/claude-code-session-state/state"
|
||||
import { _resetForTesting as resetModelFallbackState } from "./src/hooks/model-fallback/hook"
|
||||
|
||||
beforeEach(() => {
|
||||
_resetForTesting()
|
||||
resetClaudeSessionState()
|
||||
resetModelFallbackState()
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user