test: remove 17 low-value suites from audit batch 848 (#36461)

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
OrcaWin
2026-10-30 14:35:29 -07:00
committed by GitHub
co-authored by OrcaWin
parent a079f51991
commit 24bf181d56
18 changed files with 0 additions and 1332 deletions
-14
View File
@@ -2330,7 +2330,6 @@
"src/main/emulator/scrcpy-video-registry.test.ts": 57,
"src/main/emulator/serve-sim-accessibility-tree.test.ts": 62,
"src/main/emulator/serve-sim-ax-normalization.test.ts": 35,
"src/main/emulator/serve-sim-detached-session.test.ts": 30,
"src/main/emulator/serve-sim-execution.test.ts": 64,
"src/main/emulator/serve-sim-helper-processes.test.ts": 59,
"src/main/emulator/serve-sim-kill-contract.test.ts": 1307,
@@ -2404,7 +2403,6 @@
"src/main/git/command-runner/wsl-host-failure.test.ts": 120,
"src/main/git/command-runner/wsl-service-failure-direct-git.test.ts": 186,
"src/main/git/commit-object-ref.test.ts": 25,
"src/main/git/commit.test.ts": 178,
"src/main/git/create-event-repo-probe.test.ts": 59,
"src/main/git/exact-ref-probe.test.ts": 60,
"src/main/git/fetch-error-classification.test.ts": 51,
@@ -2576,7 +2574,6 @@
"src/main/gitea/client-scan-invalidation.test.ts": 485,
"src/main/gitea/client.test.ts": 385,
"src/main/gitea/pull-request-creation.test.ts": 293,
"src/main/gitea/pull-request-mappers.test.ts": 29,
"src/main/gitea/repository-ref.test.ts": 436,
"src/main/github/account-binding-required-host.test.ts": 220,
"src/main/github/auth-diagnose.test.ts": 58,
@@ -5020,7 +5017,6 @@
"src/main/runtime/orchestration/chat-assignee.test.ts": 2933,
"src/main/runtime/orchestration/chat-worker-legacy-failure-read.test.ts": 1651,
"src/main/runtime/orchestration/chat-worker-request-failures.test.ts": 1678,
"src/main/runtime/orchestration/cli-command.test.ts": 57,
"src/main/runtime/orchestration/codex-reconnect-failed-dispatch.test.ts": 6144,
"src/main/runtime/orchestration/configured-worker-agent-selector.test.ts": 32,
"src/main/runtime/orchestration/coordinator-decision-gates.test.ts": 361,
@@ -5572,7 +5568,6 @@
"src/main/runtime/rpc/web-session-pairing.test.ts": 590,
"src/main/runtime/rpc/workspace-creator-context.test.ts": 32,
"src/main/runtime/rpc/worktree-catalog-snapshot.test.ts": 52,
"src/main/runtime/rpc/worktree-ps-other-client-marks.test.ts": 92,
"src/main/runtime/rpc/worktree-removal-marker-projection.test.ts": 348,
"src/main/runtime/rpc/ws-empty-payload-frame-write.test.ts": 95,
"src/main/runtime/rpc/ws-transport-accept-order.test.ts": 67,
@@ -7364,7 +7359,6 @@
"src/renderer/src/components/editor/editor-model-uri-parity.test.ts": 154,
"src/renderer/src/components/editor/editor-model-uri.test.ts": 43,
"src/renderer/src/components/editor/editor-panel-draft-selector.test.ts": 322,
"src/renderer/src/components/editor/editor-panel-git-entry-selector.test.ts": 44,
"src/renderer/src/components/editor/editor-panel-render-model.test.ts": 2054,
"src/renderer/src/components/editor/editor-path-display.test.ts": 34,
"src/renderer/src/components/editor/editor-path-move-inflight.test.ts": 49,
@@ -7949,7 +7943,6 @@
"src/renderer/src/components/native-chat/native-chat-working-suppression.test.ts": 42,
"src/renderer/src/components/native-chat/omp-model-switch-capability.test.ts": 266,
"src/renderer/src/components/native-chat/serialized-screen-background-rows.test.ts": 112,
"src/renderer/src/components/native-chat/structured-agent-session-delivery-notices.kept-card.test.ts": 427,
"src/renderer/src/components/native-chat/structured-agent-session-delivery-notices.test.ts": 234,
"src/renderer/src/components/native-chat/structured-agent-session-legacy-outbox.test.ts": 383,
"src/renderer/src/components/native-chat/structured-agent-session-message-hand-back.test.ts": 377,
@@ -8212,7 +8205,6 @@
"src/renderer/src/components/right-sidebar/ai-vault-search-hit-hosts.test.ts": 45,
"src/renderer/src/components/right-sidebar/ai-vault-search-scope-identity.test.tsx": 479,
"src/renderer/src/components/right-sidebar/ai-vault-search-session.test.ts": 88,
"src/renderer/src/components/right-sidebar/ai-vault-session-chat-action.test.ts": 1625,
"src/renderer/src/components/right-sidebar/ai-vault-session-cli-fork.test.ts": 1630,
"src/renderer/src/components/right-sidebar/ai-vault-session-conditional-refresh-hook.test.tsx": 1736,
"src/renderer/src/components/right-sidebar/ai-vault-session-conditional-refresh.test.ts": 133,
@@ -8324,7 +8316,6 @@
"src/renderer/src/components/right-sidebar/pr-comments-ai-launch-ack.test.ts": 75,
"src/renderer/src/components/right-sidebar/pr-comments-list-selection.test.tsx": 1815,
"src/renderer/src/components/right-sidebar/push-target-upstream-refresh-cache.test.ts": 184,
"src/renderer/src/components/right-sidebar/review-cache-entry-selection.test.ts": 24,
"src/renderer/src/components/right-sidebar/right-panel-comment-composer.ime-enter.test.tsx": 273,
"src/renderer/src/components/right-sidebar/right-panel-comment-focus-timers.test.ts": 82,
"src/renderer/src/components/right-sidebar/right-sidebar-effective-tab.test.ts": 34,
@@ -8332,7 +8323,6 @@
"src/renderer/src/components/right-sidebar/right-sidebar-width.test.ts": 61,
"src/renderer/src/components/right-sidebar/runSourceControlAgentActionStart.test.ts": 276,
"src/renderer/src/components/right-sidebar/search-match-open.test.ts": 100,
"src/renderer/src/components/right-sidebar/search-rows.test.ts": 35,
"src/renderer/src/components/right-sidebar/source-control-action-recipe-match.test.ts": 190,
"src/renderer/src/components/right-sidebar/source-control-active-open-file-keys.test.ts": 28,
"src/renderer/src/components/right-sidebar/source-control-branch-context-row.test.tsx": 248,
@@ -9824,7 +9814,6 @@
"src/renderer/src/components/terminal-pane/use-terminal-scroll-visibility-memory.test.ts": 56,
"src/renderer/src/components/terminal-pane/use-terminal-tab-cold-parking.test.ts": 461,
"src/renderer/src/components/terminal-pane/use-terminal-window-wake-recovery.test.ts": 333,
"src/renderer/src/components/terminal-pane/use-wsl-host-unavailable-reason.test.ts": 1271,
"src/renderer/src/components/terminal-pane/useTerminalFontZoom.test.ts": 197,
"src/renderer/src/components/terminal-pane/wrapped-terminal-http-link-limits.test.ts": 166,
"src/renderer/src/components/terminal-pane/wrapped-terminal-http-link-provider.test.ts": 396,
@@ -11352,7 +11341,6 @@
"src/renderer/src/store/slices/linear.test.ts": 388,
"src/renderer/src/store/slices/local-detected-agent-state.test.ts": 191,
"src/renderer/src/store/slices/native-chat-launch-draft-teardown.test.ts": 1318,
"src/renderer/src/store/slices/new-issue-draft.test.ts": 34,
"src/renderer/src/store/slices/new-markdown.test.ts": 1089,
"src/renderer/src/store/slices/orca-profiles-auth-actions-connect-overlap.test.ts": 1268,
"src/renderer/src/store/slices/orca-profiles-auth-actions-sign-in-wait.test.ts": 1130,
@@ -11478,7 +11466,6 @@
"src/renderer/src/store/slices/tabs/tabs-reconciliation-batch-identity.test.ts": 1309,
"src/renderer/src/store/slices/tabs/tabs-reconciliation-empty-groups.test.ts": 1204,
"src/renderer/src/store/slices/tabs/tabs-root-group.test.ts": 1263,
"src/renderer/src/store/slices/task-creation-drafts.test.ts": 50,
"src/renderer/src/store/slices/terminal-helpers.test.ts": 68,
"src/renderer/src/store/slices/terminal-input-activity-store-write.test.ts": 1443,
"src/renderer/src/store/slices/terminal-layout-pty-ownership.test.ts": 1313,
@@ -11664,7 +11651,6 @@
"src/renderer/src/web/web-preload-api-runtime-calls.test.ts": 838,
"src/renderer/src/web/web-preload-api-runtime-environment.test.ts": 1240,
"src/renderer/src/web/web-preload-api-settings.test.ts": 2080,
"src/renderer/src/web/web-preload-api-ssh.test.ts": 682,
"src/renderer/src/web/web-preload-api-ui-pairing-local-fields.test.ts": 488,
"src/renderer/src/web/web-preload-api-ui.test.ts": 1703,
"src/renderer/src/web/web-preload-api-workspace-catalog.test.ts": 1393,
@@ -1,76 +0,0 @@
import { describe, expect, it } from 'vitest'
import { toBrowserConsoleResult, toBrowserNetworkLogResult } from './agent-browser-log-entries'
// Trimmed from real agent-browser 0.27.3 and 0.41.0 `--json` data; both print the same fields.
const consoleOutput = {
messages: [
{ args: [{ type: 'string', value: 'hello log' }], text: 'hello log', type: 'log' },
{ args: [{ type: 'string', value: 'a warning' }], text: 'a warning', type: 'warning' },
{ args: [{ type: 'string', value: 'an error' }], text: 'an error', type: 'error' }
]
}
const networkOutput = {
requests: [
{
headers: { 'Accept-Language': 'en-US,en;q=0.9' },
method: 'GET',
mimeType: 'text/html',
requestId: 'BECA21D6BA0B635E9916700B48479394',
resourceType: 'Document',
responseHeaders: { 'Content-Length': '254' },
status: 200,
timestamp: 1793283228914,
url: 'http://127.0.0.1:47811/page.html'
},
{
headers: { 'Accept-Language': 'en-US,en;q=0.9' },
method: 'GET',
requestId: '45376.2',
resourceType: 'Fetch',
timestamp: 1793283228914,
url: 'https://example.com/?a=1'
}
]
}
describe('toBrowserConsoleResult', () => {
it('maps messages to entries and keeps the newest up to the limit', () => {
expect(toBrowserConsoleResult(consoleOutput, undefined)).toEqual({
entries: [
{ level: 'log', text: 'hello log' },
{ level: 'warning', text: 'a warning' },
{ level: 'error', text: 'an error' }
],
truncated: false
})
expect(toBrowserConsoleResult(consoleOutput, 2)).toEqual({
entries: [
{ level: 'warning', text: 'a warning' },
{ level: 'error', text: 'an error' }
],
truncated: true
})
})
})
describe('toBrowserNetworkLogResult', () => {
it('maps requests to entries, including ones without a response, up to the limit', () => {
expect(toBrowserNetworkLogResult(networkOutput, undefined)).toEqual({
entries: [
{
url: 'http://127.0.0.1:47811/page.html',
method: 'GET',
status: 200,
mimeType: 'text/html',
timestamp: 1793283228914
},
{ url: 'https://example.com/?a=1', method: 'GET', timestamp: 1793283228914 }
],
truncated: false
})
expect(toBrowserNetworkLogResult(networkOutput, 1).entries).toEqual([
{ url: 'https://example.com/?a=1', method: 'GET', timestamp: 1793283228914 }
])
})
})
@@ -1,76 +0,0 @@
import { describe, expect, it } from 'vitest'
import {
deriveAxUrlFromStreamUrl,
parseServeSimDetachedSession
} from './serve-sim-detached-session'
describe('parseServeSimDetachedSession', () => {
it('uses serve-sim streamUrl when present', () => {
const info = parseServeSimDetachedSession(
{
device: 'device-1',
streamUrl: 'http://127.0.0.1:3100/stream.mjpeg',
wsUrl: 'ws://127.0.0.1:3100/ws'
},
'device-1'
)
expect(info).toMatchObject({
deviceUdid: 'device-1',
streamUrl: 'http://127.0.0.1:3100/stream.mjpeg',
wsUrl: 'ws://127.0.0.1:3100/ws',
axUrl: 'http://127.0.0.1:3100/ax'
})
})
it('derives the device-scoped AX endpoint and preserves an explicit one', () => {
const derived = parseServeSimDetachedSession(
{
streamUrl: 'http://127.0.0.1:3200/helper/device-1/stream.mjpeg',
wsUrl: 'ws://127.0.0.1:3200/helper/device-1/ws'
},
'device-1'
)
const explicit = parseServeSimDetachedSession(
{
streamUrl: 'http://127.0.0.1:3200/stream.mjpeg',
wsUrl: 'ws://127.0.0.1:3200/ws',
axUrl: 'http://127.0.0.1:3200/custom-ax'
},
'device-1'
)
expect(derived.axUrl).toBe('http://127.0.0.1:3200/helper/device-1/ax')
expect(explicit.axUrl).toBe('http://127.0.0.1:3200/custom-ax')
})
it('derives the MJPEG stream endpoint from older serve-sim url output', () => {
const info = parseServeSimDetachedSession(
{
device: 'device-2',
url: 'http://127.0.0.1:3100',
wsUrl: 'ws://127.0.0.1:3100/ws'
},
'device-2'
)
expect(info.streamUrl).toBe('http://127.0.0.1:3100/stream.mjpeg')
})
})
describe('deriveAxUrlFromStreamUrl', () => {
it('swaps the mjpeg stream suffix for /ax', () => {
expect(deriveAxUrlFromStreamUrl('http://127.0.0.1:3100/stream.mjpeg')).toBe(
'http://127.0.0.1:3100/ax'
)
expect(deriveAxUrlFromStreamUrl('http://127.0.0.1:3200/helper/device-1/stream.mjpeg')).toBe(
'http://127.0.0.1:3200/helper/device-1/ax'
)
})
it('never fabricates an /ax endpoint from a non-mjpeg or missing url', () => {
expect(deriveAxUrlFromStreamUrl('http://127.0.0.1:3100/stream.h264')).toBeUndefined()
expect(deriveAxUrlFromStreamUrl('http://127.0.0.1:3100/')).toBeUndefined()
expect(deriveAxUrlFromStreamUrl(undefined)).toBeUndefined()
})
})
-81
View File
@@ -1,81 +0,0 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
const { gitExecFileAsyncMock } = vi.hoisted(() => ({
gitExecFileAsyncMock: vi.fn()
}))
vi.mock('./runner', () => ({
gitExecFileAsync: gitExecFileAsyncMock,
gitExecFileAsyncBuffer: vi.fn()
}))
import { commitChanges } from './status'
describe('commitChanges', () => {
beforeEach(() => {
gitExecFileAsyncMock.mockReset()
})
it('returns success when git commit completes', async () => {
gitExecFileAsyncMock.mockResolvedValue({ stdout: '[main abc123] message\n', stderr: '' })
const result = await commitChanges('/repo', 'feat: add commit action')
expect(gitExecFileAsyncMock).toHaveBeenCalledWith(['commit', '-m', 'feat: add commit action'], {
cwd: '/repo'
})
expect(result).toEqual({ success: true })
})
it('returns stderr when commit fails (e.g. pre-commit hook)', async () => {
gitExecFileAsyncMock.mockRejectedValue({
stderr: 'pre-commit hook failed: lint errors\n'
})
const result = await commitChanges('/repo', 'feat: commit with lint errors')
expect(result).toEqual({
success: false,
error: 'pre-commit hook failed: lint errors\n'
})
})
it('returns stdout when git writes to stdout (e.g. nothing to commit)', async () => {
gitExecFileAsyncMock.mockRejectedValue({
stdout: 'nothing to commit, working tree clean\n',
stderr: ''
})
const result = await commitChanges('/repo', 'feat: empty commit')
expect(result).toEqual({
success: false,
error: 'nothing to commit, working tree clean\n'
})
})
it('prefers stderr over stdout when both are present', async () => {
gitExecFileAsyncMock.mockRejectedValue({
stdout: 'some stdout output\n',
stderr: 'hook rejected\n'
})
const result = await commitChanges('/repo', 'feat: both channels')
expect(result).toEqual({
success: false,
error: 'hook rejected\n'
})
})
it('falls back to Error.message when stdout/stderr are empty', async () => {
gitExecFileAsyncMock.mockRejectedValue(new Error('spawn git ENOENT'))
const result = await commitChanges('/repo', 'feat: missing git')
expect(result).toEqual({
success: false,
error: 'spawn git ENOENT'
})
})
})
@@ -1,77 +0,0 @@
import { describe, expect, it } from 'vitest'
import {
deriveGiteaCommitStatus,
mapGiteaMergeable,
mapGiteaPullRequest,
mapGiteaPullRequestState
} from './pull-request-mappers'
describe('Gitea pull request mappers', () => {
it('maps pull request states', () => {
expect(mapGiteaPullRequestState({ state: 'open' })).toBe('open')
expect(mapGiteaPullRequestState({ state: 'closed' })).toBe('closed')
expect(mapGiteaPullRequestState({ state: 'open', draft: true })).toBe('draft')
expect(mapGiteaPullRequestState({ state: 'closed', draft: true })).toBe('closed')
expect(mapGiteaPullRequestState({ state: 'closed', merged: true })).toBe('merged')
})
it('maps mergeability', () => {
expect(mapGiteaMergeable(true)).toBe('MERGEABLE')
expect(mapGiteaMergeable(false)).toBe('CONFLICTING')
expect(mapGiteaMergeable(undefined)).toBe('UNKNOWN')
})
it('derives commit status from the combined state', () => {
expect(deriveGiteaCommitStatus({ state: 'success' })).toBe('success')
expect(deriveGiteaCommitStatus({ state: 'failure' })).toBe('failure')
expect(deriveGiteaCommitStatus({ state: 'error' })).toBe('failure')
expect(deriveGiteaCommitStatus({ state: 'pending' })).toBe('pending')
expect(deriveGiteaCommitStatus({ state: 'skipped' })).toBe('neutral')
})
it('rolls up individual statuses when the combined state is neutral', () => {
expect(
deriveGiteaCommitStatus({
state: '',
statuses: [{ status: 'success' }, { status: 'failure' }]
})
).toBe('failure')
expect(
deriveGiteaCommitStatus({
statuses: [{ status: 'success' }, { status: 'pending' }]
})
).toBe('pending')
expect(deriveGiteaCommitStatus({ statuses: [{ status: 'success' }] })).toBe('success')
expect(deriveGiteaCommitStatus({ statuses: [] })).toBe('neutral')
})
it('maps a raw pull request to the hosted review shape', () => {
expect(
mapGiteaPullRequest(
{
number: 12,
title: 'Gitea branch',
state: 'open',
html_url: 'https://git.example.com/team/project/pulls/12',
updated_at: '2026-05-15T00:00:00Z',
mergeable: true,
head: { sha: 'abc123' }
},
'success'
)
).toEqual({
number: 12,
title: 'Gitea branch',
state: 'open',
url: 'https://git.example.com/team/project/pulls/12',
status: 'success',
updatedAt: '2026-05-15T00:00:00Z',
mergeable: 'MERGEABLE',
headSha: 'abc123'
})
})
it('rejects incomplete pull request payloads', () => {
expect(mapGiteaPullRequest({ number: 1, title: 'missing url' }, 'neutral')).toBeNull()
})
})
@@ -1,78 +0,0 @@
import { describe, expect, it } from 'vitest'
import { resolveTerminalOrchestrationCliCommand } from './cli-command'
describe('resolveTerminalOrchestrationCliCommand', () => {
it('uses orca-ide for a pane recorded as WSL', () => {
expect(
resolveTerminalOrchestrationCliCommand({
connectionId: null,
isWsl: true,
worktreeId: 'repo::C:\\repo'
})
).toBe('orca-ide')
})
it('uses project runtime and WSL paths when restored pane metadata is unavailable', () => {
expect(
resolveTerminalOrchestrationCliCommand({
connectionId: null,
isWsl: null,
worktreeId: 'repo::C:\\repo',
projectRuntime: {
status: 'resolved',
runtime: {
kind: 'wsl',
hostPlatform: 'wsl',
projectId: 'project',
distro: 'Ubuntu',
reason: 'project-override',
cacheKey: 'project:wsl:Ubuntu'
}
}
})
).toBe('orca-ide')
expect(
resolveTerminalOrchestrationCliCommand({
connectionId: null,
isWsl: null,
worktreeId: 'repo::\\\\wsl.localhost\\Ubuntu\\home\\alice\\repo'
})
).toBe('orca-ide')
})
it('preserves native and SSH bare-orca commands', () => {
expect(
resolveTerminalOrchestrationCliCommand({
connectionId: null,
isWsl: false,
worktreeId: 'repo::/home/alice/repo'
})
).toBe('orca')
expect(
resolveTerminalOrchestrationCliCommand({
connectionId: 'ssh-1',
isWsl: null,
worktreeId: 'repo::\\\\wsl.localhost\\Ubuntu\\home\\alice\\repo'
})
).toBe('orca')
})
it('uses the runtime-provided command locally but never leaks it to SSH', () => {
expect(
resolveTerminalOrchestrationCliCommand({
connectionId: null,
isWsl: true,
worktreeId: 'repo::C:\\repo',
runtimeCliCommand: 'orca-dev'
})
).toBe('orca-dev')
expect(
resolveTerminalOrchestrationCliCommand({
connectionId: 'ssh-1',
isWsl: true,
worktreeId: 'repo::C:\\repo',
runtimeCliCommand: 'orca-dev'
})
).toBe('orca')
})
})
@@ -1,80 +0,0 @@
import { describe, expect, it } from 'vitest'
import type {
RuntimeWorktreePsResult,
RuntimeWorktreePsSummary
} from '../../../shared/runtime-worktree-contracts'
import type { RpcContext } from './core'
import { markWorktreePsOtherClientRows } from './worktree-ps-other-client-marks'
function row(
worktreeId: string,
creatorProvenance?: RuntimeWorktreePsSummary['creatorProvenance']
): RuntimeWorktreePsSummary {
return {
worktreeId,
repoId: 'repo',
repo: 'repo',
path: `/repo/${worktreeId}`,
branch: worktreeId,
isArchived: false,
isMainWorktree: false,
hasHostSidebarActivity: false,
parentWorktreeId: null,
childWorktreeIds: [],
displayName: worktreeId,
workspaceStatus: 'in-progress',
sortOrder: 0,
linkedIssue: null,
linkedPR: null,
linkedLinearIssue: null,
linkedGitLabMR: null,
linkedGitLabIssue: null,
comment: '',
isPinned: false,
isActive: false,
unread: false,
liveTerminalCount: 0,
hasAttachedPty: false,
lastOutputAt: null,
preview: '',
status: 'inactive',
agents: [],
...(creatorProvenance ? { creatorProvenance } : {})
}
}
const rows = [
row('desktop', { kind: 'host' }),
row('laptop', { kind: 'paired-device', deviceId: 'laptop' }),
row('unknown')
]
const result: RuntimeWorktreePsResult = { worktrees: rows, totalCount: 4, truncated: false }
function context(
overrides: Partial<Pick<RpcContext, 'clientKind' | 'pairedDeviceParentId'>>
): Parameters<typeof markWorktreePsOtherClientRows>[1] {
return overrides
}
function marked(next: RuntimeWorktreePsResult): string[] {
return next.worktrees.filter((entry) => entry.desktopOtherClient).map((entry) => entry.worktreeId)
}
describe('markWorktreePsOtherClientRows', () => {
it("marks, for this host's own phone, the rows its sidebar calls another client's", () => {
expect(
marked(markWorktreePsOtherClientRows(result, context({ clientKind: 'mobile' })))
).toEqual(['laptop'])
})
it('leaves rows untouched for any other caller', () => {
expect(markWorktreePsOtherClientRows(result, context({ clientKind: 'runtime' }))).toBe(result)
expect(markWorktreePsOtherClientRows(result, context({}))).toBe(result)
expect(
markWorktreePsOtherClientRows(
result,
context({ clientKind: 'mobile', pairedDeviceParentId: 'other-desktop' })
)
).toBe(result)
})
})
@@ -1,75 +0,0 @@
import { describe, expect, it } from 'vitest'
import type { GitBranchChangeEntry } from '../../../../shared/git-diff-compare-types'
import type { GitStatusEntry } from '../../../../shared/git-status-types'
import {
selectEditorPanelGitBranchEntries,
selectEditorPanelGitStatusEntries
} from './editor-panel-git-entry-selector'
describe('editor panel Git entry selectors', () => {
it('ignore background worktree writes across mounted editor panels', () => {
const panelCount = 200
const worktreeId = 'worktree-active'
const statusEntries = [{ path: 'src/index.ts' }] as GitStatusEntry[]
const branchEntries = [{ path: 'src/index.ts' }] as GitBranchChangeEntry[]
let gitStatusByWorktree = { [worktreeId]: statusEntries }
let gitBranchChangesByWorktree = { [worktreeId]: branchEntries }
let wholeMapInvalidations = 0
let scopedEntryInvalidations = 0
for (let write = 0; write < 200; write += 1) {
const previousStatusMap = gitStatusByWorktree
gitStatusByWorktree = {
...gitStatusByWorktree,
[`background-${write}`]: [{ path: `generated-${write}.ts` } as GitStatusEntry]
}
const previousBranchMap = gitBranchChangesByWorktree
gitBranchChangesByWorktree = {
...gitBranchChangesByWorktree,
[`background-${write}`]: [{ path: `generated-${write}.ts` } as GitBranchChangeEntry]
}
for (let panel = 0; panel < panelCount; panel += 1) {
wholeMapInvalidations += Number(previousStatusMap !== gitStatusByWorktree)
wholeMapInvalidations += Number(previousBranchMap !== gitBranchChangesByWorktree)
scopedEntryInvalidations += Number(
selectEditorPanelGitStatusEntries({ gitStatusByWorktree }, worktreeId) !== statusEntries
)
scopedEntryInvalidations += Number(
selectEditorPanelGitBranchEntries({ gitBranchChangesByWorktree }, worktreeId) !==
branchEntries
)
}
}
expect(wholeMapInvalidations).toBe(80_000)
expect(scopedEntryInvalidations).toBe(0)
})
it('publishes owning entry replacements and handles an absent worktree', () => {
const firstStatus = [{ path: 'src/old.ts' }] as GitStatusEntry[]
const nextStatus = [{ path: 'src/new.ts' }] as GitStatusEntry[]
const firstBranch = [{ path: 'src/old.ts' }] as GitBranchChangeEntry[]
const nextBranch = [{ path: 'src/new.ts' }] as GitBranchChangeEntry[]
expect(
selectEditorPanelGitStatusEntries({ gitStatusByWorktree: { active: firstStatus } }, 'active')
).toBe(firstStatus)
expect(
selectEditorPanelGitStatusEntries({ gitStatusByWorktree: { active: nextStatus } }, 'active')
).toBe(nextStatus)
expect(
selectEditorPanelGitBranchEntries(
{ gitBranchChangesByWorktree: { active: firstBranch } },
'active'
)
).toBe(firstBranch)
expect(
selectEditorPanelGitBranchEntries(
{ gitBranchChangesByWorktree: { active: nextBranch } },
'active'
)
).toBe(nextBranch)
expect(selectEditorPanelGitStatusEntries({ gitStatusByWorktree: {} }, null)).toBeUndefined()
})
})
@@ -1,73 +0,0 @@
// After host admission as a queued card, its own row must not show sending/failure regardless of local delivery phase.
import { expect, it } from 'vitest'
import type { AgentJournalSubmission } from '../../../../shared/agent-session-journal-types'
import { agentJournalSubmissionKey } from '../../../../shared/agent-session-journal-item-key'
import { structuredAgentSessionSendBody } from '../../../../shared/structured-agent-session-send-mutation'
import { structuredAgentSessionDeliveryNotices } from './structured-agent-session-delivery-notices'
import type { StructuredAgentSessionPendingSend } from './structured-agent-session-pending-sends'
const KEPT_ID = 'client-kept'
function pendingSend(
patch: Partial<StructuredAgentSessionPendingSend> = {}
): StructuredAgentSessionPendingSend {
return {
clientMessageId: KEPT_ID,
sessionId: 'session-1',
body: structuredAgentSessionSendBody('the kept words', []),
previewUris: [],
queuedAt: 1,
phase: 'sending',
issued: false,
...patch
}
}
const restartRejected: AgentJournalSubmission = {
clientMessageId: KEPT_ID,
fence: 2,
payloadFingerprint: 'fingerprint-kept',
dispatchState: 'rejected',
providerItemId: null,
reason: 'Orca restarted before this message was sent.',
rejection: { kind: 'hostRestarted' },
submittedAt: 1,
resolvedAt: 2,
recovered: true
}
const kept: AgentJournalSubmission = { ...restartRejected, keptAsQueuedMessageId: KEPT_ID }
function notices(
send: StructuredAgentSessionPendingSend,
submissions: readonly AgentJournalSubmission[]
) {
return structuredAgentSessionDeliveryNotices({
pending: [send],
submissions,
agentName: 'Claude',
startFailures: []
})
}
// Still being readied, on its way, or resent under its id after a lost answer.
const SENDS = [
pendingSend(),
pendingSend({ issued: true }),
pendingSend({ phase: 'recorded', issued: true })
]
it('gives a kept send no notice, so it never reads "Sending…" or not sent', () => {
for (const send of SENDS) {
expect([...notices(send, [kept])]).toEqual([])
}
})
it('still says not sent, never "Sending…", for a send rejected without being kept', () => {
for (const send of SENDS) {
const notice = notices(send, [restartRejected]).get(agentJournalSubmissionKey(KEPT_ID))
expect(notice).toMatchObject({ text: expect.any(String) })
expect(notice).not.toHaveProperty('sending')
}
})
@@ -1,79 +0,0 @@
import { describe, expect, it } from 'vitest'
import type { AgentJournalSubmission } from '../../../../shared/agent-session-journal-types'
import type { StructuredAgentSessionPendingSend } from './structured-agent-session-pending-sends'
import {
pendingQueueSendsOnTheirWay,
pendingSendsOutsideQueuedCards
} from './structured-agent-session-sending-queued-cards'
function submission(clientMessageId: string, queuedMessageId?: string): AgentJournalSubmission {
return {
clientMessageId,
fence: 1,
payloadFingerprint: 'fingerprint',
dispatchState: 'pending',
providerItemId: null,
reason: null,
submittedAt: 1,
resolvedAt: null,
...(queuedMessageId !== undefined ? { queuedMessageId } : {})
}
}
describe('queue sends on their way', () => {
it('a mid-turn queue send on its way is no bubble; a plain or recorded one is, until its row', () => {
const entry = (
clientMessageId: string,
overrides: Partial<StructuredAgentSessionPendingSend> = {}
): StructuredAgentSessionPendingSend => ({
clientMessageId,
sessionId: 'session-1',
body: { kind: 'message', role: 'user', blocks: [{ type: 'text', text: clientMessageId }] },
previewUris: [],
queuedAt: 1,
phase: 'sending',
issued: true,
...overrides
})
const ids = (entries: readonly StructuredAgentSessionPendingSend[]): string[] =>
entries.map((candidate) => candidate.clientMessageId)
const sends = [
entry('queued', { delivery: 'queue-if-active' }),
entry('plain'),
entry('recorded', { phase: 'recorded' })
]
// Pending queued sends use cards while working; plain/recorded sends remain bubbles until host ownership appears.
expect(ids(pendingSendsOutsideQueuedCards(sends, [], true))).toEqual(['plain', 'recorded'])
expect(ids(pendingSendsOutsideQueuedCards(sends, [], false))).toEqual([
'queued',
'plain',
'recorded'
])
expect(ids(pendingSendsOutsideQueuedCards(sends, ['plain'], false))).toEqual([
'queued',
'recorded'
])
})
it('a sending card ends once the host records the send or hands its card off', () => {
const entry: StructuredAgentSessionPendingSend = {
clientMessageId: 'a',
sessionId: 'session-1',
body: { kind: 'message', role: 'user', blocks: [{ type: 'text', text: 'a' }] },
previewUris: [],
queuedAt: 1,
phase: 'sending',
issued: true,
delivery: 'queue-if-active'
}
const onItsWay = (submissions: AgentJournalSubmission[]) =>
pendingQueueSendsOnTheirWay([entry], [], true, submissions).map(
(candidate) => candidate.clientMessageId
)
expect(onItsWay([])).toEqual(['a'])
expect(onItsWay([submission('a')])).toEqual([])
expect(onItsWay([submission('a-hand-off', 'a')])).toEqual([])
expect(pendingQueueSendsOnTheirWay([entry], ['a'], true, [])).toEqual([])
expect(pendingQueueSendsOnTheirWay([entry], [], false, [])).toEqual([])
expect(pendingQueueSendsOnTheirWay([{ ...entry, phase: 'recorded' }], [], true, [])).toEqual([])
})
})
@@ -1,78 +0,0 @@
import { describe, expect, it } from 'vitest'
import type { PluginListEntry } from './plugin-list-entries'
import { matchesPluginFilter, pluginFilterCategories } from './plugin-list-filter'
function entry(
categories: string[],
sourceId: string | null,
catalogIds: string[] = sourceId ? [sourceId] : []
): PluginListEntry {
return {
pluginKey: `p.${categories.join('-')}`,
name: 'P',
publisher: null,
version: null,
description: null,
official: false,
categories,
types: [],
minimumOrca: null,
updateVersion: null,
catalogIds,
updatable: false,
autoUpdate: { updatedTo: null, needsReview: false },
installed: null,
listing: sourceId
? {
marketplaceSourceId: sourceId,
marketplaceName: 'Catalog',
marketplaceOwner: 'owner',
marketplaceCommit: 'c',
pluginKey: 'p',
source: { kind: 'git', url: 'https://example.invalid/c.git', ref: 'main' },
categories,
official: false,
bundled: false
}
: null,
verifiedSource: { kind: 'unverified' },
alsoListedBy: []
}
}
describe('plugin list filter', () => {
it('counts categories without the trust label, and matches category and catalog together', () => {
const themes = entry(['themes', 'official'], 'official')
const icons = entry(['icons'], 'acme')
expect(pluginFilterCategories([themes, icons])).toEqual([
['themes', 1],
['icons', 1]
])
const filter = { categories: new Set(['themes']), sourceIds: new Set(['official']) }
expect(matchesPluginFilter(themes, filter)).toBe(true)
expect(matchesPluginFilter(icons, filter)).toBe(false)
expect(matchesPluginFilter(entry(['themes'], null), filter)).toBe(false)
expect(matchesPluginFilter(icons, { categories: new Set(), sourceIds: new Set() })).toBe(true)
})
it('folds catalog categories into readable kinds and keeps unknown ones', () => {
const terminal = entry(['terminal-themes'], 'official')
const recipes = entry(['vm-recipes'], 'official')
const odd = entry(['music'], 'official')
expect(pluginFilterCategories([terminal, recipes, odd])).toEqual([
['themes', 1],
['machines', 1],
['music', 1]
])
expect(
matchesPluginFilter(terminal, { categories: new Set(['themes']), sourceIds: new Set() })
).toBe(true)
})
it('matches a plugin under any catalog that lists it', () => {
const shared = entry(['themes'], 'official', ['official', 'acme'])
expect(
matchesPluginFilter(shared, { categories: new Set(), sourceIds: new Set(['acme']) })
).toBe(true)
})
})
@@ -1,80 +0,0 @@
import { describe, expect, it } from 'vitest'
import type { AiVaultSession } from '../../../../shared/ai-vault-types'
import type { AiVaultSearchHit } from '../../../../shared/ai-vault-search-types'
import { resolveAiVaultSessionRowChatActions } from './ai-vault-session-chat-action'
const session: AiVaultSession = {
id: 'local:claude:s-1:/tmp/s-1.jsonl',
executionHostId: 'local',
agent: 'claude',
sessionId: 's-1',
title: 'Fix auth retry',
cwd: '/repo',
branch: null,
model: null,
filePath: '/tmp/s-1.jsonl',
codexHome: null,
createdAt: null,
updatedAt: null,
modifiedAt: '2026-09-17T00:00:00.000Z',
messageCount: 2,
totalTokens: 0,
previewMessages: [{ role: 'user', text: 'Fix it', timestamp: null }],
queuedMessageCount: 0,
subagentTranscriptCount: 0,
resumeCommand: 'claude --resume s-1',
subagent: null
}
const hit: AiVaultSearchHit = {
agent: 'claude',
sessionId: 's-1',
title: 'Fix auth retry',
cwd: '/repo',
branch: null,
updatedAt: null,
messageCount: 2,
score: 1,
source: { presence: 'missing' },
evidence: null
}
function actions(overrides: Partial<Parameters<typeof resolveAiVaultSessionRowChatActions>[0]>) {
return resolveAiVaultSessionRowChatActions({
session,
originalPaneTarget: null,
structuredSessionOpen: false,
resumeState: { blocked: false, worktreeId: 'wt-1', usesSessionWorktree: true },
resumeInChat: { available: true, workspaceId: 'wt-own' },
searchHit: undefined,
...overrides
})
}
describe('session row chat actions', () => {
it('resumes with ▶ only while ▶ is enabled and shown', () => {
expect(actions({})).toMatchObject({ resumeDisabled: false, resumeWorktreeId: 'wt-1' })
expect(
actions({ resumeState: { blocked: true, worktreeId: 'wt-1', usesSessionWorktree: true } })
).toMatchObject({ resumeDisabled: true, resumeWorktreeId: null })
// An open chat hides ▶; switching to it is the only offer.
expect(actions({ structuredSessionOpen: true }).resumeWorktreeId).toBeNull()
expect(
actions({ session: { ...session, messageCount: 0, previewMessages: [] } })
).toMatchObject({ resumeDisabled: true, resumeWorktreeId: null })
})
it('offers nothing a hidden button would not', () => {
expect(
actions({ resumeInChat: { available: false, reason: 'remote' } }).resumeInNewChatWorkspaceId
).toBeNull()
// A search hit whose transcript is gone cannot resume, whatever eligibility said.
expect(actions({ searchHit: hit })).toEqual({
canJumpToOriginalPane: false,
resumeDisabled: true,
resumeWorktreeId: null,
resumeInNewChatWorkspaceId: null,
resumeInNewCliWorktreeId: null
})
})
})
@@ -1,79 +0,0 @@
import { describe, expect, it } from 'vitest'
import { selectReviewCacheData, selectReviewCacheEntry } from './review-cache-entry-selection'
type Review = { id: string }
type ReviewEntry = { data: Review | null; fetchedAt: number }
const ACTIVE_KEY = 'repo-active::feature'
function replaceUnrelatedEntry(
cache: Record<string, ReviewEntry>,
index: number
): Record<string, ReviewEntry> {
return {
...cache,
[`repo-background-${index % 100}::feature`]: {
data: { id: `background-${index}` },
fetchedAt: index
}
}
}
describe('review cache entry selection', () => {
it('turns unrelated active-panel cache invalidations into stable selections', () => {
const activeHostedReview = { id: 'hosted-active' }
const activePullRequest = { id: 'pr-active' }
let hostedCache: Record<string, ReviewEntry> = {
[ACTIVE_KEY]: { data: activeHostedReview, fetchedAt: 1 }
}
let pullRequestCache: Record<string, ReviewEntry> = {
[ACTIVE_KEY]: { data: activePullRequest, fetchedAt: 1 }
}
let previousHostedMap = hostedCache
let previousPullRequestMap = pullRequestCache
let previousHostedSelection = selectReviewCacheData(hostedCache, ACTIVE_KEY)
let previousPullRequestSelection = selectReviewCacheEntry(pullRequestCache, ACTIVE_KEY)
let wholeMapInvalidations = 0
let scopedSelectionInvalidations = 0
for (let index = 0; index < 200; index += 1) {
hostedCache = replaceUnrelatedEntry(hostedCache, index)
pullRequestCache = replaceUnrelatedEntry(pullRequestCache, index)
if (hostedCache !== previousHostedMap) {
wholeMapInvalidations += 1
}
if (pullRequestCache !== previousPullRequestMap) {
wholeMapInvalidations += 1
}
const hostedSelection = selectReviewCacheData(hostedCache, ACTIVE_KEY)
const pullRequestSelection = selectReviewCacheEntry(pullRequestCache, ACTIVE_KEY)
if (hostedSelection !== previousHostedSelection) {
scopedSelectionInvalidations += 1
}
if (pullRequestSelection !== previousPullRequestSelection) {
scopedSelectionInvalidations += 1
}
previousHostedMap = hostedCache
previousPullRequestMap = pullRequestCache
previousHostedSelection = hostedSelection
previousPullRequestSelection = pullRequestSelection
}
expect(wholeMapInvalidations).toBe(400)
expect(scopedSelectionInvalidations).toBe(0)
})
it('publishes relevant entry replacements and handles absent keys', () => {
const first = { data: { id: 'first' }, fetchedAt: 1 }
const second = { data: { id: 'second' }, fetchedAt: 2 }
expect(selectReviewCacheEntry({ [ACTIVE_KEY]: first }, ACTIVE_KEY)).toBe(first)
expect(selectReviewCacheEntry({ [ACTIVE_KEY]: second }, ACTIVE_KEY)).toBe(second)
expect(selectReviewCacheData({ [ACTIVE_KEY]: second }, ACTIVE_KEY)).toBe(second.data)
expect(selectReviewCacheEntry({}, ACTIVE_KEY)).toBeUndefined()
expect(selectReviewCacheData({}, ACTIVE_KEY)).toBeNull()
expect(selectReviewCacheEntry({ [ACTIVE_KEY]: first }, null)).toBeUndefined()
})
})
@@ -1,76 +0,0 @@
import { describe, expect, it } from 'vitest'
import { buildSearchRows } from './search-rows'
describe('buildSearchRows', () => {
it('includes file headers and expanded matches in row order (summary is rendered separately)', () => {
const rows = buildSearchRows(
{
totalMatches: 3,
truncated: false,
files: [
{
filePath: '/repo/a.ts',
relativePath: 'a.ts',
matches: [
{ line: 1, column: 1, matchLength: 3, lineContent: 'foo' },
{ line: 2, column: 5, matchLength: 3, lineContent: 'bar foo' }
]
},
{
filePath: '/repo/b.ts',
relativePath: 'nested/b.ts',
matches: [{ line: 8, column: 2, matchLength: 3, lineContent: ' foo' }]
}
]
},
new Set<string>()
)
expect(rows.map((row) => row.type)).toEqual(['file', 'match', 'match', 'file', 'match'])
})
it('omits match rows for collapsed files', () => {
const rows = buildSearchRows(
{
totalMatches: 2,
truncated: true,
files: [
{
filePath: '/repo/a.ts',
relativePath: 'a.ts',
matches: [{ line: 1, column: 1, matchLength: 3, lineContent: 'foo' }]
},
{
filePath: '/repo/b.ts',
relativePath: 'b.ts',
matches: [{ line: 2, column: 1, matchLength: 3, lineContent: 'foo' }]
}
]
},
new Set<string>(['/repo/a.ts'])
)
expect(rows.map((row) => row.type)).toEqual(['file', 'file', 'match'])
})
it('preserves the file result object for renderer-side count normalization', () => {
const fileResult = {
filePath: '/repo/a.ts',
relativePath: 'a.ts',
matchCount: 5,
matches: [{ line: 1, column: 1, matchLength: 3, lineContent: 'foo' }]
}
const rows = buildSearchRows(
{
totalMatches: 5,
truncated: false,
files: [fileResult]
},
new Set<string>()
)
expect(rows[0]).toMatchObject({ type: 'file', fileResult })
expect(rows[1]).toMatchObject({ type: 'match', fileResult })
})
})
@@ -1,77 +0,0 @@
import { describe, expect, it } from 'vitest'
import {
createTestStore,
runtimeOwnedRepoState,
seedStore
} from '../../store/slices/store-test-helpers'
import { getDefaultSettings } from '../../../../shared/constants'
import { selectWslHostUnavailableReason } from './use-wsl-host-unavailable-reason'
const WORKTREE = 'wsl-repo::/home/me/app'
function stateWith(options: { enabled: boolean; serverFiles?: 'present' | 'missing' }) {
const store = createTestStore()
seedStore(store, {
...runtimeOwnedRepoState('wsl:ubuntu', 'wsl-repo', '/home/me/app'),
runtimeEnvironments: [
{
id: 'wsl:ubuntu',
name: 'Ubuntu (WSL)',
createdAt: 0,
updatedAt: 0,
lastUsedAt: null,
runtimeId: null,
preferredEndpointId: 'ws',
endpoints: [],
orcadDeployment: { kind: 'wsl', distro: 'Ubuntu', localPort: 42000, remotePort: 6768 }
}
],
wslHostServerFiles: options.serverFiles ?? 'present'
})
store.setState({
settings: { ...getDefaultSettings('/home/me'), experimentalWslHosts: options.enabled }
})
return store.getState()
}
describe('selectWslHostUnavailableReason', () => {
it('says a WSL host’s terminal is turned off rather than reconnecting', () => {
expect(selectWslHostUnavailableReason(stateWith({ enabled: false }), WORKTREE)).toBe(
'turned-off'
)
})
it('prefers the missing server files, and is quiet when the host can run', () => {
expect(
selectWslHostUnavailableReason(stateWith({ enabled: true, serverFiles: 'missing' }), WORKTREE)
).toBe('server-files-missing')
expect(selectWslHostUnavailableReason(stateWith({ enabled: true }), WORKTREE)).toBeNull()
})
it('leaves other hosts’ workspaces alone', () => {
expect(
selectWslHostUnavailableReason(stateWith({ enabled: false }), 'repo1::/repo1')
).toBeNull()
})
it('is quiet when no WSL host exists, even for a workspace on another runtime', () => {
const store = createTestStore()
seedStore(store, {
...runtimeOwnedRepoState('paired', 'remote-repo', '/srv/app'),
runtimeEnvironments: [
{
id: 'paired',
name: 'Paired server',
createdAt: 0,
updatedAt: 0,
lastUsedAt: null,
runtimeId: null,
preferredEndpointId: 'ws',
endpoints: []
}
]
})
store.setState({ settings: { ...getDefaultSettings('/home/me'), experimentalWslHosts: false } })
expect(selectWslHostUnavailableReason(store.getState(), 'remote-repo::/srv/app')).toBeNull()
})
})
@@ -1,79 +0,0 @@
import { create } from 'zustand'
import { describe, expect, it } from 'vitest'
import { createNewIssueDraftSlice } from './new-issue-draft'
import type { AppState } from '../types'
import type { GitHubAssignableUser } from '../../../../shared/github/pull-request-types'
function makeStore() {
return create<Pick<AppState, 'newIssueDraft' | 'setNewIssueDraft' | 'clearNewIssueDraft'>>()(
(...args) => createNewIssueDraftSlice(...(args as Parameters<typeof createNewIssueDraftSlice>))
)
}
const assignee: GitHubAssignableUser = { login: 'octocat', name: 'Octo', avatarUrl: '' }
describe('createNewIssueDraftSlice', () => {
it('starts with no draft', () => {
expect(makeStore().getState().newIssueDraft).toBeNull()
})
it('seeds a fresh empty draft with the patch when none exists', () => {
const store = makeStore()
store.getState().setNewIssueDraft({ title: 'Bug' })
expect(store.getState().newIssueDraft).toEqual({
title: 'Bug',
body: '',
labels: [],
assignees: [],
repoId: null
})
})
it('shallow-merges the patch into the current draft', () => {
const store = makeStore()
store.getState().setNewIssueDraft({
title: 'Bug',
body: 'details',
labels: ['p1'],
assignees: [assignee],
repoId: 'repo-a'
})
store.getState().setNewIssueDraft({ body: 'more details' })
expect(store.getState().newIssueDraft).toEqual({
title: 'Bug',
body: 'more details',
labels: ['p1'],
assignees: [assignee],
repoId: 'repo-a'
})
})
it('clears the draft back to null', () => {
const store = makeStore()
store.getState().setNewIssueDraft({ title: 'Bug', repoId: 'repo-a' })
store.getState().clearNewIssueDraft()
expect(store.getState().newIssueDraft).toBeNull()
})
it('seeds fresh label/assignee arrays per empty draft (no shared-constant aliasing)', () => {
// Partial patches must seed fresh label/assignee arrays; shared defaults let mutations corrupt all future drafts.
const a = makeStore()
const b = makeStore()
a.getState().setNewIssueDraft({ title: 'A' })
b.getState().setNewIssueDraft({ title: 'B' })
expect(a.getState().newIssueDraft?.labels).not.toBe(b.getState().newIssueDraft?.labels)
expect(a.getState().newIssueDraft?.assignees).not.toBe(b.getState().newIssueDraft?.assignees)
a.getState().newIssueDraft?.labels.push('leak')
const c = makeStore()
c.getState().setNewIssueDraft({ title: 'C' })
expect(c.getState().newIssueDraft?.labels).toEqual([])
})
})
@@ -1,80 +0,0 @@
import { create } from 'zustand'
import { describe, expect, it } from 'vitest'
import {
createTaskCreationDraftsSlice,
isTaskCreationDraftContentful
} from './task-creation-drafts'
import type { AppState } from '../types'
function makeStore() {
return create<
Pick<
AppState,
| 'newLinearIssueDraft'
| 'setNewLinearIssueDraft'
| 'clearNewLinearIssueDraft'
| 'newLinearProjectDraft'
| 'setNewLinearProjectDraft'
| 'clearNewLinearProjectDraft'
| 'newJiraIssueDraft'
| 'setNewJiraIssueDraft'
| 'clearNewJiraIssueDraft'
>
>()((...args) =>
createTaskCreationDraftsSlice(...(args as Parameters<typeof createTaskCreationDraftsSlice>))
)
}
describe('createTaskCreationDraftsSlice', () => {
it('starts with no drafts', () => {
const state = makeStore().getState()
expect(state.newLinearIssueDraft).toBeNull()
expect(state.newLinearProjectDraft).toBeNull()
expect(state.newJiraIssueDraft).toBeNull()
})
it('stores and clears each draft independently', () => {
const store = makeStore()
store.getState().setNewLinearIssueDraft({ title: 'Linear bug', body: 'details' })
store.getState().setNewLinearProjectDraft({
name: 'Roadmap',
description: 'summary',
content: 'brief'
})
store.getState().setNewJiraIssueDraft({ title: 'Jira bug', body: 'steps' })
store.getState().clearNewLinearIssueDraft()
expect(store.getState().newLinearIssueDraft).toBeNull()
expect(store.getState().newLinearProjectDraft).toEqual({
name: 'Roadmap',
description: 'summary',
content: 'brief'
})
expect(store.getState().newJiraIssueDraft).toEqual({ title: 'Jira bug', body: 'steps' })
})
it('replaces a draft wholesale on set', () => {
const store = makeStore()
store.getState().setNewJiraIssueDraft({ title: 'first', body: 'text' })
store.getState().setNewJiraIssueDraft({ title: 'second', body: '' })
expect(store.getState().newJiraIssueDraft).toEqual({ title: 'second', body: '' })
})
})
describe('isTaskCreationDraftContentful', () => {
it('rejects an all-empty or whitespace-only form', () => {
expect(isTaskCreationDraftContentful({ title: '', body: '' })).toBe(false)
expect(isTaskCreationDraftContentful({ title: ' ', body: '\n\t' })).toBe(false)
})
it('accepts any field with typed text', () => {
expect(isTaskCreationDraftContentful({ title: 'Bug', body: '' })).toBe(true)
expect(isTaskCreationDraftContentful({ name: '', description: '', content: 'brief' })).toBe(
true
)
})
})
@@ -1,74 +0,0 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import type { RuntimeRpcResponse } from '../../../shared/runtime-rpc-envelope'
import {
installBrowserGlobals,
writeStoredRuntimeEnvironment
} from './web-preload-api-test-harness'
describe('web SSH preload API', () => {
beforeEach(() => {
vi.resetModules()
})
afterEach(() => {
vi.unstubAllGlobals()
vi.doUnmock('./web-runtime-client')
})
it('preserves full and partial authority states from the paired runtime', async () => {
const runtimeCalls: { method: string; params: unknown }[] = []
vi.doMock('./web-runtime-client', () => ({
WebRuntimeClient: class {
call(method: string, params?: unknown): Promise<RuntimeRpcResponse<unknown>> {
runtimeCalls.push({ method, params })
const state =
method === 'ssh.connect'
? {
targetId: 'ssh-1',
status: 'connected',
error: null,
reconnectAttempt: 0,
providerEpoch: 'web-provider-epoch',
connectionGeneration: 23
}
: {
targetId: 'ssh-1',
status: 'connected',
error: null,
reconnectAttempt: 0,
providerEpoch: 'partial-provider-epoch'
}
return Promise.resolve({
id: `call-${runtimeCalls.length}`,
ok: true,
result: { state },
_meta: { runtimeId: 'runtime-1' }
})
}
close(): void {}
}
}))
const globals = installBrowserGlobals('Linux')
writeStoredRuntimeEnvironment(globals.storage)
const { installWebPreloadApi } = await import('./web-preload-api')
installWebPreloadApi()
await expect(globals.window.api.ssh.connect({ targetId: 'ssh-1' })).resolves.toMatchObject({
providerEpoch: 'web-provider-epoch',
connectionGeneration: 23
})
const partial = await globals.window.api.ssh.getState({ targetId: 'ssh-1' })
expect(partial).toMatchObject({ providerEpoch: 'partial-provider-epoch' })
expect(partial).not.toHaveProperty('connectionGeneration')
// A background connect stays automatic on the host, so it cannot lift a cancelled sign-in.
await globals.window.api.ssh.connect({ targetId: 'ssh-1', automatic: true })
expect(runtimeCalls).toEqual([
{ method: 'ssh.connect', params: { targetId: 'ssh-1' } },
{ method: 'ssh.getState', params: { targetId: 'ssh-1' } },
{ method: 'ssh.connect', params: { targetId: 'ssh-1', automatic: true } }
])
})
})