mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-14 10:18:14 +00:00
fix(test): run bucket paths explicitly
This commit is contained in:
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');
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user