mirror of
https://github.com/stablyai/orca.git
synced 2026-10-01 00:02:10 +00:00
test: retire long-tail cases whose input cannot reach the behavior they name (#24101)
Sweeps the triage-only backlog: 2,269 files that earlier waves saw and skipped for size, reconstructed from the unread lists five waves of auditors disclosed. 35 case declarations removed across 15 files, 2 test files deleted, 487 lines gone. No production file touched. These are large integration suites, so the junk here is individual cases buried among real coverage rather than whole bad files. The dominant defect was again a case whose input cannot reach the behavior its title names: - `resume-sleeping-agent-session-remote-compat.test.ts` (deleted) — two cases titled for "transport-level host authority on a capable host" and "host authority is not known". `resume-sleeping-agent-session.ts` has no host-authority or capability concept at all, and its only read of `origin` is `if (!record.origin && record.state === 'done')`, unreachable for both rows. Both executed one identical path. The surviving contract is owned by `resume-sleeping-agent-session-execution-host-scope.test.ts`, which drives a real host catalog. - `project-group-header-drag.test.ts` (deleted) — four cases setting `data-project-group-header-id`, which the predicate never reads. Its subject, `isProjectGroupHeaderActionTarget`, is byte-identical to `isRepoHeaderActionTarget` apart from the function name and imports the same `REPO_HEADER_ACTION_SELECTOR`, so all four cases were a strict subset of `project-header-drag.test.ts` using identical `data-repo-header-*` fixtures. - `remote-worktree-history-cleanup.test.ts` — "repeats idempotent cleanup through the PTY owner" against a six-line best-effort forward with zero dedupe state. The case called it twice and asserted the mock recorded two calls, which is arithmetic over the test's own loop; nothing about idempotence was established. Also removed: - Runtime assertions of type-level facts, where production already makes the check at a stronger boundary: `const adapterSatisfiesPort: AdapterIsPort = true` followed by `expect(...).toBe(true)` — unconditionally true, while `createExpoGenerationFileSystem(): GenerationFileSystem` is explicitly annotated and passed into `createGenerationStore` at a typed call site. And a case named "does not typecheck" whose runtime assertion is a length check on its own literal, declaring its own local annotation so it could never notice the production annotation weakening. - Private predicate tests duplicated at a real boundary: four `repo-slug-cache` cases delivered by `repo-slug-index.test.ts`, which drives the same resolution through the hook, the real store and the preload bridge, while the cache-level versions hand-seed the internal map and break on a cache-key format change. - Duplicate invocations owned at the shared boundary, including commit and push recovery cases owned by `src/shared/source-control-recovery-agent-command.test.ts`. Kept deliberately, verified rather than assumed: the production duplication behind the deleted drag test was left alone, because `REPO_HEADER_ACTION_SELECTOR` ends in generic `button, a, input, textarea, select`, so genuine action targets inside a group header still match — it is an unspecialised copy-paste, not a live bug, and collapsing two functions is a refactor. Reported instead. Auditors' probes produced 20, 11 and 13 candidate hits for the signature-versus-title shape across their chunks; every one was inspected and every one was genuine coverage. No deletion in this wave rests on a probe alone. Coverage is partial and stated as such: of 2,269 files, roughly 100 were read case-by-case and the remainder reviewed at title-plus-import level. Each auditor listed its own unread set. The largest remaining surfaces are `src/main/agent-hooks` (95), `src/main/claude` (100), `src/renderer/src/lib/pane-manager` (62) and the 20 largest sidebar suites. Verified: 2,583 desktop test files / 25,636 cases pass, plus one pre-existing `it.fails` marker; the two modified mobile files pass (57 cases); `check-reliability-gates.mjs` 140 gates; `check:code-quality:changed` 0 new findings. Both deleted files confirmed absent from the gate manifest, `cloud/package.json` and `mobile/tests-typecheck-baseline.txt`.
This commit is contained in:
@@ -6,7 +6,7 @@ import {
|
||||
} from './bridge-envelope'
|
||||
import { BRIDGE_HAPTICS_GRANT, BRIDGE_HAPTICS_NOTIFY } from './bridge-haptics-notify'
|
||||
import { BRIDGE_PAGE_PAINTED } from './bridge-page-painted'
|
||||
import { bridgeNotifyRefusal, type BridgeNotifyName } from './bridge-notify-grants'
|
||||
import { bridgeNotifyRefusal } from './bridge-notify-grants'
|
||||
|
||||
const GRANTED = [BRIDGE_FAULT_GRANT]
|
||||
|
||||
@@ -159,29 +159,6 @@ describe('the haptics notify', () => {
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* The totality shown rather than described.
|
||||
*
|
||||
* The docstring above says a name with no row is a compile error; this is the error. Every row the
|
||||
* table has, less the haptics one, against the same `Record` over the union — checked by
|
||||
* `tsconfig.test.json`, so the day the omission stops being an error the unused directive is.
|
||||
*/
|
||||
describe('a grant table missing a row', () => {
|
||||
it('does not typecheck', () => {
|
||||
// @ts-expect-error TS2741: no row for the haptics notify, the hole the Record closes.
|
||||
const incomplete: Readonly<Record<BridgeNotifyName, string | null>> = {
|
||||
foreground: null,
|
||||
terminalViewport: null,
|
||||
navigate: 'navigate',
|
||||
[BRIDGE_NAVIGATE_BACK_NOTIFY]: 'navigate',
|
||||
storage: 'storage',
|
||||
[BRIDGE_EXTERNAL_LINK_GRANT]: BRIDGE_EXTERNAL_LINK_GRANT,
|
||||
[BRIDGE_FAULT_GRANT]: BRIDGE_FAULT_GRANT
|
||||
}
|
||||
expect(Object.keys(incomplete)).toHaveLength(7)
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
* The page reporting on its own document.
|
||||
*
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { createGenerationStore, MAX_CACHED_HOSTS } from './generation-store'
|
||||
import { deriveHostCacheKey } from './host-cache-key'
|
||||
import type {
|
||||
createExpoGenerationFileSystem,
|
||||
GenerationFileSystem
|
||||
} from './generation-store-file-system'
|
||||
import type { MobileWebBundleFetchResult } from '../transport/mobile-web-bundle-fetch'
|
||||
import type { MobileWebBundleManifestRead } from '../transport/mobile-web-bundle-reply-schemas'
|
||||
import { computeMobileWebBundleId } from '../../../src/shared/mobile-web-bundle/manifest-contract'
|
||||
@@ -14,12 +10,6 @@ import {
|
||||
type FakeGenerationFileSystem as FakeFileSystem
|
||||
} from './generation-file-system-fake'
|
||||
|
||||
// The adapter is deliberately untested at runtime — it would need a device filesystem — so this is
|
||||
// the check that it still answers the port the store is written against.
|
||||
type AdapterIsPort =
|
||||
ReturnType<typeof createExpoGenerationFileSystem> extends GenerationFileSystem ? true : false
|
||||
const adapterSatisfiesPort: AdapterIsPort = true
|
||||
|
||||
const ROOT = FAKE_GENERATION_ROOT
|
||||
const HOST = deriveHostCacheKey('host-a')
|
||||
|
||||
@@ -581,10 +571,6 @@ describe('generation store', () => {
|
||||
expect((await store.readActiveGeneration(host))?.buildId).toBe(BUILD)
|
||||
}
|
||||
})
|
||||
|
||||
it('keeps the adapter aligned with the port', () => {
|
||||
expect(adapterSatisfiesPort).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,16 +2,6 @@ import { describe, expect, it, vi } from 'vitest'
|
||||
import { deleteRemoteWorktreeHistory } from './remote-worktree-history-cleanup'
|
||||
|
||||
describe('deleteRemoteWorktreeHistory', () => {
|
||||
it('repeats idempotent cleanup through the PTY owner', async () => {
|
||||
const deleteWorktreeHistory = vi.fn().mockResolvedValue(undefined)
|
||||
const provider = { deleteWorktreeHistory } as never
|
||||
|
||||
await deleteRemoteWorktreeHistory(provider, 'repo-1::/remote/wt')
|
||||
await deleteRemoteWorktreeHistory(provider, 'repo-1::/remote/wt')
|
||||
|
||||
expect(deleteWorktreeHistory).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
it('degrades safely when an old relay does not expose cleanup', async () => {
|
||||
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {})
|
||||
const provider = {
|
||||
|
||||
-18
@@ -71,24 +71,6 @@ describe('SourceControl commit failure recovery prompt', () => {
|
||||
expect(appendCommitFailureCustomInstruction(prompt, ' ')).toBe(prompt)
|
||||
})
|
||||
|
||||
it('leaves blank launch templates blank so the launcher can reject them', () => {
|
||||
expect(
|
||||
buildCommitFailureAgentCommandInput({
|
||||
commandInputTemplate: ' ',
|
||||
basePrompt: 'Fix this commit failure.'
|
||||
})
|
||||
).toBe('')
|
||||
})
|
||||
|
||||
it('falls back to the base commit-failure prompt when no launch template is saved', () => {
|
||||
expect(
|
||||
buildCommitFailureAgentCommandInput({
|
||||
commandInputTemplate: undefined,
|
||||
basePrompt: 'Fix this commit failure.'
|
||||
})
|
||||
).toBe('Fix this commit failure.')
|
||||
})
|
||||
|
||||
it('trims custom launch overrides before the direct launch path uses them', () => {
|
||||
expect(
|
||||
buildCommitFailureAgentCommandInput({
|
||||
|
||||
@@ -3,27 +3,8 @@ import {
|
||||
appendPushFailureCustomInstruction,
|
||||
buildFixPushFailurePrompt
|
||||
} from '../../../../shared/source-control-push-failure'
|
||||
import { buildPushFailureAgentCommandInput } from '../../../../shared/source-control-push-failure-agent-command'
|
||||
|
||||
describe('SourceControl push failure recovery prompt', () => {
|
||||
it('leaves blank launch templates blank so the launcher can reject them', () => {
|
||||
expect(
|
||||
buildPushFailureAgentCommandInput({
|
||||
commandInputTemplate: ' ',
|
||||
basePrompt: 'Fix this push failure.'
|
||||
})
|
||||
).toBe('')
|
||||
})
|
||||
|
||||
it('falls back to the base push-failure prompt when no launch template is saved', () => {
|
||||
expect(
|
||||
buildPushFailureAgentCommandInput({
|
||||
commandInputTemplate: undefined,
|
||||
basePrompt: 'Fix this push failure.'
|
||||
})
|
||||
).toBe('Fix this push failure.')
|
||||
})
|
||||
|
||||
it('adds one-time custom instructions before the response contract', () => {
|
||||
const prompt = buildFixPushFailurePrompt({
|
||||
summary: 'Pre-push hook failed.',
|
||||
|
||||
@@ -1,63 +1,6 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import type { AgentStatusEntry } from '../../../../shared/agent-status-types'
|
||||
import type { TerminalTab } from '../../../../shared/terminal-tab-types'
|
||||
|
||||
vi.mock('@/lib/agent-status', () => ({
|
||||
detectAgentStatusFromTitle: vi.fn((title: string) => {
|
||||
if (title.includes('permission')) {
|
||||
return 'permission'
|
||||
}
|
||||
if (title.includes('working')) {
|
||||
return 'working'
|
||||
}
|
||||
return null
|
||||
}),
|
||||
isExplicitAgentStatusFresh: vi.fn(
|
||||
(entry: AgentStatusEntry, now: number, staleAfterMs: number) =>
|
||||
now - entry.updatedAt <= staleAfterMs
|
||||
)
|
||||
}))
|
||||
|
||||
import { getWorktreeStatus } from '@/lib/worktree-status'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { shouldBeginWorktreeRename } from './WorktreeCard'
|
||||
|
||||
function makeTerminalTab(title: string): TerminalTab {
|
||||
return {
|
||||
id: 'tab-1',
|
||||
worktreeId: 'repo1::/tmp/wt',
|
||||
ptyId: 'pty-1',
|
||||
title,
|
||||
customTitle: null,
|
||||
color: null,
|
||||
sortOrder: 0,
|
||||
createdAt: 0
|
||||
}
|
||||
}
|
||||
|
||||
describe('getWorktreeStatus', () => {
|
||||
it('treats browser-only worktrees as active', () => {
|
||||
expect(getWorktreeStatus([], [{ id: 'browser-1' }], {})).toBe('active')
|
||||
})
|
||||
|
||||
it('keeps terminal agent states higher priority than browser presence', () => {
|
||||
// Why: liveness gate now requires ptyIdsByTabId, not tab.ptyId. Pass a
|
||||
// populated live-pty map so this assertion exercises the live-tab branch.
|
||||
// Titles are real classifiable shapes: getWorktreeStatus reads the shared
|
||||
// classifier through pane-agent-evidence, which this file does not mock.
|
||||
const livePtyIds = { 'tab-1': ['pty-1'] }
|
||||
expect(
|
||||
getWorktreeStatus(
|
||||
[makeTerminalTab('Claude - action required')],
|
||||
[{ id: 'browser-1' }],
|
||||
livePtyIds
|
||||
)
|
||||
).toBe('permission')
|
||||
expect(
|
||||
getWorktreeStatus([makeTerminalTab('mimo working')], [{ id: 'browser-1' }], livePtyIds)
|
||||
).toBe('working')
|
||||
})
|
||||
})
|
||||
|
||||
describe('shouldBeginWorktreeRename', () => {
|
||||
it('matches unscoped legacy rename requests by worktree id', () => {
|
||||
expect(shouldBeginWorktreeRename({ worktreeId: 'wt-1' }, 'wt-1', 'all:wt-1')).toBe(true)
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
// @vitest-environment happy-dom
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import { isProjectGroupHeaderActionTarget } from './project-group-header-drag'
|
||||
|
||||
function createHeader(markup: string): HTMLElement {
|
||||
const header = document.createElement('div')
|
||||
header.setAttribute('data-project-group-header-id', 'group-1')
|
||||
header.innerHTML = markup
|
||||
document.body.appendChild(header)
|
||||
return header
|
||||
}
|
||||
|
||||
describe('project group header action targets', () => {
|
||||
it('ignores explicit project action wrappers', () => {
|
||||
const header = createHeader(`
|
||||
<span data-repo-header-action="" tabindex="0">
|
||||
<span id="icon"></span>
|
||||
</span>
|
||||
`)
|
||||
|
||||
expect(isProjectGroupHeaderActionTarget(header.querySelector('#icon'), header)).toBe(true)
|
||||
})
|
||||
|
||||
it('ignores the project header actions overlay (including gaps between icons)', () => {
|
||||
const header = createHeader(`
|
||||
<div data-repo-header-actions="">
|
||||
<button type="button" data-repo-header-action=""><span id="icon"></span></button>
|
||||
</div>
|
||||
`)
|
||||
|
||||
expect(
|
||||
isProjectGroupHeaderActionTarget(header.querySelector('[data-repo-header-actions]'), header)
|
||||
).toBe(true)
|
||||
expect(isProjectGroupHeaderActionTarget(header.querySelector('#icon'), header)).toBe(true)
|
||||
})
|
||||
|
||||
it('ignores the hover collapse affordance', () => {
|
||||
const header = createHeader(`
|
||||
<div data-repo-header-collapse-affordance="">
|
||||
<span id="chevron"></span>
|
||||
</div>
|
||||
`)
|
||||
|
||||
expect(isProjectGroupHeaderActionTarget(header.querySelector('#chevron'), header)).toBe(true)
|
||||
})
|
||||
|
||||
it('does not ignore plain header text or the header itself', () => {
|
||||
const header = createHeader('<span id="label">Group</span>')
|
||||
|
||||
expect(isProjectGroupHeaderActionTarget(header.querySelector('#label'), header)).toBe(false)
|
||||
expect(isProjectGroupHeaderActionTarget(header, header)).toBe(false)
|
||||
})
|
||||
})
|
||||
@@ -172,19 +172,6 @@ describe('registerZoomIpcBridge', () => {
|
||||
expect(zoom.dispatchZoomLevelChanged).toHaveBeenCalledWith('ui', 110)
|
||||
})
|
||||
|
||||
it('applies app zoom for an active terminal tab after terminal focus is released', async () => {
|
||||
const zoom = await mountZoomBridge({
|
||||
activeTabType: 'terminal',
|
||||
activeElement: makeTarget({})
|
||||
})
|
||||
|
||||
zoom.fire('in')
|
||||
|
||||
expect(zoom.applyUIZoom).toHaveBeenCalledWith(0.5)
|
||||
expect(zoom.setUI).toHaveBeenCalledWith({ uiZoomLevel: 0.5 })
|
||||
expect(zoom.dispatchZoomLevelChanged).toHaveBeenCalledWith('ui', 110)
|
||||
})
|
||||
|
||||
it('leaves zoom to the terminal while terminal input holds focus', async () => {
|
||||
const zoom = await mountZoomBridge({
|
||||
activeTabType: 'terminal',
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
isClaudeAgent,
|
||||
isClaudeManagementTitle,
|
||||
normalizeTerminalTitle,
|
||||
isExplicitAgentStatusFresh,
|
||||
mapAgentStatusStateToVisualStatus,
|
||||
formatAgentTypeLabel,
|
||||
agentTypeToIconAgent
|
||||
@@ -735,23 +734,6 @@ describe('createAgentStatusTracker', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('isExplicitAgentStatusFresh', () => {
|
||||
it('treats the boundary (now - updatedAt == staleAfterMs) as fresh', () => {
|
||||
// Why: uses `<=`, so equality at the boundary stays fresh (not stale one tick before the TTL).
|
||||
const staleAfterMs = 60_000
|
||||
const now = 1_000_000
|
||||
const entry = { updatedAt: now - staleAfterMs }
|
||||
expect(isExplicitAgentStatusFresh(entry, now, staleAfterMs)).toBe(true)
|
||||
})
|
||||
|
||||
it('treats one millisecond past the boundary as stale', () => {
|
||||
const staleAfterMs = 60_000
|
||||
const now = 1_000_000
|
||||
const entry = { updatedAt: now - staleAfterMs - 1 }
|
||||
expect(isExplicitAgentStatusFresh(entry, now, staleAfterMs)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('mapAgentStatusStateToVisualStatus', () => {
|
||||
it("maps 'working' to 'working'", () => {
|
||||
expect(mapAgentStatusStateToVisualStatus('working')).toBe('working')
|
||||
|
||||
@@ -3,7 +3,6 @@ import type { Repo } from '../../../shared/repo-types'
|
||||
import {
|
||||
getComposerEligibleRepos,
|
||||
resolveComposerActiveRepoId,
|
||||
resolveComposerGitRepoId,
|
||||
resolveComposerRepoId
|
||||
} from './new-workspace-composer-repo'
|
||||
|
||||
@@ -19,77 +18,6 @@ function makeRepo(id: string, overrides: Partial<Repo> = {}): Repo {
|
||||
}
|
||||
|
||||
describe('new-workspace-composer-repo', () => {
|
||||
it('matches the composer repo priority order', () => {
|
||||
const eligibleRepos = [
|
||||
makeRepo('first'),
|
||||
makeRepo('active'),
|
||||
makeRepo('initial'),
|
||||
makeRepo('draft')
|
||||
]
|
||||
|
||||
expect(
|
||||
resolveComposerRepoId({
|
||||
eligibleRepos,
|
||||
draftRepoId: 'draft',
|
||||
initialRepoId: 'initial',
|
||||
activeRepoId: 'active'
|
||||
})
|
||||
).toBe('draft')
|
||||
})
|
||||
|
||||
it('falls back through initial, active, then first eligible repo', () => {
|
||||
const eligibleRepos = [makeRepo('first'), makeRepo('active')]
|
||||
|
||||
expect(resolveComposerRepoId({ eligibleRepos, initialRepoId: 'missing' })).toBe('first')
|
||||
expect(resolveComposerRepoId({ eligibleRepos, activeRepoId: 'active' })).toBe('active')
|
||||
})
|
||||
|
||||
it('returns null for create-base prefetch when the composer default is a folder repo', () => {
|
||||
const eligibleRepos = [makeRepo('folder', { kind: 'folder' }), makeRepo('git')]
|
||||
|
||||
expect(resolveComposerGitRepoId({ eligibleRepos })).toBeNull()
|
||||
})
|
||||
|
||||
it('excludes repos without paths from composer defaults', () => {
|
||||
expect(
|
||||
getComposerEligibleRepos([makeRepo('missing-path', { path: '' }), makeRepo('repo')])
|
||||
).toEqual([expect.objectContaining({ id: 'repo' })])
|
||||
})
|
||||
|
||||
it('defaults to a repo on the focused host when no explicit repo is chosen', () => {
|
||||
const eligibleRepos = [
|
||||
makeRepo('local-repo'),
|
||||
makeRepo('ssh-repo', { connectionId: 'win-vm' }),
|
||||
makeRepo('runtime-repo', { executionHostId: 'runtime:env-1' })
|
||||
]
|
||||
|
||||
expect(resolveComposerRepoId({ eligibleRepos, focusedHostScope: 'ssh:win-vm' })).toBe(
|
||||
'ssh-repo'
|
||||
)
|
||||
expect(resolveComposerRepoId({ eligibleRepos, focusedHostScope: 'runtime:env-1' })).toBe(
|
||||
'runtime-repo'
|
||||
)
|
||||
expect(resolveComposerRepoId({ eligibleRepos, focusedHostScope: 'local' })).toBe('local-repo')
|
||||
})
|
||||
|
||||
it('lets explicit draft/initial/active choices win over the focused host', () => {
|
||||
const eligibleRepos = [makeRepo('local-repo'), makeRepo('ssh-repo', { connectionId: 'win-vm' })]
|
||||
|
||||
expect(
|
||||
resolveComposerRepoId({
|
||||
eligibleRepos,
|
||||
activeRepoId: 'local-repo',
|
||||
focusedHostScope: 'ssh:win-vm'
|
||||
})
|
||||
).toBe('local-repo')
|
||||
})
|
||||
|
||||
it('ignores host scope "all" and falls back to the first eligible repo', () => {
|
||||
const eligibleRepos = [makeRepo('local-repo'), makeRepo('ssh-repo', { connectionId: 'win-vm' })]
|
||||
|
||||
expect(resolveComposerRepoId({ eligibleRepos, focusedHostScope: 'all' })).toBe('local-repo')
|
||||
})
|
||||
|
||||
it('falls back to the first eligible repo when the focused host has no repos', () => {
|
||||
const eligibleRepos = [makeRepo('local-repo')]
|
||||
|
||||
|
||||
@@ -46,54 +46,6 @@ describe('repo slug cache host identity', () => {
|
||||
).toEqual([enterprise])
|
||||
})
|
||||
|
||||
it('routes an upstream project row to the fork clone that tracks it', () => {
|
||||
const fork = { ...repo('fork'), upstream: { owner: 'SciPhi-AI', repo: 'R2R' } }
|
||||
slugByRepoId.set(
|
||||
slugCacheKey(fork.id, settingsForRepoOwner(fork, null)),
|
||||
githubRepoIdentityKey({ owner: 'me', repo: 'r2r-mirror' })
|
||||
)
|
||||
|
||||
expect(lookupReposBySlugFromCache([fork], null, 'SciPhi-AI/R2R')).toEqual([fork])
|
||||
})
|
||||
|
||||
it('prefers the clone that owns the slug over a fork of it', () => {
|
||||
const origin = repo('origin')
|
||||
const fork = { ...repo('fork'), upstream: { owner: 'SciPhi-AI', repo: 'R2R' } }
|
||||
slugByRepoId.set(
|
||||
slugCacheKey(origin.id, settingsForRepoOwner(origin, null)),
|
||||
githubRepoIdentityKey({ owner: 'SciPhi-AI', repo: 'R2R' })
|
||||
)
|
||||
slugByRepoId.set(
|
||||
slugCacheKey(fork.id, settingsForRepoOwner(fork, null)),
|
||||
githubRepoIdentityKey({ owner: 'me', repo: 'r2r-mirror' })
|
||||
)
|
||||
|
||||
expect(lookupReposBySlugFromCache([origin, fork], null, 'SciPhi-AI/R2R')).toEqual([origin])
|
||||
})
|
||||
|
||||
it('does not route a GHES row to a same-named github.com fork parent', () => {
|
||||
const fork = { ...repo('fork'), upstream: { owner: 'acme', repo: 'widgets' } }
|
||||
slugByRepoId.set(
|
||||
slugCacheKey(fork.id, settingsForRepoOwner(fork, null)),
|
||||
githubRepoIdentityKey({ owner: 'me', repo: 'widgets' })
|
||||
)
|
||||
|
||||
expect(lookupReposBySlugFromCache([fork], null, 'acme/widgets', 'ghe.example:8443')).toEqual([])
|
||||
})
|
||||
|
||||
it('scopes a host-less fork parent to the host the fork itself was cloned from', () => {
|
||||
const enterpriseFork = { ...repo('fork'), upstream: { owner: 'acme', repo: 'widgets' } }
|
||||
slugByRepoId.set(
|
||||
slugCacheKey(enterpriseFork.id, settingsForRepoOwner(enterpriseFork, null)),
|
||||
githubRepoIdentityKey({ owner: 'me', repo: 'widgets', host: 'ghe.example:8443' })
|
||||
)
|
||||
|
||||
expect(
|
||||
lookupReposBySlugFromCache([enterpriseFork], null, 'acme/widgets', 'ghe.example:8443')
|
||||
).toEqual([enterpriseFork])
|
||||
expect(lookupReposBySlugFromCache([enterpriseFork], null, 'acme/widgets')).toEqual([])
|
||||
})
|
||||
|
||||
it('drops the fork alias while its own origin is unresolved', () => {
|
||||
const fork = { ...repo('fork'), upstream: { owner: 'acme', repo: 'widgets' } }
|
||||
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
import { afterEach, describe, expect, it } from 'vitest'
|
||||
import type { SleepingAgentSessionRecord } from '../../../shared/agent-session-resume'
|
||||
import { useAppStore } from '@/store'
|
||||
import { resumeSleepingAgentSessionsForWorktree } from './resume-sleeping-agent-session'
|
||||
|
||||
const initialState = useAppStore.getState()
|
||||
|
||||
function record(origin: 'live' | 'quit'): SleepingAgentSessionRecord {
|
||||
return {
|
||||
paneKey: 'tab-1:leaf-1',
|
||||
tabId: 'tab-1',
|
||||
worktreeId: 'wt-1',
|
||||
agent: 'claude',
|
||||
providerSession: { key: 'session_id', id: 'sess-1' },
|
||||
prompt: 'finish the task',
|
||||
state: 'working',
|
||||
capturedAt: 1,
|
||||
updatedAt: 1,
|
||||
origin
|
||||
}
|
||||
}
|
||||
|
||||
function setRemoteSleepRecord(value: SleepingAgentSessionRecord): void {
|
||||
useAppStore.setState({
|
||||
settings: { ...initialState.settings, activeRuntimeEnvironmentId: 'env-1' },
|
||||
tabsByWorktree: {
|
||||
'wt-1': [
|
||||
{
|
||||
id: 'tab-1',
|
||||
ptyId: null,
|
||||
worktreeId: 'wt-1',
|
||||
title: 'shell',
|
||||
customTitle: null,
|
||||
color: null,
|
||||
sortOrder: 0,
|
||||
createdAt: 1
|
||||
}
|
||||
]
|
||||
},
|
||||
sleepingAgentSessionsByPaneKey: { [value.paneKey]: value }
|
||||
} as never)
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
useAppStore.setState(initialState, true)
|
||||
})
|
||||
|
||||
describe('remote sleeping-agent compatibility', () => {
|
||||
it('queues records for transport-level host authority on a capable host', () => {
|
||||
const value = record('live')
|
||||
setRemoteSleepRecord(value)
|
||||
|
||||
expect(resumeSleepingAgentSessionsForWorktree('wt-1')).toBe(1)
|
||||
expect(useAppStore.getState().sleepingAgentSessionsByPaneKey[value.paneKey]).toBeUndefined()
|
||||
})
|
||||
|
||||
it('preserves legacy automatic wake when host authority is not known', () => {
|
||||
const value = record('quit')
|
||||
setRemoteSleepRecord(value)
|
||||
|
||||
expect(resumeSleepingAgentSessionsForWorktree('wt-1')).toBe(1)
|
||||
expect(useAppStore.getState().sleepingAgentSessionsByPaneKey[value.paneKey]).toBeUndefined()
|
||||
})
|
||||
})
|
||||
@@ -114,28 +114,6 @@ describe('createLinearSlice invalidation', () => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
it('keeps literal search queries separate from list cache keys', async () => {
|
||||
const store = createTestStore()
|
||||
store.setState({
|
||||
linearStatus: { connected: true, viewer: null, selectedWorkspaceId: 'workspace-1' },
|
||||
linearListCache: {
|
||||
'workspace-1::list::all::36::': { data: { items: [issue('LIST')] }, fetchedAt: Date.now() }
|
||||
}
|
||||
})
|
||||
linearSearchIssues.mockResolvedValueOnce([issue('SEARCH')])
|
||||
|
||||
await expect(store.getState().searchLinearIssues('list::all', 36)).resolves.toMatchObject([
|
||||
{ id: 'SEARCH' }
|
||||
])
|
||||
|
||||
expect(
|
||||
store.getState().getCachedLinearIssues({ kind: 'search', query: 'list::all', limit: 36 })
|
||||
).toMatchObject([{ id: 'SEARCH' }])
|
||||
expect(
|
||||
store.getState().getCachedLinearIssues({ kind: 'list', filter: 'all', limit: 36 })
|
||||
).toMatchObject({ items: [{ id: 'LIST' }] })
|
||||
})
|
||||
|
||||
it('refreshing a linked Linear issue invalidates stale issue collection caches', async () => {
|
||||
const store = createTestStore()
|
||||
linearGetIssue.mockResolvedValueOnce(issue('issue-id'))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { eventSchemas, setupScriptImportProviderSchema } from './telemetry-events'
|
||||
import { eventSchemas } from './telemetry-events'
|
||||
|
||||
describe('setup script prompt schemas', () => {
|
||||
it('accepts a bucketed candidate prompt exposure', () => {
|
||||
@@ -148,14 +148,4 @@ describe('setup script prompt schemas', () => {
|
||||
})
|
||||
expect(parsed.success).toBe(false)
|
||||
})
|
||||
|
||||
it('keeps the provider schema in sync with known setup import providers', () => {
|
||||
expect(setupScriptImportProviderSchema.options).toEqual([
|
||||
'superset',
|
||||
'conductor',
|
||||
'codex',
|
||||
'cmux',
|
||||
'package-manager'
|
||||
])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -6,15 +6,10 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import {
|
||||
addRepoSetupStepActionSchema,
|
||||
AGENT_KIND_VALUES,
|
||||
agentKindSchema,
|
||||
errorClassSchema,
|
||||
eventSchemas,
|
||||
isCohortExtendedEvent,
|
||||
SETTINGS_CHANGED_WHITELIST,
|
||||
settingsChangedKeySchema
|
||||
isCohortExtendedEvent
|
||||
} from './telemetry-events'
|
||||
import { FEATURE_INTERACTION_IDS, getFeatureInteractionCategory } from './feature-interactions'
|
||||
import { appStarSourceSchema } from './gh-star-source'
|
||||
|
||||
describe('feature_interaction_usage_bucket_reached schema', () => {
|
||||
@@ -33,20 +28,6 @@ describe('feature_interaction_usage_bucket_reached schema', () => {
|
||||
expect(isCohortExtendedEvent('feature_interaction_usage_bucket_reached')).toBe(true)
|
||||
})
|
||||
|
||||
it('keeps the feature id enum in sync with the catalog', () => {
|
||||
const schema = eventSchemas.feature_interaction_usage_bucket_reached
|
||||
for (const feature_id of FEATURE_INTERACTION_IDS) {
|
||||
expect(
|
||||
schema.safeParse({
|
||||
feature_id,
|
||||
feature_category: getFeatureInteractionCategory(feature_id),
|
||||
count_bucket: 'count_1',
|
||||
bucket_source: 'crossed_now'
|
||||
}).success
|
||||
).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
it('rejects unknown enum values and mismatched categories', () => {
|
||||
const valid = {
|
||||
feature_id: 'github-tasks',
|
||||
@@ -585,16 +566,6 @@ describe('settings_changed schema', () => {
|
||||
).toBe(true)
|
||||
})
|
||||
|
||||
it('accepts whitelisted setting keys', () => {
|
||||
for (const key of SETTINGS_CHANGED_WHITELIST) {
|
||||
const parsed = eventSchemas.settings_changed.safeParse({
|
||||
setting_key: key,
|
||||
value_kind: 'bool'
|
||||
})
|
||||
expect(parsed.success).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
it('rejects non-whitelisted setting keys', () => {
|
||||
const parsed = eventSchemas.settings_changed.safeParse({
|
||||
setting_key: 'telemetryOptIn', // deliberately excluded from the whitelist
|
||||
@@ -605,21 +576,9 @@ describe('settings_changed schema', () => {
|
||||
})
|
||||
|
||||
describe('exported enum schemas', () => {
|
||||
it('agentKindSchema accepts the known product IDs', () => {
|
||||
for (const kind of AGENT_KIND_VALUES) {
|
||||
expect(agentKindSchema.safeParse(kind).success).toBe(true)
|
||||
}
|
||||
})
|
||||
|
||||
it('errorClassSchema rejects novel classes', () => {
|
||||
expect(errorClassSchema.safeParse('kernel_panic').success).toBe(false)
|
||||
})
|
||||
|
||||
it('settingsChangedKeySchema membership matches SETTINGS_CHANGED_WHITELIST', () => {
|
||||
for (const key of SETTINGS_CHANGED_WHITELIST) {
|
||||
expect(settingsChangedKeySchema.safeParse(key).success).toBe(true)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('remote_outbound_budget_close schema', () => {
|
||||
|
||||
Reference in New Issue
Block a user