/** * PlaywrightSubprocessExecutor — runs a Playwright test script in a child process. * * Unlike browser-script-executor which reuses the shared browser session, * this executor spawns an isolated Playwright browser process so E2E tests * do not interfere with the agent's interactive browser session. */ import type { E2eSupportFile } from '../types'; export interface PlaywrightSubprocessOptions { script: string; executionId: string; baseUrl?: string; timeoutMs?: number; envVars?: Record; /** * プロジェクト共有のサポートファイル(例: `lib/login.page.ts`)。 * 実行ごとの専用ディレクトリ(runDir)へ相対パスのまま展開され、 * spec 本体から相対 import できるようになる。 */ supportFiles?: E2eSupportFile[]; /** * 各 `test.step()` ごとにハーネス側でフルページのスクリーンショットを * 自動取得するか(既定: true)。true の場合、生成スクリプトが * `testInfo.attach()` を呼んでいなくても、プリロードモジュール * (`STEP_SCREENSHOT_PATCH_TEMPLATE`)を `NODE_OPTIONS=--require` で * 注入し、トップレベルの各ステップ後に自動でスクリーンショットを添付する。 * false の場合はプリロードを注入しない。 */ captureStepScreenshots?: boolean; /** * Basic 認証(HTTP Basic)で保護された環境向けの資格情報。指定時、 * Playwright の `use.httpCredentials` に注入される。ただし平文の値は * per-run config 本文には書かれず、`E2E_HTTP_CREDENTIALS_USERNAME` / * `E2E_HTTP_CREDENTIALS_PASSWORD` として子プロセスの env にのみ渡され、 * config は `process.env.E2E_HTTP_CREDENTIALS_*` を参照する(baseURL が * `process.env.E2E_BASE_URL` を参照するのと同じ流儀)。 */ httpCredentials?: { username: string; password: string; }; } export interface PlaywrightSubprocessStepResult { title: string; status: 'passed' | 'failed' | 'skipped'; error?: string; duration?: number; /** @deprecated Local filesystem path — kept only for backward compatibility. Prefer `screenshotBase64`. */ screenshotPath?: string; /** ISO timestamp of when this step ran, derived from the test's startTime plus cumulative prior step durations. */ executedAt?: string; /** Base64-encoded PNG captured via `testInfo.attach()` inside the corresponding `test.step()` call. */ screenshotBase64?: string; /** * Reason a whole test was skipped via `test.skip(cond, reason)`. Extracted * from the test result's `annotations` (the `{ type: 'skip', description }` * entry) in the LEGACY per-test branch. Only present for skipped steps. */ skipReason?: string; } export interface PlaywrightSubprocessResult { success: boolean; totalTests: number; passedTests: number; failedTests: number; steps: PlaywrightSubprocessStepResult[]; errorOutput?: string; /** * True when the whole-subprocess timeout fired. On timeout the executor no * longer discards everything: a graceful SIGINT lets Playwright flush a * partial `result.json`, so `steps`/`failedTests` may still carry the REAL * per-test failures that were the true cause. `errorOutput` always notes the * timeout so it is never hidden behind those partial results. Callers use * this to distinguish "timed out but recovered partial evidence" (report as * failed) from "timed out with nothing recovered" (report as error). */ timedOut?: boolean; } /** * Grace period after a timeout SIGINT before escalating to SIGKILL. * * On timeout we send SIGINT first so Playwright can run its `onEnd` reporter * hook and flush a partial `result.json` (SIGKILL would kill it before that, * losing every already-recorded per-test failure). If the process is still * alive after this window it is force-killed with SIGKILL. */ export declare const SIGKILL_GRACE_MS = 5000; /** * Final deadline after SIGKILL before force-resolving the Promise regardless of * whether `close` ever fired. * * Playwright forks Chromium as a GRANDCHILD that inherits the direct child's * stdio pipes. SIGKILLing only the direct child can leave the grandchild * holding those pipes open, so the `close` event never fires and this Promise * would stay unresolved forever — hanging the whole agent. When this window * elapses with no `close`, we force-resolve as `timedOut` so the run always * settles (the timeout is still surfaced as the cause). */ export declare const FORCE_RESOLVE_AFTER_SIGKILL_MS = 5000; /** * Attachment-name prefix used by the harness step-screenshot preload. Each * auto-captured screenshot is attached as `${HARNESS_STEP_SCREENSHOT_PREFIX}` * where `` is the 0-based top-level `test.step()` call order. Both the * preload template (which writes the name) and `parsePlaywrightJsonOutput` * (which reads it back) share this single constant so the two never drift. */ export declare const HARNESS_STEP_SCREENSHOT_PREFIX = "harness-step-screenshot-"; /** * Parse Playwright JSON reporter output into a structured result. * Expected format: { suites: [{ specs: [{ tests: [{ results: [...] }] }] }] } */ declare function parsePlaywrightJsonOutput(jsonContent: string): PlaywrightSubprocessResult; /** * Run a Playwright test script in a child process. * * Expands the spec, an optional set of project support files, and a per-run * Playwright config into a dedicated run directory under the OS temp dir, * executes the spec via the Playwright CLI, and parses the JSON reporter * output. The run directory is always cleaned up. */ export declare function runPlaywrightSubprocess(options: PlaywrightSubprocessOptions): Promise; /** Exported for testing */ export { parsePlaywrightJsonOutput }; //# sourceMappingURL=playwright-subprocess-executor.d.ts.map