mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 16:47:34 +00:00
test: remove 49 low-value test cases (#34678)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
@@ -2920,7 +2920,6 @@
|
||||
"src/main/ipc/github-repo-access-guards.test.ts": 614,
|
||||
"src/main/ipc/github-repo-routing-twin-host.test.ts": 91,
|
||||
"src/main/ipc/github-ssh-connection-routing.test.ts": 508,
|
||||
"src/main/ipc/github-star-telemetry.test.ts": 520,
|
||||
"src/main/ipc/github-wsl-runtime-routing.test.ts": 726,
|
||||
"src/main/ipc/gitlab-repo-access.test.ts": 111,
|
||||
"src/main/ipc/gitlab.test.ts": 181,
|
||||
@@ -3208,7 +3207,6 @@
|
||||
"src/main/ipc/session-window-view-save.test.ts": 1386,
|
||||
"src/main/ipc/session.test.ts": 307,
|
||||
"src/main/ipc/settings-delayed-response.test.ts": 1717,
|
||||
"src/main/ipc/settings-telemetry.test.ts": 976,
|
||||
"src/main/ipc/settings.test.ts": 833,
|
||||
"src/main/ipc/shallow-watch-delivery-probe-lifetime.test.ts": 77,
|
||||
"src/main/ipc/shallow-watch-delivery-probe.test.ts": 68,
|
||||
@@ -3691,7 +3689,6 @@
|
||||
"src/main/native-chat/agent-session-wire/structured-agent-session-late-proof-tool-ends.test.ts": 757,
|
||||
"src/main/native-chat/agent-session-wire/structured-agent-session-late-settlement.test.ts": 1910,
|
||||
"src/main/native-chat/agent-session-wire/structured-agent-session-launch-env.test.ts": 237,
|
||||
"src/main/native-chat/agent-session-wire/structured-agent-session-launch-permission.test.ts": 262,
|
||||
"src/main/native-chat/agent-session-wire/structured-agent-session-launch-send-after-create.test.ts": 857,
|
||||
"src/main/native-chat/agent-session-wire/structured-agent-session-lease-renewer.test.ts": 714,
|
||||
"src/main/native-chat/agent-session-wire/structured-agent-session-legacy-handoff-record.test.ts": 1623,
|
||||
@@ -5358,7 +5355,6 @@
|
||||
"src/main/runtime/rpc/methods/github-pr-refresh-reason.test.ts": 653,
|
||||
"src/main/runtime/rpc/methods/github.test.ts": 565,
|
||||
"src/main/runtime/rpc/methods/gitlab.test.ts": 606,
|
||||
"src/main/runtime/rpc/methods/host-capabilities.test.ts": 489,
|
||||
"src/main/runtime/rpc/methods/hosted-review.test.ts": 918,
|
||||
"src/main/runtime/rpc/methods/jira-attachment-image.test.ts": 453,
|
||||
"src/main/runtime/rpc/methods/jira-board-filter-rpc.test.ts": 784,
|
||||
@@ -5481,7 +5477,6 @@
|
||||
"src/main/runtime/rpc/methods/publish-capability-settings.test.ts": 3997,
|
||||
"src/main/runtime/rpc/methods/repo-badge-color.test.ts": 650,
|
||||
"src/main/runtime/rpc/methods/repo.test.ts": 458,
|
||||
"src/main/runtime/rpc/methods/runtime-client-capabilities.test.ts": 656,
|
||||
"src/main/runtime/rpc/methods/session-tab-agent-capability-mutations.test.ts": 912,
|
||||
"src/main/runtime/rpc/methods/session-tab-agent-status-projection.test.ts": 716,
|
||||
"src/main/runtime/rpc/methods/session-tab-browser-placement-mutations.test.ts": 1185,
|
||||
@@ -5743,7 +5738,6 @@
|
||||
"src/main/runtime/runtime-managed-worktree-queries.test.ts": 889,
|
||||
"src/main/runtime/runtime-metadata-ownership-watch.test.ts": 79,
|
||||
"src/main/runtime/runtime-metadata.test.ts": 190,
|
||||
"src/main/runtime/runtime-migration-catalog-capabilities.test.ts": 2571,
|
||||
"src/main/runtime/runtime-mobile-agent-status-builder.test.ts": 68,
|
||||
"src/main/runtime/runtime-mobile-agent-status-first-turn.test.ts": 58,
|
||||
"src/main/runtime/runtime-mobile-codex-side-title.test.ts": 3712,
|
||||
@@ -5974,7 +5968,6 @@
|
||||
"src/main/runtime/structured-conversation-tab-title.test.ts": 46,
|
||||
"src/main/runtime/structured-session-child-env.test.ts": 234,
|
||||
"src/main/runtime/structured-session-cli-login-shell.test.ts": 255,
|
||||
"src/main/runtime/structured-session-mail-redrive-wiring.test.ts": 3192,
|
||||
"src/main/runtime/structured-session-worktree-teardown.test.ts": 315,
|
||||
"src/main/runtime/structured-worker-agent-presence.test.ts": 223,
|
||||
"src/main/runtime/structured-worker-at-rest.test.ts": 1524,
|
||||
@@ -6375,7 +6368,6 @@
|
||||
"src/main/ssh/orcad-migration-manifest-golden.test.ts": 618,
|
||||
"src/main/ssh/orcad-migration-path-rewrite.test.ts": 153,
|
||||
"src/main/ssh/orcad-migration-repository-link.test.ts": 2877,
|
||||
"src/main/ssh/orcad-migration-scrollback-retention-wiring.test.ts": 56,
|
||||
"src/main/ssh/orcad-migration-snapshot-coordinator.test.ts": 225,
|
||||
"src/main/ssh/orcad-migration-snapshot-resume.test.ts": 1406,
|
||||
"src/main/ssh/orcad-migration-source-fence.test.ts": 2559,
|
||||
|
||||
@@ -164,7 +164,6 @@ const NODE_RUNTIME_INCLUDE = [
|
||||
'src/main/native-chat/agent-session-wire/structured-agent-session-permission-mode.test.ts',
|
||||
'src/main/native-chat/agent-session-wire/structured-agent-session-queued-legacy-import.test.ts',
|
||||
'src/main/runtime/agent-session-conversation-name-store.test.ts',
|
||||
'src/main/runtime/structured-session-mail-redrive-wiring.test.ts',
|
||||
'src/main/runtime/rpc/ws-transport.test.ts',
|
||||
'src/main/runtime/rpc/dispatcher-transport-parity.test.ts',
|
||||
'src/main/runtime/rpc/methods/structured-agent-session-visual.test.ts',
|
||||
|
||||
@@ -28,8 +28,7 @@ it('routes native-chat journal and record-store SQLite contracts through Node',
|
||||
'src/main/native-chat/agent-session-wire/structured-agent-session-status-feed.test.ts',
|
||||
'src/main/native-chat/agent-session-wire/structured-agent-session-status-first-input-identity.test.ts',
|
||||
'src/main/native-chat/structured-chat-naming.test.ts',
|
||||
'src/main/runtime/agent-session-conversation-name-store.test.ts',
|
||||
'src/main/runtime/structured-session-mail-redrive-wiring.test.ts'
|
||||
'src/main/runtime/agent-session-conversation-name-store.test.ts'
|
||||
])
|
||||
)
|
||||
})
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import { expect, it } from 'vitest'
|
||||
import { codexSpawnEnoent, WINDOWS_ONLY_AGENT_CLI_DIR } from './windows-only-agent-cli'
|
||||
|
||||
it('words a Codex spawn ENOENT by what was resolved', () => {
|
||||
expect(codexSpawnEnoent(`${WINDOWS_ONLY_AGENT_CLI_DIR}/codex`)).toEqual({
|
||||
message:
|
||||
'Codex is installed only on Windows, not in this WSL distro. Install it inside the distro.',
|
||||
missing: true
|
||||
})
|
||||
expect(codexSpawnEnoent('codex')).toEqual({ message: 'Codex CLI not found.', missing: true })
|
||||
expect(codexSpawnEnoent('/usr/lib/node_modules/codex/bin/codex.js').missing).toBe(false)
|
||||
})
|
||||
@@ -1,92 +0,0 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
const mocks = await vi.hoisted(async () => {
|
||||
const { createGitHubIpcMocks } = await import('./github-ipc-module-mocks')
|
||||
return createGitHubIpcMocks()
|
||||
})
|
||||
|
||||
vi.mock('electron', () => mocks.electron)
|
||||
vi.mock('../github/client', () => mocks.client)
|
||||
vi.mock('../github/work-item-details', () => mocks.workItemDetails)
|
||||
vi.mock('../github/pr-refresh-coordinator', () => mocks.prRefresh)
|
||||
vi.mock('../telemetry/client', () => mocks.telemetry)
|
||||
vi.mock('../telemetry/cohort-classifier', () => mocks.cohort)
|
||||
vi.mock('./ui', () => mocks.ui)
|
||||
|
||||
import { registerGitHubHandlers } from './github'
|
||||
import { createGitHubIpcHarness } from './github-ipc-test-harness'
|
||||
|
||||
const { getAuthenticatedViewer: getAuthenticatedViewerMock, starOrca: starOrcaMock } = mocks.client
|
||||
const { track: trackMock } = mocks.telemetry
|
||||
const { getCohortAtEmit: getCohortAtEmitMock } = mocks.cohort
|
||||
|
||||
describe('registerGitHubHandlers', () => {
|
||||
const harness = createGitHubIpcHarness(mocks)
|
||||
const { handlers, store, stats } = harness
|
||||
|
||||
beforeEach(harness.reset)
|
||||
|
||||
it('forwards the authenticated viewer lookup', async () => {
|
||||
getAuthenticatedViewerMock.mockResolvedValue({ login: 'octocat', email: 'octocat@example.com' })
|
||||
|
||||
registerGitHubHandlers(store as never, stats as never)
|
||||
|
||||
await expect(handlers['gh:viewer'](null, undefined)).resolves.toEqual({
|
||||
login: 'octocat',
|
||||
email: 'octocat@example.com'
|
||||
})
|
||||
expect(getAuthenticatedViewerMock).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('emits app_starred_orca once after a successful star with cohort context', async () => {
|
||||
starOrcaMock.mockResolvedValue(true)
|
||||
getCohortAtEmitMock.mockReturnValue({ nth_repo_added: 3 })
|
||||
|
||||
registerGitHubHandlers(store as never, stats as never)
|
||||
|
||||
await expect(handlers['gh:starOrca'](null, 'settings')).resolves.toBe(true)
|
||||
|
||||
expect(starOrcaMock).toHaveBeenCalledTimes(1)
|
||||
expect(getCohortAtEmitMock).toHaveBeenCalledTimes(1)
|
||||
expect(trackMock).toHaveBeenCalledTimes(1)
|
||||
expect(trackMock).toHaveBeenCalledWith('app_starred_orca', {
|
||||
source: 'settings',
|
||||
nth_repo_added: 3
|
||||
})
|
||||
})
|
||||
|
||||
it('does not emit app_starred_orca when the star action returns false', async () => {
|
||||
starOrcaMock.mockResolvedValue(false)
|
||||
|
||||
registerGitHubHandlers(store as never, stats as never)
|
||||
|
||||
await expect(handlers['gh:starOrca'](null, 'landing')).resolves.toBe(false)
|
||||
|
||||
expect(starOrcaMock).toHaveBeenCalledTimes(1)
|
||||
expect(trackMock).not.toHaveBeenCalled()
|
||||
expect(getCohortAtEmitMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('does not emit app_starred_orca when the star action throws', async () => {
|
||||
starOrcaMock.mockRejectedValue(new Error('gh failed'))
|
||||
|
||||
registerGitHubHandlers(store as never, stats as never)
|
||||
|
||||
await expect(handlers['gh:starOrca'](null, 'star_nag')).rejects.toThrow('gh failed')
|
||||
|
||||
expect(trackMock).not.toHaveBeenCalled()
|
||||
expect(getCohortAtEmitMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('preserves star result but skips telemetry for an invalid IPC source', async () => {
|
||||
starOrcaMock.mockResolvedValue(true)
|
||||
|
||||
registerGitHubHandlers(store as never, stats as never)
|
||||
|
||||
await expect(handlers['gh:starOrca'](null, 'github_website')).resolves.toBe(true)
|
||||
|
||||
expect(starOrcaMock).toHaveBeenCalledTimes(1)
|
||||
expect(trackMock).not.toHaveBeenCalled()
|
||||
expect(getCohortAtEmitMock).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
@@ -1,85 +0,0 @@
|
||||
import { expect, it, vi } from 'vitest'
|
||||
|
||||
const {
|
||||
handleMock,
|
||||
setMainUiLanguageMock,
|
||||
rebuildSystemTrayMenuMock,
|
||||
applyElectronProxySettingsMock,
|
||||
applyAgentStatusHooksEnabledMock,
|
||||
trackMock
|
||||
} = vi.hoisted(() => ({
|
||||
handleMock: vi.fn(),
|
||||
setMainUiLanguageMock: vi.fn(),
|
||||
rebuildSystemTrayMenuMock: vi.fn(),
|
||||
applyElectronProxySettingsMock: vi.fn(),
|
||||
applyAgentStatusHooksEnabledMock: vi.fn(),
|
||||
trackMock: vi.fn()
|
||||
}))
|
||||
|
||||
vi.mock('electron', () => ({
|
||||
app: { getPath: vi.fn(() => '/test/user-data') },
|
||||
BrowserWindow: { getAllWindows: vi.fn(() => []) },
|
||||
ipcMain: { handle: handleMock, on: vi.fn() },
|
||||
nativeTheme: { themeSource: 'system' }
|
||||
}))
|
||||
vi.mock('../telemetry/client', () => ({ track: trackMock }))
|
||||
vi.mock('../telemetry/cohort-classifier', () => ({
|
||||
getCohortAtEmit: () => ({ nth_repo_added: 2 })
|
||||
}))
|
||||
vi.mock('../ssh/config/ssh-config-parser', () => ({
|
||||
loadUserSshConfig: () => ({ hosts: [] }),
|
||||
sshConfigHostsToTargets: () => []
|
||||
}))
|
||||
vi.mock('../ghostty/index', () => ({ previewGhosttyImport: vi.fn() }))
|
||||
vi.mock('../warp-themes', () => ({ previewWarpThemeImport: vi.fn() }))
|
||||
vi.mock('../network/proxy-settings', () => ({
|
||||
applyElectronProxySettings: applyElectronProxySettingsMock
|
||||
}))
|
||||
vi.mock('../browser/browser-session-proxy', () => ({
|
||||
applyBrowserSessionProxies: vi.fn().mockResolvedValue(undefined)
|
||||
}))
|
||||
vi.mock('../browser/browser-session-registry', () => ({
|
||||
browserSessionRegistry: { listProfiles: vi.fn(() => []) }
|
||||
}))
|
||||
vi.mock('../app-icon', () => ({ applyAppIcon: vi.fn() }))
|
||||
vi.mock('../ai-vault-search/session-search-enablement', () => ({
|
||||
applySessionSearchSettingsChange: vi.fn()
|
||||
}))
|
||||
vi.mock('../agent-hooks/managed-agent-hook-controls', () => ({
|
||||
applyAgentStatusHooksEnabled: applyAgentStatusHooksEnabledMock
|
||||
}))
|
||||
vi.mock('../worktree-root-preparation', () => ({
|
||||
prepareLocalWorktreeRootsForRepos: vi.fn().mockResolvedValue(undefined)
|
||||
}))
|
||||
vi.mock('../menu/register-app-menu', () => ({ rebuildAppMenu: vi.fn() }))
|
||||
vi.mock('../tray/system-tray', () => ({ rebuildSystemTrayMenu: rebuildSystemTrayMenuMock }))
|
||||
vi.mock('../i18n/main-i18n', () => ({ setMainUiLanguage: setMainUiLanguageMock }))
|
||||
|
||||
import { registerSettingsHandlers } from './settings'
|
||||
|
||||
it('records Agent Dashboard enablement only for a real setting transition', async () => {
|
||||
const store = {
|
||||
getSettings: vi.fn(() => ({ experimentalAgentDashboardPopout: false })),
|
||||
updateSettings: vi.fn(() => ({ experimentalAgentDashboardPopout: true })),
|
||||
onSettingsChanged: vi.fn(() => () => {})
|
||||
}
|
||||
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: This handler only uses the settings methods supplied by the fixture.
|
||||
registerSettingsHandlers(store as never)
|
||||
const handler = handleMock.mock.calls.find(([channel]) => channel === 'settings:set')?.[1]
|
||||
if (typeof handler !== 'function') {
|
||||
throw new Error('Missing settings:set handler')
|
||||
}
|
||||
|
||||
await handler({ sender: { id: 1 } }, { experimentalAgentDashboardPopout: true })
|
||||
|
||||
expect(trackMock).toHaveBeenCalledWith('agent_dashboard_enabled', { enabled: true })
|
||||
|
||||
trackMock.mockClear()
|
||||
store.getSettings.mockReturnValue({ experimentalAgentDashboardPopout: true })
|
||||
await handler({ sender: { id: 1 } }, { experimentalAgentDashboardPopout: true })
|
||||
expect(trackMock).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
vi.mock('../claude/agent-view-service', () => ({
|
||||
getClaudeAgentViewService: () => ({ reconcile: async () => {} })
|
||||
}))
|
||||
@@ -10,12 +10,6 @@ import {
|
||||
afterEach(() => resetHostMallocTunablesForTests())
|
||||
|
||||
describe('host malloc tunables', () => {
|
||||
it('launches with the mmap threshold glibc reads at exec', () => {
|
||||
expect(Object.fromEntries(hostMallocTunablesLaunchEnv()).GLIBC_TUNABLES).toBe(
|
||||
'glibc.malloc.mmap_threshold=16384'
|
||||
)
|
||||
})
|
||||
|
||||
it('removes what the launch set from this process, and keeps it only for the daemon', () => {
|
||||
const env: NodeJS.ProcessEnv = {
|
||||
PATH: '/bin',
|
||||
@@ -49,16 +43,3 @@ describe('host malloc tunables', () => {
|
||||
expect(HOST_MALLOC_TUNABLES).toContain('mmap_threshold')
|
||||
})
|
||||
})
|
||||
|
||||
describe('host process entries', () => {
|
||||
it.each(['../orcad/main.ts', '../daemon/daemon-entry.ts'])(
|
||||
'%s claims the tunables before importing anything that could start a child',
|
||||
async (entry) => {
|
||||
const { readFile } = await import('node:fs/promises')
|
||||
const source = await readFile(new URL(entry, import.meta.url), 'utf8')
|
||||
expect(source.match(/^import .*$/m)?.[0]).toBe(
|
||||
"import '../memory/host-malloc-tunables-claim'"
|
||||
)
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import type { AgentSessionRecord } from '../../../shared/agent-session-record'
|
||||
import { claudeAndCodexDeclared } from './structured-agent-session-adapter-router-test-support'
|
||||
import { structuredAgentSessionLaunchPermission } from './structured-agent-session-launch-permission'
|
||||
|
||||
function record(provider: string, saved: Record<string, string> | undefined): AgentSessionRecord {
|
||||
const { permissionMode, ...options } = saved ?? {}
|
||||
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the launch mode reads only the record's id, agent, options and mode.
|
||||
return { sessionId: 'session-1', provider, options, permissionMode } as AgentSessionRecord
|
||||
}
|
||||
|
||||
function launchPermission(provider: string, options?: Record<string, string>) {
|
||||
return structuredAgentSessionLaunchPermission(
|
||||
{ agents: claudeAndCodexDeclared() },
|
||||
record(provider, options)
|
||||
)
|
||||
}
|
||||
|
||||
describe('the permission mode a chat starts with', () => {
|
||||
it('delegates saved own settings', async () => {
|
||||
for (const provider of ['claude', 'codex']) {
|
||||
await expect(launchPermission(provider, { permissionMode: 'own' })).resolves.toBe('own')
|
||||
}
|
||||
})
|
||||
|
||||
it('has none for an unregistered agent or one with no modes', async () => {
|
||||
await expect(launchPermission('grok', { permissionMode: 'full-access' })).resolves.toBe(null)
|
||||
await expect(launchPermission('pi', { permissionMode: 'full-access' })).resolves.toBe(null)
|
||||
})
|
||||
})
|
||||
@@ -1,4 +1,4 @@
|
||||
import { mkdtempSync, readFileSync, rmSync } from 'node:fs'
|
||||
import { mkdtempSync, rmSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
@@ -33,13 +33,6 @@ async function ensureFrom(
|
||||
}
|
||||
|
||||
describe('orcad agent-session claim signer', () => {
|
||||
it('wires the persistent signer from orcad user data into its runtime', () => {
|
||||
const entry = readFileSync(join(import.meta.dirname, 'orcad-entry.ts'), 'utf8')
|
||||
expect(entry).toContain(
|
||||
'agentSessionClaimSigner: loadAgentSessionClaimSigner(runtimeUserDataPath, runtimeUserDataPath)'
|
||||
)
|
||||
})
|
||||
|
||||
it('adopts the live PTY after an orcad restart instead of starting a second writer', async () => {
|
||||
const userData = mkdtempSync(join(tmpdir(), 'orcad-claim-signer-'))
|
||||
try {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { mkdtempSync, readFileSync, rmSync } from 'node:fs'
|
||||
import { mkdtempSync, rmSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
@@ -68,15 +68,4 @@ describe('orcad automations', () => {
|
||||
cleanups.forEach((cleanup) => cleanup())
|
||||
}
|
||||
})
|
||||
|
||||
it('lets a host with no enabled schedule and no unsettled run idle out', () => {
|
||||
const store = { listAutomations: () => [], listAutomationRuns: () => [] }
|
||||
expect(orcadAutomationsKeepHostBusy(store)).toBe(false)
|
||||
})
|
||||
|
||||
it('orcad starts the service with its runtime and feeds it to managed idle exit', () => {
|
||||
const entry = readFileSync(join(import.meta.dirname, 'orcad-entry.ts'), 'utf8')
|
||||
expect(entry).toContain('startOrcadAutomations(runtime, profileStore, registerCleanup)')
|
||||
expect(entry).toContain('automationsBusy: () => orcadAutomationsKeepHostBusy(profileStore)')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { join } from 'node:path'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import {
|
||||
flushOrcadProfileStoreForShutdown,
|
||||
@@ -152,46 +150,4 @@ describe('orcad profile-state shutdown', () => {
|
||||
vi.useRealTimers()
|
||||
}
|
||||
})
|
||||
|
||||
it('flushes durably before closing the profile store', async () => {
|
||||
const events: string[] = []
|
||||
const store = {
|
||||
flushFinalOrThrowAsync: vi.fn(async () => {
|
||||
events.push('flush')
|
||||
}),
|
||||
freezeWritesAsync: vi.fn(async () => {
|
||||
events.push('freeze')
|
||||
})
|
||||
}
|
||||
|
||||
await flushOrcadProfileStoreForShutdown(store)
|
||||
|
||||
expect(store.flushFinalOrThrowAsync).toHaveBeenCalledExactlyOnceWith()
|
||||
expect(store.freezeWritesAsync).toHaveBeenCalledOnce()
|
||||
expect(events).toEqual(['flush', 'freeze'])
|
||||
})
|
||||
|
||||
it('closes the profile store even when the durable flush fails', async () => {
|
||||
const flushError = new Error('profile flush failed')
|
||||
const freezeWritesAsync = vi.fn(async () => {})
|
||||
const store = {
|
||||
flushFinalOrThrowAsync: vi.fn(async () => {
|
||||
throw flushError
|
||||
}),
|
||||
freezeWritesAsync
|
||||
}
|
||||
|
||||
await expect(flushOrcadProfileStoreForShutdown(store)).rejects.toBe(flushError)
|
||||
expect(freezeWritesAsync).toHaveBeenCalledOnce()
|
||||
})
|
||||
})
|
||||
|
||||
describe('orcad runtime cleanup order', () => {
|
||||
it('closes notification dismissals in a cleanup that runs after RPC stops', () => {
|
||||
const entry = readFileSync(join(import.meta.dirname, 'orcad-entry.ts'), 'utf8')
|
||||
const close = entry.indexOf('registerCleanup(() => runtime.closeNotificationDismissals())')
|
||||
const rpcStop = entry.indexOf('registerCleanup(() => rpc.stop())')
|
||||
expect(close).toBeGreaterThan(-1)
|
||||
expect(close).toBeLessThan(rpcStop)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -107,16 +107,3 @@ describe('orcad trace file', () => {
|
||||
expect(readFileSync(join(dataRoot, 'logs'), 'utf8')).toBe('not a folder')
|
||||
})
|
||||
})
|
||||
|
||||
// Inspect entry wiring without booting the full runtime.
|
||||
it('orcad installs the trace file before its runtime and closes it after every quit handler', () => {
|
||||
const entry = readFileSync(join(import.meta.dirname, 'orcad-entry.ts'), 'utf8')
|
||||
const install = entry.indexOf('closeOrcadObservability = installOrcadObservability()')
|
||||
expect(install).toBeGreaterThan(-1)
|
||||
expect(install).toBeLessThan(entry.indexOf('new OrcaRuntimeService('))
|
||||
const quit = entry.indexOf(' runOrcadQuitHandlers()\n')
|
||||
expect(quit).toBeGreaterThan(-1)
|
||||
const close = entry.indexOf(' closeOrcadObservability()\n', quit)
|
||||
expect(close).toBeGreaterThan(quit)
|
||||
expect(entry.slice(quit, close)).toContain('} finally {')
|
||||
})
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
import '../unused-default-rpc-methods.test-fixture'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { RpcDispatcher } from '../dispatcher'
|
||||
import type { RpcRequest } from '../core'
|
||||
import type { OrcaRuntimeService } from '../../orca-runtime'
|
||||
|
||||
const {
|
||||
isPwshAvailable,
|
||||
isPwshAvailableAsync,
|
||||
isWslAvailableAsync,
|
||||
listWslDistros,
|
||||
listWslDistrosAsync,
|
||||
isGitBashAvailable
|
||||
} = vi.hoisted(() => ({
|
||||
isPwshAvailable: vi.fn(),
|
||||
isPwshAvailableAsync: vi.fn(),
|
||||
isWslAvailableAsync: vi.fn(),
|
||||
listWslDistros: vi.fn(),
|
||||
listWslDistrosAsync: vi.fn(),
|
||||
isGitBashAvailable: vi.fn()
|
||||
}))
|
||||
|
||||
vi.mock('../../../pwsh', () => ({ isPwshAvailable, isPwshAvailableAsync }))
|
||||
vi.mock('../../../wsl', () => ({
|
||||
isWslAvailableAsync,
|
||||
listWslDistros,
|
||||
listWslDistrosAsync
|
||||
}))
|
||||
vi.mock('../../../git-bash', () => ({ isGitBashAvailable }))
|
||||
|
||||
import { HOST_CAPABILITY_METHODS } from './host-capabilities'
|
||||
|
||||
function makeRequest(method: string, params?: unknown): RpcRequest {
|
||||
return { id: 'req-1', authToken: 'tok', method, params }
|
||||
}
|
||||
|
||||
describe('host capability RPC methods', () => {
|
||||
beforeEach(() => {
|
||||
isPwshAvailable.mockReset()
|
||||
isPwshAvailableAsync.mockReset()
|
||||
isWslAvailableAsync.mockReset()
|
||||
listWslDistros.mockReset()
|
||||
listWslDistrosAsync.mockReset()
|
||||
isGitBashAvailable.mockReset()
|
||||
})
|
||||
|
||||
it('reports Windows shell capability probes through explicit methods', async () => {
|
||||
isPwshAvailableAsync.mockResolvedValue(true)
|
||||
isWslAvailableAsync.mockResolvedValue(true)
|
||||
listWslDistrosAsync.mockResolvedValue(['Ubuntu'])
|
||||
isGitBashAvailable.mockReturnValue(true)
|
||||
const runtime = { getRuntimeId: () => 'test-runtime' } as unknown as OrcaRuntimeService
|
||||
const dispatcher = new RpcDispatcher({ runtime, methods: HOST_CAPABILITY_METHODS })
|
||||
|
||||
await expect(dispatcher.dispatch(makeRequest('host.pwsh.isAvailable'))).resolves.toMatchObject({
|
||||
ok: true,
|
||||
result: true
|
||||
})
|
||||
await expect(dispatcher.dispatch(makeRequest('host.wsl.isAvailable'))).resolves.toMatchObject({
|
||||
ok: true,
|
||||
result: true
|
||||
})
|
||||
await expect(dispatcher.dispatch(makeRequest('host.wsl.listDistros'))).resolves.toMatchObject({
|
||||
ok: true,
|
||||
result: ['Ubuntu']
|
||||
})
|
||||
await expect(
|
||||
dispatcher.dispatch(makeRequest('host.gitBash.isAvailable'))
|
||||
).resolves.toMatchObject({
|
||||
ok: true,
|
||||
result: true
|
||||
})
|
||||
})
|
||||
|
||||
// Paired capability reads must not block the main loop with synchronous wsl.exe/pwsh.exe probes (up to 5s).
|
||||
it('answers the Windows shell capability methods without a blocking spawn', async () => {
|
||||
isPwshAvailableAsync.mockResolvedValue(false)
|
||||
isWslAvailableAsync.mockResolvedValue(false)
|
||||
listWslDistrosAsync.mockResolvedValue([])
|
||||
const runtime = { getRuntimeId: () => 'test-runtime' } as unknown as OrcaRuntimeService
|
||||
const dispatcher = new RpcDispatcher({ runtime, methods: HOST_CAPABILITY_METHODS })
|
||||
|
||||
await dispatcher.dispatch(makeRequest('host.wsl.isAvailable'))
|
||||
await dispatcher.dispatch(makeRequest('host.wsl.listDistros'))
|
||||
await dispatcher.dispatch(makeRequest('host.pwsh.isAvailable'))
|
||||
|
||||
expect(isWslAvailableAsync).toHaveBeenCalledTimes(1)
|
||||
expect(listWslDistrosAsync).toHaveBeenCalledTimes(1)
|
||||
expect(isPwshAvailableAsync).toHaveBeenCalledTimes(1)
|
||||
expect(listWslDistros).not.toHaveBeenCalled()
|
||||
expect(isPwshAvailable).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
@@ -1,75 +0,0 @@
|
||||
import '../unused-default-rpc-methods.test-fixture'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { STRUCTURED_AGENT_SESSION_RUNTIME_CAPABILITY } from '../../../../shared/protocol-version'
|
||||
import type { OrcaRuntimeService } from '../../orca-runtime'
|
||||
import type { RpcRequest } from '../core'
|
||||
import { RpcDispatcher } from '../dispatcher'
|
||||
import { RUNTIME_CLIENT_CAPABILITY_METHODS } from './runtime-client-capabilities'
|
||||
|
||||
function makeRequest(params: unknown): RpcRequest {
|
||||
return {
|
||||
id: 'req-1',
|
||||
authToken: 'tok',
|
||||
method: 'runtime.clientCapabilities.update',
|
||||
params
|
||||
}
|
||||
}
|
||||
|
||||
function dispatcher(): RpcDispatcher {
|
||||
return new RpcDispatcher({
|
||||
runtime: { getRuntimeId: () => 'runtime-1' } as unknown as OrcaRuntimeService,
|
||||
methods: RUNTIME_CLIENT_CAPABILITY_METHODS
|
||||
})
|
||||
}
|
||||
|
||||
describe('runtime.clientCapabilities.update', () => {
|
||||
it('updates the authenticated socket capability set after auth', async () => {
|
||||
const updateClientCapabilities = vi.fn()
|
||||
|
||||
const response = await dispatcher().dispatch(
|
||||
makeRequest({
|
||||
clientCapabilities: [STRUCTURED_AGENT_SESSION_RUNTIME_CAPABILITY]
|
||||
}),
|
||||
{ clientKind: 'mobile', updateClientCapabilities }
|
||||
)
|
||||
|
||||
expect(response).toMatchObject({
|
||||
ok: true,
|
||||
result: { clientCapabilities: [STRUCTURED_AGENT_SESSION_RUNTIME_CAPABILITY] }
|
||||
})
|
||||
expect(updateClientCapabilities).toHaveBeenCalledWith([
|
||||
STRUCTURED_AGENT_SESSION_RUNTIME_CAPABILITY
|
||||
])
|
||||
})
|
||||
|
||||
it('rejects malformed upgrades without mutating authenticated state', async () => {
|
||||
const updateClientCapabilities = vi.fn()
|
||||
|
||||
const response = await dispatcher().dispatch(
|
||||
makeRequest({
|
||||
clientCapabilities: [42]
|
||||
}),
|
||||
{ clientKind: 'mobile', updateClientCapabilities }
|
||||
)
|
||||
|
||||
expect(response).toMatchObject({
|
||||
ok: false,
|
||||
error: { code: 'invalid_argument' }
|
||||
})
|
||||
expect(updateClientCapabilities).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('fails closed when a transport has no post-auth updater', async () => {
|
||||
const response = await dispatcher().dispatch(
|
||||
makeRequest({
|
||||
clientCapabilities: [STRUCTURED_AGENT_SESSION_RUNTIME_CAPABILITY]
|
||||
}),
|
||||
{ clientKind: 'runtime' }
|
||||
)
|
||||
|
||||
expect(response).toMatchObject({
|
||||
ok: false,
|
||||
error: { message: 'client_capabilities_update_unsupported' }
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -1,58 +0,0 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { OrcaRuntimeService } from './orca-runtime-test-mocks.spec'
|
||||
import { store } from './orca-runtime-test-fixtures.spec'
|
||||
import { ORCAD_MIGRATION_MANIFEST_VERSION } from '../../shared/orcad-migration/orcad-migration-manifest-validation'
|
||||
import type {
|
||||
OrcadMigrationCatalogState,
|
||||
OrcadMigrationManifest
|
||||
} from '../../shared/orcad-migration/orcad-migration-manifest'
|
||||
|
||||
const manifest: OrcadMigrationManifest = {
|
||||
version: ORCAD_MIGRATION_MANIFEST_VERSION,
|
||||
migrationId: 'migration-capabilities',
|
||||
createdAt: '2026-08-30T12:00:00.000Z',
|
||||
source: { sshTargetId: 'source', sshTargetGeneration: null, targetLabel: 'Source' },
|
||||
payload: { repositories: [], projectGroups: [], folderWorkspaces: [] },
|
||||
manifestSha256: '0'.repeat(64)
|
||||
}
|
||||
|
||||
const staged: OrcadMigrationCatalogState = {
|
||||
state: 'staged',
|
||||
migrationId: manifest.migrationId,
|
||||
manifestSha256: manifest.manifestSha256,
|
||||
stagedAt: manifest.createdAt
|
||||
}
|
||||
|
||||
describe('runtime migration catalog capabilities', () => {
|
||||
it('refuses a catalog read when the runtime has no store', () => {
|
||||
const runtime = new OrcaRuntimeService(null)
|
||||
expect(() => runtime.getOrcadMigrationCatalogState(manifest)).toThrow('runtime_unavailable')
|
||||
})
|
||||
|
||||
it('refuses a missing catalog reader on a partial store', () => {
|
||||
const runtime = new OrcaRuntimeService(store)
|
||||
expect(() => runtime.getOrcadMigrationCatalogState(manifest)).toThrow('runtime_unavailable')
|
||||
})
|
||||
|
||||
it('refuses staging before mutation when the partial store cannot flush', async () => {
|
||||
const stage = vi.fn(() => staged)
|
||||
const runtime = new OrcaRuntimeService({ ...store, stageOrcadMigrationCatalog: stage })
|
||||
await expect(runtime.stageOrcadMigrationCatalog(manifest)).rejects.toThrow(
|
||||
'runtime_unavailable'
|
||||
)
|
||||
expect(stage).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('admits staging with only the methods that operation needs', async () => {
|
||||
const stage = vi.fn(() => staged)
|
||||
const flush = vi.fn(async () => {})
|
||||
const runtime = new OrcaRuntimeService({
|
||||
...store,
|
||||
stageOrcadMigrationCatalog: stage,
|
||||
flushPendingOrThrowAsync: flush
|
||||
})
|
||||
await expect(runtime.stageOrcadMigrationCatalog(manifest)).resolves.toBe(staged)
|
||||
expect(stage).toHaveBeenCalledWith(manifest)
|
||||
expect(flush).toHaveBeenCalledOnce()
|
||||
})
|
||||
})
|
||||
@@ -1,63 +0,0 @@
|
||||
// Exercise production status-to-mail-redrive wiring; integration tests inject that callback and cannot detect missing runtime wiring.
|
||||
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import type { AgentSessionStatusSummary } from '../../shared/agent-session-wire'
|
||||
import type * as StructuredAgentSessionRuntime from './structured-agent-session-runtime'
|
||||
import type { StructuredAgentSessionRuntimeDeps } from './structured-agent-session-runtime'
|
||||
|
||||
const installed = vi.hoisted((): { deps: StructuredAgentSessionRuntimeDeps | null } => ({
|
||||
deps: null
|
||||
}))
|
||||
|
||||
vi.mock('./structured-agent-session-runtime', async (importOriginal) => ({
|
||||
...(await importOriginal<typeof StructuredAgentSessionRuntime>()),
|
||||
ensureStructuredAgentSessionHost: vi.fn(async (deps: StructuredAgentSessionRuntimeDeps) => {
|
||||
installed.deps = deps
|
||||
return {}
|
||||
})
|
||||
}))
|
||||
|
||||
const { OrcaRuntimeService } = await import('./orca-runtime')
|
||||
const { OrchestrationDb } = await import('./orchestration/db')
|
||||
|
||||
describe("the runtime's own structured host install", () => {
|
||||
it('reports every session status change to the mail redrive', async () => {
|
||||
const runtime = new OrcaRuntimeService()
|
||||
const redrive = vi
|
||||
.spyOn(runtime, 'onStructuredSessionStatusForMail')
|
||||
.mockImplementation(() => {})
|
||||
await runtime.ensureStructuredAgentSessionHost()
|
||||
const summary: AgentSessionStatusSummary = {
|
||||
sessionId: 'claude_1234abcd',
|
||||
workspaceId: 'workspace-1',
|
||||
agent: 'claude',
|
||||
status: 'idle',
|
||||
latestPrompt: '',
|
||||
updatedAt: 0
|
||||
}
|
||||
try {
|
||||
installed.deps?.onSessionStatusChanged?.(summary, { replay: false })
|
||||
} catch {
|
||||
// The same callback's rename half needs a store this bare runtime does not have.
|
||||
}
|
||||
expect(redrive).toHaveBeenCalledWith(summary)
|
||||
})
|
||||
|
||||
it('logs a redrive the database fails, so the status callback goes on to the workspace rename', () => {
|
||||
const runtime = new OrcaRuntimeService()
|
||||
const closed = new OrchestrationDb(':memory:')
|
||||
closed.close()
|
||||
vi.spyOn(runtime, 'getExistingOrchestrationDb').mockReturnValue(closed)
|
||||
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
||||
expect(() =>
|
||||
runtime.onStructuredSessionStatusForMail({
|
||||
sessionId: '4a1f6c2e-8b3d-4e7a-9c15-0d2b6e8f1a37',
|
||||
status: 'idle'
|
||||
})
|
||||
).not.toThrow()
|
||||
expect(warn).toHaveBeenCalledWith(
|
||||
'[orchestration] structured session mail redrive failed',
|
||||
expect.objectContaining({ sessionId: '4a1f6c2e-8b3d-4e7a-9c15-0d2b6e8f1a37' })
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -1,11 +1,6 @@
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { parseRuntimeClientCapabilities } from './rpc/runtime-client-capabilities'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { ELECTRON_REMOTE_RUNTIME_CLIENT_CAPABILITIES } from '../../shared/electron-remote-runtime-client-capabilities'
|
||||
import {
|
||||
NATIVE_REMOTE_RUNTIME_CLIENT_CAPABILITIES,
|
||||
RUNTIME_CAPABILITIES
|
||||
} from '../../shared/protocol-version'
|
||||
import { NATIVE_REMOTE_RUNTIME_CLIENT_CAPABILITIES } from '../../shared/protocol-version'
|
||||
import { TERMINAL_IMAGE_VIEWER_CAPABILITY } from '../../shared/terminal-image-viewer-capability'
|
||||
import {
|
||||
applyClaudeTerminalImageViewerEnv,
|
||||
@@ -15,24 +10,6 @@ import {
|
||||
const paired = { caller: { kind: 'paired-device', deviceId: 'phone' } as const }
|
||||
afterEach(() => vi.unstubAllEnvs())
|
||||
describe('Claude images follow the launching viewer', () => {
|
||||
it('advertises image decoding only for Electron viewers', () => {
|
||||
expect(ELECTRON_REMOTE_RUNTIME_CLIENT_CAPABILITIES).toContain(TERMINAL_IMAGE_VIEWER_CAPABILITY)
|
||||
expect(parseRuntimeClientCapabilities(ELECTRON_REMOTE_RUNTIME_CLIENT_CAPABILITIES)).toEqual(
|
||||
ELECTRON_REMOTE_RUNTIME_CLIENT_CAPABILITIES
|
||||
)
|
||||
expect(
|
||||
readFileSync(
|
||||
new URL(
|
||||
'../../../mobile/src/transport/mobile-runtime-client-capabilities.ts',
|
||||
import.meta.url
|
||||
),
|
||||
'utf8'
|
||||
)
|
||||
).not.toContain('TERMINAL_IMAGE_VIEWER_CAPABILITY')
|
||||
for (const caps of [NATIVE_REMOTE_RUNTIME_CLIENT_CAPABILITIES, RUNTIME_CAPABILITIES]) {
|
||||
expect(caps).not.toContain(TERMINAL_IMAGE_VIEWER_CAPABILITY)
|
||||
}
|
||||
})
|
||||
it.each([undefined, [], NATIVE_REMOTE_RUNTIME_CLIENT_CAPABILITIES])(
|
||||
'keeps older and native clients on old output %#',
|
||||
(clientCapabilities) => {
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import type { OrcadMigrationManifest } from '../../shared/orcad-migration/orcad-migration-manifest'
|
||||
import type { OrcadMigrationSourceCutover } from '../../shared/orcad-migration/orcad-migration-source-cutover'
|
||||
|
||||
const journal = vi.hoisted(() => {
|
||||
const state: {
|
||||
cutovers: Pick<OrcadMigrationSourceCutover, 'phase' | 'manifest'>[]
|
||||
listener: ((userDataPath: string) => void) | null
|
||||
} = { cutovers: [], listener: null }
|
||||
return state
|
||||
})
|
||||
vi.mock('./orcad-migration-cutover-journal', () => ({
|
||||
listOrcadMigrationSourceCutovers: () => journal.cutovers,
|
||||
setOrcadMigrationJournalChangeListener: (listener: (path: string) => void) => {
|
||||
journal.listener = listener
|
||||
}
|
||||
}))
|
||||
|
||||
const { installOrcadMigrationScrollbackRetention } =
|
||||
await import('./orcad-migration-scrollback-retention-wiring')
|
||||
|
||||
function manifest(migrationId: string): OrcadMigrationManifest {
|
||||
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the wiring only forwards manifests; the store fake reads the id.
|
||||
return { migrationId } as OrcadMigrationManifest
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
journal.cutovers = []
|
||||
journal.listener = null
|
||||
})
|
||||
|
||||
describe('scrollback retention follows the migration journal', () => {
|
||||
it('holds from the fence until commit, across journal changes and a restart', () => {
|
||||
const sync = vi.fn<(pending: readonly OrcadMigrationManifest[]) => void>()
|
||||
const held = (): string[] =>
|
||||
(sync.mock.calls.at(-1)?.[0] ?? []).map((entry) => entry.migrationId)
|
||||
journal.cutovers = [{ phase: 'source-fenced', manifest: manifest('m1') }]
|
||||
|
||||
// Startup rebuilds what an unfinished journal holds.
|
||||
installOrcadMigrationScrollbackRetention('/profile', {
|
||||
syncOrcadMigrationScrollbackRetention: sync
|
||||
})
|
||||
expect(held()).toEqual(['m1'])
|
||||
|
||||
journal.cutovers = [{ phase: 'destination-staged', manifest: manifest('m1') }]
|
||||
journal.listener?.('/profile')
|
||||
expect(held()).toEqual(['m1'])
|
||||
|
||||
journal.cutovers = [{ phase: 'destination-committed', manifest: manifest('m1') }]
|
||||
journal.listener?.('/profile')
|
||||
expect(held()).toEqual([])
|
||||
})
|
||||
|
||||
it('keeps what it holds when the journal cannot be read', () => {
|
||||
const sync = vi.fn()
|
||||
installOrcadMigrationScrollbackRetention('/profile', {
|
||||
syncOrcadMigrationScrollbackRetention: sync
|
||||
})
|
||||
journal.cutovers = new Proxy([], {
|
||||
get: () => {
|
||||
throw new Error('unreadable')
|
||||
}
|
||||
})
|
||||
journal.listener?.('/profile')
|
||||
expect(sync).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
@@ -49,18 +49,6 @@ describe('burst-cap', () => {
|
||||
expect(allowed).toBeLessThanOrEqual(15)
|
||||
})
|
||||
|
||||
it('emits exactly one warn the first time the per-event cap is crossed', () => {
|
||||
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
||||
for (let i = 0; i < 30; i++) {
|
||||
consumeBurstToken('app_opened')
|
||||
}
|
||||
consumeBurstToken('app_opened')
|
||||
consumeBurstToken('app_opened')
|
||||
consumeBurstToken('app_opened')
|
||||
consumeBurstToken('app_opened')
|
||||
expect(warn).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('rejects unknown event names without creating a bucket (prevents unbounded Map growth)', () => {
|
||||
// Reject untrusted unknown IPC names before bucket allocation or unique bogus names grow the map indefinitely.
|
||||
const sizeBefore = _getBurstCapStateForTests().perEventBuckets.size
|
||||
@@ -114,17 +102,6 @@ describe('burst-cap', () => {
|
||||
expect(consumeConsentMutationToken()).toBe(false)
|
||||
})
|
||||
|
||||
it('emits exactly one warn when the consent-mutation cap is first crossed', () => {
|
||||
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
||||
for (let i = 0; i < 5; i++) {
|
||||
consumeConsentMutationToken()
|
||||
}
|
||||
consumeConsentMutationToken()
|
||||
consumeConsentMutationToken()
|
||||
consumeConsentMutationToken()
|
||||
expect(warn).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('consent-mutation bucket resets across sessions, not within one', () => {
|
||||
for (let i = 0; i < 5; i++) {
|
||||
consumeConsentMutationToken()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { afterEach, beforeEach, describe, expect, it, type vi } from 'vitest'
|
||||
import type { Store } from '../persistence'
|
||||
import { _setShuttingDownForTests, track, trackAppOpenedOnce } from './client'
|
||||
import {
|
||||
@@ -37,21 +37,6 @@ describe('track()', () => {
|
||||
})
|
||||
})
|
||||
|
||||
// Bound outgoing property keys to the declared schemas plus process-person flag so SDK upgrades cannot silently widen payloads.
|
||||
it('serialized property set is exactly CommonProps plus EventProps plus $process_person_profile', () => {
|
||||
track('workspace_created', { source: 'command_palette', from_existing_branch: true })
|
||||
const call = mock.capture.mock.calls[0]![0]
|
||||
const allowed = new Set([
|
||||
...Object.keys(BASE_COMMON),
|
||||
'source',
|
||||
'from_existing_branch',
|
||||
'$process_person_profile'
|
||||
])
|
||||
for (const key of Object.keys(call.properties)) {
|
||||
expect(allowed.has(key)).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
it('respects the shutdown gate', () => {
|
||||
_setShuttingDownForTests(true)
|
||||
track('app_opened', {})
|
||||
@@ -78,25 +63,6 @@ describe('track()', () => {
|
||||
expect(mock.capture).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('enforces per-event burst cap (30 per minute default)', () => {
|
||||
for (let i = 0; i < 50; i++) {
|
||||
track('app_opened', {})
|
||||
}
|
||||
expect(mock.capture).toHaveBeenCalledTimes(30)
|
||||
})
|
||||
|
||||
it('enforces the per-session 1000-event global ceiling across event names', () => {
|
||||
vi.useFakeTimers()
|
||||
vi.setSystemTime(new Date('2026-05-03T00:00:00Z'))
|
||||
// Refill per-event caps to isolate the session ceiling.
|
||||
for (let i = 0; i < 1500; i++) {
|
||||
vi.advanceTimersByTime(10_000)
|
||||
track('app_opened', {})
|
||||
}
|
||||
expect(mock.capture).toHaveBeenCalledTimes(1000)
|
||||
vi.useRealTimers()
|
||||
})
|
||||
|
||||
it('drops invalid events before calling capture', () => {
|
||||
track('agent_error', {
|
||||
error_class: 'unknown',
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { setLocalRuntimeCapabilitiesForTests } from '@/runtime/local-runtime-capabilities'
|
||||
import { adoptAgentSessionLaunchVerdict } from './agent-session-launch-plan'
|
||||
import { FLOATING_TERMINAL_WORKTREE_ID, getDefaultSettings } from '../../../shared/constants'
|
||||
import { getDefaultSettings } from '../../../shared/constants'
|
||||
import { resolveSourceControlActionRecipe } from '../../../shared/source-control-ai'
|
||||
import type { SourceControlActionRecipe } from '../../../shared/source-control-ai-actions'
|
||||
import { sourceControlActionLaunchOptions } from '../../../shared/source-control-action-launch-preferences'
|
||||
@@ -118,55 +118,6 @@ describe('launchAgentInNewTab terminal tab activation', () => {
|
||||
expect(mockCreateTab).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
// Store activation is scoped to the launch workspace, so floating launches cannot move main-window selection.
|
||||
it.each(['wt-1', FLOATING_TERMINAL_WORKTREE_ID])(
|
||||
'selects the new tab within %s only',
|
||||
async (worktreeId) => {
|
||||
const { launchAgentInNewTab } = await import('./launch-agent-in-new-tab')
|
||||
|
||||
launchAgentInNewTab({ requestId: 'request-1', agent: 'codex', worktreeId })
|
||||
|
||||
expect(mockCreateTab.mock.calls[0]?.[3]).not.toHaveProperty('activate')
|
||||
expect(mockSetActiveTabType).toHaveBeenCalledExactlyOnceWith('terminal', worktreeId)
|
||||
}
|
||||
)
|
||||
|
||||
it('scopes a floating terminal fallback to the floating workspace with Chat UI on', async () => {
|
||||
store.settings = placementSettings({
|
||||
experimentalNativeChat: true,
|
||||
nativeChatSessionOptions: {
|
||||
codex: {
|
||||
model: 'gpt-5.2-codex',
|
||||
valuesByModel: { 'gpt-5.2-codex': { effort: 'medium' } }
|
||||
}
|
||||
}
|
||||
})
|
||||
const { launchAgentInNewTab } = await import('./launch-agent-in-new-tab')
|
||||
|
||||
launchAgentInNewTab({
|
||||
requestId: 'request-2',
|
||||
agent: 'codex',
|
||||
worktreeId: FLOATING_TERMINAL_WORKTREE_ID
|
||||
})
|
||||
|
||||
expect(mockCreateTab).toHaveBeenCalledWith(
|
||||
FLOATING_TERMINAL_WORKTREE_ID,
|
||||
undefined,
|
||||
undefined,
|
||||
{
|
||||
launchAgent: 'codex',
|
||||
quickCommandLabel: undefined,
|
||||
pendingStartup: expect.anything()
|
||||
}
|
||||
)
|
||||
expect(mockSetActiveTabType).toHaveBeenCalledExactlyOnceWith(
|
||||
'terminal',
|
||||
FLOATING_TERMINAL_WORKTREE_ID
|
||||
)
|
||||
// Chat UI model preferences belong to structured chats, not a terminal fallback.
|
||||
expect(queuedStartups()[0]).not.toHaveProperty('sessionOptions')
|
||||
})
|
||||
|
||||
it('applies a saved action choice as terminal flags by scope', async () => {
|
||||
const { launchAgentInNewTab } = await import('./launch-agent-in-new-tab')
|
||||
const base = getDefaultSettings('/tmp')
|
||||
|
||||
@@ -21,19 +21,6 @@ describe('list multi selection', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('replaces selection on plain click', () => {
|
||||
const result = updateSelection({
|
||||
visibleIds,
|
||||
previousSelectedIds: new Set(['wt-1', 'wt-2']),
|
||||
previousAnchorId: 'wt-1',
|
||||
targetId: 'wt-3',
|
||||
intent: 'replace'
|
||||
})
|
||||
|
||||
expect([...result.selectedIds]).toEqual(['wt-3'])
|
||||
expect(result.anchorId).toBe('wt-3')
|
||||
})
|
||||
|
||||
it('toggles one worktree without dropping the rest', () => {
|
||||
const result = updateSelection({
|
||||
visibleIds,
|
||||
|
||||
@@ -64,25 +64,6 @@ vi.mock('@xterm/xterm', () => ({
|
||||
}))
|
||||
|
||||
describe('createPaneDOM link tooltips', () => {
|
||||
it('anchors WebLinks hover text to the unpadded terminal window corner', () => {
|
||||
const leafId = '11111111-1111-4111-8111-111111111111' as TerminalLeafId
|
||||
const pane = createPaneDOM(
|
||||
1,
|
||||
leafId,
|
||||
{ linkOpenHint: () => 'open hint' },
|
||||
{ active: null } as never,
|
||||
{} as never,
|
||||
vi.fn(),
|
||||
vi.fn()
|
||||
)
|
||||
|
||||
// CSS owns tooltip corner offsets; JS must not reintroduce inline padding drift.
|
||||
expect(pane.linkTooltip.classList.contains('pane-link-tooltip')).toBe(true)
|
||||
expect(pane.linkTooltip.style.left).toBe('')
|
||||
expect(pane.linkTooltip.style.bottom).toBe('')
|
||||
expect(pane.linkTooltip.style.display).toBe('none')
|
||||
})
|
||||
|
||||
// Require caller hint wiring at compile time instead of silently falling back to stale copy.
|
||||
it('re-resolves the caller hint on every hover so setting changes apply live', () => {
|
||||
const leafId = '11111111-1111-4111-8111-111111111111' as TerminalLeafId
|
||||
@@ -104,68 +85,6 @@ describe('createPaneDOM link tooltips', () => {
|
||||
webLinksAddonMock.options?.hover?.({} as MouseEvent, 'http://localhost:5180/')
|
||||
expect(pane.linkTooltip.textContent).toBe('http://localhost:5180/ (second hint)')
|
||||
})
|
||||
|
||||
it('lets callers replace WebLinks hover text for display-only labels', async () => {
|
||||
const labeledText = 'http://main.orca.localhost:60016/ (localhost:5180; click to open)'
|
||||
const leafId = '11111111-1111-4111-8111-111111111111' as TerminalLeafId
|
||||
const pane = createPaneDOM(
|
||||
1,
|
||||
leafId,
|
||||
{
|
||||
linkOpenHint: () => 'open hint',
|
||||
formatLinkTooltip: async () => labeledText
|
||||
},
|
||||
{ active: null } as never,
|
||||
{} as never,
|
||||
vi.fn(),
|
||||
vi.fn()
|
||||
)
|
||||
|
||||
webLinksAddonMock.options?.hover?.({} as MouseEvent, 'http://localhost:5180/')
|
||||
await Promise.resolve()
|
||||
|
||||
expect(pane.linkTooltip.textContent).toBe(labeledText)
|
||||
})
|
||||
|
||||
// Both link hooks need hovered pane identity; global runtime focus cannot decide its host routes.
|
||||
it('identifies the hovered pane to both tooltip hooks', () => {
|
||||
const leafId = '11111111-1111-4111-8111-111111111111' as TerminalLeafId
|
||||
const linkOpenHint = vi.fn(() => 'open hint')
|
||||
const formatLinkTooltip = vi.fn(() => null)
|
||||
createPaneDOM(
|
||||
7,
|
||||
leafId,
|
||||
{ linkOpenHint, formatLinkTooltip },
|
||||
{ active: null } as never,
|
||||
{} as never,
|
||||
vi.fn(),
|
||||
vi.fn()
|
||||
)
|
||||
|
||||
webLinksAddonMock.options?.hover?.({} as MouseEvent, 'http://localhost:5180/')
|
||||
|
||||
expect(linkOpenHint).toHaveBeenCalledWith(7)
|
||||
expect(formatLinkTooltip).toHaveBeenCalledWith(7, 'http://localhost:5180/', 'open hint')
|
||||
})
|
||||
|
||||
it('identifies the clicked pane to link routing', () => {
|
||||
const leafId = '11111111-1111-4111-8111-111111111111' as TerminalLeafId
|
||||
const onLinkClick = vi.fn()
|
||||
createPaneDOM(
|
||||
7,
|
||||
leafId,
|
||||
{ linkOpenHint: () => 'open hint', onLinkClick },
|
||||
{ active: null } as never,
|
||||
{} as never,
|
||||
vi.fn(),
|
||||
vi.fn()
|
||||
)
|
||||
const event = {} as MouseEvent
|
||||
|
||||
webLinksAddonMock.handler?.(event, 'https://example.com')
|
||||
|
||||
expect(onLinkClick).toHaveBeenCalledWith(7, event, 'https://example.com')
|
||||
})
|
||||
})
|
||||
|
||||
describe('createPaneDOM mouse encoding', () => {
|
||||
|
||||
@@ -115,47 +115,6 @@ describe('session write subscriber allocation', () => {
|
||||
}
|
||||
)
|
||||
|
||||
it('allocates nothing for store writes that touch no session field', () => {
|
||||
const harness = createHarness()
|
||||
try {
|
||||
harness.write()
|
||||
vi.advanceTimersByTime(500)
|
||||
|
||||
const writes = 200
|
||||
const calls = countFilterCalls(() => {
|
||||
for (let write = 0; write < writes; write += 1) {
|
||||
harness.write((previous) => ({
|
||||
agentStatusByPaneKey: { ...previous.agentStatusByPaneKey, [`p-${write}`]: {} } as never
|
||||
}))
|
||||
}
|
||||
})
|
||||
expect(calls).toBe(0)
|
||||
} finally {
|
||||
harness.dispose()
|
||||
}
|
||||
})
|
||||
|
||||
it('still allocates and persists when a session field really changes', () => {
|
||||
const harness = createHarness()
|
||||
try {
|
||||
harness.write()
|
||||
vi.advanceTimersByTime(500)
|
||||
harness.persisted.length = 0
|
||||
|
||||
const writes = 20
|
||||
const calls = countFilterCalls(() => {
|
||||
for (let write = 0; write < writes; write += 1) {
|
||||
harness.write(() => ({ activeTabId: `tab-${write}` }))
|
||||
}
|
||||
})
|
||||
expect(calls).toBe(writes)
|
||||
vi.advanceTimersByTime(500)
|
||||
expect(harness.persisted).toHaveLength(1)
|
||||
} finally {
|
||||
harness.dispose()
|
||||
}
|
||||
})
|
||||
|
||||
it('still wakes a deferred write when an unrelated field changes', () => {
|
||||
let state = makeSessionState()
|
||||
const listeners: ((next: AppState) => void)[] = []
|
||||
|
||||
@@ -167,10 +167,6 @@ function sentTypes(): string[] {
|
||||
}
|
||||
|
||||
describe('simulator tabs in a layout-owner build', () => {
|
||||
it('starts with main holding the window’s layout', () => {
|
||||
expectSaveTeachesMainNothing()
|
||||
})
|
||||
|
||||
it('opens a simulator tab in the active group through main, and closes it there', async () => {
|
||||
const tabId = ensureSimulatorTab(WORKTREE, { placement: 'activeGroup' })
|
||||
expect(tabId).toBeTruthy()
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import {
|
||||
TERMINAL_INPUT_ACTIVITY_WRITE_INTERVAL_MS,
|
||||
flushTerminalInputActivity,
|
||||
getPendingTerminalInputActivityCountForTests,
|
||||
mergePendingTerminalInputActivity,
|
||||
readLastTerminalInputAt,
|
||||
@@ -10,7 +9,6 @@ import {
|
||||
} from './terminal-input-activity-coalescing'
|
||||
|
||||
const PANE = 'tab-1:leaf-1'
|
||||
const OTHER_PANE = 'tab-2:leaf-2'
|
||||
|
||||
// Minimal stand-in for the store slot the real commit writes into.
|
||||
function createStore(initial: Record<string, number> = {}) {
|
||||
@@ -95,25 +93,6 @@ describe('terminal input activity coalescing', () => {
|
||||
expect(getPendingTerminalInputActivityCountForTests()).toBe(0)
|
||||
})
|
||||
|
||||
it('does not resurrect a pane key that teardown deleted', () => {
|
||||
const store = createStore()
|
||||
|
||||
type(store, PANE, 1_000)
|
||||
type(store, OTHER_PANE, 1_000)
|
||||
type(store, PANE, 1_100)
|
||||
type(store, OTHER_PANE, 1_100)
|
||||
expect(getPendingTerminalInputActivityCountForTests()).toBe(2)
|
||||
|
||||
delete store.stored[PANE]
|
||||
|
||||
flushTerminalInputActivity()
|
||||
|
||||
expect(PANE in store.stored).toBe(false)
|
||||
expect(readLastTerminalInputAt(store.stored, PANE)).toBeUndefined()
|
||||
expect(mergePendingTerminalInputActivity(store.stored)[PANE]).toBeUndefined()
|
||||
expect(store.stored[OTHER_PANE]).toBe(1_100)
|
||||
})
|
||||
|
||||
it('writes immediately again once the coalescing window has passed', () => {
|
||||
const store = createStore()
|
||||
|
||||
|
||||
@@ -158,13 +158,6 @@ describe('detected worktree index', () => {
|
||||
expect(matches[1]).toBe(second)
|
||||
})
|
||||
|
||||
it('treats undefined, empty, and empty-bucket catalogs as unpublished', () => {
|
||||
expect(hasIndexedDetectedWorktree(undefined, 'repo::wt')).toBe(false)
|
||||
expect(findIndexedDetectedWorktrees(undefined, 'repo::wt')).toEqual([])
|
||||
expect(hasIndexedDetectedWorktree({}, 'repo::wt')).toBe(false)
|
||||
expect(hasIndexedDetectedWorktree({ repo: { worktrees: [] } }, 'repo::wt')).toBe(false)
|
||||
})
|
||||
|
||||
it('re-indexes a new catalog identity instead of serving stale hits', () => {
|
||||
const worktree = { id: 'repo::wt', repoId: 'repo' }
|
||||
const before = { repo: { worktrees: [worktree] } }
|
||||
|
||||
Reference in New Issue
Block a user