diff --git a/mobile/src/transport/client-context.test.ts b/mobile/src/transport/client-context.test.ts index 99a8e31fa4f..23bdd0cc79a 100644 --- a/mobile/src/transport/client-context.test.ts +++ b/mobile/src/transport/client-context.test.ts @@ -644,40 +644,6 @@ describe('useAllHostClients', () => { } }) - it('keeps startup connection fanout constant for a large saved-host list', async () => { - const hosts = Array.from({ length: 1_000 }, (_, index) => ({ - ...HOST, - id: `host-${index}`, - name: `Host ${index}`, - lastConnected: index - })) - const hostIds = hosts.map((host) => host.id) - const autoConnectHostIds = selectHomeAutoConnectHostIds(hosts) - connectMock.mockReturnValue(makeFakeClient('connected')) - loadHostsMock.mockResolvedValue(hosts) - - let renderer: ReactTestRenderer | null = null - function Probe(): null { - useAllHostClients(hostIds, { autoConnectHostIds }) - return null - } - - try { - await act(async () => { - renderer = create(createElement(RpcClientProvider, null, createElement(Probe))) - await Promise.resolve() - }) - expect(connectMock).toHaveBeenCalledTimes(3) - expect(connectMock.mock.calls.map(([host]) => host.id)).toEqual([ - 'host-999', - 'host-998', - 'host-997' - ]) - } finally { - act(() => renderer?.unmount()) - } - }) - it('closes a demoted Home client when the recent-host set rotates', async () => { const hosts = [ { ...HOST, id: 'host-a', lastConnected: 4 }, diff --git a/mobile/src/transport/connection-health.test.ts b/mobile/src/transport/connection-health.test.ts index ba2d0e4ae00..0e619e5e29b 100644 --- a/mobile/src/transport/connection-health.test.ts +++ b/mobile/src/transport/connection-health.test.ts @@ -80,12 +80,6 @@ describe('classifyConnection Tailscale hint', () => { expect('hint' in warning && warning.hint).toBeFalsy() }) - it('keeps plain labels when no endpoint is provided', () => { - const verdict = classifyConnection({ ...base, reconnectAttempts: 3 }) - expect(verdict.kind).toBe('warning') - expect('hint' in verdict && verdict.hint).toBeFalsy() - }) - it('never hints on healthy states', () => { const verdict = classifyConnection({ state: 'connected', diff --git a/mobile/src/transport/connection-log-persistence-revisions.test.ts b/mobile/src/transport/connection-log-persistence-revisions.test.ts index abe40775911..cf3f57929b0 100644 --- a/mobile/src/transport/connection-log-persistence-revisions.test.ts +++ b/mobile/src/transport/connection-log-persistence-revisions.test.ts @@ -100,22 +100,4 @@ describe('connection log persistence revisions', () => { expect(save).toHaveBeenCalledTimes(2) expect(save).toHaveBeenLastCalledWith('a', store.get('a')) }) - - it('writes once per snapshot during a sustained failure', async () => { - const save = vi.fn(async () => {}) - const store = createConnectionLogStore(200, { load: async () => [], save }) - await store.hydrate('a') - await drain() - save.mockReset().mockRejectedValue(new Error('unavailable')) - for (let i = 0; i < 3; i++) { - store.append('a', entry(i)) - } - await drain() - expect(save).toHaveBeenCalledTimes(1) - save.mockClear().mockResolvedValue(undefined) - store.append('a', entry(3)) - await drain() - expect(save).toHaveBeenCalledTimes(1) - expect(save).toHaveBeenLastCalledWith('a', store.get('a')) - }) }) diff --git a/mobile/src/transport/foreground-stale-dial-restart.test.ts b/mobile/src/transport/foreground-stale-dial-restart.test.ts index 39410e8fc3f..b7467f6354c 100644 --- a/mobile/src/transport/foreground-stale-dial-restart.test.ts +++ b/mobile/src/transport/foreground-stale-dial-restart.test.ts @@ -115,19 +115,6 @@ function suspend(backgroundMs: number): void { vi.setSystemTime(Date.now() + backgroundMs) } -// Steps the clock one second at a time and reports how long the user has to sit -// on "Connecting…" before the client opens its next socket. -async function millisecondsUntilNextDial(dialsBefore: number): Promise { - const limitMs = 180_000 - for (let elapsedMs = 0; elapsedMs <= limitMs; elapsedMs += 1_000) { - if (sockets.length > dialsBefore) { - return elapsedMs - } - await vi.advanceTimersByTimeAsync(1_000) - } - return limitMs -} - // Waits out the current backoff so the phone is suspended mid-dial — the state // the reporter's phone resumed into — rather than between dials. async function advanceUntilDialing(client: ReturnType): Promise { @@ -181,36 +168,6 @@ describe('foregrounding a phone that was suspended mid-dial', () => { expect(client.getState()).toBe('connected') }) - it('does not strand the user on "Connecting…" for a minute after returning', async () => { - const client = connect(TAILSCALE_ENDPOINT, 'token', 'server-key') - latest().authenticate() - latest().close() - - // The desktop drops off the network while the user is still in the app, so - // the tiered backoff climbs into its slow tail (15s, 30s, 60s) before they - // ever leave. This is what makes the post-resume wait a full minute. - for (let dial = 0; dial < 6; dial++) { - await vi.advanceTimersByTimeAsync(12_000 + 60_000) - } - expect(client.getReconnectAttempt()).toBeGreaterThanOrEqual(6) - await advanceUntilDialing(client) - - suspend(90_000) - const dialsBefore = sockets.length - client.notifyForeground() - - // The desktop is reachable again and the user is looking at the screen, so - // the redial has to be in flight now — not after the abandoned socket's - // connect budget expires and another tail-length backoff is waited out. - expect(await millisecondsUntilNextDial(dialsBefore)).toBe(0) - - latest().authenticate() - expect(client.getState()).toBe('connected') - expect(label(client, TAILSCALE_ENDPOINT)).toBe('Connected') - - client.close() - }) - it('clears the escalated label once the foreground redial lands', async () => { const client = connect(TAILSCALE_ENDPOINT, 'token', 'server-key') latest().authenticate() diff --git a/mobile/src/transport/host-credential-cleanup.test.ts b/mobile/src/transport/host-credential-cleanup.test.ts index 146a845a96b..46d905fbdc1 100644 --- a/mobile/src/transport/host-credential-cleanup.test.ts +++ b/mobile/src/transport/host-credential-cleanup.test.ts @@ -111,21 +111,6 @@ describe('host credential cleanup', () => { expect(deleteCredential).toHaveBeenCalledOnce() }) - it('returns after durable intent without waiting for the native delete', async () => { - vi.useFakeTimers() - const deleteCredential = vi.fn(() => new Promise(() => undefined)) - - await expect( - scheduleHostCredentialCleanup('host-1', deleteCredential, 3_000) - ).resolves.toBeUndefined() - await flushMicrotasks() - - expect(storedPendingIds).toEqual(['host-1']) - expect(deleteCredential).toHaveBeenCalledOnce() - - await vi.advanceTimersByTimeAsync(3_000) - }) - it('clears a timed-out pending entry when the native delete later succeeds', async () => { vi.useFakeTimers() let resolveDelete: (() => void) | null = null diff --git a/src/renderer/src/hooks/agent-hook-completion-background-turn-notifications.test.ts b/src/renderer/src/hooks/agent-hook-completion-background-turn-notifications.test.ts index 256ae62d058..032dfdf8b20 100644 --- a/src/renderer/src/hooks/agent-hook-completion-background-turn-notifications.test.ts +++ b/src/renderer/src/hooks/agent-hook-completion-background-turn-notifications.test.ts @@ -217,53 +217,4 @@ describe('Claude background-turn completion notifications', () => { }) expect(banners[0]?.stateStartedAt).not.toBe(banners[1]?.stateStartedAt) }) - - it('notifies every turn under a persistent session cron with distinct ids', async () => { - const cron = [{ id: 'cron-1' }] - const { banners } = await play([ - { - at: 1_700_000_000_000, - payload: { hook_event_name: 'UserPromptSubmit', prompt: 'first' } - }, - { - at: 1_700_000_001_000, - payload: { - hook_event_name: 'Stop', - last_assistant_message: 'First done.', - session_crons: cron - } - }, - { - at: 1_700_000_002_000, - payload: { hook_event_name: 'UserPromptSubmit', prompt: 'second' } - }, - { - at: 1_700_000_003_000, - payload: { - hook_event_name: 'Stop', - last_assistant_message: 'Second done.', - session_crons: cron - } - }, - { - at: 1_700_000_004_000, - payload: { hook_event_name: 'UserPromptSubmit', prompt: 'third' } - }, - { - at: 1_700_000_005_000, - payload: { - hook_event_name: 'Stop', - last_assistant_message: 'Third done.', - session_crons: cron - } - } - ]) - - expect(banners.map((banner) => banner.body)).toEqual([ - 'First done.', - 'Second done.', - 'Third done.' - ]) - expect(new Set(banners.map((banner) => banner.stateStartedAt)).size).toBe(3) - }) }) diff --git a/src/renderer/src/hooks/agent-hook-completion-grok-notifications.test.ts b/src/renderer/src/hooks/agent-hook-completion-grok-notifications.test.ts index dd7073c3a8c..8962d8174ee 100644 --- a/src/renderer/src/hooks/agent-hook-completion-grok-notifications.test.ts +++ b/src/renderer/src/hooks/agent-hook-completion-grok-notifications.test.ts @@ -150,14 +150,6 @@ describe('Grok hook completion notifications', () => { }) }) - it('keeps the captured SessionEnd and shutdown Stop tail silent', async () => { - const shutdownTail = capturedHooks.filter( - (hook) => hook.reason === 'shutdown' || hook.hookEventName === 'session_end' - ) - - expect(await play(shutdownTail)).toHaveLength(0) - }) - it.each([ { eventName: 'StopFailure', @@ -205,43 +197,6 @@ describe('Grok hook completion notifications', () => { }) }) - // Pins grok-events.ts finite-task allowlist; broadening it to monitors or sessionCrons must redden. - it.each([ - { - label: 'monitor', - backgroundTasks: [ - { id: 'monitor-1', type: 'monitor', status: 'running', description: 'watch the build' } - ], - sessionCrons: [] - }, - { - label: 'cron', - backgroundTasks: [], - sessionCrons: [ - { id: 'cron-1', schedule: 'every minute', recurring: true, prompt: 'check the build' } - ] - } - ])('announces with only a running $label outstanding', async (scenario) => { - const notifications = await play([ - { - hookEventName: 'UserPromptSubmit', - timestamp: '2026-09-12T03:01:00.000Z', - prompt: 'finish the request' - }, - { - hookEventName: 'Stop', - timestamp: '2026-09-12T03:01:01.000Z', - reason: 'end_turn', - stopHookActive: false, - backgroundTasks: scenario.backgroundTasks, - sessionCrons: scenario.sessionCrons - } - ]) - vi.advanceTimersByTime(1_500) - - expect(notifications).toHaveLength(1) - }) - it('stays silent while a background subagent outlives the main agent, then announces once', async () => { const turn = (timestamp: string, promptId: string, backgroundTasks: unknown[]) => [ { hookEventName: 'UserPromptSubmit', timestamp, sessionId: 'session-1', promptId }, @@ -277,35 +232,6 @@ describe('Grok hook completion notifications', () => { }) }) - it('does not announce a delayed cancellation after the next prompt starts', async () => { - const notifications = await play([ - { - hookEventName: 'UserPromptSubmit', - timestamp: '2026-09-12T03:02:00.000Z', - sessionId: 'session-1', - promptId: 'prompt-old', - prompt: 'old turn' - }, - { - hookEventName: 'UserPromptSubmit', - timestamp: '2026-09-12T03:02:01.000Z', - sessionId: 'session-1', - promptId: 'prompt-new', - prompt: 'new turn' - }, - { - hookEventName: 'StopCancelled', - timestamp: '2026-09-12T03:02:02.000Z', - sessionId: 'session-1', - promptId: 'prompt-old', - reason: 'user_interrupt' - } - ]) - vi.advanceTimersByTime(1_500) - - expect(notifications).toHaveLength(0) - }) - it('announces once from idle_prompt after repeated continuation Stops', async () => { const notifications = await play([ { diff --git a/src/renderer/src/hooks/agent-hook-completion-notifications.test.ts b/src/renderer/src/hooks/agent-hook-completion-notifications.test.ts index 0f2d6948f0b..d28a8615d4d 100644 --- a/src/renderer/src/hooks/agent-hook-completion-notifications.test.ts +++ b/src/renderer/src/hooks/agent-hook-completion-notifications.test.ts @@ -230,28 +230,6 @@ describe('agent hook completion notifications', () => { expect(dispatchTerminalNotification).toHaveBeenCalledTimes(1) }) - it('tracks hook completion for terminal attention when OS completion notifications are disabled', async () => { - mockStoreState.settings.experimentalTerminalAttention = true - mockStoreState.settings.notifications.agentTaskComplete = false - const { observeAgentHookCompletionForNotification } = - await import('./agent-hook-completion-notifications') - - observeAgentHookCompletionForNotification({ - paneKey, - worktreeId: 'wt-1', - payload: hookStatus('done') - }) - vi.advanceTimersByTime(HOOK_DONE_QUIET_MS) - - expect(dispatchTerminalNotification).toHaveBeenCalledWith( - 'wt-1', - expect.objectContaining({ - source: 'agent-task-complete', - paneKey - }) - ) - }, 15_000) - it('uses tab-level PTY liveness when an inactive pane leaf binding is temporarily missing', async () => { mockStoreState.terminalLayoutsByTabId = { 'tab-1': { @@ -372,35 +350,6 @@ describe('agent hook completion notifications', () => { ) }) - it('carries hook stateStartedAt into delayed completion notifications', async () => { - const { observeAgentHookCompletionForNotification } = - await import('./agent-hook-completion-notifications') - - observeAgentHookCompletionForNotification({ - paneKey, - worktreeId: 'wt-1', - payload: { ...hookStatus('working'), stateStartedAt: 1_700_000_000_000 } - }) - observeAgentHookCompletionForNotification({ - paneKey, - worktreeId: 'wt-1', - payload: { ...hookStatus('done'), stateStartedAt: 1_700_000_010_000 } - }) - vi.advanceTimersByTime(HOOK_DONE_QUIET_MS) - - expect(dispatchTerminalNotification).toHaveBeenCalledWith( - 'wt-1', - expect.objectContaining({ - source: 'agent-task-complete', - paneKey, - agentStatusSnapshot: expect.objectContaining({ - state: 'done', - stateStartedAt: 1_700_000_010_000 - }) - }) - ) - }) - it('does not fire a completion notification for a session-boundary done row', async () => { const { observeAgentHookCompletionForNotification } = await import('./agent-hook-completion-notifications') @@ -438,34 +387,6 @@ describe('agent hook completion notifications', () => { expect(dispatchTerminalNotification).toHaveBeenCalledTimes(1) }) - it('does not notify twice when the same done hook snapshot replays after activation', async () => { - const { observeAgentHookCompletionForNotification } = - await import('./agent-hook-completion-notifications') - - observeAgentHookCompletionForNotification({ - paneKey, - worktreeId: 'wt-1', - payload: { ...hookStatus('working'), stateStartedAt: 1_700_000_000_000 } - }) - observeAgentHookCompletionForNotification({ - paneKey, - worktreeId: 'wt-1', - payload: { ...hookStatus('done'), stateStartedAt: 1_700_000_010_000 } - }) - vi.advanceTimersByTime(HOOK_DONE_QUIET_MS) - - expect(dispatchTerminalNotification).toHaveBeenCalledTimes(1) - - observeAgentHookCompletionForNotification({ - paneKey, - worktreeId: 'wt-1', - payload: { ...hookStatus('done'), stateStartedAt: 1_700_000_010_000 } - }) - vi.advanceTimersByTime(HOOK_DONE_QUIET_MS) - - expect(dispatchTerminalNotification).toHaveBeenCalledTimes(1) - }) - it('prunes retained coordinators when pane liveness is removed from the store', async () => { const { _getAgentHookCompletionNotificationCoordinatorCountForTest, @@ -518,45 +439,6 @@ describe('agent hook completion notifications', () => { expect(dispatchTerminalNotification).not.toHaveBeenCalled() }) - it('does not notify on each Cursor shell tool hook during a working turn', async () => { - const { observeAgentHookCompletionForNotification } = - await import('./agent-hook-completion-notifications') - - observeAgentHookCompletionForNotification({ - paneKey, - worktreeId: 'wt-1', - payload: { - state: 'working', - prompt: 'fix the bug', - agentType: 'cursor' - } - }) - observeAgentHookCompletionForNotification({ - paneKey, - worktreeId: 'wt-1', - payload: { - state: 'working', - prompt: 'fix the bug', - agentType: 'cursor', - toolName: 'Shell', - toolInput: 'pnpm test' - } - }) - observeAgentHookCompletionForNotification({ - paneKey, - worktreeId: 'wt-1', - payload: { - state: 'working', - prompt: 'fix the bug', - agentType: 'cursor', - toolName: 'Read', - toolInput: '/repo/src/app.ts' - } - }) - - expect(dispatchTerminalNotification).not.toHaveBeenCalled() - }) - it('notifies when a Claude permission request needs input without completing the task', async () => { const { observeAgentHookCompletionForNotification } = await import('./agent-hook-completion-notifications') @@ -617,13 +499,6 @@ describe('agent hook completion notifications', () => { ) }) - it('notifies for a blocked Codex permission request', async () => { - seedCodexPane(paneKey) - await observeCodexPermissionPause('blocked') - - expect(dispatchTerminalNotification).toHaveBeenCalledTimes(1) - }) - it('does not notify on Grok routine permission prompt notifications during tool use', async () => { const { observeAgentHookCompletionForNotification } = await import('./agent-hook-completion-notifications') @@ -701,68 +576,6 @@ describe('agent hook completion notifications', () => { ) }) - it('suppresses an internal milestone completion when hook work resumes before quiet', async () => { - const { observeAgentHookCompletionForNotification } = - await import('./agent-hook-completion-notifications') - - observeAgentHookCompletionForNotification({ - paneKey, - worktreeId: 'wt-1', - payload: hookStatus('working') - }) - observeAgentHookCompletionForNotification({ - paneKey, - worktreeId: 'wt-1', - payload: hookStatus('done') - }) - vi.advanceTimersByTime(HOOK_DONE_QUIET_MS - 1) - expect(dispatchTerminalNotification).not.toHaveBeenCalled() - expect( - dispatchAgentHookTerminalLifecycle.mock.calls.filter( - ([, payload]) => payload.state === 'done' - ) - ).toHaveLength(0) - - observeAgentHookCompletionForNotification({ - paneKey, - worktreeId: 'wt-1', - payload: hookStatus('working') - }) - vi.advanceTimersByTime(HOOK_DONE_QUIET_MS) - expect(dispatchTerminalNotification).not.toHaveBeenCalled() - expect( - dispatchAgentHookTerminalLifecycle.mock.calls.filter( - ([, payload]) => payload.state === 'done' - ) - ).toHaveLength(0) - - observeAgentHookCompletionForNotification({ - paneKey, - worktreeId: 'wt-1', - payload: hookStatus('done') - }) - vi.advanceTimersByTime(HOOK_DONE_QUIET_MS) - - expect(dispatchTerminalNotification).toHaveBeenCalledTimes(1) - expect(dispatchAgentHookTerminalLifecycle).toHaveBeenCalledWith( - paneKey, - expect.objectContaining({ state: 'done', agentType: 'codex' }) - ) - expect(dispatchTerminalNotification).toHaveBeenCalledWith( - 'wt-1', - expect.objectContaining({ - source: 'agent-task-complete', - paneKey, - agentStatusSnapshot: expect.objectContaining({ - state: 'done', - agentType: 'codex', - prompt: 'implement notifications', - lastAssistantMessage: 'Done.' - }) - }) - ) - }) - const MANY_PANES = [ { tabId: 'tab-1', leafId: '11111111-1111-4111-8111-111111111111', ptyId: 'pty-1' }, { tabId: 'tab-2', leafId: '22222222-2222-4222-8222-222222222222', ptyId: 'pty-2' }, diff --git a/src/renderer/src/hooks/agent-hook-completion-store-sync.test.ts b/src/renderer/src/hooks/agent-hook-completion-store-sync.test.ts index 972059d56c1..846f6dce594 100644 --- a/src/renderer/src/hooks/agent-hook-completion-store-sync.test.ts +++ b/src/renderer/src/hooks/agent-hook-completion-store-sync.test.ts @@ -174,23 +174,4 @@ describe('agent hook completion store sync', () => { }) expect(shouldSyncAgentHookCompletionForStoreUpdate(reorderedTabs, twoTabPrevious)).toBe(true) }) - - it('compares effective tracking state instead of unrelated settings identity', () => { - const previous = createState({ - settings: { - experimentalTerminalAttention: true, - notifications: { enabled: false, agentTaskComplete: false } - } - }) - const stillTrackedByNotifications = createState({ - ...previous, - settings: { - experimentalTerminalAttention: false, - notifications: { enabled: true, agentTaskComplete: true } - } - }) - expect(shouldSyncAgentHookCompletionForStoreUpdate(stillTrackedByNotifications, previous)).toBe( - false - ) - }) }) diff --git a/src/renderer/src/hooks/composer-branch-selection.test.ts b/src/renderer/src/hooks/composer-branch-selection.test.ts index e19aad2a013..6cd9d44feb9 100644 --- a/src/renderer/src/hooks/composer-branch-selection.test.ts +++ b/src/renderer/src/hooks/composer-branch-selection.test.ts @@ -274,17 +274,6 @@ describe('resolveComposerBranchReuse', () => { ).toEqual({ reuseEligibleBranch: 'feature-x', defaultReuse: true }) }) - it('treats a slash-containing local branch as reusable (ref equals local name)', () => { - expect( - resolveComposerBranchReuse({ - refName: 'fix/bug-0', - localBranchName: 'fix/bug-0', - selectionProducedOverride: true, - branchCheckedOutElsewhere: false - }) - ).toEqual({ reuseEligibleBranch: 'fix/bug-0', defaultReuse: true }) - }) - it('does not offer reuse for a remote-only ref (ref carries an origin/ prefix)', () => { expect( resolveComposerBranchReuse({ diff --git a/src/renderer/src/hooks/composer-drop-failure-toast.test.ts b/src/renderer/src/hooks/composer-drop-failure-toast.test.ts index ab2945065cb..5bc2aebbe4f 100644 --- a/src/renderer/src/hooks/composer-drop-failure-toast.test.ts +++ b/src/renderer/src/hooks/composer-drop-failure-toast.test.ts @@ -48,15 +48,6 @@ describe('showComposerDropFailureToast', () => { } }) - it('passes a free-form failure reason straight through', () => { - showComposerDropFailureToast({ - failureCount: 2, - total: 4, - commonFailure: { status: 'failed', reason: 'EACCES: permission denied' } - }) - expect(lastToast().description).toBe('EACCES: permission denied') - }) - it('shows no description when nothing explained the failure', () => { showComposerDropFailureToast({ failureCount: 1, total: 2 }) expect(lastToast().description).toBeUndefined() @@ -82,10 +73,4 @@ describe('showComposerDropFailureToast', () => { expect(first).toBeDefined() expect(lastToast().id).toBe(first) }) - - it('gives no reason at all when the batch failed for differing reasons', () => { - showComposerDropFailureToast({ failureCount: 3, total: 6 }) - expect(lastToast().title).toBe('3 of 6 items could not be attached.') - expect(lastToast().description).toBeUndefined() - }) }) diff --git a/src/renderer/src/hooks/composer-drop-owner.test.ts b/src/renderer/src/hooks/composer-drop-owner.test.ts index 16192aad8d5..fe95275b90b 100644 --- a/src/renderer/src/hooks/composer-drop-owner.test.ts +++ b/src/renderer/src/hooks/composer-drop-owner.test.ts @@ -10,10 +10,4 @@ describe('composer drop owner', () => { expect(isCurrentComposerDropOwner([page, modal], page)).toBe(false) expect(isCurrentComposerDropOwner([page, modal], modal)).toBe(true) }) - - it('rejects async drop completions after their owner unmounts', () => { - const owner = Symbol('owner') - - expect(isCurrentComposerDropOwner([], owner)).toBe(false) - }) }) diff --git a/src/renderer/src/hooks/composer-state/attachment-drop-lifetime.test.tsx b/src/renderer/src/hooks/composer-state/attachment-drop-lifetime.test.tsx index d1d7b6859d8..577d7c1fdf1 100644 --- a/src/renderer/src/hooks/composer-state/attachment-drop-lifetime.test.tsx +++ b/src/renderer/src/hooks/composer-state/attachment-drop-lifetime.test.tsx @@ -139,21 +139,6 @@ describe('local composer drop lifetime', () => { expect(hook.attach).not.toHaveBeenCalled() }) - it('keeps the current request pending until it settles', async () => { - const gate = Promise.withResolvers() - authorize.mockImplementationOnce(() => gate.promise) - const hook = renderDrop() - const settled = vi.fn() - const pending = hook.result.current.applyLocalComposerDrop(['/drop/one']).then(settled) - hook.unmount() - await Promise.resolve() - expect(settled).not.toHaveBeenCalled() - gate.resolve() - await pending - expect(settled).toHaveBeenCalledOnce() - expect(stat).not.toHaveBeenCalled() - }) - it('preserves mixed results, order, duplicate filtering and one failure report', async () => { const order: string[] = [] authorize.mockImplementation(async ({ targetPath }) => { diff --git a/src/renderer/src/hooks/composer-state/full-creation-structured-launch.test.ts b/src/renderer/src/hooks/composer-state/full-creation-structured-launch.test.ts deleted file mode 100644 index 47ef1c875c2..00000000000 --- a/src/renderer/src/hooks/composer-state/full-creation-structured-launch.test.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest' - -type BeginArgs = { - plan: unknown - target: { worktreeId: string } - beforeOpen?: (sessionId: string) => boolean | void -} - -const mocks = vi.hoisted(() => ({ - beginStructuredAgentSessionProvisionalLaunch: - vi.fn<(args: BeginArgs) => { sessionId: string; tab: { id: string } } | null>() -})) - -vi.mock('@/lib/structured-agent-session-provisional-tab', () => ({ - beginStructuredAgentSessionProvisionalLaunch: mocks.beginStructuredAgentSessionProvisionalLaunch -})) - -import { adoptAgentSessionLaunchVerdict } from '@/lib/agent-session-launch-plan' -import { beginFullCreationStructuredLaunch } from './full-creation-structured-launch' - -const plan = adoptAgentSessionLaunchVerdict({ - route: 'structured-native-chat', - agent: 'codex', - prompt: 'Fix the route', - promptDelivery: 'auto-submit' -}) - -describe('beginFullCreationStructuredLaunch', () => { - beforeEach(() => { - vi.clearAllMocks() - mocks.beginStructuredAgentSessionProvisionalLaunch.mockImplementation((args) => { - args.beforeOpen?.('session-1') - return { sessionId: 'session-1', tab: { id: 'agent-session:session-1' } } - }) - }) - - it('allocates the final identity before revealing and opening the chat surface', () => { - const order: string[] = [] - mocks.beginStructuredAgentSessionProvisionalLaunch.mockImplementation((args) => { - order.push('begin') - args.beforeOpen?.('session-1') - order.push('open') - return { sessionId: 'session-1', tab: { id: 'agent-session:session-1' } } - }) - - const launch = beginFullCreationStructuredLaunch({ - plan, - worktreeId: 'worktree-1', - beforeOpen: (sessionId) => { - order.push(`reveal:${sessionId}`) - return true - } - }) - - expect(launch).toMatchObject({ sessionId: 'session-1', tab: { id: 'agent-session:session-1' } }) - expect(order).toEqual(['begin', 'reveal:session-1', 'open']) - expect(mocks.beginStructuredAgentSessionProvisionalLaunch).toHaveBeenCalledWith({ - plan, - hooks: {}, - target: { worktreeId: 'worktree-1' }, - beforeOpen: expect.any(Function) - }) - }) - - it('returns no surface when reveal or ownership is refused', () => { - mocks.beginStructuredAgentSessionProvisionalLaunch.mockReturnValue(null) - - expect( - beginFullCreationStructuredLaunch({ plan, worktreeId: 'worktree-1', beforeOpen: vi.fn() }) - ).toBeNull() - }) -}) diff --git a/src/renderer/src/hooks/composer-state/multiple-create-reset.test.ts b/src/renderer/src/hooks/composer-state/multiple-create-reset.test.ts index c2ba2f2664d..b9f68bf3550 100644 --- a/src/renderer/src/hooks/composer-state/multiple-create-reset.test.ts +++ b/src/renderer/src/hooks/composer-state/multiple-create-reset.test.ts @@ -15,20 +15,6 @@ const sources: LinkedWorkItemSummary[] = [ number: 42, title: 'Fix checkout', url: 'https://github.com/acme/app/pull/42' - }, - { - provider: 'github', - type: 'issue', - number: 43, - title: 'Fix checkout', - url: 'https://github.com/acme/app/issues/43' - }, - { - provider: 'gitlab', - type: 'mr', - number: 44, - title: 'Fix checkout', - url: 'https://gitlab.com/acme/app/-/merge_requests/44' } ] @@ -135,36 +121,4 @@ describe('create more source reset', () => { expect(result.current.branchAutoNameRef.current).toBe('') } ) - - it.each(['linear', 'jira'] as const)('clears a %s task on a folder target', (provider) => { - const item: LinkedWorkItemSummary = { - provider, - type: 'issue', - number: 0, - title: 'Fix checkout', - url: - provider === 'linear' - ? 'https://linear.app/acme/issue/APP-45' - : 'https://acme.atlassian.net/browse/APP-45' - } - const { result } = renderHook(() => useSelectedSourceReset(item, true)) - expect(result.current.selection?.kind).toBe(provider) - - act(() => result.current.resetForNextCreate()) - - expect(result.current.selection).toBeNull() - expect(result.current.linkedWorkItem).toBeNull() - expect(result.current.name).toBe('') - expect(result.current.note).toBe('') - }) - - it('clears a plain branch selection before the next create', () => { - const { result } = renderHook(() => useSelectedSourceReset(null, false, 'feature/checkout')) - expect(result.current.selection).toEqual({ kind: 'branch', label: 'feature/checkout' }) - - act(() => result.current.resetForNextCreate()) - - expect(result.current.selection).toBeNull() - expect(result.current.baseBranch).toBeUndefined() - }) }) diff --git a/src/renderer/src/hooks/installed-agent-skill-discovery.test.ts b/src/renderer/src/hooks/installed-agent-skill-discovery.test.ts index f55623f87b0..73616fb065b 100644 --- a/src/renderer/src/hooks/installed-agent-skill-discovery.test.ts +++ b/src/renderer/src/hooks/installed-agent-skill-discovery.test.ts @@ -204,23 +204,6 @@ describe('installed agent skill discovery lifecycle', () => { expect(discover).toHaveBeenLastCalledWith(LOCAL, { projectRuntime: repairProjectRuntime }) }) - it('keys WSL targets by distro so two distros do not share one entry', async () => { - const discover = discoverSkillsForRuntimeTarget - discover.mockResolvedValueOnce(result(1)) - discover.mockResolvedValueOnce(result(2)) - - await expect( - discoverInstalledAgentSkills(false, { runtime: 'wsl', wslDistro: 'Ubuntu' }) - ).resolves.toEqual(result(1)) - await expect( - discoverInstalledAgentSkills(false, { runtime: 'wsl', wslDistro: 'Debian' }) - ).resolves.toEqual(result(2)) - await expect( - discoverInstalledAgentSkills(false, { runtime: 'wsl', wslDistro: 'Ubuntu' }) - ).resolves.toEqual(result(1)) - expect(discover).toHaveBeenCalledTimes(2) - }) - it('keys targets by runtime and project identity', () => { expect(getSkillDiscoveryTargetKey(undefined)).toBe('host') expect(getSkillDiscoveryTargetKey({ runtime: 'wsl', wslDistro: 'Ubuntu' })).toBe('wsl:Ubuntu') @@ -254,24 +237,6 @@ describe('installed agent skill discovery lifecycle', () => { ) }) - it('isolates project-runtime caches by target-contained filters', async () => { - discoverSkillsForRuntimeTarget.mockResolvedValueOnce(result(1)).mockResolvedValueOnce(result(2)) - - await expect( - discoverInstalledAgentSkills(false, { - projectRuntime: resolvedWslProjectRuntime, - names: ['orchestration'] - }) - ).resolves.toEqual(result(1)) - await expect( - discoverInstalledAgentSkills(false, { - projectRuntime: resolvedWslProjectRuntime, - names: ['computer-use'] - }) - ).resolves.toEqual(result(2)) - - expect(discoverSkillsForRuntimeTarget).toHaveBeenCalledTimes(2) - }) it('keys the bounded cache by runtime scope, not by the client target', async () => { // Why: #6887 scopes remote scans by environment. The cap rewrites this same // module, so pin that getRuntimeScopedSkillDiscoveryKey stays the producer —