mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 16:47:34 +00:00
test: trim redundant checks and strengthen workspace persistence (#33208)
* test: trim redundant telemetry checks and exercise session producers * test: include persistence producer in renderer typecheck --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
@@ -57,6 +57,7 @@
|
||||
"../src/main/persistence/tracking-repos/worktree-identity-row-repoint.ts",
|
||||
"../src/main/persistence/restoring-sessions/tab-terminal-pane-binding-repair.ts",
|
||||
"../src/main/persistence/window-save-view.ts",
|
||||
"../src/main/persistence/runtime-authored-workspace-session-fields.ts",
|
||||
"../src/main/runtime/terminal/recovery/shutdown-reconnect-facts.ts",
|
||||
"../src/main/persistence/applying-settings/ui-state-update.ts",
|
||||
"../src/main/persistence/applying-settings/ui-selection-normalization.ts",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { createHostConnectRefetchGate } from '../transport/host-connect-refetch-gate'
|
||||
import type { RpcClient } from '../transport/rpc-client'
|
||||
import {
|
||||
@@ -50,7 +50,7 @@ function fakeSession(): FakeSession {
|
||||
}
|
||||
|
||||
// Drains the promise chain so a retry queued in a .catch has reached the transport.
|
||||
const flush = () => new Promise((resolve) => setTimeout(resolve, 0))
|
||||
const flush = () => vi.advanceTimersByTimeAsync(0)
|
||||
|
||||
function catalogResponse(count: number, active: number): RpcResponse {
|
||||
const worktrees = Array.from({ length: count }, (_, index) => ({
|
||||
@@ -79,6 +79,13 @@ function infoStore() {
|
||||
const notDisposed = () => false
|
||||
|
||||
describe('fetchHomeHostWorktreeInfo', () => {
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers({ toFake: ['Date', 'setTimeout', 'clearTimeout'] })
|
||||
vi.setSystemTime(1_700_000_000_000)
|
||||
})
|
||||
afterEach(() => {
|
||||
vi.useRealTimers()
|
||||
})
|
||||
it('keeps the last proven counts when the in-flight read rejects', async () => {
|
||||
const store = infoStore()
|
||||
const host = fakeSession()
|
||||
@@ -106,15 +113,13 @@ describe('fetchHomeHostWorktreeInfo', () => {
|
||||
it('stamps when the host proved the counts', async () => {
|
||||
const store = infoStore()
|
||||
const host = fakeSession()
|
||||
const before = Date.now()
|
||||
|
||||
const loaded = fetchHomeHostWorktreeInfo(host.client, 'host-1', store.setInfo, notDisposed)
|
||||
host.settle(catalogResponse(3, 1))
|
||||
await loaded
|
||||
|
||||
const provenAt = store.current['host-1'].countsProvenAt
|
||||
expect(provenAt).toBeGreaterThanOrEqual(before)
|
||||
expect(provenAt).toBeLessThanOrEqual(Date.now())
|
||||
expect(provenAt).toBe(1_700_000_000_000)
|
||||
})
|
||||
|
||||
it('marks a host whose catalog never loaded as unavailable, not empty', async () => {
|
||||
@@ -231,10 +236,23 @@ describe('fetchHomeHostWorktreeInfo', () => {
|
||||
const store = infoStore()
|
||||
const host = fakeSession()
|
||||
|
||||
const done = fetchHomeHostWorktreeInfo(host.client, 'host-1', store.setInfo, () => true)
|
||||
let disposed = false
|
||||
const done = fetchHomeHostWorktreeInfo(host.client, 'host-1', store.setInfo, () => disposed)
|
||||
disposed = true
|
||||
host.settle(new Error('socket closed mid-request'))
|
||||
await done
|
||||
expect(store.current['host-1']).toBeUndefined()
|
||||
|
||||
disposed = false
|
||||
const successful = fetchHomeHostWorktreeInfo(
|
||||
host.client,
|
||||
'host-1',
|
||||
store.setInfo,
|
||||
() => disposed
|
||||
)
|
||||
disposed = true
|
||||
host.settle(catalogResponse(3, 1))
|
||||
await successful
|
||||
expect(store.current['host-1']).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -91,12 +91,10 @@ describe('homeHostWorktreeSummary', () => {
|
||||
|
||||
it('stops calling aged-out counts live even while a refresh is only pending', () => {
|
||||
// A snapshot rehydrated from a previous app session describes a host we have not reached yet.
|
||||
expect(homeHostWorktreeSummary(loaded, provenAt + HOME_WORKTREE_COUNTS_LIVE_MAX_AGE_MS)).toBe(
|
||||
'12 worktrees · 2 active'
|
||||
expect(homeHostWorktreeSummary(loaded, provenAt + 600_000)).toBe('12 worktrees · 2 active')
|
||||
expect(homeHostWorktreeSummary(loaded, provenAt + 600_001)).toBe(
|
||||
'Last known: 12 worktrees · 2 active'
|
||||
)
|
||||
expect(
|
||||
homeHostWorktreeSummary(loaded, provenAt + HOME_WORKTREE_COUNTS_LIVE_MAX_AGE_MS + 1)
|
||||
).toBe('Last known: 12 worktrees · 2 active')
|
||||
expect(homeHostWorktreeSummary(loaded, provenAt + 3 * 86_400_000)).toBe(
|
||||
'Last known: 12 worktrees · 2 active'
|
||||
)
|
||||
|
||||
@@ -74,6 +74,14 @@ describe('readLastVisitedWorktreeOnHost', () => {
|
||||
}
|
||||
expect(readLastVisitedWorktreeOnHost(raw, 'host-0')).toBeNull()
|
||||
expect(readLastVisitedWorktreeOnHost(raw, 'host-19')).toEqual({ worktreeId: 'repo::/w/a' })
|
||||
expect(readLastVisitedWorktreeOnHost(raw, 'host-3')).toBeNull()
|
||||
expect(readLastVisitedWorktreeOnHost(raw, 'host-4')).toEqual({ worktreeId: 'repo::/w/a' })
|
||||
raw = withLastVisitedWorktree(raw, { hostId: 'host-4', worktreeId: 'repo::/w/revisited' })
|
||||
raw = withLastVisitedWorktree(raw, { hostId: 'host-20', worktreeId: 'repo::/w/new' })
|
||||
expect(readLastVisitedWorktreeOnHost(raw, 'host-4')).toEqual({
|
||||
worktreeId: 'repo::/w/revisited'
|
||||
})
|
||||
expect(readLastVisitedWorktreeOnHost(raw, 'host-5')).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -121,16 +129,12 @@ describe('writeLastVisitedWorktree', () => {
|
||||
|
||||
it('handles a store that refuses the write instead of leaving the rejection loose', async () => {
|
||||
storage.rejection = new Error('quota exceeded')
|
||||
const seen: unknown[] = []
|
||||
const listener = (reason: unknown) => seen.push(reason)
|
||||
process.on('unhandledRejection', listener)
|
||||
try {
|
||||
await writeLastVisitedWorktree({ hostId: 'host-1', worktreeId: 'repo::/w/c' })
|
||||
await new Promise<void>((resolve) => setImmediate(resolve))
|
||||
await expect(
|
||||
writeLastVisitedWorktree({ hostId: 'host-1', worktreeId: 'repo::/w/c' })
|
||||
).resolves.toBeUndefined()
|
||||
} finally {
|
||||
process.off('unhandledRejection', listener)
|
||||
storage.rejection = null
|
||||
}
|
||||
expect(seen).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -63,6 +63,10 @@ describe('the desktop’s server list', () => {
|
||||
const [first, second] = await Promise.all([feed.read(), feed.read()])
|
||||
expect(second).toBe(first)
|
||||
expect(listCalls(session)).toBe(1)
|
||||
expect(feed.getSnapshot()).toBe(first)
|
||||
await feed.read()
|
||||
expect(feed.getSnapshot()).toBe(first)
|
||||
expect(listCalls(session)).toBe(2)
|
||||
})
|
||||
|
||||
it('keeps polling after a read slower than the poll', async () => {
|
||||
|
||||
@@ -8,6 +8,8 @@ describe('the Workspace options chip', () => {
|
||||
it('badges the active-filter count as the desktop does, capped at 9+', () => {
|
||||
expect(workspaceOptionsBadgeText(0)).toBeNull()
|
||||
expect(workspaceOptionsBadgeText(2)).toBe('2')
|
||||
expect(workspaceOptionsBadgeText(9)).toBe('9')
|
||||
expect(workspaceOptionsBadgeText(10)).toBe('9+')
|
||||
expect(workspaceOptionsBadgeText(12)).toBe('9+')
|
||||
})
|
||||
|
||||
|
||||
@@ -168,6 +168,8 @@ describe('getWorktreeHostContextLabels', () => {
|
||||
]
|
||||
const linux = applyWorktreeHostContextLabels(rows, { ...sources, hostPlatform: 'linux' })
|
||||
expect(linux[0].hostContextLabel).toBe('Local Linux')
|
||||
const windows = applyWorktreeHostContextLabels(rows, { ...sources, hostPlatform: 'win32' })
|
||||
expect(windows[0].hostContextLabel).toBe('Local Windows')
|
||||
const unknown = applyWorktreeHostContextLabels(rows, { ...sources, hostPlatform: null })
|
||||
expect(unknown[0].hostContextLabel).toBe('This computer')
|
||||
})
|
||||
|
||||
@@ -8,21 +8,39 @@ import {
|
||||
} from './worktree-host-row-identity'
|
||||
import type { Worktree } from './workspace-list-types'
|
||||
|
||||
function row(worktreeId: string, hostId: string, overrides: Partial<Worktree> = {}): Worktree {
|
||||
return { worktreeId, hostId, displayName: worktreeId, ...overrides } as Worktree
|
||||
function row(
|
||||
worktreeId: string,
|
||||
hostId: Worktree['hostId'],
|
||||
overrides: Partial<Worktree> = {}
|
||||
): Worktree {
|
||||
return {
|
||||
worktreeId,
|
||||
hostId,
|
||||
displayName: worktreeId,
|
||||
repoId: 'repo',
|
||||
repo: 'orca',
|
||||
branch: 'feature',
|
||||
path: `/workspaces/${worktreeId}`,
|
||||
liveTerminalCount: 0,
|
||||
hasAttachedPty: false,
|
||||
unread: false,
|
||||
isPinned: false,
|
||||
linkedPR: null,
|
||||
...overrides
|
||||
}
|
||||
}
|
||||
|
||||
describe('removeWorktreeRow', () => {
|
||||
// Deleting on one host used to clear the other host's identically-named row from the list.
|
||||
it('keeps a same-id workspace that lives on another host', () => {
|
||||
const local = row('shared', 'host-a')
|
||||
const remote = row('shared', 'host-b')
|
||||
const local = row('shared', 'ssh:a')
|
||||
const remote = row('shared', 'ssh:b')
|
||||
|
||||
expect(removeWorktreeRow([local, remote], local)).toEqual([remote])
|
||||
})
|
||||
|
||||
it('removes the matching row', () => {
|
||||
const only = row('shared', 'host-a')
|
||||
const only = row('shared', 'ssh:a')
|
||||
|
||||
expect(removeWorktreeRow([only], only)).toEqual([])
|
||||
})
|
||||
@@ -36,24 +54,24 @@ describe('getWorktreeRowIdentity', () => {
|
||||
|
||||
describe('host-qualified row display state', () => {
|
||||
it('clears the optimistic active row only when the same host confirms it', () => {
|
||||
const pending = getWorktreeRowIdentity(row('shared', 'host-a'))
|
||||
const pending = getWorktreeRowIdentity(row('shared', 'ssh:a'))
|
||||
|
||||
expect(
|
||||
clearConfirmedActiveWorktreeIdentity(pending, [row('shared', 'host-b', { isActive: true })])
|
||||
clearConfirmedActiveWorktreeIdentity(pending, [row('shared', 'ssh:b', { isActive: true })])
|
||||
).toBe(pending)
|
||||
expect(
|
||||
clearConfirmedActiveWorktreeIdentity(pending, [row('shared', 'host-a', { isActive: true })])
|
||||
clearConfirmedActiveWorktreeIdentity(pending, [row('shared', 'ssh:a', { isActive: true })])
|
||||
).toBeNull()
|
||||
})
|
||||
|
||||
it('retains slept rows only while the same host still has live terminals', () => {
|
||||
const local = row('shared', 'host-a')
|
||||
const remote = row('shared', 'host-b')
|
||||
const local = row('shared', 'ssh:a')
|
||||
const remote = row('shared', 'ssh:b')
|
||||
const retained = retainLiveSleptWorktreeIdentities(
|
||||
new Set([getWorktreeRowIdentity(local), getWorktreeRowIdentity(remote)]),
|
||||
[
|
||||
row('shared', 'host-a', { liveTerminalCount: 0 }),
|
||||
row('shared', 'host-b', { liveTerminalCount: 1 })
|
||||
row('shared', 'ssh:a', { liveTerminalCount: 0 }),
|
||||
row('shared', 'ssh:b', { liveTerminalCount: 1 })
|
||||
]
|
||||
)
|
||||
|
||||
@@ -61,10 +79,10 @@ describe('host-qualified row display state', () => {
|
||||
})
|
||||
|
||||
it('keeps first-match behavior when confirmed identities are duplicated', () => {
|
||||
const identity = getWorktreeRowIdentity(row('shared', 'host-a'))
|
||||
const identity = getWorktreeRowIdentity(row('shared', 'ssh:a'))
|
||||
const retained = retainLiveSleptWorktreeIdentities(new Set([identity]), [
|
||||
row('shared', 'host-a', { liveTerminalCount: 0 }),
|
||||
row('shared', 'host-a', { liveTerminalCount: 1 })
|
||||
row('shared', 'ssh:a', { liveTerminalCount: 0 }),
|
||||
row('shared', 'ssh:a', { liveTerminalCount: 1 })
|
||||
])
|
||||
|
||||
expect([...retained]).toEqual([])
|
||||
@@ -74,10 +92,7 @@ describe('host-qualified row display state', () => {
|
||||
const rowCount = 64
|
||||
let worktreeIdReads = 0
|
||||
const confirmed = Array.from({ length: rowCount }, (_, index) => {
|
||||
const worktree = {
|
||||
hostId: `host-${index}`,
|
||||
liveTerminalCount: 1
|
||||
} as Worktree
|
||||
const worktree = row(`worktree-${index}`, `ssh:host-${index}`, { liveTerminalCount: 1 })
|
||||
Object.defineProperty(worktree, 'worktreeId', {
|
||||
configurable: true,
|
||||
get: () => {
|
||||
@@ -90,20 +105,17 @@ describe('host-qualified row display state', () => {
|
||||
const previous = new Set(
|
||||
Array.from({ length: rowCount }, (_, index) => {
|
||||
const reversed = rowCount - index - 1
|
||||
return `host-${reversed}|worktree-${reversed}`
|
||||
return `ssh:host-${reversed}|worktree-${reversed}`
|
||||
})
|
||||
)
|
||||
|
||||
expect(retainLiveSleptWorktreeIdentities(previous, confirmed)).toBe(previous)
|
||||
const legacyIdentityReads = (rowCount * (rowCount + 1)) / 2
|
||||
expect(legacyIdentityReads).toBe(2_080)
|
||||
expect(worktreeIdReads).toBe(rowCount)
|
||||
expect(legacyIdentityReads - worktreeIdReads).toBe(2_016)
|
||||
})
|
||||
|
||||
it('applies active and slept overrides to the matching host row only', () => {
|
||||
const local = row('shared', 'host-a')
|
||||
const remote = row('shared', 'host-b')
|
||||
const local = row('shared', 'ssh:a')
|
||||
const remote = row('shared', 'ssh:b')
|
||||
|
||||
const rows = applyWorktreeRowDisplayState(
|
||||
[local, remote],
|
||||
@@ -112,8 +124,8 @@ describe('host-qualified row display state', () => {
|
||||
)
|
||||
|
||||
expect(rows).toMatchObject([
|
||||
{ hostId: 'host-a', liveTerminalCount: 0, status: 'inactive', isActive: false },
|
||||
{ hostId: 'host-b', isActive: true }
|
||||
{ hostId: 'ssh:a', liveTerminalCount: 0, status: 'inactive', isActive: false },
|
||||
{ hostId: 'ssh:b', isActive: true }
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -28,7 +28,6 @@ function worktree(repoId: string, id: string, repo = repoId): Worktree {
|
||||
path: `/tmp/orca/${repoId}/${id}`,
|
||||
liveTerminalCount: 0,
|
||||
hasAttachedPty: false,
|
||||
preview: '',
|
||||
unread: false,
|
||||
isPinned: false,
|
||||
linkedPR: null,
|
||||
@@ -94,7 +93,10 @@ describe('every worktree stays visible regardless of repo.list contents', () =>
|
||||
|
||||
it("narrows to the desktop's shown hosts, and its legacy scope alone narrows too", () => {
|
||||
// The phone's host filter is the desktop's: rows on hosts it hides are hidden here as well.
|
||||
const worktrees = [worktree('local-repo', 'x'), worktree('runtime-repo', 'y')]
|
||||
const worktrees = [
|
||||
{ ...worktree('local-repo', 'x'), hostId: 'local' as const },
|
||||
{ ...worktree('runtime-repo', 'y'), hostId: 'runtime:devbox' as const }
|
||||
]
|
||||
const catalogRepos = [
|
||||
['local-repo', 'local-repo'],
|
||||
['runtime-repo', 'runtime-repo']
|
||||
@@ -102,13 +104,13 @@ describe('every worktree stays visible regardless of repo.list contents', () =>
|
||||
|
||||
expect(
|
||||
visibleWorktreeIds(worktrees, catalogRepos, { visibleWorkspaceHostIds: ['runtime:devbox'] })
|
||||
).toEqual([])
|
||||
).toEqual(['y'])
|
||||
expect(
|
||||
visibleWorktreeIds(worktrees, catalogRepos, {
|
||||
visibleWorkspaceHostIds: null,
|
||||
workspaceHostScope: 'local'
|
||||
})
|
||||
).toEqual(['x', 'y'])
|
||||
).toEqual(['x'])
|
||||
expect(visibleWorktreeIds(worktrees, catalogRepos, { workspaceHostScope: 'all' })).toEqual([
|
||||
'x',
|
||||
'y'
|
||||
|
||||
@@ -11,6 +11,8 @@ function agent(overrides: Partial<RuntimeWorktreeAgentRow> = {}): RuntimeWorktre
|
||||
state: 'working',
|
||||
agentType: 'codex',
|
||||
prompt: 'fix mobile lag',
|
||||
taskTitle: null,
|
||||
displayName: null,
|
||||
lastAssistantMessage: null,
|
||||
toolName: null,
|
||||
toolInput: null,
|
||||
|
||||
@@ -57,7 +57,19 @@ describe('getWorktreeMetaGlyphPresence', () => {
|
||||
expect(Object.values(getWorktreeMetaGlyphPresence(row, ALL)).some(Boolean)).toBe(false)
|
||||
expect(
|
||||
Object.values(
|
||||
getWorktreeMetaGlyphPresence({ ...row, automationCreated: true, cliCreated: true }, none)
|
||||
getWorktreeMetaGlyphPresence(
|
||||
{
|
||||
...row,
|
||||
comment: 'note',
|
||||
automationCreated: true,
|
||||
cliCreated: true,
|
||||
linkedIssue: 3,
|
||||
linkedLinearIssue: 'ENG-1',
|
||||
linkedGitLabMR: 4,
|
||||
linkedItems: [{ provider: 'jira', type: 'issue', number: 1 }]
|
||||
},
|
||||
none
|
||||
)
|
||||
).some(Boolean)
|
||||
).toBe(false)
|
||||
})
|
||||
|
||||
@@ -109,6 +109,3 @@ src/transport/runtime-capability-probe.test.ts
|
||||
src/transport/settings-host-client-lifecycle.test.ts
|
||||
src/worktree/agent-row-display.test.ts
|
||||
src/worktree/host-worktree-refresh.test.ts
|
||||
src/worktree/worktree-host-row-identity.test.ts
|
||||
src/worktree/worktree-list-completeness.test.ts
|
||||
src/worktree/worktree-list-snapshot.test.ts
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { getDefaultWorkspaceSession } from '../../../shared/constants'
|
||||
import { preserveRuntimeAuthoredWorkspaceSessionFields } from '../../../main/persistence/runtime-authored-workspace-session-fields'
|
||||
import { parseWorkspaceSession } from '../../../shared/workspace-session-schema'
|
||||
import { useAppStore, type AppState } from '@/store'
|
||||
import { applyDefaultTerminalTabs } from './worktree-default-terminal-tabs'
|
||||
@@ -17,23 +18,6 @@ const DEFAULT_TABS = {
|
||||
tabs: [{ title: 'Claude' }]
|
||||
}
|
||||
|
||||
function preserveRuntimeAuthoredWorkspaceSessionFields<T extends Record<string, unknown>>(
|
||||
next: T,
|
||||
prior: T
|
||||
): T {
|
||||
const marks = prior.defaultTerminalTabsAppliedByWorktreeId
|
||||
if (!marks || typeof marks !== 'object') {
|
||||
return next
|
||||
}
|
||||
return {
|
||||
...next,
|
||||
defaultTerminalTabsAppliedByWorktreeId: {
|
||||
...marks,
|
||||
...(next.defaultTerminalTabsAppliedByWorktreeId as Record<string, boolean> | undefined)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
describe('defaultTerminalTabsAppliedByWorktreeId persist round-trip', () => {
|
||||
beforeEach(() => {
|
||||
initialState = useAppStore.getState()
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import type { RuntimeHostStatusSnapshot } from '../../../shared/runtime-host-status'
|
||||
import {
|
||||
runtimeEnvironmentStatusFromSnapshot,
|
||||
type RuntimeHostStatusSnapshot
|
||||
} from '../../../shared/runtime-host-status'
|
||||
import type { RuntimeStatus } from '../../../shared/runtime-types'
|
||||
import {
|
||||
isDisconnectedRuntimeHostState,
|
||||
@@ -41,10 +44,8 @@ function makeSnapshot(
|
||||
/** The entry shape `applyRuntimeHostStatusSnapshot` writes for a given snapshot. */
|
||||
function entryForSnapshot(snapshot: RuntimeHostStatusSnapshot) {
|
||||
return {
|
||||
snapshot,
|
||||
checkedAt: snapshot.checkedAt,
|
||||
connectionGeneration: 4,
|
||||
status: snapshot.verification === 'verified' && !snapshot.retired ? snapshot.status : null
|
||||
...runtimeEnvironmentStatusFromSnapshot(snapshot),
|
||||
connectionGeneration: 4
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +88,7 @@ describe('mirror targets and host connection state agree on one host', () => {
|
||||
expect(mirrorTargets(entry)).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('keeps the same target across verified -> unverifiable -> verified', () => {
|
||||
it('keeps the same target across verified and unverifiable snapshots', () => {
|
||||
const verified = mirrorTargets(entryForSnapshot(makeSnapshot({ verification: 'verified' })))
|
||||
const unverifiable = mirrorTargets(
|
||||
entryForSnapshot(makeSnapshot({ verification: 'unavailable', sequence: 2 }))
|
||||
|
||||
@@ -204,8 +204,8 @@ describe('workspace session editor drafts', () => {
|
||||
})
|
||||
)
|
||||
|
||||
expect(payload.openFilesByWorktree?.['wt-1']?.[0]).toEqual(
|
||||
expect.not.objectContaining({ readOnly: expect.anything() })
|
||||
)
|
||||
const persisted = payload.openFilesByWorktree?.['wt-1']?.[0]
|
||||
expect(persisted).toEqual(expect.objectContaining({ filePath: '/tmp/clean.md' }))
|
||||
expect(persisted).not.toHaveProperty('readOnly')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { SESSION_RELEVANT_FIELDS, type WorkspaceSessionSnapshot } from './workspace-session'
|
||||
|
||||
describe('SESSION_RELEVANT_FIELDS', () => {
|
||||
// Why: this list gates the App-level session-write debounce subscriber.
|
||||
// A snapshot field omitted here would persist stale data after that field changes.
|
||||
const fixture: Record<keyof WorkspaceSessionSnapshot, true> = {
|
||||
activeRepoId: true,
|
||||
activeWorkspaceKey: true,
|
||||
activeWorkspaceExecutionHostId: true,
|
||||
activeWorktreeId: true,
|
||||
activeTabId: true,
|
||||
tabsByWorktree: true,
|
||||
ptyIdsByTabId: true,
|
||||
terminalLayoutsByTabId: true,
|
||||
localOnlyScrollbackByTabId: true,
|
||||
activeTabIdByWorktree: true,
|
||||
openFiles: true,
|
||||
editorDrafts: true,
|
||||
markdownFrontmatterVisible: true,
|
||||
activeFileIdByWorktree: true,
|
||||
activeTabTypeByWorktree: true,
|
||||
browserTabsByWorktree: true,
|
||||
browserPagesByWorkspace: true,
|
||||
activeBrowserTabIdByWorktree: true,
|
||||
browserUrlHistory: true,
|
||||
workspaceDocHistory: true,
|
||||
remoteBrowserPageHandlesByPageId: true,
|
||||
unifiedTabsByWorktree: true,
|
||||
groupsByWorktree: true,
|
||||
layoutByWorktree: true,
|
||||
activeGroupIdByWorktree: true,
|
||||
sshConnectionStates: true,
|
||||
repos: true,
|
||||
worktreesByRepo: true,
|
||||
lastKnownRelayPtyIdByTabId: true,
|
||||
lastVisitedAtByWorktreeId: true,
|
||||
defaultTerminalTabsAppliedByWorktreeId: true,
|
||||
sleepingAgentSessionsByPaneKey: true,
|
||||
clientHostedBrowserCloseIntentsByEnvironment: true,
|
||||
pairedTerminalTabCloseIntentsByEnvironment: true,
|
||||
pendingReconnectPtyIdByTabId: true,
|
||||
deferredSshSessionIdsByTabId: true
|
||||
}
|
||||
|
||||
it('contains every key of WorkspaceSessionSnapshot', () => {
|
||||
const fixtureKeys = Object.keys(fixture)
|
||||
expect(
|
||||
fixtureKeys.every((k) => (SESSION_RELEVANT_FIELDS as readonly string[]).includes(k))
|
||||
).toBe(true)
|
||||
expect(SESSION_RELEVANT_FIELDS.length).toBe(fixtureKeys.length)
|
||||
})
|
||||
|
||||
it('has no duplicate entries', () => {
|
||||
expect(new Set(SESSION_RELEVANT_FIELDS).size).toBe(SESSION_RELEVANT_FIELDS.length)
|
||||
})
|
||||
})
|
||||
@@ -1,16 +1,10 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { CONTEXTUAL_TOUR_IDS } from './contextual-tours'
|
||||
import {
|
||||
FEATURE_EDUCATION_CONTEXTUAL_TOUR_IDS,
|
||||
normalizeFeatureEducationSource,
|
||||
normalizeSetupGuideSource
|
||||
} from './feature-education-telemetry'
|
||||
|
||||
describe('feature education telemetry constants', () => {
|
||||
it('keeps contextual tour telemetry ids aligned with tour definitions', () => {
|
||||
expect(FEATURE_EDUCATION_CONTEXTUAL_TOUR_IDS).toEqual(CONTEXTUAL_TOUR_IDS)
|
||||
})
|
||||
|
||||
it('normalizes unknown telemetry sources to a bounded fallback', () => {
|
||||
expect(normalizeFeatureEducationSource('tasks_open')).toBe('tasks_open')
|
||||
expect(normalizeFeatureEducationSource('workspace_agent_sessions_visible')).toBe(
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// round-trips without coercion.
|
||||
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { errorClassSchema, eventSchemas, isCohortExtendedEvent } from './telemetry-events'
|
||||
import { eventSchemas } from './telemetry-events'
|
||||
|
||||
describe('feature_interaction_usage_bucket_reached schema', () => {
|
||||
it('accepts a valid bucket payload', () => {
|
||||
@@ -18,10 +18,6 @@ describe('feature_interaction_usage_bucket_reached schema', () => {
|
||||
expect(parsed.success).toBe(true)
|
||||
})
|
||||
|
||||
it('is in the runtime cohort-injection roster', () => {
|
||||
expect(isCohortExtendedEvent('feature_interaction_usage_bucket_reached')).toBe(true)
|
||||
})
|
||||
|
||||
it('rejects unknown enum values and mismatched categories', () => {
|
||||
const valid = {
|
||||
feature_id: 'github-tasks',
|
||||
@@ -139,10 +135,6 @@ describe('star_nag_outcome schema', () => {
|
||||
expect(eventSchemas.star_nag_outcome.safeParse(valid).success).toBe(true)
|
||||
})
|
||||
|
||||
it('is in the runtime cohort-injection roster', () => {
|
||||
expect(isCohortExtendedEvent('star_nag_outcome')).toBe(true)
|
||||
})
|
||||
|
||||
it('accepts next_threshold only as a positive integer for deferrals', () => {
|
||||
expect(
|
||||
eventSchemas.star_nag_outcome.safeParse({
|
||||
@@ -398,15 +390,6 @@ describe('workspace_created schema', () => {
|
||||
})
|
||||
expect(parsed.success).toBe(true)
|
||||
})
|
||||
|
||||
it('rejects extra keys via .strict()', () => {
|
||||
const parsed = eventSchemas.workspace_created.safeParse({
|
||||
source: 'command_palette',
|
||||
from_existing_branch: true,
|
||||
branch: 'refs/heads/main' // raw branch name is UGC — rejected by .strict()
|
||||
})
|
||||
expect(parsed.success).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('agent_started schema', () => {
|
||||
@@ -498,14 +481,6 @@ describe('add_repo_default_checkout_handoff schema', () => {
|
||||
})
|
||||
|
||||
describe('workspace_create_failed schema', () => {
|
||||
it('accepts a valid payload', () => {
|
||||
const parsed = eventSchemas.workspace_create_failed.safeParse({
|
||||
source: 'sidebar',
|
||||
error_class: 'git_failed'
|
||||
})
|
||||
expect(parsed.success).toBe(true)
|
||||
})
|
||||
|
||||
it('rejects unknown error_class values', () => {
|
||||
const parsed = eventSchemas.workspace_create_failed.safeParse({
|
||||
source: 'sidebar',
|
||||
@@ -565,12 +540,6 @@ describe('settings_changed schema', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('exported enum schemas', () => {
|
||||
it('errorClassSchema rejects novel classes', () => {
|
||||
expect(errorClassSchema.safeParse('kernel_panic').success).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('remote_outbound_budget_close schema', () => {
|
||||
it('round-trips every emitter', () => {
|
||||
for (const emitter of ['size', 'queue']) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { eventSchemas } from './telemetry-event-registry'
|
||||
import { WORKTREE_CREATE_PHASES } from './worktree/create-timing-vocabulary'
|
||||
|
||||
const created = eventSchemas.workspace_created
|
||||
const failed = eventSchemas.workspace_create_failed
|
||||
@@ -41,11 +40,6 @@ describe('workspace_created timing fields', () => {
|
||||
expect(created.safeParse(fullCreatedPayload).success).toBe(true)
|
||||
})
|
||||
|
||||
it('accepts a duration for every timed phase', () => {
|
||||
const phases = Object.fromEntries(WORKTREE_CREATE_PHASES.map((phase) => [`${phase}_ms`, 1]))
|
||||
expect(created.safeParse({ ...fullCreatedPayload, ...phases }).success).toBe(true)
|
||||
})
|
||||
|
||||
it('accepts a miss with its reason', () => {
|
||||
const parsed = created.safeParse({
|
||||
source: 'sidebar',
|
||||
|
||||
Reference in New Issue
Block a user