fix(test): run bucket paths explicitly

This commit is contained in:
Tam Nhu Tran committed 2026-06-14 11:55:01 -04:00
1 parent 7e6e12d008
commit 27c8a9570b
12 files changed
+668 -304

No files matched your search

@@ -27,7 +27,7 @@ function makeBrowserConfig(enabled = false, policy: 'auto' | 'always' | 'never'
describe('resolveBrowserLaunchFlags — no browser flags', () => {
it('returns undefined override and passes args through unchanged', async () => {
mock.module('../../utils/browser', () => ({
mock.module('../../../utils/browser', () => ({
appendBrowserToolArgs: (a: string[]) => a,
resolveBrowserLaunchFlagResolution: (_args: string[]) => ({
override: undefined,
@@ -40,7 +40,7 @@ describe('resolveBrowserLaunchFlags — no browser flags', () => {
resolveOptionalBrowserAttachRuntime: async () => ({ runtimeEnv: undefined }),
syncBrowserMcpToConfigDir: () => true,
}));
mock.module('../../../config/unified-config-loader', () => ({
mock.module('../../../config/config-loader-facade', () => ({
getBrowserConfig: () => makeBrowserConfig(false),
loadOrCreateUnifiedConfig: () => ({}),
getThinkingConfig: () => ({}),
@@ -58,7 +58,7 @@ describe('resolveBrowserLaunchFlags — no browser flags', () => {
describe('resolveBrowserLaunchFlags — with browser-launch override', () => {
it('returns override and strips the browser flag from args', async () => {
mock.module('../../utils/browser', () => ({
mock.module('../../../utils/browser', () => ({
appendBrowserToolArgs: (a: string[]) => a,
resolveBrowserLaunchFlagResolution: (_args: string[]) => ({
override: 'force-enable' as const,
@@ -71,7 +71,7 @@ describe('resolveBrowserLaunchFlags — with browser-launch override', () => {
resolveOptionalBrowserAttachRuntime: async () => ({ runtimeEnv: undefined }),
syncBrowserMcpToConfigDir: () => true,
}));
mock.module('../../../config/unified-config-loader', () => ({
mock.module('../../../config/config-loader-facade', () => ({
getBrowserConfig: () => makeBrowserConfig(true, 'auto'),
loadOrCreateUnifiedConfig: () => ({}),
getThinkingConfig: () => ({}),
@@ -98,7 +98,7 @@ describe('resolveBrowserLaunchFlags — blocked override warning', () => {
});
it('emits warn() when getBlockedBrowserOverrideWarning returns a message', async () => {
mock.module('../../utils/browser', () => ({
mock.module('../../../utils/browser', () => ({
appendBrowserToolArgs: (a: string[]) => a,
resolveBrowserLaunchFlagResolution: (args: string[]) => ({
override: 'force-enable' as const,
@@ -111,7 +111,7 @@ describe('resolveBrowserLaunchFlags — blocked override warning', () => {
resolveOptionalBrowserAttachRuntime: async () => ({ runtimeEnv: undefined }),
syncBrowserMcpToConfigDir: () => true,
}));
mock.module('../../../config/unified-config-loader', () => ({
mock.module('../../../config/config-loader-facade', () => ({
getBrowserConfig: () => makeBrowserConfig(false, 'never'),
loadOrCreateUnifiedConfig: () => ({}),
getThinkingConfig: () => ({}),
@@ -128,7 +128,7 @@ describe('resolveBrowserLaunchFlags — blocked override warning', () => {
describe('resolveBrowserRuntime — attach disabled', () => {
it('returns undefined browserRuntimeEnv when browser attach is disabled', async () => {
mock.module('../../utils/browser', () => ({
mock.module('../../../utils/browser', () => ({
appendBrowserToolArgs: (a: string[]) => a,
resolveBrowserLaunchFlagResolution: (a: string[]) => ({
override: undefined,
@@ -141,7 +141,7 @@ describe('resolveBrowserRuntime — attach disabled', () => {
resolveOptionalBrowserAttachRuntime: async () => ({ runtimeEnv: undefined }),
syncBrowserMcpToConfigDir: () => true,
}));
mock.module('../../../config/unified-config-loader', () => ({
mock.module('../../../config/config-loader-facade', () => ({
getBrowserConfig: () => makeBrowserConfig(false),
loadOrCreateUnifiedConfig: () => ({}),
getThinkingConfig: () => ({}),
@@ -158,7 +158,7 @@ describe('resolveBrowserRuntime — attach disabled', () => {
describe('resolveBrowserRuntime — active runtime env', () => {
it('returns runtimeEnv when browser attach resolves successfully', async () => {
const fakeRuntimeEnv = { CCS_BROWSER_DEVTOOLS_WS_URL: 'ws://127.0.0.1:9222/json' };
mock.module('../../utils/browser', () => ({
mock.module('../../../utils/browser', () => ({
appendBrowserToolArgs: (a: string[]) => a,
resolveBrowserLaunchFlagResolution: (a: string[]) => ({
override: 'force-enable' as const,
@@ -171,7 +171,7 @@ describe('resolveBrowserRuntime — active runtime env', () => {
resolveOptionalBrowserAttachRuntime: async () => ({ runtimeEnv: fakeRuntimeEnv }),
syncBrowserMcpToConfigDir: () => true,
}));
mock.module('../../../config/unified-config-loader', () => ({
mock.module('../../../config/config-loader-facade', () => ({
getBrowserConfig: () => makeBrowserConfig(true, 'always'),
loadOrCreateUnifiedConfig: () => ({}),
getThinkingConfig: () => ({}),
@@ -34,7 +34,7 @@ mock.module('child_process', () => ({
const mockEscapeShellArg = jest.fn((s: string) => `"${s}"`);
const mockGetWindowsEscapedCommandShell = jest.fn().mockReturnValue('cmd.exe');
mock.module('../../utils/shell-executor', () => ({
mock.module('../../../utils/shell-executor', () => ({
escapeShellArg: mockEscapeShellArg,
getWindowsEscapedCommandShell: mockGetWindowsEscapedCommandShell,
}));
@@ -46,7 +46,7 @@ mock.module('../../config/config-generator', () => ({
getProviderConfig: jest.fn(),
}));
mock.module('../../utils/websearch-manager', () => ({
mock.module('../../../utils/websearch-manager', () => ({
appendThirdPartyWebSearchToolArgs: (args: string[]) => args,
createWebSearchTraceContext: jest.fn().mockReturnValue({}),
ensureWebSearchMcpOrThrow: jest.fn(),
@@ -54,17 +54,17 @@ mock.module('../../utils/websearch-manager', () => ({
getWebSearchHookEnv: jest.fn().mockReturnValue({}),
}));
mock.module('../../utils/image-analysis', () => ({
mock.module('../../../utils/image-analysis', () => ({
appendThirdPartyImageAnalysisToolArgs: (args: string[]) => [...args, '--mcp-image-analysis'],
syncImageAnalysisMcpToConfigDir: jest.fn(),
ensureImageAnalysisMcpOrThrow: jest.fn().mockReturnValue(true),
}));
mock.module('../../utils/browser', () => ({
mock.module('../../../utils/browser', () => ({
appendBrowserToolArgs: (args: string[]) => [...args, '--browser'],
}));
mock.module('../accounts/account-manager', () => ({
mock.module('../../accounts/account-manager', () => ({
getDefaultAccount: jest.fn().mockReturnValue(null),
}));
@@ -82,7 +82,7 @@ mock.module('../account-resolution', () => ({
}));
// Dynamic import for quota-manager
mock.module('../quota/quota-manager', () => ({
mock.module('../../quota/quota-manager', () => ({
startQuotaMonitor: jest.fn(),
stopQuotaMonitor: jest.fn(),
}));
@@ -202,7 +202,7 @@ describe('launchClaude', () => {
it('uses shell mode for .cmd executables on Windows', async () => {
await launchClaude(baseContext({ claudeCli: 'C:\\tools\\claude.cmd' }));
const spawnOpts = mockSpawn.mock.calls[0][2] as { shell: string | boolean };
const spawnOpts = mockSpawn.mock.calls[0][1] as { shell: string | boolean };
// shell property should be set (cmd.exe from mock)
expect(spawnOpts.shell).toBeTruthy();
});
@@ -5,7 +5,7 @@
* silent for healthy ones, covering both simple and composite providers.
*/
import { afterEach, beforeEach, describe, expect, it, jest } from 'bun:test';
import { afterEach, beforeEach, describe, expect, it, jest, mock } from 'bun:test';
// ── Stubs ─────────────────────────────────────────────────────────────────────
@@ -23,26 +23,21 @@ const mockGetSuggestedReplacementModel = jest
.fn<string | undefined, [string, string]>()
.mockReturnValue(undefined);
jest.mock('../model-warnings', () => {
// We test the real implementation — only mock its dependencies
return jest.requireActual('../model-warnings');
});
jest.mock('../../config/model-config', () => ({
mock.module('../../config/model-config', () => ({
getCurrentModel: mockGetCurrentModel,
}));
jest.mock('../../cliproxy/model-catalog', () => ({
mock.module('../../model-catalog', () => ({
isModelBroken: mockIsModelBroken,
getModelIssueUrl: mockGetModelIssueUrl,
findModel: mockFindModel,
getSuggestedReplacementModel: mockGetSuggestedReplacementModel,
}));
// We import from real path after jest.mock so actual module is used
import { warnBrokenModels } from '../model-warnings';
import type { ExecutorConfig } from '../../types';
const { warnBrokenModels } = await import('../model-warnings');
// ── Helpers ────────────────────────────────────────────────────────────────────
function makeSimpleCfg(overrides: Partial<ExecutorConfig> = {}): ExecutorConfig {
@@ -150,6 +150,7 @@ export async function resolveAccounts(
}
}
process.exit(1);
return { earlyExit: true };
}
setDefaultAccount(provider, account.id);
touchAccount(provider, account.id);
@@ -166,6 +167,7 @@ export async function resolveAccounts(
console.error(fail(`No account found for ${providerConfig.displayName}`));
console.error(` Run "ccs ${provider} --auth" to add an account first`);
process.exit(1);
return { earlyExit: true };
}
try {
const success = renameAccount(provider, defaultAccount.id, setNickname);
@@ -174,12 +176,15 @@ export async function resolveAccounts(
} else {
console.error(fail('Failed to rename account'));
process.exit(1);
return { earlyExit: true };
}
} catch (err) {
console.error(fail(err instanceof Error ? err.message : 'Failed to rename account'));
process.exit(1);
return { earlyExit: true };
}
process.exit(0);
return { earlyExit: true };
}
return { earlyExit: false };
@@ -12,12 +12,14 @@
* by a direct atomic write; the running-proxy PATCH path is covered at the
* clearDrainOrderPriorities unit level (drain-order.test.ts).
*/
import { afterEach, beforeEach, describe, expect, it, spyOn } from 'bun:test';
import { afterEach, beforeEach, describe, expect, it, mock, spyOn } from 'bun:test';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { handleOrderSubcommand } from '../order-subcommand';
mock.module('../../../cliproxy/proxy/proxy-detector', () => ({
detectRunningProxy: async () => ({ running: false, verified: false }),
}));
describe('handleOrderSubcommand', () => {
let tempHome: string;
@@ -52,6 +54,13 @@ describe('handleOrderSubcommand', () => {
return import(`../../../cliproxy/accounts/registry?order-subcommand=${Date.now()}`);
}
async function runOrderSubcommand(args: string[]): Promise<void> {
const { handleOrderSubcommand } = await import(
`../order-subcommand?order-subcommand=${Date.now()}`
);
await handleOrderSubcommand(args);
}
beforeEach(() => {
tempHome = fs.mkdtempSync(path.join(os.tmpdir(), 'ccs-order-subcommand-'));
originalCcsHome = process.env.CCS_HOME;
@@ -86,7 +95,7 @@ describe('handleOrderSubcommand', () => {
registerAccount('claude', 'claude-a.json', 'a@x.com');
registerAccount('claude', 'claude-b.json', 'b@x.com');
await handleOrderSubcommand(['claude']);
await runOrderSubcommand(['claude']);
const output = lines.join('\n');
// b@x.com (priority 5) must appear before a@x.com (priority 1).
@@ -113,7 +122,7 @@ describe('handleOrderSubcommand', () => {
registerAccount('claude', 'claude-a.json', 'a@x.com');
registerAccount('claude', 'claude-b.json', 'b@x.com');
await handleOrderSubcommand(['claude']);
await runOrderSubcommand(['claude']);
const output = lines.join('\n');
expect(output).toContain('no priority set');
@@ -131,7 +140,7 @@ describe('handleOrderSubcommand', () => {
registerAccount('claude', 'claude-b.json', 'b@x.com');
saveDrainOrderConfig('claude', { mode: 'manual', orderedIds: ['a@x.com', 'b@x.com'] });
await handleOrderSubcommand(['claude', '--reset']);
await runOrderSubcommand(['claude', '--reset']);
// Residual priority is actually gone from disk (not just config deleted).
expect('priority' in readAuthFile('claude-a.json')).toBe(false);
@@ -149,7 +158,7 @@ describe('handleOrderSubcommand', () => {
const { registerAccount } = await registerClaude();
registerAccount('claude', 'claude-a.json', 'a@x.com');
await handleOrderSubcommand(['claude', '--reset']);
await runOrderSubcommand(['claude', '--reset']);
const output = lines.join('\n');
expect(output).toContain('reset to file order');
+1
View File
@@ -231,6 +231,7 @@ export class DeltaAccumulator {
if (usage) {
this.inputTokens = usage.prompt_tokens || usage.input_tokens || 0;
this.outputTokens = usage.completion_tokens || usage.output_tokens || 0;
this.usageReceived = true;
}
}