mirror of
https://github.com/stablyai/orca.git
synced 2026-11-01 17:47:40 +00:00
* wip: connect fails for hosts the managed server can't serve; remove relay session, deploy and relay UI * wip: delete relay-only client modules left unreachable, prune their tests and gates * wip: format * wip: exhaustive unserved message * wip: drop relay attestation test for the deleted ownership proof * fix: prune stale baselines; type the test transport stub * fix(ssh): census proves leftover relay leases; name the remedy for older terminals; translate every connect-failure surface * test(ssh): leftover leases defer to the host census * test(e2e): remove relay-path SSH e2e specs and their CI lanes * test(e2e): drop the auto-convert case that built its relay era through a live relay * test(e2e): mark relay-era browser and catalog journeys fixme until they seed a profile * test(e2e): seed relay-era browser and catalog journeys from a saved profile The three journeys built their old-version state through a connect without an orcad template, which now refuses the host. They now start from a seeded relay-era profile, so the first connect converts the host as an upgrading user's would. * chore(ci): drop shard timings for the deleted relay tests * test(e2e): carry a relay-era login cookie across the browser conversion; own every launch * test(ci): drop the deleted SSH layout oracle from its route * test(e2e): open the retained browser after conversion, retrying a pre-connect card * test(e2e): bind the relay-era browser partition before seeding its cookie A relay-era build always recorded the partition binding before a page stored data in it. Seeding the cookie into an unbound partition made the binding store refuse it (browser_route_partition_binding_store_invalid), so the retained tab showed the generic routing card and Retry could never clear it. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: m4air <m4air@Mac.localdomain> Co-authored-by: Claude <noreply@anthropic.com>
167 lines
7.4 KiB
TypeScript
167 lines
7.4 KiB
TypeScript
/**
|
|
* Playwright globalSetup: builds the Electron app and creates a test git repo.
|
|
*
|
|
* Why: _electron.launch() needs the compiled output in out/main/index.js.
|
|
* Running electron-vite build here ensures the tests are always against
|
|
* the current source, without requiring the user to remember a manual step.
|
|
*
|
|
* Why: a dedicated test repo makes the suite idempotent — tests don't
|
|
* depend on whatever the user has open. The repo path is written to a
|
|
* temp file so the worker fixture can pick it up at runtime.
|
|
*/
|
|
|
|
import { execSync } from 'node:child_process'
|
|
import { randomUUID } from 'node:crypto'
|
|
import { existsSync, mkdirSync, mkdtempSync, realpathSync, writeFileSync } from 'node:fs'
|
|
import path from 'node:path'
|
|
import os from 'node:os'
|
|
import { prepareDockerSshRelayImage } from './helpers/docker-ssh-relay-image'
|
|
|
|
export const E2E_TEST_REPO_PATH_FILE_ENV = 'ORCA_E2E_TEST_REPO_PATH_FILE'
|
|
const RUN_TEST_REPO_PATH_FILE =
|
|
process.env[E2E_TEST_REPO_PATH_FILE_ENV] ??
|
|
path.join(os.tmpdir(), `orca-e2e-test-repo-path-${randomUUID()}.txt`)
|
|
|
|
export function workerTestRepositoryPathFile(runPathFile: string, workerIndex?: string): string {
|
|
if (workerIndex === undefined) {
|
|
return runPathFile
|
|
}
|
|
if (!/^\d+$/.test(workerIndex)) {
|
|
throw new Error('Invalid Playwright worker index')
|
|
}
|
|
return `${runPathFile}.worker-${workerIndex}`
|
|
}
|
|
|
|
// Restart helpers and the app fixture must read the same worker-owned repository.
|
|
export const TEST_REPO_PATH_FILE = workerTestRepositoryPathFile(
|
|
RUN_TEST_REPO_PATH_FILE,
|
|
process.env.TEST_WORKER_INDEX
|
|
)
|
|
const ELECTRON_E2E_BUILD_TIMEOUT_MS = 300_000
|
|
const CLI_E2E_BUILD_TIMEOUT_MS = 120_000
|
|
const WEB_E2E_BUILD_TIMEOUT_MS = 300_000
|
|
|
|
export default function globalSetup(): void {
|
|
// Why: workers and teardown need this run's path, never another concurrent run's.
|
|
process.env[E2E_TEST_REPO_PATH_FILE_ENV] = TEST_REPO_PATH_FILE
|
|
const root = process.cwd()
|
|
const outMain = path.join(root, 'out', 'main', 'index.js')
|
|
const outCli = path.join(root, 'out', 'cli', 'index.js')
|
|
const outWeb = path.join(root, 'out', 'web', 'web-index.html')
|
|
const outLinuxRelay = path.join(root, 'out', 'relay', 'linux-x64', 'relay.js')
|
|
|
|
// ── 1. Build the Electron app ──────────────────────────────────────
|
|
if (process.env.SKIP_BUILD && existsSync(outMain)) {
|
|
console.error('[e2e] SKIP_BUILD set and out/main/index.js exists — skipping build')
|
|
} else {
|
|
// Why: --mode e2e is the build-time signal that exposes window.__store;
|
|
// the explicit env var keeps older local overrides working too.
|
|
console.error('[e2e] Building Electron app with electron-vite build --mode e2e...')
|
|
execSync('npx electron-vite build --mode e2e', {
|
|
env: { ...process.env, VITE_EXPOSE_STORE: 'true' },
|
|
cwd: root,
|
|
stdio: 'inherit',
|
|
// Why: Windows renderer builds can exceed 120s on local/CI hosts even
|
|
// when healthy; global setup should not fail before specs can run.
|
|
timeout: ELECTRON_E2E_BUILD_TIMEOUT_MS
|
|
})
|
|
console.error('[e2e] Build complete.')
|
|
}
|
|
if (process.env.SKIP_BUILD && existsSync(outCli)) {
|
|
console.error('[e2e] SKIP_BUILD set and out/cli/index.js exists — skipping CLI build')
|
|
// Artifact downloads lose executable bits; each runner still needs its local dev launcher.
|
|
execSync('pnpm run prepare:cli-output', {
|
|
cwd: root,
|
|
stdio: 'inherit',
|
|
timeout: CLI_E2E_BUILD_TIMEOUT_MS
|
|
})
|
|
} else {
|
|
console.error('[e2e] Building bundled CLI...')
|
|
execSync('pnpm run build:cli', {
|
|
cwd: root,
|
|
stdio: 'inherit',
|
|
timeout: CLI_E2E_BUILD_TIMEOUT_MS
|
|
})
|
|
console.error('[e2e] CLI build complete.')
|
|
}
|
|
if (process.env.ORCA_E2E_WEB_CLIENT === '1') {
|
|
if (process.env.SKIP_BUILD && existsSync(outWeb)) {
|
|
console.error('[e2e] SKIP_BUILD set and web client exists — skipping web build')
|
|
} else {
|
|
// Why: paired-browser specs need the web bundle served by the runtime; ordinary Electron E2E does not.
|
|
console.error('[e2e] Building paired runtime web client...')
|
|
execSync('pnpm run build:web', {
|
|
env: { ...process.env, VITE_EXPOSE_STORE: 'true' },
|
|
cwd: root,
|
|
stdio: 'inherit',
|
|
timeout: WEB_E2E_BUILD_TIMEOUT_MS
|
|
})
|
|
console.error('[e2e] Web client build complete.')
|
|
}
|
|
}
|
|
if (
|
|
process.env.ORCA_E2E_SSH_DOCKER === '1' ||
|
|
(process.env.ORCA_E2E_SKILL_STAGING === '1' && Boolean(process.env.ORCA_E2E_SKILL_SSH_HOST))
|
|
) {
|
|
if (process.env.SKIP_BUILD && existsSync(outLinuxRelay)) {
|
|
console.error('[e2e] SKIP_BUILD set and SSH relay bundle exists — skipping relay build')
|
|
} else {
|
|
// Why: explicit SSH specs need deployable Relay outputs in source-tree runs.
|
|
console.error('[e2e] Building SSH relay bundle for SSH E2E...')
|
|
execSync('pnpm run build:relay', {
|
|
cwd: root,
|
|
stdio: 'inherit',
|
|
timeout: 120_000
|
|
})
|
|
}
|
|
}
|
|
if (process.env.ORCA_E2E_SSH_DOCKER === '1') {
|
|
console.error('[e2e] Preparing Docker OpenSSH fixture image...')
|
|
prepareDockerSshRelayImage(root)
|
|
}
|
|
|
|
// ── 2. Create a seeded test git repo ───────────────────────────────
|
|
// Why: each test run gets its own git repo so the suite is fully
|
|
// idempotent. No test depends on whatever repos the user has open.
|
|
// Why: realpathSync so the seeded path matches the store's repo.path on
|
|
// macOS, where os.tmpdir() (/var/...) symlinks to /private/var/... and the
|
|
// app canonicalizes repo.path via `git rev-parse --show-toplevel` on add.
|
|
const testRepoDir = realpathSync(mkdtempSync(path.join(os.tmpdir(), 'orca-e2e-repo-')))
|
|
|
|
execSync('git init', { cwd: testRepoDir, stdio: 'pipe' })
|
|
execSync('git config user.email "e2e@test.local"', { cwd: testRepoDir, stdio: 'pipe' })
|
|
execSync('git config user.name "E2E Test"', { cwd: testRepoDir, stdio: 'pipe' })
|
|
|
|
// Seed test data files
|
|
writeFileSync(
|
|
path.join(testRepoDir, 'README.md'),
|
|
'# Orca E2E Test Repo\n\nThis repo was created automatically for Playwright tests.\n'
|
|
)
|
|
writeFileSync(path.join(testRepoDir, 'CLAUDE.md'), '# CLAUDE.md\n\nTest instructions for E2E.\n')
|
|
writeFileSync(
|
|
path.join(testRepoDir, 'package.json'),
|
|
`${JSON.stringify({ name: 'orca-e2e-test', version: '0.0.0', private: true }, null, 2)}\n`
|
|
)
|
|
writeFileSync(path.join(testRepoDir, '.gitignore'), 'node_modules/\n')
|
|
mkdirSync(path.join(testRepoDir, 'src'), { recursive: true })
|
|
writeFileSync(path.join(testRepoDir, 'src', 'index.ts'), 'export const hello = "world"\n')
|
|
writeFileSync(path.join(testRepoDir, 'src', 'diff-note-layout.ts'), 'export const seed = true\n')
|
|
|
|
execSync('git add -A', { cwd: testRepoDir, stdio: 'pipe' })
|
|
execSync('git commit -m "Initial commit for E2E tests"', { cwd: testRepoDir, stdio: 'pipe' })
|
|
|
|
// Why: several tests verify worktree-switching behavior (terminal content
|
|
// retention, browser tab retention). They need at least 2 worktrees.
|
|
// Creating one here makes those tests run instead of being skipped.
|
|
const worktreeDir = path.join(testRepoDir, '..', `orca-e2e-worktree-${randomUUID()}`)
|
|
execSync(`git worktree add "${worktreeDir}" -b e2e-secondary`, {
|
|
cwd: testRepoDir,
|
|
stdio: 'pipe'
|
|
})
|
|
console.error(`[e2e] Secondary worktree created at ${worktreeDir}`)
|
|
|
|
// Write the test repo path so the fixture can read it
|
|
writeFileSync(TEST_REPO_PATH_FILE, testRepoDir)
|
|
console.error(`[e2e] Test repo created at ${testRepoDir}`)
|
|
}
|