mirror of
https://github.com/stablyai/orca.git
synced 2026-11-13 09:27:29 +00:00
test: remove 20 low-value tests across 11 files (#37404)
* test: remove 20 low-value test declarations * test: prune allowances for removed Git profiling suite --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
@@ -596,7 +596,6 @@
|
||||
1 test-no-real-time-wait:tests/e2e/large-file-count-fixtures.ts
|
||||
1 test-no-real-time-wait:tests/e2e/large-markdown-preview.spec.ts
|
||||
1 test-no-real-time-wait:tests/e2e/layout-stream-loss-reopen.spec.ts
|
||||
1 test-no-real-time-wait:tests/e2e/main-thread-git-cost.spec.ts
|
||||
1 test-no-real-time-wait:tests/e2e/markdown-table-row-backspace.spec.ts
|
||||
1 test-no-real-time-wait:tests/e2e/native-chat-history-prepend-anchor.spec.ts
|
||||
3 test-no-real-time-wait:tests/e2e/notification-sound-replay.spec.ts
|
||||
@@ -1386,7 +1385,6 @@
|
||||
1 test-timeout-needs-reason:tests/e2e/layout-compat-serve-restart-keeps-at-at-terminals.spec.ts
|
||||
1 test-timeout-needs-reason:tests/e2e/linear-issue-view-persistence.spec.ts
|
||||
1 test-timeout-needs-reason:tests/e2e/local-cli-terminal-retention.spec.ts
|
||||
1 test-timeout-needs-reason:tests/e2e/main-thread-git-cost.spec.ts
|
||||
1 test-timeout-needs-reason:tests/e2e/manual-worktree-order-persistence.spec.ts
|
||||
1 test-timeout-needs-reason:tests/e2e/markdown-literal-save-reopen.spec.ts
|
||||
1 test-timeout-needs-reason:tests/e2e/markdown-review-selection-performance.spec.ts
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { shouldRetryTerminate, TERMINATE_RETRY_AFTER_MS } from './wsl-terminate-retry'
|
||||
|
||||
const stillListed = {
|
||||
retried: false,
|
||||
confirmedStopped: false,
|
||||
msSinceTerminate: TERMINATE_RETRY_AFTER_MS,
|
||||
spawnsSinceTerminate: []
|
||||
}
|
||||
|
||||
describe('shouldRetryTerminate', () => {
|
||||
it('retries a terminate that never took when Orca launched nothing since', () => {
|
||||
expect(shouldRetryTerminate(stillListed)).toBe(true)
|
||||
})
|
||||
|
||||
it.each([
|
||||
[
|
||||
'a wsl.exe launch',
|
||||
{ file: 'C:\\Windows\\System32\\wsl.exe', args: ['-d', 'Ubuntu', '--exec', 'sh'] }
|
||||
],
|
||||
['a running-list read', { file: 'wsl.exe', args: ['--list', '--running', '--quiet'] }],
|
||||
['a UNC touch', { file: 'fs', args: ['stat', '\\\\wsl.localhost\\Ubuntu\\tmp'] }],
|
||||
[
|
||||
'a terminal spawn',
|
||||
{ file: 'pty', args: ['[pty:history] worktreeId=wt::\\\\wsl.localhost\\Ubuntu shell=bash'] }
|
||||
]
|
||||
])('fails instead of retrying after %s, which could be the boot', (_label, spawn) => {
|
||||
expect(shouldRetryTerminate({ ...stillListed, spawnsSinceTerminate: [spawn] })).toBe(false)
|
||||
})
|
||||
|
||||
it('ignores spawns that cannot touch WSL', () => {
|
||||
expect(
|
||||
shouldRetryTerminate({
|
||||
...stillListed,
|
||||
spawnsSinceTerminate: [{ file: 'git.exe', args: ['status'] }]
|
||||
})
|
||||
).toBe(true)
|
||||
})
|
||||
|
||||
it('retries at most once', () => {
|
||||
expect(shouldRetryTerminate({ ...stillListed, retried: true })).toBe(false)
|
||||
})
|
||||
|
||||
it('gives the first terminate time to show before retrying', () => {
|
||||
expect(
|
||||
shouldRetryTerminate({ ...stillListed, msSinceTerminate: TERMINATE_RETRY_AFTER_MS - 1 })
|
||||
).toBe(false)
|
||||
})
|
||||
|
||||
it('never retries once a read saw the distro stopped', () => {
|
||||
expect(shouldRetryTerminate({ ...stillListed, confirmedStopped: true })).toBe(false)
|
||||
})
|
||||
})
|
||||
@@ -1,5 +1,3 @@
|
||||
// STA-2854: test host-local parking policy separately from authoritative stream/input/reconnect.
|
||||
// A windowless runtime proves already-attached PTY streams do not depend on the renderer; the final case covers initially unattached PTYs.
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { OrcaRuntimeService } from '../../src/main/runtime/orca-runtime'
|
||||
import { RpcDispatcher } from '../../src/main/runtime/rpc/dispatcher'
|
||||
@@ -13,154 +11,15 @@ import {
|
||||
encodeTerminalStreamJson,
|
||||
encodeTerminalStreamText
|
||||
} from '../../src/shared/terminal-stream-protocol'
|
||||
import {
|
||||
TERMINAL_TAB_COLD_PARK_DELAY_MS,
|
||||
TERMINAL_TAB_HOT_RETAIN_LIMIT,
|
||||
canParkTerminalTabRenderer,
|
||||
selectColdParkedTerminalTabs
|
||||
} from '../../src/renderer/src/components/terminal-pane/terminal-hidden-view-parking'
|
||||
import { buildTerminalTabColdParkCandidates } from '../../src/renderer/src/components/terminal-pane/terminal-tab-park-candidates'
|
||||
import { createTerminalTabActivationOrder } from '../../src/renderer/src/components/terminal-pane/terminal-tab-activation-order'
|
||||
import type { TerminalTab } from '../../src/shared/terminal-tab-types'
|
||||
|
||||
const WORKTREE_ID = 'repo-1::/tmp/wt'
|
||||
// Use host-owned snapshot-backed daemon PTYs, matching the remotely viewed local pane.
|
||||
const ptyIdFor = (n: number): string => `${WORKTREE_ID}@@aaaaaaa${n}`
|
||||
const SUBSCRIBED_TAB_ID = 'tab-remote-viewed'
|
||||
const MARKER_BEFORE_PARK = 'STA2854-BEFORE-PARK'
|
||||
const MARKER_AFTER_PARK = 'STA2854-AFTER-PARK'
|
||||
const MARKER_AFTER_RECONNECT = 'STA2854-AFTER-RECONNECT'
|
||||
const CLIENT_INPUT = 'echo STA2854-INPUT\r'
|
||||
|
||||
function tabModel(id: string, ptyId: string): TerminalTab {
|
||||
return { id, ptyId, generation: 1 } as unknown as TerminalTab
|
||||
}
|
||||
|
||||
// Exceed hot retention with hidden host tabs, including the remotely subscribed target.
|
||||
function hiddenHostTabs(): TerminalTab[] {
|
||||
const tabs: TerminalTab[] = [tabModel(SUBSCRIBED_TAB_ID, ptyIdFor(0))]
|
||||
for (let i = 1; i <= TERMINAL_TAB_HOT_RETAIN_LIMIT + 1; i += 1) {
|
||||
tabs.push(tabModel(`tab-${i}`, ptyIdFor(i)))
|
||||
}
|
||||
return tabs
|
||||
}
|
||||
|
||||
describe('STA-2854 A: host cold-park policy vs an active remote subscriber', () => {
|
||||
it('parks a locally hidden host pane that a remote client is actively viewing', () => {
|
||||
const tabs = hiddenHostTabs()
|
||||
const hiddenSinceByTabId = new Map<string, number>()
|
||||
const activationOrder = createTerminalTabActivationOrder()
|
||||
const t0 = 1_000_000
|
||||
|
||||
buildTerminalTabColdParkCandidates({
|
||||
terminalTabs: tabs,
|
||||
assignments: new Map(),
|
||||
isWorktreeActive: false,
|
||||
activeTerminalTabId: null,
|
||||
portalTabIds: new Set(),
|
||||
shouldMeasureHiddenWorktree: false,
|
||||
hiddenSinceByTabId,
|
||||
activationOrder,
|
||||
nowMs: t0
|
||||
})
|
||||
expect(hiddenSinceByTabId.get(SUBSCRIBED_TAB_ID)).toBe(t0)
|
||||
|
||||
// Pass 2: exactly the cold-park hysteresis later. The remote client has
|
||||
// been driving this tab the whole time; the policy has no input for that.
|
||||
const nowMs = t0 + TERMINAL_TAB_COLD_PARK_DELAY_MS
|
||||
const candidates = buildTerminalTabColdParkCandidates({
|
||||
terminalTabs: tabs,
|
||||
assignments: new Map(),
|
||||
isWorktreeActive: false,
|
||||
activeTerminalTabId: null,
|
||||
portalTabIds: new Set(),
|
||||
shouldMeasureHiddenWorktree: false,
|
||||
hiddenSinceByTabId,
|
||||
activationOrder,
|
||||
nowMs
|
||||
})
|
||||
const subscribedCandidate = candidates.find((c) => c.id === SUBSCRIBED_TAB_ID)!
|
||||
|
||||
expect(
|
||||
canParkTerminalTabRenderer({
|
||||
worktreeId: WORKTREE_ID,
|
||||
terminalTab: subscribedCandidate,
|
||||
pendingStartupByTabId: {},
|
||||
parkingEnabled: true,
|
||||
nowMs
|
||||
})
|
||||
).toBe(true)
|
||||
|
||||
const parked = selectColdParkedTerminalTabs({
|
||||
worktreeId: WORKTREE_ID,
|
||||
terminalTabs: candidates,
|
||||
pendingStartupByTabId: {},
|
||||
parkingEnabled: true,
|
||||
nowMs
|
||||
})
|
||||
expect(parked.has(SUBSCRIBED_TAB_ID)).toBe(true)
|
||||
|
||||
// Negative control: local visibility is the only thing that saves it.
|
||||
const visibleCandidate = { ...subscribedCandidate, isVisible: true, hiddenSinceMs: null }
|
||||
expect(
|
||||
canParkTerminalTabRenderer({
|
||||
worktreeId: WORKTREE_ID,
|
||||
terminalTab: visibleCandidate,
|
||||
pendingStartupByTabId: {},
|
||||
parkingEnabled: true,
|
||||
nowMs
|
||||
})
|
||||
).toBe(false)
|
||||
})
|
||||
|
||||
it('does not reset the hidden clock when a remote subscribe background-mounts the tab', () => {
|
||||
const tabs = hiddenHostTabs()
|
||||
const hiddenSinceByTabId = new Map<string, number>()
|
||||
const activationOrder = createTerminalTabActivationOrder()
|
||||
const t0 = 1_000_000
|
||||
|
||||
buildTerminalTabColdParkCandidates({
|
||||
terminalTabs: tabs,
|
||||
assignments: new Map(),
|
||||
isWorktreeActive: false,
|
||||
activeTerminalTabId: null,
|
||||
portalTabIds: new Set(),
|
||||
shouldMeasureHiddenWorktree: false,
|
||||
hiddenSinceByTabId,
|
||||
activationOrder,
|
||||
nowMs: t0
|
||||
})
|
||||
|
||||
// A background reconnect keeps the stale hidden timestamp, so its first pass is already eligible to park.
|
||||
const remountNowMs = t0 + 4 * 60 * 60_000
|
||||
const candidates = buildTerminalTabColdParkCandidates({
|
||||
terminalTabs: tabs,
|
||||
assignments: new Map(),
|
||||
isWorktreeActive: false,
|
||||
activeTerminalTabId: null,
|
||||
portalTabIds: new Set(),
|
||||
shouldMeasureHiddenWorktree: false,
|
||||
hiddenSinceByTabId,
|
||||
activationOrder,
|
||||
nowMs: remountNowMs
|
||||
})
|
||||
const subscribedCandidate = candidates.find((c) => c.id === SUBSCRIBED_TAB_ID)!
|
||||
expect(subscribedCandidate.hiddenSinceMs).toBe(t0)
|
||||
expect(remountNowMs - subscribedCandidate.hiddenSinceMs!).toBeGreaterThan(
|
||||
TERMINAL_TAB_COLD_PARK_DELAY_MS
|
||||
)
|
||||
expect(
|
||||
selectColdParkedTerminalTabs({
|
||||
worktreeId: WORKTREE_ID,
|
||||
terminalTabs: candidates,
|
||||
pendingStartupByTabId: {},
|
||||
parkingEnabled: true,
|
||||
nowMs: remountNowMs
|
||||
}).has(SUBSCRIBED_TAB_ID)
|
||||
).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
type RuntimeInternals = {
|
||||
recordPtyWorktree: (
|
||||
ptyId: string,
|
||||
|
||||
@@ -65,63 +65,6 @@ async function openFixtureJiraList(page: Page): Promise<void> {
|
||||
}, ISSUE)
|
||||
}
|
||||
|
||||
test('Jira titles and sort headings adapt to panel width inside a wide window', async ({
|
||||
orcaPage
|
||||
}) => {
|
||||
await openFixtureJiraList(orcaPage)
|
||||
|
||||
const title = orcaPage.getByRole('heading', { name: ISSUE_TITLE })
|
||||
await expect(title).toBeVisible()
|
||||
let previousDesktopTitleWidth: number | null = null
|
||||
for (const width of [500, 780, 1050, 1320]) {
|
||||
const panelWidth = await title.evaluate((element, width) => {
|
||||
const host =
|
||||
element.closest('[role="button"]')?.parentElement?.parentElement?.parentElement
|
||||
?.parentElement?.parentElement
|
||||
if (!(host instanceof HTMLElement)) {
|
||||
throw new Error('Jira list host unavailable')
|
||||
}
|
||||
host.style.width = `${width}px`
|
||||
host.style.maxWidth = 'none'
|
||||
return host.getBoundingClientRect().width
|
||||
}, width)
|
||||
expect(panelWidth).toBe(width)
|
||||
const titleWidthExpectation = expect.poll(() =>
|
||||
title.evaluate((element) => element.getBoundingClientRect().width)
|
||||
)
|
||||
await (width === 780
|
||||
? titleWidthExpectation.toBeGreaterThanOrEqual(180)
|
||||
: titleWidthExpectation.toBeGreaterThan(200))
|
||||
const mobileSort = orcaPage.getByTestId('jira-mobile-sort-controls')
|
||||
const assignee = orcaPage.getByRole('button', { name: 'Assignee', exact: true })
|
||||
await (width < 768 ? expect(mobileSort).toBeVisible() : expect(mobileSort).toBeHidden())
|
||||
await (width >= 1024 ? expect(assignee).toBeVisible() : expect(assignee).toBeHidden())
|
||||
if (width >= 768) {
|
||||
const grids = await title.evaluate((element) => {
|
||||
const row = element.closest('[role="button"]')
|
||||
const host = row?.parentElement?.parentElement?.parentElement?.parentElement?.parentElement
|
||||
const header = host?.querySelector('button[aria-pressed]')?.parentElement
|
||||
if (!row || !header) {
|
||||
throw new Error('Jira header or row unavailable')
|
||||
}
|
||||
return [
|
||||
getComputedStyle(row).gridTemplateColumns.split(' '),
|
||||
getComputedStyle(header).gridTemplateColumns.split(' ')
|
||||
]
|
||||
})
|
||||
// The scroll gutter narrows the flexible title; fixed tracks must still match.
|
||||
expect(grids[0].filter((_, index) => index !== 1)).toEqual(
|
||||
grids[1].filter((_, index) => index !== 1)
|
||||
)
|
||||
const titleWidth = await title.evaluate((element) => element.getBoundingClientRect().width)
|
||||
if (previousDesktopTitleWidth !== null) {
|
||||
expect(titleWidth).toBeGreaterThan(previousDesktopTitleWidth)
|
||||
}
|
||||
previousDesktopTitleWidth = titleWidth
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test('Jira planning columns persist and hiding a sorted field selects a visible fallback', async ({
|
||||
orcaPage
|
||||
}) => {
|
||||
|
||||
@@ -187,8 +187,3 @@ test('routes landing preflight across runtime switch and reconnect', async ({
|
||||
electronApp,
|
||||
orcaPage
|
||||
}, testInfo) => runRuntimePreflightJourney(electronApp, orcaPage, testInfo, false))
|
||||
|
||||
test('routes landing preflight across runtime switch and reconnect @headful', async ({
|
||||
electronApp,
|
||||
orcaPage
|
||||
}, testInfo) => runRuntimePreflightJourney(electronApp, orcaPage, testInfo, true))
|
||||
|
||||
@@ -303,26 +303,6 @@ describe('launchAgentBackgroundSession remote runtime and SSH startup delivery',
|
||||
expect(mockDispatchEvent).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('forwards Hermes startup queries through SSH command transport', async () => {
|
||||
state.repos = [{ id: 'repo-1', connectionId: 'ssh-1', path: '/repo' }]
|
||||
const { launchAgentBackgroundSession } =
|
||||
await import('../../src/renderer/src/lib/launch-agent-background-session')
|
||||
|
||||
await launchAgentBackgroundSession({
|
||||
agent: 'hermes',
|
||||
worktreeId: 'wt-1',
|
||||
prompt: 'remote automation prompt'
|
||||
})
|
||||
|
||||
expect(mockSpawn).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
command: expect.stringContaining('ORCA_HERMES_STARTUP_QUERY'),
|
||||
connectionId: 'ssh-1',
|
||||
env: expect.objectContaining({ ORCA_HERMES_STARTUP_QUERY: 'remote automation prompt' })
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it.each(['claude', 'codex'] as const)(
|
||||
'has the relay type the %s launch line instead of writing it from the renderer',
|
||||
async (agent) => {
|
||||
@@ -356,21 +336,6 @@ describe('launchAgentBackgroundSession remote runtime and SSH startup delivery',
|
||||
}
|
||||
)
|
||||
|
||||
it('has the relay type a promptless SSH background launch too', async () => {
|
||||
state.repos = [{ id: 'repo-1', connectionId: 'ssh-1', path: '/repo' }]
|
||||
const { launchAgentBackgroundSession } =
|
||||
await import('../../src/renderer/src/lib/launch-agent-background-session')
|
||||
|
||||
await launchAgentBackgroundSession({ agent: 'codex', worktreeId: 'wt-1' })
|
||||
|
||||
expect(mockSpawn.mock.calls[0]?.[0]).toEqual(
|
||||
expect.objectContaining({
|
||||
commandDelivery: 'provider',
|
||||
startupCommandDelivery: 'shell-ready'
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it.each([true, false])(
|
||||
'creates background sessions with negotiated keyboard support: %s',
|
||||
async (keyboardSupported) => {
|
||||
@@ -468,23 +433,6 @@ describe('launchAgentBackgroundSession remote runtime and SSH startup delivery',
|
||||
}
|
||||
)
|
||||
|
||||
it('advertises keyboard support for a background OMP launch', async () => {
|
||||
useRemoteAgentBackgroundRuntime(state)
|
||||
const { launchAgentBackgroundSession } =
|
||||
await import('../../src/renderer/src/lib/launch-agent-background-session')
|
||||
await launchAgentBackgroundSession({ agent: 'omp', worktreeId: 'wt-1', prompt: 'review' })
|
||||
expect(mockRuntimeEnvironmentCall).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
method: 'terminal.createAgentSession',
|
||||
params: expect.objectContaining({
|
||||
agent: 'omp',
|
||||
terminalKittyKeyboardProtocol: true,
|
||||
presentation: 'background'
|
||||
})
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it('aborts the remote exit wait and closes the stream when run observers are released', async () => {
|
||||
useRemoteAgentBackgroundRuntime(state)
|
||||
const streamSend = vi.fn()
|
||||
|
||||
@@ -19,68 +19,6 @@ import { projectAgentLaunchSettings } from '../../src/shared/agent-launch-settin
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
describe('launchAgentInNewTab paired web runtime', () => {
|
||||
it.each([true, false, 'failed'] as const)('delegates agent quick launch (%s)', async (mode) => {
|
||||
store.settings.agentDefaultArgs = { claude: '--model "model with spaces"' }
|
||||
const activate = mode === true
|
||||
const status = mode === 'failed' ? 'failed' : 'created'
|
||||
mocks.createWebRuntimeSessionTerminal.mockResolvedValue({
|
||||
outcome: {
|
||||
status,
|
||||
...(status === 'failed' ? { message: 'The host refused the launch.' } : {})
|
||||
},
|
||||
hostTabId: 'host-tab::leaf-1'
|
||||
})
|
||||
store.tabsByWorktree['wt-1'].push({ id: 'local-agent-tab', launchAgent: 'claude' })
|
||||
const { launchAgentInNewTab } =
|
||||
await import('../../src/renderer/src/lib/launch-agent-in-new-tab')
|
||||
|
||||
const result = launchAgentInNewTab({
|
||||
requestId: 'request-1',
|
||||
activate,
|
||||
agent: 'claude',
|
||||
worktreeId: 'wt-1',
|
||||
groupId: 'group-1'
|
||||
})
|
||||
|
||||
expect(result).toEqual(
|
||||
expect.objectContaining({
|
||||
surface: { kind: 'host-published' },
|
||||
pasteDraftAfterLaunch: false
|
||||
})
|
||||
)
|
||||
await result?.terminalCompletion
|
||||
const startupPlan = mocks.createWebRuntimeSessionTerminal.mock.calls[0][0]
|
||||
expect(mocks.createWebRuntimeSessionTerminal).toHaveBeenCalledWith({
|
||||
worktreeId: 'wt-1',
|
||||
environmentId: 'web-runtime',
|
||||
targetGroupId: 'group-1',
|
||||
activate,
|
||||
...(activate ? {} : { selectWorktree: false }),
|
||||
agentSessionKind: 'fresh',
|
||||
launchAgent: 'claude',
|
||||
preparedAgentCommand: false,
|
||||
command: startupPlan.command,
|
||||
env: startupPlan.env,
|
||||
launchConfig: startupPlan.launchConfig,
|
||||
viewMode: 'terminal'
|
||||
})
|
||||
expect(startupPlan.launchConfig.agentArgs).toBe(store.settings.agentDefaultArgs.claude)
|
||||
expect(mocks.createTab).not.toHaveBeenCalled()
|
||||
await expect(result?.terminalCompletion).resolves.toMatchObject({
|
||||
outcome: { status },
|
||||
...(status === 'created' ? { tabId: 'web-terminal-host-tab' } : {})
|
||||
})
|
||||
expect(mocks.setActiveTabType).toHaveBeenCalledTimes(activate && status === 'created' ? 1 : 0)
|
||||
expect(mocks.toastError).toHaveBeenCalledTimes(status === 'failed' ? 1 : 0)
|
||||
if (status === 'failed') {
|
||||
expect(mocks.toastError).toHaveBeenCalledExactlyOnceWith(
|
||||
expect.stringMatching(/Claude.*Check the workspace connection/)
|
||||
)
|
||||
}
|
||||
// A local tab closes locally (the host close no-ops), so a launch leaves it alone.
|
||||
expect(mocks.closeTab).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('awaits the capable host map once and preserves explicit/raw and prepared command ownership', async () => {
|
||||
mocks.capability.mockResolvedValue(true)
|
||||
store.settings.agentLaunchChoices = { claude: { model: 'sonnet', options: { effort: 'low' } } }
|
||||
@@ -549,49 +487,4 @@ describe('launchAgentInNewTab paired web runtime', () => {
|
||||
expect(store.markNativeChatLaunchPromptFailed).toHaveBeenCalledOnce()
|
||||
expect(dispatch.mock.calls).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('forwards prompt launch env and captured config to the host runtime', async () => {
|
||||
store.settings.agentDefaultArgs = { codex: '--model gpt-5 --reasoning-effort high' }
|
||||
store.settings.agentDefaultEnv = { codex: { CODEX_PROFILE: 'captured' } }
|
||||
const { launchAgentInNewTab } =
|
||||
await import('../../src/renderer/src/lib/launch-agent-in-new-tab')
|
||||
|
||||
const result = launchAgentInNewTab({
|
||||
requestId: 'request-2',
|
||||
agent: 'codex',
|
||||
worktreeId: 'wt-1',
|
||||
prompt: 'fix the spinner',
|
||||
groupId: 'group-1'
|
||||
})
|
||||
|
||||
expect(result).toEqual(
|
||||
expect.objectContaining({
|
||||
surface: { kind: 'host-published' },
|
||||
pasteDraftAfterLaunch: false
|
||||
})
|
||||
)
|
||||
await result?.terminalCompletion
|
||||
expect(mocks.createWebRuntimeSessionTerminal).toHaveBeenCalledWith({
|
||||
worktreeId: 'wt-1',
|
||||
environmentId: 'web-runtime',
|
||||
targetGroupId: 'group-1',
|
||||
activate: true,
|
||||
agentSessionKind: 'fresh',
|
||||
launchAgent: 'codex',
|
||||
preparedAgentCommand: false,
|
||||
command:
|
||||
"codex '-c' 'disable_paste_burst=true' '--model' 'gpt-5' '--reasoning-effort' 'high' 'fix the spinner'",
|
||||
env: { CODEX_PROFILE: 'captured' },
|
||||
launchConfig: {
|
||||
agentCommand: "codex '--model' 'gpt-5' '--reasoning-effort' 'high'",
|
||||
agentArgs: '--model gpt-5 --reasoning-effort high',
|
||||
agentEnv: { CODEX_PROFILE: 'captured' }
|
||||
},
|
||||
startupCommandDelivery: 'shell-ready',
|
||||
prompt: 'fix the spinner',
|
||||
promptDelivery: 'auto-submit',
|
||||
viewMode: 'terminal'
|
||||
})
|
||||
expect(mocks.createTab).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
import type { ElectronApplication, Page } from '@stablyai/playwright-test'
|
||||
import { test, expect } from './helpers/orca-app'
|
||||
import { getStoreState, waitForActiveWorktree, waitForSessionReady } from './helpers/store'
|
||||
|
||||
const FIXTURE = {
|
||||
workspace: {
|
||||
id: 'linear-workspace-3393',
|
||||
displayName: 'Linear E2E User',
|
||||
email: 'linear-e2e@example.test',
|
||||
organizationId: 'linear-org-3393',
|
||||
organizationName: 'Linear E2E Workspace'
|
||||
},
|
||||
team: {
|
||||
id: 'linear-team-3393',
|
||||
name: 'Engineering',
|
||||
key: 'ENG'
|
||||
},
|
||||
state: {
|
||||
id: 'linear-state-uuid-3393',
|
||||
name: 'In Review',
|
||||
type: 'started',
|
||||
color: '#888888',
|
||||
position: 1
|
||||
},
|
||||
issue: {
|
||||
id: 'linear-issue-3393',
|
||||
workspaceId: 'linear-workspace-3393',
|
||||
identifier: 'ENG-3393',
|
||||
title: 'Keep filter chip labels readable',
|
||||
url: 'https://linear.example.test/ENG-3393',
|
||||
state: { name: 'In Review', type: 'started', color: '#888888' },
|
||||
team: { id: 'linear-team-3393', name: 'Engineering', key: 'ENG' },
|
||||
labels: [],
|
||||
labelIds: [],
|
||||
priority: 0,
|
||||
updatedAt: '2026-08-04T18:00:00.000Z'
|
||||
}
|
||||
} as const
|
||||
|
||||
async function installLinearFilterBackend(electronApp: ElectronApplication): Promise<void> {
|
||||
await electronApp.evaluate(({ ipcMain }, fixture) => {
|
||||
ipcMain.removeHandler('linear:status')
|
||||
ipcMain.handle('linear:status', async () => ({
|
||||
connected: true,
|
||||
viewer: fixture.workspace,
|
||||
workspaces: [fixture.workspace],
|
||||
activeWorkspaceId: fixture.workspace.id,
|
||||
selectedWorkspaceId: fixture.workspace.id
|
||||
}))
|
||||
|
||||
ipcMain.removeHandler('linear:listTeams')
|
||||
ipcMain.handle('linear:listTeams', async () => [fixture.team])
|
||||
|
||||
ipcMain.removeHandler('linear:listIssues')
|
||||
ipcMain.handle('linear:listIssues', async () => ({ items: [fixture.issue], hasMore: false }))
|
||||
|
||||
ipcMain.removeHandler('linear:teamStates')
|
||||
ipcMain.handle('linear:teamStates', async () => [fixture.state])
|
||||
|
||||
ipcMain.removeHandler('linear:teamLabels')
|
||||
ipcMain.handle('linear:teamLabels', async () => [])
|
||||
|
||||
ipcMain.removeHandler('linear:teamMembers')
|
||||
ipcMain.handle('linear:teamMembers', async () => [])
|
||||
}, FIXTURE)
|
||||
}
|
||||
|
||||
async function openLinearTasks(page: Page): Promise<void> {
|
||||
await page.evaluate(async () => {
|
||||
const store = window.__store
|
||||
if (!store) {
|
||||
throw new Error('window.__store is not available')
|
||||
}
|
||||
await store.getState().checkLinearConnection(true)
|
||||
store.getState().openTaskPage({ taskSource: 'linear' })
|
||||
})
|
||||
}
|
||||
|
||||
test('Linear filter chips keep readable names after the dropdown closes', async ({
|
||||
electronApp,
|
||||
orcaPage
|
||||
}) => {
|
||||
await waitForSessionReady(orcaPage)
|
||||
await waitForActiveWorktree(orcaPage)
|
||||
await installLinearFilterBackend(electronApp)
|
||||
await openLinearTasks(orcaPage)
|
||||
|
||||
await expect
|
||||
.poll(() => getStoreState<string>(orcaPage, 'activeView'), { timeout: 5_000 })
|
||||
.toBe('tasks')
|
||||
const filtersButton = orcaPage.getByRole('button', { name: 'Filters', exact: true })
|
||||
await expect(filtersButton).toBeVisible()
|
||||
await expect(orcaPage.getByText(FIXTURE.issue.title, { exact: true })).toBeVisible()
|
||||
|
||||
await filtersButton.click()
|
||||
const popover = orcaPage.locator('[data-slot="popover-content"]')
|
||||
await popover.getByRole('button', { name: 'Status', exact: true }).click()
|
||||
await popover.getByText(FIXTURE.state.name, { exact: true }).click()
|
||||
await filtersButton.click()
|
||||
await expect(popover).toHaveCount(0)
|
||||
|
||||
const statusChip = orcaPage.getByRole('button', { name: 'Remove Status filter' }).locator('..')
|
||||
await expect(statusChip).toContainText(FIXTURE.state.name)
|
||||
await expect(statusChip).not.toContainText(FIXTURE.state.id)
|
||||
})
|
||||
@@ -102,40 +102,6 @@ describe('createLinearSlice', () => {
|
||||
expect(store.getState().linearStatusChecked).toBe(true)
|
||||
})
|
||||
|
||||
it('preserves status identity when a connection probe leaves its scope unchanged', async () => {
|
||||
const store = createTestStore()
|
||||
const currentStatus: LinearConnectionStatus = {
|
||||
connected: true,
|
||||
viewer: {
|
||||
displayName: 'Test User',
|
||||
email: 'test@example.com',
|
||||
organizationName: 'Test Org'
|
||||
},
|
||||
selectedWorkspaceId: 'workspace-1',
|
||||
activeWorkspaceId: 'workspace-1',
|
||||
workspaces: [
|
||||
{
|
||||
id: 'workspace-1',
|
||||
organizationId: 'workspace-1',
|
||||
organizationName: 'Test Org',
|
||||
displayName: 'Test User',
|
||||
email: 'test@example.com'
|
||||
}
|
||||
]
|
||||
}
|
||||
store.setState({
|
||||
linearStatus: currentStatus,
|
||||
linearStatusChecked: true,
|
||||
linearStatusContextKey: 'local#0'
|
||||
})
|
||||
linearTestConnection.mockResolvedValueOnce({ ok: true, viewer: currentStatus.viewer })
|
||||
linearStatus.mockResolvedValueOnce({ ...currentStatus, viewer: { ...currentStatus.viewer } })
|
||||
|
||||
await store.getState().testLinearConnection()
|
||||
|
||||
expect(store.getState().linearStatus).toBe(currentStatus)
|
||||
})
|
||||
|
||||
it('ignores stale forced connection checks when a newer forced check finishes first', async () => {
|
||||
const staleCheck = deferred<LinearConnectionStatus>()
|
||||
const freshCheck = deferred<LinearConnectionStatus>()
|
||||
|
||||
@@ -269,22 +269,6 @@ it.each([...failureCases, ...diagnosticControls])(
|
||||
}
|
||||
)
|
||||
|
||||
it('returns a confirmed CLI write over the unchanged wire payload', async () => {
|
||||
vi.mocked(mutations.updateIssueForAgent).mockImplementation(
|
||||
async (_id, _fields, _workspace, options) => {
|
||||
options?.beforeInvoke?.()
|
||||
return { ...issue, state: { id: 'done', name: 'Done' } }
|
||||
}
|
||||
)
|
||||
await main(['linear', 'status', 'set', 'ENG-1', '--to', 'Done', '--json'], '/tmp')
|
||||
expect(JSON.parse(String(vi.mocked(console.log).mock.calls.at(-1)?.[0]))).toMatchObject({
|
||||
ok: true,
|
||||
result: { state: { id: 'done' } }
|
||||
})
|
||||
expect(mutations.updateIssueForAgent).toHaveBeenCalledTimes(1)
|
||||
expect(process.exitCode).toBe(0)
|
||||
})
|
||||
|
||||
it('ends a stalled CLI preparation before its client timeout without a late write', async () => {
|
||||
let release = () => {}
|
||||
let entered = () => {}
|
||||
|
||||
@@ -1,213 +0,0 @@
|
||||
// Profile main’s git churn separately from typing latency, which also includes PTY relay and renderer paint.
|
||||
// V8 CPU profiles separate spawn, stdout drain and parsing; churn reports measure spawn only (whole runs for synchronous calls).
|
||||
// Run with ORCA_GIT_COST_BENCH=1 ORCA_BACKGROUND_LAUNCH=1 and the electron-headless Playwright project.
|
||||
import { expect, test } from './helpers/orca-app'
|
||||
import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
||||
import { tmpdir } from 'node:os'
|
||||
import path from 'node:path'
|
||||
import {
|
||||
createGitChurnRepos,
|
||||
registerGitChurnRepos,
|
||||
startGitChurnLoad,
|
||||
stopGitChurnLoad,
|
||||
type GitChurnStats
|
||||
} from './git-churn-load'
|
||||
|
||||
type MainThreadReport = {
|
||||
t: number
|
||||
maxGapMs?: number
|
||||
gapsOver50Ms?: number
|
||||
gapsOver250Ms?: number
|
||||
spawnCount?: number
|
||||
spawns?: Record<string, { count: number; blockMsTotal: number; blockMsMax: number }>
|
||||
marker?: string
|
||||
wallMs: number
|
||||
}
|
||||
|
||||
type Phase = { label: string; repos: number; concurrency: number; seconds: number }
|
||||
|
||||
const FILES_PER_REPO = Number(process.env.ORCA_GIT_COST_FILES ?? 400)
|
||||
const PHASE_SECONDS = Number(process.env.ORCA_GIT_COST_PHASE_SECONDS ?? 20)
|
||||
const MAX_REPOS = Number(process.env.ORCA_GIT_COST_REPOS ?? 24)
|
||||
|
||||
const PHASES: Phase[] = [
|
||||
{ label: 'idle', repos: 0, concurrency: 0, seconds: PHASE_SECONDS },
|
||||
{ label: 'c1', repos: MAX_REPOS, concurrency: 1, seconds: PHASE_SECONDS },
|
||||
{ label: 'c4', repos: MAX_REPOS, concurrency: 4, seconds: PHASE_SECONDS },
|
||||
{ label: 'c8', repos: MAX_REPOS, concurrency: 8, seconds: PHASE_SECONDS },
|
||||
{ label: 'c16', repos: MAX_REPOS, concurrency: 16, seconds: PHASE_SECONDS },
|
||||
{ label: 'c32', repos: MAX_REPOS, concurrency: 32, seconds: PHASE_SECONDS }
|
||||
]
|
||||
|
||||
test.use({
|
||||
orcaAppExtraEnv: { ORCA_MAIN_THREAD_DIAGNOSTICS: '1', ORCA_BACKGROUND_LAUNCH: '1' }
|
||||
})
|
||||
|
||||
test.describe('main-thread git orchestration cost', () => {
|
||||
test.skip(
|
||||
process.env.ORCA_GIT_COST_BENCH !== '1',
|
||||
'Diagnostic bench; set ORCA_GIT_COST_BENCH=1 to run'
|
||||
)
|
||||
test.setTimeout((PHASES.reduce((sum, phase) => sum + phase.seconds, 0) + 600) * 1000)
|
||||
|
||||
test('measures spawn / drain / parse split under git churn', async ({
|
||||
orcaPage,
|
||||
electronApp
|
||||
}, testInfo) => {
|
||||
const reports: MainThreadReport[] = []
|
||||
const stderr = electronApp.process().stderr
|
||||
expect(stderr, 'electron stderr must be piped for the churn probe').toBeTruthy()
|
||||
let buffer = ''
|
||||
stderr?.setEncoding('utf-8')
|
||||
stderr?.on('data', (chunk: string) => {
|
||||
buffer += chunk
|
||||
let index = buffer.indexOf('\n')
|
||||
while (index !== -1) {
|
||||
const line = buffer.slice(0, index).trimEnd()
|
||||
buffer = buffer.slice(index + 1)
|
||||
index = buffer.indexOf('\n')
|
||||
const match = /^\[main-thread\] (\{.*\})$/.exec(line)
|
||||
if (!match) {
|
||||
continue
|
||||
}
|
||||
try {
|
||||
reports.push({ ...JSON.parse(match[1]), wallMs: Date.now() })
|
||||
} catch {
|
||||
// ignore malformed probe line
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const churnRoot = mkdtempSync(path.join(tmpdir(), 'orca-git-cost-'))
|
||||
const profileDir = path.join(testInfo.outputDir, 'main-profiles')
|
||||
mkdirSync(profileDir, { recursive: true })
|
||||
const results: Record<string, unknown>[] = []
|
||||
try {
|
||||
const repos = createGitChurnRepos(churnRoot, MAX_REPOS, FILES_PER_REPO)
|
||||
const registration = await registerGitChurnRepos(
|
||||
orcaPage,
|
||||
repos.map((repo) => repo.path)
|
||||
)
|
||||
expect(
|
||||
registration,
|
||||
`churn repos were not registered: ${registration.failures.join('; ')}`
|
||||
).toMatchObject({ registered: repos.length })
|
||||
|
||||
for (const phase of PHASES) {
|
||||
const profilePath = path.join(profileDir, `main-${phase.label}.cpuprofile`)
|
||||
await startMainProfiler(electronApp)
|
||||
const startedAt = Date.now()
|
||||
if (phase.concurrency > 0) {
|
||||
await startGitChurnLoad(
|
||||
orcaPage,
|
||||
repos.slice(0, phase.repos).map((repo) => repo.path),
|
||||
{ concurrency: phase.concurrency, admissionTier: 'status' }
|
||||
)
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve, phase.seconds * 1000))
|
||||
const churn: GitChurnStats | null =
|
||||
phase.concurrency > 0 ? await stopGitChurnLoad(orcaPage) : null
|
||||
const endedAt = Date.now()
|
||||
const wallMs = await stopMainProfiler(electronApp, profilePath)
|
||||
// Skip the first window: it straddles the previous phase's tail.
|
||||
const phaseReports = reports.filter(
|
||||
(report) =>
|
||||
!report.marker && report.wallMs >= startedAt + 5_000 && report.wallMs <= endedAt + 1_000
|
||||
)
|
||||
results.push({
|
||||
phase: phase.label,
|
||||
repos: phase.repos,
|
||||
concurrency: phase.concurrency,
|
||||
windowMs: endedAt - startedAt,
|
||||
profileWallMs: wallMs,
|
||||
reportCount: phaseReports.length,
|
||||
maxGapMs: Math.max(0, ...phaseReports.map((report) => report.maxGapMs ?? 0)),
|
||||
gapsOver50Ms: sum(phaseReports.map((report) => report.gapsOver50Ms ?? 0)),
|
||||
gapsOver250Ms: sum(phaseReports.map((report) => report.gapsOver250Ms ?? 0)),
|
||||
spawnCount: sum(phaseReports.map((report) => report.spawnCount ?? 0)),
|
||||
spawns: mergeSpawns(phaseReports),
|
||||
churn,
|
||||
profilePath
|
||||
})
|
||||
console.log(`[git-cost] ${JSON.stringify(results.at(-1))}`)
|
||||
}
|
||||
} finally {
|
||||
await stopGitChurnLoad(orcaPage).catch(() => null)
|
||||
rmSync(churnRoot, { recursive: true, force: true })
|
||||
}
|
||||
const summaryPath = path.join(profileDir, 'summary.json')
|
||||
writeFileSync(summaryPath, JSON.stringify({ filesPerRepo: FILES_PER_REPO, results }, null, 2))
|
||||
console.log(`[git-cost] summary=${summaryPath}`)
|
||||
expect(readFileSync(summaryPath, 'utf8').length).toBeGreaterThan(0)
|
||||
})
|
||||
})
|
||||
|
||||
function sum(values: number[]): number {
|
||||
return values.reduce((total, value) => total + value, 0)
|
||||
}
|
||||
|
||||
function mergeSpawns(
|
||||
reports: MainThreadReport[]
|
||||
): Record<string, { count: number; blockMsTotal: number; blockMsMax: number }> {
|
||||
const merged: Record<string, { count: number; blockMsTotal: number; blockMsMax: number }> = {}
|
||||
for (const report of reports) {
|
||||
for (const [key, stats] of Object.entries(report.spawns ?? {})) {
|
||||
const entry = (merged[key] ??= { count: 0, blockMsTotal: 0, blockMsMax: 0 })
|
||||
entry.count += stats.count
|
||||
entry.blockMsTotal = Math.round((entry.blockMsTotal + stats.blockMsTotal) * 100) / 100
|
||||
entry.blockMsMax = Math.max(entry.blockMsMax, stats.blockMsMax)
|
||||
}
|
||||
}
|
||||
return merged
|
||||
}
|
||||
|
||||
/** V8 CPU profile of the MAIN process, taken from inside main via node:inspector. */
|
||||
async function startMainProfiler(electronApp: {
|
||||
evaluate: <R, A>(fn: (electron: unknown, arg: A) => R | Promise<R>, arg: A) => Promise<R>
|
||||
}): Promise<void> {
|
||||
await electronApp.evaluate(async (_electron, intervalUs: number) => {
|
||||
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: diagnostic-only scratch globals owned by this bench.
|
||||
const scope = globalThis as unknown as Record<string, unknown>
|
||||
const inspector = process.getBuiltinModule('node:inspector')
|
||||
const session = new inspector.Session()
|
||||
session.connect()
|
||||
type InspectorParams = { interval?: number }
|
||||
const post = (method: string, params?: InspectorParams): Promise<Record<string, unknown>> =>
|
||||
new Promise((resolve, reject) => {
|
||||
session.post(method, params, (error, result) =>
|
||||
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: node:inspector types the callback payload as unknown; every Profiler reply is an object.
|
||||
error ? reject(error) : resolve(result as Record<string, unknown>)
|
||||
)
|
||||
})
|
||||
await post('Profiler.enable')
|
||||
await post('Profiler.setSamplingInterval', { interval: intervalUs })
|
||||
await post('Profiler.start')
|
||||
scope.__orcaGitCostProfiler = { session, post, startedAt: Date.now() }
|
||||
}, 500)
|
||||
}
|
||||
|
||||
async function stopMainProfiler(
|
||||
electronApp: {
|
||||
evaluate: <R, A>(fn: (electron: unknown, arg: A) => R | Promise<R>, arg: A) => Promise<R>
|
||||
},
|
||||
outPath: string
|
||||
): Promise<number> {
|
||||
return electronApp.evaluate(async (_electron, target: string) => {
|
||||
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: same bench-owned global installed above.
|
||||
const scope = globalThis as unknown as Record<string, unknown>
|
||||
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the shape startMainProfiler stored on this same global, in this same process.
|
||||
const handle = scope.__orcaGitCostProfiler as {
|
||||
session: { disconnect: () => void }
|
||||
post: (method: string, params?: { interval?: number }) => Promise<Record<string, unknown>>
|
||||
startedAt: number
|
||||
}
|
||||
const { profile } = await handle.post('Profiler.stop')
|
||||
const wallMs = Date.now() - handle.startedAt
|
||||
process
|
||||
.getBuiltinModule('node:fs')
|
||||
.writeFileSync(target, JSON.stringify(profile), { mode: 0o600 })
|
||||
handle.session.disconnect()
|
||||
delete scope.__orcaGitCostProfiler
|
||||
return wallMs
|
||||
}, outPath)
|
||||
}
|
||||
@@ -56,27 +56,6 @@ test.describe('Markdown nested toggle regression', () => {
|
||||
}
|
||||
})
|
||||
|
||||
test('a nested toggle on disk reopens as editable toggles', async ({ orcaPage }, testInfo) => {
|
||||
const context = await getActiveWorktreeContext(orcaPage)
|
||||
let filePath: string | null = null
|
||||
|
||||
try {
|
||||
filePath = await createMarkdownFixture(
|
||||
context,
|
||||
NESTED_TOGGLE_FIXTURE_DIRECTORY,
|
||||
'nested-toggle-reopen',
|
||||
testInfo.workerIndex,
|
||||
NESTED_TOGGLE_MARKDOWN
|
||||
)
|
||||
await openMarkdownFixture(orcaPage, context, filePath)
|
||||
await waitForRichMarkdownEditor(orcaPage)
|
||||
|
||||
await expectEditableNestedToggles(orcaPage)
|
||||
} finally {
|
||||
await cleanupMarkdownFixture(filePath)
|
||||
}
|
||||
})
|
||||
|
||||
test('editing a nested toggle survives save and reopen', async ({ orcaPage }, testInfo) => {
|
||||
const context = await getActiveWorktreeContext(orcaPage)
|
||||
const sentinel = `editedInsideNestedToggle${Date.now()}`
|
||||
|
||||
Reference in New Issue
Block a user