Files
orca/config/scripts/pr-e2e-route-contracts.test.mjs
T
Neil eb7f4d9c31 test(wsl-host): native chat on a WSL host through the fake transport, including a stopped distro (#34573)
* test(wsl-host): native chat on a WSL host through the fake transport, including a stopped distro

* test(wsl-host): type the chat spec's focus host id

* test(wsl-host): harden the WSL host chat spec and re-run fake-connector specs on change

* test(wsl-host): scope the chat reply check to the transcript and test the fake's route

Find the prompt only in the transcript so the composer can't stand in for it,
re-check the boot-free stop window after unfocusing, right before the focus,
give the fake's distros.json temp file its own name so it can't collide with the
spec's, and test that the fake connector routes to both WSL host specs.
2026-10-27 16:02:12 -07:00

568 lines
25 KiB
JavaScript

import { describe, expect, it } from 'vitest'
import { existsSync, readdirSync, readFileSync } from 'node:fs'
import { join, resolve } from 'node:path'
import { parse } from 'yaml'
import {
classifyE2eJobs,
DEDICATED_E2E_SPECS,
MANAGED_SSH_E2E_SPEC_PREFIX,
ORCAD_SERVE_MODE_SWITCH_E2E_SPEC,
WINDOWS_COPY_FILE_E2E_SPEC,
WINDOWS_MISSING_APPDATA_E2E_SPEC,
selectGeneralE2eSpecs
} from './ci-e2e-job-selection.mjs'
import { classifyPrJobs } from './pr-code-change-scope.mjs'
import { testImportClosure } from './e2e-test-import-closure.mjs'
import { isLayoutOracleSource, LAYOUT_ORACLE_E2E_SPECS } from './pr-layout-oracle-route.mjs'
import {
hasNativeImeSourceChange,
MANUAL_ONLY_E2E_SPECS,
PR_E2E_SOURCE_ROUTES,
selectPrE2eSpecs,
shouldRunReusablePrE2e
} from './pr-e2e-source-routing.mjs'
const projectDir = resolve(import.meta.dirname, '../..')
const prWorkflow = parse(readFileSync(join(projectDir, '.github/workflows/pr.yml'), 'utf8'))
const e2eWorkflow = parse(readFileSync(join(projectDir, '.github/workflows/e2e.yml'), 'utf8'))
describe('browser native focus routing', () => {
it('selects the general E2E lane for focus adapter and image fixture changes', () => {
const spec = 'tests/e2e/browser-image-link-focus.spec.ts'
for (const file of [
'src/renderer/src/components/browser-pane/assemble-chrome/browser-page-guest-focus.ts',
'tests/e2e/helpers/browser-link-server.ts'
]) {
const specs = selectPrE2eSpecs([file])
expect(specs, file).toContain(spec)
expect(selectGeneralE2eSpecs(specs), file).toContain(spec)
expect(classifyE2eJobs(JSON.stringify(specs)).e2e_run_changed, file).toBe(true)
}
})
})
describe('pr-e2e-native-only-routing', () => {
const workflow = prWorkflow
const filterStep = workflow.jobs.code_paths.steps.find((step) => step.id === 'e2e_filter')
describe('native-only PR E2E routing', () => {
it('avoids generic E2E allocation for native-only changes while preserving its IME lane', () => {
for (const file of [
'tests/e2e/terminal-ibus-hangul-native.spec.ts',
'config/scripts/run-terminal-ibus-hangul-e2e.mjs'
]) {
expect(hasNativeImeSourceChange([file])).toBe(true)
expect(shouldRunReusablePrE2e([file])).toBe(false)
}
expect(shouldRunReusablePrE2e([])).toBe(false)
for (const spec of [
'tests/e2e/paired-startup-exec-readiness.spec.ts',
'tests/e2e/terminal-ime-exact-byte.spec.ts',
'tests/e2e/future.spec.ts'
]) {
expect(shouldRunReusablePrE2e([spec])).toBe(true)
expect(
shouldRunReusablePrE2e(['tests/e2e/terminal-ibus-hangul-native.spec.ts', spec])
).toBe(true)
}
expect(filterStep.run).toContain('pr-e2e-source-routing.mjs --reusable-workflow')
expect(filterStep.run).toContain('if [ "$SHOULD_RUN" = true ]; then')
})
})
})
describe('pr-e2e-pane-close-routing', () => {
// #21005 changed pane close/retirement across three transports with E2E skipped: routes covered binders but missed unbinders.
const PENDING_PANE_CLOSE_CHANGE = [
'src/renderer/src/components/terminal-pane/retire-unbound-ipc-terminal-pane.ts',
'src/renderer/src/components/terminal-pane/retire-unbound-runtime-terminal-pane.ts',
'src/renderer/src/components/terminal-pane/terminal-pane-close-admission.ts',
'src/renderer/src/components/terminal-pane/terminal-pane-retirement-ownership.ts',
'src/renderer/src/components/terminal-pane/use-terminal-pane-close-actions.ts',
'src/renderer/src/store/terminals/terminal-tab-close-providers.ts'
]
const CLOSE_ROUTE = PR_E2E_SOURCE_ROUTES.find(
(route) => route.id === 'terminal-pane.close-and-retirement'
)
describe('pane close and retirement PR E2E routing', () => {
it('selects the close specs for a pane close lifecycle change', () => {
expect(selectPrE2eSpecs(PENDING_PANE_CLOSE_CHANGE)).toEqual([
'tests/e2e/paired-remote-split-pane-host-retired-ghost.spec.ts',
'tests/e2e/terminal-pane-close-layout-consistency.spec.ts',
'tests/e2e/terminal-parked-close-retirement.spec.ts'
])
expect(shouldRunReusablePrE2e(PENDING_PANE_CLOSE_CHANGE)).toBe(true)
})
it('routes each unbind authority on its own, not just as a group', () => {
expect(CLOSE_ROUTE, 'the close route was renamed or removed').toBeDefined()
// Assert each single path; union could hide missed routes behind one match.
for (const file of PENDING_PANE_CLOSE_CHANGE) {
expect(selectPrE2eSpecs([file]), file).toEqual(CLOSE_ROUTE.specs.toSorted())
}
})
it('keeps every routed spec and authority a real file', () => {
for (const spec of CLOSE_ROUTE.specs) {
expect(existsSync(join(projectDir, spec)), spec).toBe(true)
}
for (const file of PENDING_PANE_CLOSE_CHANGE) {
expect(existsSync(join(projectDir, file)), file).toBe(true)
}
})
it('leaves unrelated changes alone', () => {
// Neighbours in the same directories that this route must not claim.
for (const file of [
'src/renderer/src/components/terminal-pane/CloseTerminalDialog.tsx',
'src/renderer/src/components/terminal-pane/terminal-hidden-view-parking.ts',
'src/renderer/src/runtime/runtime-rpc-client.ts',
'src/renderer/src/store/terminals/terminal-tab-close-providers.test.ts'
]) {
expect(CLOSE_ROUTE.matches(file), file).toBe(false)
}
})
})
})
describe('pr-e2e-layout-oracle-routing', () => {
/** One product file per layout writer family; each alone must run the oracle. */
const LAYOUT_AUTHORITIES = [
'src/shared/workspace-layout/workspace-layout-pane-commands.ts',
'src/shared/workspace-layout/old-client/old-client-session-tab-rows.ts',
'src/main/persistence/terminal-topology/terminal-topology-commit.ts',
'src/main/persistence/restoring-sessions/session-owner-fields.ts',
'src/main/persistence/loading-store/pty-binding-persistence.ts',
'src/main/remote-layout-snapshot/remote-layout-snapshot-recorder.ts',
'src/main/runtime/terminal/launch/terminal-split-surface.ts',
'src/main/runtime/terminal/adoption/adopt-terminal-orphans-from-inventory.ts',
'src/main/runtime/runtime-terminal-orphan-adoption.ts',
'src/main/runtime/session-tabs/headless-tab-group-moves.ts',
'src/main/runtime/terminal/launch/terminal-create.ts',
'src/main/runtime/terminal/stop/worktree-terminal-stop.ts',
'src/renderer/src/runtime/mobile-session-tab-close.ts',
'src/renderer/src/runtime/runtime-layout-client.ts',
'src/renderer/src/store/slices/tabs.ts',
'src/renderer/src/store/slices/tabs/tabs-move-actions.ts',
'tests/e2e/workspace-layout-oracle-known-on-main.ts',
'tests/e2e/helpers/workspace-layout-oracle-compare.ts',
...LAYOUT_ORACLE_E2E_SPECS
]
/** Widened while the layout-holder stack is open: these still write layout. */
const STACK_WRITERS = [
'src/renderer/src/store/slices/terminals.ts',
'src/renderer/src/components/terminal-pane/TerminalPane.tsx',
'src/renderer/src/runtime/sync-runtime-graph.ts',
'src/renderer/src/runtime/web-session-tabs-sync/store-patch.ts',
'src/main/runtime/terminal/launch/terminal-split.ts',
'src/main/runtime/workspaces/workspace-file-session-targets.ts',
'src/main/runtime/session-graph/session-window-graph.ts',
'src/main/runtime/session-tabs/mobile-session-hydration.ts',
'src/main/runtime/session-tabs/mobile-session-reconciliation.ts',
'src/main/runtime/session-tabs/mobile-session-preservation.ts',
'src/main/runtime/workspaces/session-hosts/get-runtime-id.ts',
'src/main/runtime/mobile-session-layout-projection.ts',
'src/main/runtime/headless-runtime-graph.ts',
'src/main/persistence/loading-store/session-host-partitions.ts',
'src/main/persistence/loading-store/workspace-session-snapshot-publication.ts',
'src/renderer/src/store/slices/tab-group-reference-repair.ts',
'src/renderer/src/store/slices/terminal-session-row-hydration.ts',
'src/renderer/src/store/workspace-layout-cache.ts',
'src/renderer/src/app-shell/use-runtime-graph-sync.ts',
'src/renderer/src/components/tab-group/tab-drag-drop-commit.ts',
'src/shared/remote-layout-snapshot.ts',
'src/shared/terminal-leaf-move.ts',
'src/main/ipc/pty/ipc/leaf-move.ts',
'src/main/persistence/closed-terminal-tab-write-fence.ts',
'src/main/runtime/runtime-workspace-session-controller.ts',
'src/main/runtime/workspaces/persisted-surfaces/has-exact-persisted-terminal-surface-identity.ts',
'src/main/runtime/terminal-surface-close.ts',
'src/main/runtime/terminal/output/terminal-derived-agent-facts.ts',
'src/main/runtime/terminal/output/terminal-output-generation.ts',
'src/main/runtime/session-tabs/mobile-session-membership.ts',
'src/main/runtime/session-tabs/pty-backed-session-publication.ts',
'src/renderer/src/components/terminal/terminal-tab-actions.ts',
'src/renderer/src/components/tab-bar/web-runtime-tab-move-mirror.ts',
'src/shared/rpc-contract/workspace-layout-params.ts',
'src/renderer/src/store/slices/recently-closed-tabs.ts'
]
/** Every test file the oracle specs import, transitively: a change there can break the gate. */
const oracleHarnessFiles = () => testImportClosure(projectDir, LAYOUT_ORACLE_E2E_SPECS)
describe('workspace layout oracle merge gate', () => {
it('routes each layout authority and stack writer on its own', () => {
for (const file of [...LAYOUT_AUTHORITIES, ...STACK_WRITERS]) {
expect(isLayoutOracleSource(file), file).toBe(true)
expect(classifyPrJobs([file]).layout_oracle, file).toBe(true)
expect(existsSync(join(projectDir, file)), file).toBe(true)
}
})
it('routes every test file the oracle specs import', () => {
const harness = oracleHarnessFiles()
expect(harness.length).toBeGreaterThan(LAYOUT_ORACLE_E2E_SPECS.length)
expect(harness.filter((file) => !isLayoutOracleSource(file))).toEqual([])
})
it('leaves tests, fixtures, harnesses and unrelated runtime modules alone', () => {
for (const file of [
'src/main/persistence/terminal-topology/terminal-topology-commit.test.ts',
'src/main/persistence/terminal-topology/terminal-leaf-move-fixture.ts',
'src/main/runtime/orca-runtime-tests/mobile-session-tabs-part-03.spec.ts',
'src/main/runtime/session-tabs/headless-tab-group-moves.test.ts',
'src/main/runtime/session-tabs/headless-tab-group-moves-fixture.ts',
'src/main/runtime/session-tabs/session-tabs-inventory-test-fixture.ts',
'src/main/runtime/terminal/stop/worktree-terminal-stop.test.ts',
'src/main/runtime/terminal/stop/worktree-terminal-stop-fixture.ts',
'src/main/runtime/terminal/stop/worktree-terminal-stop.ts.backup',
'src/main/runtime/terminal/stop/worktree-terminal-stop-extra.ts',
'src/main/runtime/runtime-durable-store-fixture.ts',
'src/main/runtime/orchestration/db/worker-terminal/worker-terminal-store.ts',
'src/main/runtime/rpc/methods/terminal/terminal-create.ts',
'src/main/runtime/runtime-rpc-database.ts',
'src/main/runtime/orca-runtime-files.ts',
'src/main/runtime/workspaces/persisted-surfaces/automation-operations.ts',
'src/main/runtime/workspaces/persisted-surfaces/has-exact-persisted-terminal-surface-identity.test.ts',
'src/renderer/src/runtime/remote-runtime-terminal-multiplexer.ts',
'src/renderer/src/runtime/web-session-tabs-sync-test-harness.ts',
'src/renderer/src/runtime/sync-runtime-graph-test-harness.ts',
'src/renderer/src/runtime/sync-runtime-graph.test.ts',
'tests/e2e/workspace-layout-oracle-latency.spec.ts'
]) {
expect(isLayoutOracleSource(file), file).toBe(false)
}
expect(classifyPrJobs(['src/main/runtime/orca-runtime-files.ts']).layout_oracle).toBe(false)
})
it('keeps the oracle specs out of the advisory e2e job', () => {
expect(selectPrE2eSpecs(LAYOUT_AUTHORITIES)).toEqual([])
expect(shouldRunReusablePrE2e(LAYOUT_AUTHORITIES)).toBe(false)
})
it('runs exactly the oracle specs, each in the lane that can run it', () => {
const job = prWorkflow.jobs.layout_oracle
expect(job.uses).toBe('./.github/workflows/e2e.yml')
// The merge commit, so a stale-base PR cannot pass on an old main.
expect(job.with.ref).toBe('${{ github.sha }}')
const specs = JSON.parse(job.with.test_files)
expect(specs.toSorted()).toEqual(LAYOUT_ORACLE_E2E_SPECS.toSorted())
// Window spec runs in the changed-spec lane; headless runs in the orcad lane.
expect(selectGeneralE2eSpecs(specs)).toEqual(['tests/e2e/workspace-layout-oracle.spec.ts'])
expect(classifyE2eJobs(job.with.test_files)).toEqual({
e2e_run_changed: true,
e2e_needs_build: true
})
})
it('blocks the merge on the oracle and passes when it is skipped', () => {
const verify = prWorkflow.jobs.verify
const gate = verify.steps.find((step) => step.name === 'Require successful checks')
expect(verify.needs).toContain('layout_oracle')
expect(gate.run).toContain(
'check_job layout_oracle "$LAYOUT_ORACLE" "$LAYOUT_ORACLE_SHOULD_RUN"'
)
// Two calls of the reusable workflow in one run must not share artifact names.
expect(prWorkflow.jobs.layout_oracle.with.artifact_suffix).toBeTruthy()
expect(prWorkflow.jobs.e2e.with.artifact_suffix).toBeUndefined()
})
})
})
describe('ssh-browser-e2e-routing', () => {
const workflow = e2eWorkflow
it('executes both Docker network routes in a Node job with their opt-in enabled', () => {
const spec = 'tests/e2e/ssh-browser-network-execution-route.docker.unit.test.ts'
const job = workflow.jobs['ssh-browser-network-route']
const install = job.steps.find(
(step) => step.uses === './.github/actions/install-node-dependencies'
)
const run = job.steps.find(
(step) => step.name === 'Run Docker SSH browser network route journeys'
)
expect(job['runs-on']).toBe('blacksmith-4vcpu-ubuntu-2404')
expect(job.if).toContain("inputs.test_files == ''")
expect(job.if).toContain(spec)
expect(install.with['native-runtime']).toBe('node')
expect(run.env.ORCA_RUN_DOCKER_SSH_BROWSER_E2E).toBe('1')
expect(run.run).toContain(`vitest run --config config/vitest.config.ts ${spec}`)
expect(run['continue-on-error']).toBeUndefined()
expect(DEDICATED_E2E_SPECS).toContain(spec)
for (const changed of [
spec,
'src/main/browser/ssh-browser-network-execution-route.ts',
'src/main/browser/browser-network-deferred-socket.ts',
'src/main/browser/browser-network-execution-route.ts',
'src/main/browser/system-ssh-socks-client-socket.ts',
'src/main/ssh/system-transport/system-ssh-dynamic-forward-process.ts',
'tests/e2e/helpers/docker-ssh-host-target.ts',
'tests/e2e/helpers/docker-ssh-host-image.ts'
]) {
expect(selectPrE2eSpecs([changed])).toContain(spec)
}
expect(selectPrE2eSpecs(['src/renderer/src/components/Unrelated.tsx'])).not.toContain(spec)
expect(selectPrE2eSpecs(['tests/e2e/helpers/docker-ssh-host-terminal-tabs.ts'])).not.toContain(
spec
)
})
})
describe('orcad-e2e-routing', () => {
const root = projectDir
const jobs = e2eWorkflow.jobs
const ORCAD_AUTO_CONVERT_E2E_SPEC = 'tests/e2e/ssh-orcad-auto-convert.spec.ts'
const ORCAD_IDLE_EXIT_E2E_SPEC = 'tests/e2e/ssh-orcad-idle-exit.spec.ts'
const ORCAD_OPEN_IN_OWNER_E2E_SPEC = 'tests/e2e/ssh-orcad-open-in-owner.spec.ts'
const ORCAD_JOURNEY_E2E_SPECS = [
'tests/e2e/ssh-orcad-terminal-journeys.spec.ts',
'tests/e2e/ssh-orcad-workspace-tools.spec.ts',
'tests/e2e/ssh-orcad-vm-provisioned-root.spec.ts'
]
function expectRouted(files, spec) {
for (const file of files) {
expect(existsSync(resolve(root, file)), file).toBe(true)
expect(selectPrE2eSpecs([file]), file).toContain(spec)
expect(shouldRunReusablePrE2e([file]), file).toBe(true)
}
}
it('routes the mode-switch spec from its serve sources and harness', () => {
expectRouted(
[
'src/main/orcad/orcad-lifecycle.ts',
'src/main/daemon/daemon-spawner.ts',
'tests/e2e/helpers/orca-serve-cli-host.ts',
'tests/e2e/helpers/headless-paired-runtime-host.ts'
],
ORCAD_SERVE_MODE_SWITCH_E2E_SPEC
)
})
it('routes the missing-AppData spec from its startup sources and harness', () => {
expectRouted(
['src/main/startup/windows-app-data-path.ts', 'tests/e2e/helpers/orca-serve-cli-host.ts'],
WINDOWS_MISSING_APPDATA_E2E_SPEC
)
})
it('routes the Windows file-copy spec from its clipboard sources', () => {
expectRouted(
[
'src/main/window/clipboard-file-copy.ts',
'src/main/window/clipboard-ipc-handlers.ts',
'src/renderer/src/components/right-sidebar/file-explorer-row-file-transfer.ts'
],
WINDOWS_COPY_FILE_E2E_SPEC
)
})
it('routes the auto-convert spec from its conversion sources and harness', () => {
expectRouted(
[
'src/main/managed-server/lifecycle/orcad-runtime-conversion.ts',
'tests/e2e/helpers/orcad-convert-flow.ts',
'tests/e2e/helpers/orcad-convert-host.ts',
'tests/e2e/helpers/orcad-template-variant.ts',
'tests/e2e/helpers/orcad-upgrade-profile.ts'
],
ORCAD_AUTO_CONVERT_E2E_SPEC
)
expect(
selectPrE2eSpecs(['src/main/managed-server/lifecycle/orcad-runtime-conversion.test.ts'])
).not.toContain(ORCAD_AUTO_CONVERT_E2E_SPEC)
})
it('routes the idle-exit spec from its idle sources and the shared convert harness', () => {
expectRouted(
[
'src/shared/orcad-idle-exit.ts',
'src/main/managed-server/install/orcad-remote-runtime-control.ts',
'src/main/managed-server/lifecycle/orcad-managed-serving.ts',
'tests/e2e/helpers/orcad-convert-flow.ts',
'tests/e2e/helpers/orcad-convert-host.ts'
],
ORCAD_IDLE_EXIT_E2E_SPEC
)
})
it('builds the e2e app when only a build-dependent orcad spec is requested', () => {
for (const spec of [
ORCAD_SERVE_MODE_SWITCH_E2E_SPEC,
ORCAD_AUTO_CONVERT_E2E_SPEC,
ORCAD_IDLE_EXIT_E2E_SPEC,
ORCAD_OPEN_IN_OWNER_E2E_SPEC
]) {
expect(classifyE2eJobs(JSON.stringify([spec])), spec).toEqual({
e2e_run_changed: false,
e2e_needs_build: true
})
}
expect(jobs['orcad-ssh-docker'].needs).toEqual(['build'])
})
it('passes the requested managed-SSH specs to the sharded lane', () => {
const lane = jobs['orcad-ssh-docker']
expect(lane.if).toBe(
`inputs.test_files == '' || contains(inputs.test_files, '${MANAGED_SSH_E2E_SPEC_PREFIX}')`
)
expect(lane.strategy.matrix.shard).toBe(
`\${{ fromJSON(inputs.managed_ssh_shards || '["1/2","2/2"]') }}`
)
const run = lane.steps.find((step) => step.env?.ORCA_E2E_SSH_DOCKER === '1').run
expect(run).toContain('"${TEST_FILES[@]}"')
expect(run).toContain('--shard="$SHARD"')
for (const spec of [
ORCAD_AUTO_CONVERT_E2E_SPEC,
ORCAD_IDLE_EXIT_E2E_SPEC,
ORCAD_OPEN_IN_OWNER_E2E_SPEC,
...ORCAD_JOURNEY_E2E_SPECS
]) {
expect(existsSync(resolve(root, spec)), spec).toBe(true)
expect(spec.startsWith(MANAGED_SSH_E2E_SPEC_PREFIX), spec).toBe(true)
}
})
it('runs the Windows-only specs on one runner, each only when requested', () => {
expect(jobs['windows-missing-appdata-startup']).toBeUndefined()
const job = jobs['orcad-serve-mode-switch-windows']
for (const spec of [
ORCAD_SERVE_MODE_SWITCH_E2E_SPEC,
WINDOWS_MISSING_APPDATA_E2E_SPEC,
WINDOWS_COPY_FILE_E2E_SPEC
]) {
expect(job.if, spec).toContain(`contains(inputs.test_files, '${spec}')`)
const step = job.steps.find((candidate) => candidate.run?.includes(spec))
expect(step.if, spec).toContain(`contains(inputs.test_files, '${spec}')`)
expect(step.env.ORCA_STARTUP_DIAGNOSTICS, spec).toBeUndefined()
}
})
it('routes managed target-owner guards and menus to the real launch regression', () => {
expectRouted(
[
'src/renderer/src/lib/local-path-open-guard.ts',
'src/renderer/src/lib/external-editor-open-capability.ts',
'src/renderer/src/lib/worktree-runtime-owner.ts',
'src/renderer/src/components/sidebar/WorktreeOpenInMenu.tsx',
'src/renderer/src/components/sidebar/WorktreeContextMenuView.tsx',
'src/renderer/src/components/right-sidebar/FileExplorer.tsx',
'src/renderer/src/components/right-sidebar/FileExplorerToolbar.tsx',
'src/renderer/src/components/right-sidebar/source-control/listing/entry-context-menu.tsx',
'tests/e2e/helpers/orcad-convert-flow.ts',
'tests/e2e/helpers/orcad-convert-host.ts',
'tests/e2e/helpers/orcad-upgrade-profile.ts',
'tests/e2e/helpers/docker-ssh-host-target.ts'
],
ORCAD_OPEN_IN_OWNER_E2E_SPEC
)
expect(selectPrE2eSpecs(['src/renderer/src/lib/local-path-open-guard.test.ts'])).not.toContain(
ORCAD_OPEN_IN_OWNER_E2E_SPEC
)
})
it('routes the managed-host journey specs from their harness and sources', () => {
for (const spec of ORCAD_JOURNEY_E2E_SPECS) {
expectRouted(
[
'tests/e2e/helpers/orcad-managed-workspace.ts',
'src/renderer/src/components/terminal-pane/terminal-host-workspace-file.ts',
'src/renderer/src/components/terminal-pane/terminal-host-file-link-existence.ts',
'src/renderer/src/runtime/runtime-terminal-artifact-read.ts',
// #30130's Disconnect sources merged with this lane skipped.
'src/main/ipc/ssh/ssh-host-user-disconnect.ts',
'src/main/ipc/ssh/ssh-connect-flow.ts',
'src/main/ipc/ssh/ssh-connection-handlers.ts',
'src/main/ipc/runtime-environments/runtime-environment-connectivity-handlers.ts',
'src/main/ipc/runtime-environments/runtime-environment-manual-disconnect.ts',
'src/main/ssh/connection/ssh-connection-manager.ts',
'src/main/ssh/ssh-user-disconnect.ts',
'src/renderer/src/runtime/web-session-close-intent.ts',
'src/renderer/src/runtime/web-session-close-replay.ts'
],
spec
)
expect(classifyE2eJobs(JSON.stringify([spec])), spec).toEqual({
e2e_run_changed: false,
e2e_needs_build: true
})
}
})
})
function selectsManagedSshLane(file) {
return selectPrE2eSpecs([file]).some((spec) => spec.startsWith(MANAGED_SSH_E2E_SPEC_PREFIX))
}
describe('wsl-host fake connector routing', () => {
it('runs both WSL host specs for a fake connector change', () => {
const specs = selectPrE2eSpecs(['src/main/wsl/wsl-host-e2e-fake-connector.ts'])
for (const spec of [
'tests/e2e/wsl-host-chat.spec.ts',
'tests/e2e/wsl-host-fake-transport.spec.ts'
]) {
expect(specs, spec).toContain(spec)
expect(existsSync(join(projectDir, spec)), spec).toBe(true)
}
expect(selectPrE2eSpecs(['src/main/wsl/wsl-host-e2e-fake-connector.test.ts'])).not.toContain(
'tests/e2e/wsl-host-chat.spec.ts'
)
})
})
describe('managed-SSH remote sources routing', () => {
it('gives every managed-SSH spec a source route', () => {
const routed = new Set(PR_E2E_SOURCE_ROUTES.flatMap((route) => route.specs))
const specs = readdirSync(join(projectDir, 'tests/e2e'))
.filter((name) => /^ssh-orcad-.*\.spec\.ts$/.test(name))
.map((name) => `tests/e2e/${name}`)
expect(specs.length).toBeGreaterThan(0)
expect(
specs.filter((spec) => !routed.has(spec) && !MANUAL_ONLY_E2E_SPECS.includes(spec))
).toEqual([])
})
it('starts the lane for remote product sources no hand-kept route names', () => {
for (const file of [
// #30130 and #30120 merged with the lane skipped.
'src/main/ipc/ssh/ssh.ts',
'src/cli/runtime/serve-orcad-launch.ts',
'src/main/orcad/orcad-entry.ts',
'src/main/ssh/connection/ssh-connection.ts',
'src/main/ipc/runtime-environments/runtime-environment-status-probe.ts',
'src/main/ipc/runtime-environments/orcad-runtime-lifecycle-handlers.ts',
'src/shared/protocol-version.ts',
'src/shared/remote-runtime/remote-runtime-client-error-classification.ts',
// #30047 and #30060: sidebar sleep and project removal.
'src/renderer/src/components/sidebar/sleep-worktree-flow.ts',
'src/renderer/src/components/sidebar/ssh-host-remove-resolution.ts',
'src/renderer/src/store/repos/repo-removal.ts',
// #30775: the pane banner for a managed server that refused this desktop.
'src/renderer/src/components/terminal-pane/TerminalRemoteRuntimeReconnectBanner.tsx',
'src/renderer/src/components/terminal-pane/use-managed-pairing-refused.ts',
'src/renderer/src/components/terminal-pane/TerminalPaneRuntimePortals.tsx'
]) {
expect(existsSync(join(projectDir, file)), file).toBe(true)
expect(selectsManagedSshLane(file), file).toBe(true)
}
})
it('leaves unit tests and local-only sources alone', () => {
for (const file of [
'src/main/ssh/connection/ssh-connection.test.ts',
'src/main/ipc/ssh/ssh.test.ts',
'src/main/daemon/daemon-server.ts',
'src/main/runtime/rpc/methods/accounts.ts',
'src/renderer/src/components/sidebar/WorktreeCard.tsx',
'src/renderer/src/store/repos/repo-ordering.ts',
'docs/STYLEGUIDE.md'
]) {
expect(selectsManagedSshLane(file), file).toBe(false)
}
})
})