diff --git a/packages/daemon/src/daemon.test.ts b/packages/daemon/src/daemon.test.ts index d78812f2b..550b6d6a2 100644 --- a/packages/daemon/src/daemon.test.ts +++ b/packages/daemon/src/daemon.test.ts @@ -1,4 +1,4 @@ -import { describe, it, afterEach, before, after } from 'node:test'; +import { describe, it, afterEach, before, after } from 'vitest'; import assert from 'node:assert/strict'; import { mkdtempSync, writeFileSync, readFileSync, rmSync, existsSync, mkdirSync } from 'node:fs'; import { join } from 'node:path'; diff --git a/packages/daemon/src/discord-bot.test.ts b/packages/daemon/src/discord-bot.test.ts index 0dc44da50..4ae69eabf 100644 --- a/packages/daemon/src/discord-bot.test.ts +++ b/packages/daemon/src/discord-bot.test.ts @@ -1,4 +1,4 @@ -import { describe, it, afterEach } from 'node:test'; +import { describe, it, afterEach } from 'vitest'; import assert from 'node:assert/strict'; import { mkdtempSync, readFileSync, rmSync, existsSync } from 'node:fs'; import { join } from 'node:path'; diff --git a/packages/daemon/src/event-bridge.test.ts b/packages/daemon/src/event-bridge.test.ts index 1e9c30cf3..155683813 100644 --- a/packages/daemon/src/event-bridge.test.ts +++ b/packages/daemon/src/event-bridge.test.ts @@ -6,7 +6,7 @@ * blocker handling, conversation relay, and cleanup. */ -import { describe, it, mock } from 'node:test'; +import { vi, describe, it } from 'vitest'; import assert from 'node:assert/strict'; import { EventEmitter } from 'node:events'; import { EventBridge } from './event-bridge.js'; @@ -20,10 +20,10 @@ import type { SdkAgentEvent, RpcClient, RpcExtensionUIRequest } from '@singulari function createMockLogger() { return { - debug: mock.fn(() => {}), - info: mock.fn(() => {}), - warn: mock.fn(() => {}), - error: mock.fn(() => {}), + debug: vi.fn(() => {}), + info: vi.fn(() => {}), + warn: vi.fn(() => {}), + error: vi.fn(() => {}), }; } @@ -31,18 +31,18 @@ function createMockChannelManager() { const sentMessages: unknown[] = []; const mockChannel = { id: 'ch-123', - send: mock.fn(async (_payload: unknown) => { + send: vi.fn(async (_payload: unknown) => { sentMessages.push(_payload); return { id: 'msg-1' }; }), - createMessageComponentCollector: mock.fn((_opts?: unknown) => { + createMessageComponentCollector: vi.fn((_opts?: unknown) => { const collector = new EventEmitter() as EventEmitter & { stop: (reason?: string) => void }; collector.stop = (reason?: string) => collector.emit('end', [], reason ?? 'manual'); return collector; }), }; return { - createProjectChannel: mock.fn(async (_dir: string) => mockChannel), + createProjectChannel: vi.fn(async (_dir: string) => mockChannel), _channel: mockChannel, _sentMessages: sentMessages, }; @@ -50,8 +50,8 @@ function createMockChannelManager() { function createMockClient(): BridgeClient & EventEmitter { const emitter = new EventEmitter(); - const dmSendFn = mock.fn(async () => ({})); - const fetchFn = mock.fn(async (_id: string) => ({ send: dmSendFn })); + const dmSendFn = vi.fn(async () => ({})); + const fetchFn = vi.fn(async (_id: string) => ({ send: dmSendFn })); (emitter as unknown as Record).users = { fetch: fetchFn }; return Object.assign(emitter, { users: { fetch: fetchFn }, @@ -61,11 +61,11 @@ function createMockClient(): BridgeClient & EventEmitter { function createMockSessionManager() { const sm = new EventEmitter() as EventEmitter & { - getSession: ReturnType; - resolveBlocker: ReturnType; + getSession: ReturnType; + resolveBlocker: ReturnType; }; - sm.getSession = mock.fn((_id: string) => undefined as ManagedSession | undefined); - sm.resolveBlocker = mock.fn(async (_sid: string, _resp: string) => {}); + sm.getSession = vi.fn((_id: string) => undefined as ManagedSession | undefined); + sm.resolveBlocker = vi.fn(async (_sid: string, _resp: string) => {}); return sm; } @@ -76,8 +76,8 @@ function createMockSession(overrides?: Partial): ManagedSession projectName: 'project', status: 'running' as SessionStatus, client: { - steer: mock.fn(async (_msg: string) => {}), - prompt: mock.fn(async () => ({})), + steer: vi.fn(async (_msg: string) => {}), + prompt: vi.fn(async () => ({})), } as unknown as RpcClient, events: [], pendingBlocker: null, @@ -123,8 +123,8 @@ function buildBridge(overrides?: Partial) { // --------------------------------------------------------------------------- const tick = () => new Promise((r) => setTimeout(r, 30)); -function mockFn(obj: unknown): { mock: { callCount(): number; calls: Array<{ arguments: unknown[]; result?: unknown }> } } { - return obj as { mock: { callCount(): number; calls: Array<{ arguments: unknown[]; result?: unknown }> } }; +function mockFn(obj: unknown): { mock: { callCount: number; calls: Array } } { + return obj as { mock: { callCount: number; calls: Array } }; } // --------------------------------------------------------------------------- @@ -179,12 +179,12 @@ describe('EventBridge', () => { sessionId: 'sess-1', projectDir: '/test/project', projectName: 'my-project', }); await tick(); - assert.equal(mockFn(channelManager.createProjectChannel).mock.callCount(), 1); + assert.equal(mockFn(channelManager.createProjectChannel).mock.callCount, 1); }); it('logs error and skips when channel creation fails', async () => { const failingCm = { - createProjectChannel: mock.fn(async () => { throw new Error('API error'); }), + createProjectChannel: vi.fn(async () => { throw new Error('API error'); }), }; const { bridge, sessionManager, logger } = buildBridge({ channelManager: failingCm as unknown as EventBridgeOptions['channelManager'], @@ -194,7 +194,7 @@ describe('EventBridge', () => { sessionId: 'sess-1', projectDir: '/test/project', projectName: 'my-project', }); await tick(); - assert.ok(mockFn(logger.error).mock.callCount() > 0); + assert.ok(mockFn(logger.error).mock.callCount > 0); }); }); @@ -213,7 +213,7 @@ describe('EventBridge', () => { }); await tick(); // No errors - assert.equal(mockFn(logger.error).mock.callCount(), 0); + assert.equal(mockFn(logger.error).mock.callCount, 0); }); it('filters events based on verbosity', async () => { @@ -239,7 +239,7 @@ describe('EventBridge', () => { event: { type: 'tool_execution_start', name: 'read' } as SdkAgentEvent, }); await tick(); - assert.equal(mockFn(logger.error).mock.callCount(), 0); + assert.equal(mockFn(logger.error).mock.callCount, 0); }); }); @@ -260,7 +260,7 @@ describe('EventBridge', () => { sessionId: 'sess-1', projectDir: '/test/project', projectName: 'my-project', blocker, }); await tick(); - assert.ok(mockFn(channelManager._channel.createMessageComponentCollector).mock.callCount() > 0); + assert.ok(mockFn(channelManager._channel.createMessageComponentCollector).mock.callCount > 0); }); it('sends DM when dm_on_blocker is configured', async () => { @@ -287,7 +287,7 @@ describe('EventBridge', () => { await tick(); const usersFetch = (client as unknown as Record).users.fetch; - assert.equal(mockFn(usersFetch).mock.callCount(), 1); + assert.equal(mockFn(usersFetch).mock.callCount, 1); }); it('does not send DM when dm_on_blocker is false', async () => { @@ -310,7 +310,7 @@ describe('EventBridge', () => { await tick(); const usersFetch = (client as unknown as Record).users.fetch; - assert.equal(mockFn(usersFetch).mock.callCount(), 0); + assert.equal(mockFn(usersFetch).mock.callCount, 0); }); }); @@ -340,14 +340,14 @@ describe('EventBridge', () => { const mockInteraction = { customId: 'blocker:blocker-1:confirm:true', user: { id: 'owner-1' }, - update: mock.fn(async () => {}), - reply: mock.fn(async () => {}), + update: vi.fn(async () => {}), + reply: vi.fn(async () => {}), }; collector.emit('collect', mockInteraction); await tick(); - assert.equal(mockFn(sessionManager.resolveBlocker).mock.callCount(), 1); - const args = mockFn(sessionManager.resolveBlocker).mock.calls[0]!.arguments; + assert.equal(mockFn(sessionManager.resolveBlocker).mock.callCount, 1); + const args = mockFn(sessionManager.resolveBlocker).mock.calls[0]!; assert.equal(args[0], 'sess-1'); assert.equal(args[1], 'true'); }); @@ -376,19 +376,19 @@ describe('EventBridge', () => { const mockInteraction = { customId: 'blocker:blocker-1:confirm:true', user: { id: 'stranger-99' }, - update: mock.fn(async () => {}), - reply: mock.fn(async () => {}), + update: vi.fn(async () => {}), + reply: vi.fn(async () => {}), }; collector.emit('collect', mockInteraction); await tick(); - assert.equal(mockFn(sessionManager.resolveBlocker).mock.callCount(), 0); - assert.equal(mockFn(mockInteraction.reply).mock.callCount(), 1); + assert.equal(mockFn(sessionManager.resolveBlocker).mock.callCount, 0); + assert.equal(mockFn(mockInteraction.reply).mock.callCount, 1); }); it('posts error when resolveBlocker throws', async () => { const { bridge, sessionManager, channelManager } = buildBridge(); - sessionManager.resolveBlocker = mock.fn(async () => { throw new Error('No pending blocker'); }); + sessionManager.resolveBlocker = vi.fn(async () => { throw new Error('No pending blocker'); }); bridge.start(); sessionManager.emit('session:started', { @@ -411,14 +411,14 @@ describe('EventBridge', () => { const mockInteraction = { customId: 'blocker:blocker-1:confirm:true', user: { id: 'owner-1' }, - update: mock.fn(async () => {}), - reply: mock.fn(async () => {}), + update: vi.fn(async () => {}), + reply: vi.fn(async () => {}), }; collector.emit('collect', mockInteraction); await tick(); - assert.equal(mockFn(mockInteraction.reply).mock.callCount(), 1); - const replyArg = mockFn(mockInteraction.reply).mock.calls[0]!.arguments[0] as Record; + assert.equal(mockFn(mockInteraction.reply).mock.callCount, 1); + const replyArg = mockFn(mockInteraction.reply).mock.calls[0]![0] as Record; assert.ok(String(replyArg.content).includes('Failed to resolve')); }); }); @@ -427,7 +427,7 @@ describe('EventBridge', () => { it('relays message to session steer when no pending blocker', async () => { const session = createMockSession(); const { bridge, sessionManager, client } = buildBridge(); - sessionManager.getSession = mock.fn(() => session); + sessionManager.getSession = vi.fn(() => session); bridge.start(); sessionManager.emit('session:started', { @@ -439,14 +439,14 @@ describe('EventBridge', () => { author: { id: 'owner-1', bot: false }, channelId: 'ch-123', content: 'check the test results', - react: mock.fn(async () => {}), - reply: mock.fn(async () => {}), + react: vi.fn(async () => {}), + reply: vi.fn(async () => {}), }; client.emit('messageCreate', msg); await tick(); - assert.equal(mockFn(session.client.steer).mock.callCount(), 1); - assert.equal(mockFn(session.client.steer).mock.calls[0]!.arguments[0], 'check the test results'); + assert.equal(mockFn(session.client.steer).mock.callCount, 1); + assert.equal(mockFn(session.client.steer).mock.calls[0]![0], 'check the test results'); }); it('resolves blocker via relay for input method', async () => { @@ -456,7 +456,7 @@ describe('EventBridge', () => { }; const session = createMockSession({ pendingBlocker: blocker, status: 'blocked' }); const { bridge, sessionManager, client } = buildBridge(); - sessionManager.getSession = mock.fn(() => session); + sessionManager.getSession = vi.fn(() => session); bridge.start(); sessionManager.emit('session:started', { @@ -468,20 +468,20 @@ describe('EventBridge', () => { author: { id: 'owner-1', bot: false }, channelId: 'ch-123', content: 'my-api-key-value', - react: mock.fn(async () => {}), - reply: mock.fn(async () => {}), + react: vi.fn(async () => {}), + reply: vi.fn(async () => {}), }; client.emit('messageCreate', msg); await tick(); - assert.equal(mockFn(sessionManager.resolveBlocker).mock.callCount(), 1); - assert.equal(mockFn(sessionManager.resolveBlocker).mock.calls[0]!.arguments[1], 'my-api-key-value'); + assert.equal(mockFn(sessionManager.resolveBlocker).mock.callCount, 1); + assert.equal(mockFn(sessionManager.resolveBlocker).mock.calls[0]![1], 'my-api-key-value'); }); it('ignores bot messages', async () => { const session = createMockSession(); const { bridge, sessionManager, client } = buildBridge(); - sessionManager.getSession = mock.fn(() => session); + sessionManager.getSession = vi.fn(() => session); bridge.start(); sessionManager.emit('session:started', { @@ -493,36 +493,36 @@ describe('EventBridge', () => { author: { id: 'bot-1', bot: true }, channelId: 'ch-123', content: 'automated', - react: mock.fn(async () => {}), - reply: mock.fn(async () => {}), + react: vi.fn(async () => {}), + reply: vi.fn(async () => {}), }); await tick(); - assert.equal(mockFn(session.client.steer).mock.callCount(), 0); + assert.equal(mockFn(session.client.steer).mock.callCount, 0); }); it('ignores messages in non-project channels', async () => { const session = createMockSession(); const { bridge, sessionManager, client } = buildBridge(); - sessionManager.getSession = mock.fn(() => session); + sessionManager.getSession = vi.fn(() => session); bridge.start(); client.emit('messageCreate', { author: { id: 'owner-1', bot: false }, channelId: 'random-ch-999', content: 'hello', - react: mock.fn(async () => {}), - reply: mock.fn(async () => {}), + react: vi.fn(async () => {}), + reply: vi.fn(async () => {}), }); await tick(); - assert.equal(mockFn(session.client.steer).mock.callCount(), 0); + assert.equal(mockFn(session.client.steer).mock.callCount, 0); }); it('ignores messages from unauthorized users', async () => { const session = createMockSession(); const { bridge, sessionManager, client } = buildBridge(); - sessionManager.getSession = mock.fn(() => session); + sessionManager.getSession = vi.fn(() => session); bridge.start(); sessionManager.emit('session:started', { @@ -534,21 +534,21 @@ describe('EventBridge', () => { author: { id: 'stranger-99', bot: false }, channelId: 'ch-123', content: 'hack the planet', - react: mock.fn(async () => {}), - reply: mock.fn(async () => {}), + react: vi.fn(async () => {}), + reply: vi.fn(async () => {}), }); await tick(); - assert.equal(mockFn(session.client.steer).mock.callCount(), 0); + assert.equal(mockFn(session.client.steer).mock.callCount, 0); }); it('posts error when steer fails', async () => { const session = createMockSession(); - (session.client as unknown as Record).steer = mock.fn(async () => { + (session.client as unknown as Record).steer = vi.fn(async () => { throw new Error('session dead'); }); const { bridge, sessionManager, client } = buildBridge(); - sessionManager.getSession = mock.fn(() => session); + sessionManager.getSession = vi.fn(() => session); bridge.start(); sessionManager.emit('session:started', { @@ -560,13 +560,13 @@ describe('EventBridge', () => { author: { id: 'owner-1', bot: false }, channelId: 'ch-123', content: 'try this', - react: mock.fn(async () => {}), - reply: mock.fn(async () => {}), + react: vi.fn(async () => {}), + reply: vi.fn(async () => {}), }; client.emit('messageCreate', msg); await tick(); - assert.equal(mockFn(msg.reply).mock.callCount(), 1); + assert.equal(mockFn(msg.reply).mock.callCount, 1); }); }); @@ -591,7 +591,7 @@ describe('EventBridge', () => { event: { type: 'tool_execution_start', name: 'read' } as SdkAgentEvent, }); await tick(); - assert.equal(mockFn(logger.error).mock.callCount(), 0); + assert.equal(mockFn(logger.error).mock.callCount, 0); }); }); @@ -612,7 +612,7 @@ describe('EventBridge', () => { const infoCalls = mockFn(logger.info).mock.calls; assert.ok( - infoCalls.some((c) => String(c.arguments[0]).includes('session error')), + infoCalls.some((c) => String(c[0]).includes('session error')), ); }); }); diff --git a/packages/daemon/src/event-formatter.test.ts b/packages/daemon/src/event-formatter.test.ts index 2aacb4798..f745b7141 100644 --- a/packages/daemon/src/event-formatter.test.ts +++ b/packages/daemon/src/event-formatter.test.ts @@ -1,4 +1,4 @@ -import { describe, it } from 'node:test'; +import { describe, it } from 'vitest'; import assert from 'node:assert/strict'; import { EmbedBuilder, ActionRowBuilder, ButtonBuilder } from 'discord.js'; import type { SdkAgentEvent } from '@singularity-forge/rpc-client'; diff --git a/packages/daemon/src/launchd.test.ts b/packages/daemon/src/launchd.test.ts index 96ecf073f..57b1ace7b 100644 --- a/packages/daemon/src/launchd.test.ts +++ b/packages/daemon/src/launchd.test.ts @@ -1,4 +1,4 @@ -import { describe, it, beforeEach, afterEach } from 'node:test'; +import { describe, it, beforeEach, afterEach } from 'vitest'; import assert from 'node:assert/strict'; import { mkdtempSync, existsSync, readFileSync, writeFileSync, rmSync, mkdirSync, statSync } from 'node:fs'; import { join, dirname } from 'node:path'; diff --git a/packages/daemon/src/message-batcher.test.ts b/packages/daemon/src/message-batcher.test.ts index c64cf803b..80dbbb7cf 100644 --- a/packages/daemon/src/message-batcher.test.ts +++ b/packages/daemon/src/message-batcher.test.ts @@ -1,4 +1,4 @@ -import { describe, it, beforeEach, afterEach, mock } from 'node:test'; +import { vi, describe, it, beforeEach, afterEach } from 'vitest'; import assert from 'node:assert/strict'; import { MessageBatcher } from './message-batcher.js'; import type { SendPayload, BatcherLogger } from './message-batcher.js'; @@ -21,7 +21,7 @@ function fakeEvent(content: string, hasEmbed = false): FormattedEvent { /** Create a tracking send function. */ function createSend() { const calls: SendPayload[] = []; - const fn = mock.fn(async (payload: SendPayload) => { + const fn = vi.fn(async (payload: SendPayload) => { calls.push(payload); }); return { fn, calls }; diff --git a/packages/daemon/src/orchestrator.test.ts b/packages/daemon/src/orchestrator.test.ts index 00c072bc5..c762d4b4a 100644 --- a/packages/daemon/src/orchestrator.test.ts +++ b/packages/daemon/src/orchestrator.test.ts @@ -5,7 +5,7 @@ * allowing tool execution and conversation flow testing without real API calls. */ -import { describe, it, afterEach } from 'node:test'; +import { describe, it, afterEach } from 'vitest'; import assert from 'node:assert/strict'; import { mkdtempSync, rmSync, existsSync } from 'node:fs'; import { join } from 'node:path'; diff --git a/packages/daemon/src/project-scanner.test.ts b/packages/daemon/src/project-scanner.test.ts index 0aa0a7c23..dd2ad9a1d 100644 --- a/packages/daemon/src/project-scanner.test.ts +++ b/packages/daemon/src/project-scanner.test.ts @@ -2,7 +2,7 @@ * Tests for the project scanner module. */ -import { describe, it, afterEach } from 'node:test'; +import { describe, it, afterEach } from 'vitest'; import assert from 'node:assert/strict'; import { mkdtempSync, mkdirSync, writeFileSync, rmSync, existsSync, chmodSync } from 'node:fs'; import { join } from 'node:path'; diff --git a/packages/daemon/src/session-manager.test.ts b/packages/daemon/src/session-manager.test.ts index 63175f555..0838cbde2 100644 --- a/packages/daemon/src/session-manager.test.ts +++ b/packages/daemon/src/session-manager.test.ts @@ -6,7 +6,7 @@ * and cleanup without spawning real SF processes. */ -import { describe, it, beforeEach, afterEach } from 'node:test'; +import { describe, it, beforeEach, afterEach } from 'vitest'; import assert from 'node:assert/strict'; import { resolve, basename } from 'node:path'; import { mkdtempSync, writeFileSync, mkdirSync, rmSync } from 'node:fs'; diff --git a/packages/daemon/src/verbosity.test.ts b/packages/daemon/src/verbosity.test.ts index 42c61e9b6..727d63c5b 100644 --- a/packages/daemon/src/verbosity.test.ts +++ b/packages/daemon/src/verbosity.test.ts @@ -1,4 +1,4 @@ -import { describe, it, beforeEach } from 'node:test'; +import { describe, it, beforeEach } from 'vitest'; import assert from 'node:assert/strict'; import { VerbosityManager, shouldShowAtLevel } from './verbosity.js'; diff --git a/packages/mcp-server/src/env-writer.test.ts b/packages/mcp-server/src/env-writer.test.ts index 8988725f8..a149ff959 100644 --- a/packages/mcp-server/src/env-writer.test.ts +++ b/packages/mcp-server/src/env-writer.test.ts @@ -1,7 +1,7 @@ // @singularity-forge/mcp-server — Tests for env-writer utilities // Copyright (c) 2026 Jeremy McSpadden -import { describe, it, afterEach } from 'node:test'; +import { describe, it, afterEach } from 'vitest'; import assert from 'node:assert/strict'; import { mkdtempSync, mkdirSync, rmSync, writeFileSync, readFileSync, realpathSync, symlinkSync } from 'node:fs'; import { tmpdir } from 'node:os'; diff --git a/packages/mcp-server/src/mcp-server.test.ts b/packages/mcp-server/src/mcp-server.test.ts index e61a70018..d9557dec7 100644 --- a/packages/mcp-server/src/mcp-server.test.ts +++ b/packages/mcp-server/src/mcp-server.test.ts @@ -10,7 +10,7 @@ * 4. Testing CLI path resolution via static method */ -import { describe, it, beforeEach, afterEach } from 'node:test'; +import { describe, it, beforeEach, afterEach } from 'vitest'; import assert from 'node:assert/strict'; import { resolve } from 'node:path'; import { EventEmitter } from 'node:events'; diff --git a/packages/mcp-server/src/readers/graph.test.ts b/packages/mcp-server/src/readers/graph.test.ts index f7c42435c..c210c7f8e 100644 --- a/packages/mcp-server/src/readers/graph.test.ts +++ b/packages/mcp-server/src/readers/graph.test.ts @@ -1,7 +1,7 @@ // SF MCP Server — knowledge graph reader tests // Copyright (c) 2026 Jeremy McSpadden -import { describe, it, before, after, beforeEach, afterEach } from 'node:test'; +import { describe, it, before, after, beforeEach, afterEach } from 'vitest'; import assert from 'node:assert/strict'; import { mkdirSync, writeFileSync, rmSync, existsSync, readFileSync } from 'node:fs'; import { join } from 'node:path'; diff --git a/packages/mcp-server/src/readers/readers.test.ts b/packages/mcp-server/src/readers/readers.test.ts index 1529d9e9e..d884af954 100644 --- a/packages/mcp-server/src/readers/readers.test.ts +++ b/packages/mcp-server/src/readers/readers.test.ts @@ -1,7 +1,7 @@ // SF MCP Server — reader tests // Copyright (c) 2026 Jeremy McSpadden -import { describe, it, before, after } from 'node:test'; +import { describe, it, before, after } from 'vitest'; import assert from 'node:assert/strict'; import { mkdirSync, writeFileSync, rmSync } from 'node:fs'; import { join } from 'node:path'; diff --git a/packages/mcp-server/src/secure-env-collect.test.ts b/packages/mcp-server/src/secure-env-collect.test.ts index 485a8e72a..f8fccd027 100644 --- a/packages/mcp-server/src/secure-env-collect.test.ts +++ b/packages/mcp-server/src/secure-env-collect.test.ts @@ -4,7 +4,7 @@ // Tests the secure_env_collect tool registered in createMcpServer. // Uses a mock MCP server to intercept tool registration and elicitInput calls. -import { describe, it, beforeEach } from 'node:test'; +import { describe, it, beforeEach } from 'vitest'; import assert from 'node:assert/strict'; import { mkdtempSync, mkdirSync, rmSync, writeFileSync, readFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; diff --git a/packages/pi-coding-agent/src/core/compaction/compaction.test.ts b/packages/pi-coding-agent/src/core/compaction/compaction.test.ts index 5e41bf631..8dcf38360 100644 --- a/packages/pi-coding-agent/src/core/compaction/compaction.test.ts +++ b/packages/pi-coding-agent/src/core/compaction/compaction.test.ts @@ -154,8 +154,8 @@ describe("generateSummary — chunked fallback (#2932)", () => { // Assert: should have called completeSimple more than once (chunked) assert.ok( - mockComplete.mock.callCount() > 1, - `Expected multiple calls for chunked summarization, got ${mockComplete.mock.callCount()}`, + mockComplete.mock.callCount > 1, + `Expected multiple calls for chunked summarization, got ${mockComplete.mock.callCount}`, ); // First call should be an initial summary, subsequent should be updates @@ -189,7 +189,7 @@ describe("generateSummary — chunked fallback (#2932)", () => { await generateSummary(messages, model, reserveTokens, undefined, undefined, undefined, undefined, mockComplete); assert.equal( - mockComplete.mock.callCount(), + mockComplete.mock.callCount, 1, "Should use single-pass summarization when messages fit in context window", ); diff --git a/packages/pi-coding-agent/src/core/fallback-resolver.test.ts b/packages/pi-coding-agent/src/core/fallback-resolver.test.ts index 11f705272..c92a999b7 100644 --- a/packages/pi-coding-agent/src/core/fallback-resolver.test.ts +++ b/packages/pi-coding-agent/src/core/fallback-resolver.test.ts @@ -86,8 +86,8 @@ describe("FallbackResolver — findFallback", () => { const fn = authStorage.markProviderExhausted as any; assert.equal(fn.mock.calls.length, 1); - assert.equal(fn.mock.calls[0].arguments[0], "zai"); - assert.equal(fn.mock.calls[0].arguments[1], "rate_limit"); + assert.equal(fn.mock.calls[0][0], "zai"); + assert.equal(fn.mock.calls[0][1], "rate_limit"); }); it("skips backed-off providers", async () => { diff --git a/packages/pi-coding-agent/src/core/retry-handler.test.ts b/packages/pi-coding-agent/src/core/retry-handler.test.ts index c1a83b37b..107f6966e 100644 --- a/packages/pi-coding-agent/src/core/retry-handler.test.ts +++ b/packages/pi-coding-agent/src/core/retry-handler.test.ts @@ -247,7 +247,7 @@ describe("RetryHandler — long-context entitlement 429 (#2803)", () => { // Should have called setModel with the base model const setModelCalls = (deps.agent.setModel as any).mock.calls; assert.equal(setModelCalls.length, 1); - assert.equal(setModelCalls[0].arguments[0].id, "claude-opus-4-6"); + assert.equal(setModelCalls[0][0].id, "claude-opus-4-6"); // Should have notified about model change assert.equal(onModelChangeFn.mock.calls.length, 1); @@ -343,7 +343,7 @@ describe("RetryHandler — long-context entitlement 429 (#2803)", () => { const setModelCalls = (deps.agent.setModel as any).mock.calls; assert.equal(setModelCalls.length, 1, "should apply one model downgrade"); - const downgraded = setModelCalls[0].arguments[0] as Model; + const downgraded = setModelCalls[0][0] as Model; assert.equal(downgraded.provider, "openrouter"); assert.equal(downgraded.id, "openai/gpt-5-pro"); assert.equal(downgraded.maxTokens, 297, "expected affordability cap with safety buffer"); diff --git a/scripts/migrate-to-vitest-all.mjs b/scripts/migrate-to-vitest-all.mjs index 29f9d49cf..e6c895120 100644 --- a/scripts/migrate-to-vitest-all.mjs +++ b/scripts/migrate-to-vitest-all.mjs @@ -44,15 +44,15 @@ function collectTestFiles(dirs) { } function migrateImport(content, { hasMockFn, hasMockTimers }) { - // Case 1: import test from "node:test"; + // Case 1: import test from "node:test"; (or single quotes, optional semicolon) content = content.replace( - /^import test from "node:test";$/gm, + /^import test from ["']node:test["'];?$/gm, "import { test } from 'vitest';", ); // Case 2: import { ... } from "node:test" (and variants with default import) content = content.replace( - /import\s+(test,)?\s*\{\s*([^}]+)\}\s+from\s+"node:test";?/g, + /import\s+(test,)?\s*\{\s*([^}]+)\}\s+from\s+["']node:test["'];?/g, (match, hasDefault, named) => { const namedList = named .split(",") @@ -83,7 +83,7 @@ let errors = 0; for (const file of files) { try { const content = readFileSync(file, "utf-8"); - if (!content.includes('from "node:test"')) continue; + if (!content.includes('from "node:test"') && !content.includes("from 'node:test'")) continue; const hasMockFn = content.includes("mock.fn"); const hasMockTimers = content.includes("mock.timers"); diff --git a/src/resources/extensions/sf/tests/post-exec-retry-bypass.test.ts b/src/resources/extensions/sf/tests/post-exec-retry-bypass.test.ts index 5978799d7..10255b7f4 100644 --- a/src/resources/extensions/sf/tests/post-exec-retry-bypass.test.ts +++ b/src/resources/extensions/sf/tests/post-exec-retry-bypass.test.ts @@ -231,7 +231,7 @@ describe("Post-execution blocking failure retry bypass", () => { // Non-execute-task units should return "continue" immediately assert.equal(result, "continue"); - assert.equal(pauseAutoMock.mock.callCount(), 0); + assert.equal(pauseAutoMock.mock.callCount, 0); }); test("returns continue when verification passes", async () => { @@ -256,7 +256,7 @@ describe("Post-execution blocking failure retry bypass", () => { // When verification passes, should return "continue" and not call pauseAuto assert.equal(result, "continue"); - assert.equal(pauseAutoMock.mock.callCount(), 0); + assert.equal(pauseAutoMock.mock.callCount, 0); // Retry state should be cleared assert.equal(s.pendingVerificationRetry, null); @@ -345,7 +345,7 @@ describe("Post-execution blocking failure retry bypass", () => { const result = await runPostUnitVerification(vctx, pauseAutoMock); assert.equal(result, "pause"); - assert.equal(pauseAutoMock.mock.callCount(), 1); + assert.equal(pauseAutoMock.mock.callCount, 1); const adapter = _getAdapter(); const row = adapter @@ -426,7 +426,7 @@ describe("Post-execution retry behavior", () => { // When autofix is disabled and verification fails, should pause assert.equal(result, "pause"); - assert.equal(pauseAutoMock.mock.callCount(), 1); + assert.equal(pauseAutoMock.mock.callCount, 1); // Should NOT set up a retry assert.equal(s.pendingVerificationRetry, null); diff --git a/src/resources/extensions/sf/tests/pre-execution-fail-closed.test.ts b/src/resources/extensions/sf/tests/pre-execution-fail-closed.test.ts index d6a0db926..52488390f 100644 --- a/src/resources/extensions/sf/tests/pre-execution-fail-closed.test.ts +++ b/src/resources/extensions/sf/tests/pre-execution-fail-closed.test.ts @@ -210,7 +210,7 @@ describe("Pre-execution fail-closed behavior", () => { // With valid tasks, pre-exec should pass and not pause assert.equal( - pauseAutoMock.mock.callCount(), + pauseAutoMock.mock.callCount, 0, "pauseAuto should NOT be called when pre-execution checks pass", ); @@ -267,7 +267,7 @@ describe("Pre-execution fail-closed behavior", () => { // With a blocking failure, pauseAuto should be called assert.equal( - pauseAutoMock.mock.callCount(), + pauseAutoMock.mock.callCount, 1, "pauseAuto should be called when pre-execution checks fail", ); @@ -281,7 +281,7 @@ describe("Pre-execution fail-closed behavior", () => { // Verify error notification was shown const notifyCalls = ctx.ui.notify.mock.calls; const errorNotify = notifyCalls.find( - (call: { arguments: unknown[] }) => call.arguments[1] === "error", + (call: unknown[]) => call[1] === "error", ); assert.ok( errorNotify, diff --git a/src/resources/extensions/sf/tests/pre-execution-pause-wiring.test.ts b/src/resources/extensions/sf/tests/pre-execution-pause-wiring.test.ts index 5c5259a00..cb9e6332c 100644 --- a/src/resources/extensions/sf/tests/pre-execution-pause-wiring.test.ts +++ b/src/resources/extensions/sf/tests/pre-execution-pause-wiring.test.ts @@ -312,7 +312,7 @@ describe("Pre-execution checks → pauseAuto wiring", () => { // Verify pauseAuto was called assert.equal( - pauseAutoMock.mock.callCount(), + pauseAutoMock.mock.callCount, 1, "pauseAuto should be called exactly once when pre-execution checks fail with blocking issues", ); @@ -327,9 +327,9 @@ describe("Pre-execution checks → pauseAuto wiring", () => { // Verify UI was notified of the failure const notifyCalls = ctx.ui.notify.mock.calls; const errorNotify = notifyCalls.find( - (call: { arguments: unknown[] }) => - call.arguments[1] === "error" && - String(call.arguments[0]).includes("Pre-execution checks failed"), + (call: unknown[]) => + call[1] === "error" && + String(call[0]).includes("Pre-execution checks failed"), ); assert.ok( errorNotify, @@ -360,7 +360,7 @@ describe("Pre-execution checks → pauseAuto wiring", () => { // Verify pauseAuto was called (strict mode promotes warnings to blocking) assert.equal( - pauseAutoMock.mock.callCount(), + pauseAutoMock.mock.callCount, 1, "pauseAuto should be called when strict mode is enabled and pre-execution returns warn", ); @@ -375,9 +375,9 @@ describe("Pre-execution checks → pauseAuto wiring", () => { // Verify UI was notified of the warning const notifyCalls = ctx.ui.notify.mock.calls; const warnNotify = notifyCalls.find( - (call: { arguments: unknown[] }) => - call.arguments[1] === "warning" && - String(call.arguments[0]).includes( + (call: unknown[]) => + call[1] === "warning" && + String(call[0]).includes( "Pre-execution checks passed with warnings", ), ); @@ -410,7 +410,7 @@ describe("Pre-execution checks → pauseAuto wiring", () => { // Verify pauseAuto was NOT called (warnings don't block in non-strict mode) assert.equal( - pauseAutoMock.mock.callCount(), + pauseAutoMock.mock.callCount, 0, "pauseAuto should NOT be called when strict mode is disabled and only warnings exist", ); @@ -442,7 +442,7 @@ describe("Pre-execution checks → pauseAuto wiring", () => { // Verify pauseAuto was NOT called (pre-execution checks only run for plan-slice) assert.equal( - pauseAutoMock.mock.callCount(), + pauseAutoMock.mock.callCount, 0, "pauseAuto should NOT be called for non-plan-slice unit types", ); @@ -477,7 +477,7 @@ describe("Pre-execution checks → pauseAuto wiring", () => { // Verify pauseAuto was NOT called (pre-execution checks disabled) assert.equal( - pauseAutoMock.mock.callCount(), + pauseAutoMock.mock.callCount, 0, "pauseAuto should NOT be called when enhanced_verification_pre is disabled", ); diff --git a/src/resources/extensions/sf/tests/validate-milestone-stuck-guard.test.ts b/src/resources/extensions/sf/tests/validate-milestone-stuck-guard.test.ts index 9513faa3f..63cfb2c35 100644 --- a/src/resources/extensions/sf/tests/validate-milestone-stuck-guard.test.ts +++ b/src/resources/extensions/sf/tests/validate-milestone-stuck-guard.test.ts @@ -139,9 +139,9 @@ describe("validate-milestone stuck-loop guard (#4094)", () => { ); assert.equal(result, "pause"); - assert.equal(pauseAutoMock.mock.callCount(), 1); - assert.equal(ctx.ui.notify.mock.callCount(), 1); - const notifyArgs = ctx.ui.notify.mock.calls[0].arguments; + assert.equal(pauseAutoMock.mock.callCount, 1); + assert.equal(ctx.ui.notify.mock.callCount, 1); + const notifyArgs = ctx.ui.notify.mock.calls[0]; assert.match(notifyArgs[0], /needs-remediation/); assert.equal(notifyArgs[1], "error"); }); @@ -173,7 +173,7 @@ describe("validate-milestone stuck-loop guard (#4094)", () => { ); assert.equal(result, "pause"); - assert.equal(pauseAutoMock.mock.callCount(), 1); + assert.equal(pauseAutoMock.mock.callCount, 1); }); test("continues when verdict=needs-remediation but a queued remediation slice exists", async () => { @@ -203,7 +203,7 @@ describe("validate-milestone stuck-loop guard (#4094)", () => { ); assert.equal(result, "continue"); - assert.equal(pauseAutoMock.mock.callCount(), 0); + assert.equal(pauseAutoMock.mock.callCount, 0); }); test("continues when verdict is pass", async () => { @@ -227,7 +227,7 @@ describe("validate-milestone stuck-loop guard (#4094)", () => { ); assert.equal(result, "continue"); - assert.equal(pauseAutoMock.mock.callCount(), 0); + assert.equal(pauseAutoMock.mock.callCount, 0); }); test("continues when no VALIDATION file exists yet", async () => { @@ -250,6 +250,6 @@ describe("validate-milestone stuck-loop guard (#4094)", () => { ); assert.equal(result, "continue"); - assert.equal(pauseAutoMock.mock.callCount(), 0); + assert.equal(pauseAutoMock.mock.callCount, 0); }); }); diff --git a/studio/test/tokens.test.mjs b/studio/test/tokens.test.mjs index 0911cd2c1..75603c63a 100644 --- a/studio/test/tokens.test.mjs +++ b/studio/test/tokens.test.mjs @@ -1,4 +1,4 @@ -import test from 'node:test' +import { test } from 'vitest'; import assert from 'node:assert/strict' import { readFile } from 'node:fs/promises' diff --git a/tsconfig.extensions.json b/tsconfig.extensions.json index 3cfdeff4a..68412a74b 100644 --- a/tsconfig.extensions.json +++ b/tsconfig.extensions.json @@ -23,6 +23,10 @@ }, "include": ["src/resources/extensions"], "exclude": [ - "src/resources/extensions/vectordrive/tests/**/*.ts" + "src/resources/extensions/vectordrive/tests/**/*.ts", + "src/resources/extensions/**/tests/**/*.ts", + "src/resources/extensions/**/tests/**/*.mjs", + "src/tests/**/*.ts", + "src/tests/**/*.mjs" ] }