import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import { describe, it } from "vitest"; import { hasRequiredAuthEnv, isUrlReachable, missingReadinessEnv, missingReadinessModeEnv, missingReadinessMutatingOptInEnv, missingNoTenantAccountCreateEnv, missingSubscriptionSuccessReadinessEnv, missingWorkflowOutboxDrainReadinessEnv, missingWorkflowWebhookRunReadinessEnv, resolveTargetUrl, runPlaywrightA11y, } from "./run-playwright-a11y.mjs"; function recordingSpawn(handlers) { const calls = []; function spawn(command, args, options) { calls.push({ command, args, options }); const handler = handlers[command]; if (!handler) { return { status: 1, stdout: "", stderr: "", error: new Error(`unexpected spawn for ${command}`) }; } return handler({ args, options }); } spawn.calls = calls; return spawn; } function captureLines() { const lines = []; function write(line) { lines.push(line); } write.lines = lines; return write; } function completeReadinessEnv(overrides = {}) { return { E2E_BASE_URL: "https://staging.example.test", E2E_TENANT_EMAIL: "user@example.test", E2E_TENANT_PASSWORD: "secret", E2E_NO_TENANT_EMAIL: "no-tenant@example.test", E2E_NO_TENANT_PASSWORD: "no-tenant-secret", E2E_REGISTRATION_EXPECTS_EMAIL_VERIFICATION: "0", E2E_TENANT_DASHBOARD_PATH: "/app/acme/dashboard", E2E_TENANT_SETTINGS_ACCOUNT_PATH: "/app/acme/settings/account", E2E_TENANT_SETTINGS_PROFILE_PATH: "/app/acme/settings/profile", E2E_TENANT_SUBSCRIPTION_PATH: "/app/acme/settings/subscription", E2E_TENANT_MEMBERS_PATH: "/app/acme/settings/members", E2E_TENANT_ROLES_AND_PERMISSIONS_PATH: "/app/acme/settings/roles-and-permissions", E2E_TENANT_NOTIFICATIONS_PATH: "/app/acme/settings/notifications", E2E_TENANT_LOGS_PATH: "/app/acme/settings/logs", E2E_TENANT_LOG_EVENTS_PATH: "/app/acme/settings/logs/events", E2E_TENANT_AUDIT_EXPORT_PATH: "/app/acme/settings/audit-export", E2E_TENANT_PRIVACY_PATH: "/app/acme/settings/privacy", E2E_TENANT_CHATBOT_PATH: "/app/acme/settings/chatbot", E2E_TENANT_AI_USAGE_PATH: "/app/acme/settings/ai-usage", E2E_TENANT_API_PATH: "/app/acme/settings/api", E2E_TENANT_API_KEYS_PATH: "/app/acme/settings/api/keys", E2E_TENANT_API_DOCS_PATH: "/app/acme/settings/api/docs", E2E_TENANT_API_LOGS_PATH: "/app/acme/settings/api/logs", E2E_TENANT_POLICIES_PATH: "/app/acme/settings/policies", E2E_TENANT_PORTAL_ANALYTICS_PATH: "/app/acme/portals/readiness/analytics", E2E_TENANT_PORTAL_SETTINGS_PATH: "/app/acme/portals/readiness/settings", E2E_ADMIN_EMAIL_SEQUENCES_PATH: "/admin/email-sequences", E2E_PLUGIN_SETTINGS_PATH: "/app/acme/settings/plugins/plugin-1", E2E_PLUGIN_READONLY_EMAIL: "plugin-readonly@example.test", E2E_PLUGIN_READONLY_PASSWORD: "readonly-secret", E2E_WORKFLOW_ENGINE_PATH: "/app/acme/workflows", E2E_WORKFLOW_BUILDER_PATH: "/app/acme/workflows/wf-1/builder", E2E_WORKFLOW_RUN_API_PATH: "/app/acme/workflows/wf-1/run/api", E2E_WORKFLOW_RUN_MANUAL_PATH: "/app/acme/workflows/wf-1/run", E2E_WORKFLOW_WEBHOOK_BUILDER_PATH: "/app/acme/workflows/wf-webhook/builder", E2E_WORKFLOW_WEBHOOK_RUN_MANUAL_PATH: "/app/acme/workflows/wf-webhook/run", E2E_WORKFLOW_WAITING_BUILDER_PATH: "/app/acme/workflows/wf-waiting/builder", E2E_WORKFLOW_WAITING_RUN_MANUAL_PATH: "/app/acme/workflows/wf-waiting/run", E2E_WORKFLOW_WAITING_RUN_API_PATH: "/app/acme/workflows/wf-waiting/run/api", E2E_WORKFLOW_WAITING_EXECUTIONS_PATH: "/app/acme/workflows/wf-waiting/executions", E2E_WORKFLOW_WAITING_EXECUTION_ID: "wfe-waiting-1", PLUGIN_BINARY_BASE_PATH: "/tmp/e2e-plugins", E2E_A11Y_STRICT: "1", E2E_BROWSER_MATRIX: "1", E2E_ALLOW_WORKFLOW_RUN: "1", E2E_ALLOW_REGISTRATION_CREATE: "1", E2E_ALLOW_ACCOUNT_CREATE: "1", E2E_ALLOW_NO_TENANT_ACCOUNT_CREATE: "1", E2E_ALLOW_PLUGIN_LIFECYCLE_MUTATION: "1", E2E_ALLOW_PLUGIN_SETTINGS_WRITE: "1", REQUIRE_E2E_READINESS: "1", ...overrides, }; } describe("run-playwright-a11y", () => { it("uses E2E_BASE_URL when provided", () => { assert.equal(resolveTargetUrl({ env: { E2E_BASE_URL: "https://staging.example.test" } }), "https://staging.example.test"); }); it("falls back to localhost when E2E_BASE_URL is missing", () => { assert.equal(resolveTargetUrl({ env: {} }), "http://localhost:3000"); }); it("falls back to localhost when E2E_BASE_URL is blank", () => { assert.equal(resolveTargetUrl({ env: { E2E_BASE_URL: "" } }), "http://localhost:3000"); assert.equal(resolveTargetUrl({ env: { E2E_BASE_URL: " " } }), "http://localhost:3000"); }); it("trims E2E_BASE_URL before probing the target", () => { assert.equal(resolveTargetUrl({ env: { E2E_BASE_URL: " https://staging.example.test " } }), "https://staging.example.test"); }); it("SKIPs with exit 0 when SKIP_E2E_A11Y=1 is set", () => { const spawn = recordingSpawn({}); const stdout = captureLines(); const outcome = runPlaywrightA11y({ env: { SKIP_E2E_A11Y: "1" }, spawn, stdout }); assert.deepEqual(outcome, { status: "skip", reason: "explicit-skip", exitCode: 0 }); assert.deepEqual(stdout.lines, ["SKIP_E2E_A11Y=1 set — skipping."]); assert.equal(spawn.calls.length, 0); }); it("fails instead of honoring SKIP_E2E_A11Y in required readiness lanes", () => { const spawn = recordingSpawn({}); const stdout = captureLines(); const outcome = runPlaywrightA11y({ env: { SKIP_E2E_A11Y: "1", REQUIRE_E2E_A11Y: "1", REQUIRE_AUTH_E2E: "1", REQUIRE_E2E_READINESS: "1", E2E_REQUIRE_SUBSCRIPTION_SUCCESS: "1", }, spawn, stdout, }); assert.deepEqual(outcome, { status: "fail", reason: "explicit-skip-in-required-lane", exitCode: 1 }); assert.deepEqual(stdout.lines, [ "FAIL: SKIP_E2E_A11Y=1 cannot be used with required E2E lanes: REQUIRE_E2E_A11Y=1, REQUIRE_AUTH_E2E=1, REQUIRE_E2E_READINESS=1, E2E_REQUIRE_SUBSCRIPTION_SUCCESS=1.", ]); assert.equal(spawn.calls.length, 0); }); it("SKIPs with exit 0 when the Playwright runtime is missing", () => { const spawn = recordingSpawn({ npx: () => ({ status: 1, stdout: "", stderr: "", error: new Error("ENOENT") }), }); const stdout = captureLines(); const outcome = runPlaywrightA11y({ env: {}, spawn, stdout }); assert.deepEqual(outcome, { status: "skip", reason: "runtime-missing", exitCode: 0 }); assert.match(stdout.lines[0], /^SKIP: Playwright runtime not installed/); assert.equal(spawn.calls.filter((call) => call.command === "curl").length, 0); }); it("fails instead of skipping missing runtime when REQUIRE_E2E_A11Y=1", () => { const spawn = recordingSpawn({ npx: () => ({ status: 1, stdout: "", stderr: "", error: new Error("ENOENT") }), }); const stdout = captureLines(); const outcome = runPlaywrightA11y({ env: { REQUIRE_E2E_A11Y: "1" }, spawn, stdout }); assert.deepEqual(outcome, { status: "fail", reason: "runtime-missing", exitCode: 1 }); assert.deepEqual(stdout.lines, ["FAIL: Playwright runtime not installed while REQUIRE_E2E_A11Y=1."]); }); it("SKIPs with exit 0 when the target URL is unreachable", () => { const spawn = recordingSpawn({ npx: ({ args }) => { assert.deepEqual(args, ["--no-install", "playwright", "--version"]); return { status: 0, stdout: "Version 1.59.1", stderr: "" }; }, curl: () => ({ status: 7, stdout: "", stderr: "Connection refused" }), }); const stdout = captureLines(); const outcome = runPlaywrightA11y({ env: { E2E_BASE_URL: "http://offline.example.test" }, spawn, stdout, }); assert.deepEqual(outcome, { status: "skip", reason: "target-unreachable", exitCode: 0 }); assert.ok(stdout.lines.some((line) => line === "SKIP: Target URL http://offline.example.test not reachable.")); assert.equal(spawn.calls.filter((call) => call.command === "npx" && call.args[0] === "playwright").length, 0); }); it("fails instead of skipping unreachable targets when REQUIRE_E2E_A11Y=1", () => { const spawn = recordingSpawn({ npx: ({ args }) => { assert.deepEqual(args, ["--no-install", "playwright", "--version"]); return { status: 0, stdout: "Version 1.59.1", stderr: "" }; }, curl: () => ({ status: 7, stdout: "", stderr: "Connection refused" }), }); const stdout = captureLines(); const outcome = runPlaywrightA11y({ env: { E2E_BASE_URL: "http://offline.example.test", REQUIRE_E2E_A11Y: "1" }, spawn, stdout, }); assert.deepEqual(outcome, { status: "fail", reason: "target-unreachable", exitCode: 1 }); assert.deepEqual(stdout.lines, ["FAIL: Target URL http://offline.example.test not reachable while REQUIRE_E2E_A11Y=1."]); }); it("fails before running Playwright when authenticated E2E credentials are required but missing", () => { const spawn = recordingSpawn({ npx: ({ args }) => { if (args[0] === "--no-install") { return { status: 0, stdout: "Version 1.59.1", stderr: "" }; } return { status: 0, stdout: "", stderr: "" }; }, pnpm: () => ({ status: 0, stdout: "", stderr: "" }), curl: () => ({ status: 0, stdout: "200", stderr: "" }), }); const stdout = captureLines(); const outcome = runPlaywrightA11y({ env: { E2E_BASE_URL: "https://staging.example.test", REQUIRE_AUTH_E2E: "1" }, spawn, stdout, }); assert.deepEqual(outcome, { status: "fail", reason: "auth-env-missing", exitCode: 1 }); assert.deepEqual(stdout.lines, ["FAIL: E2E_TENANT_EMAIL / E2E_TENANT_PASSWORD not set while REQUIRE_AUTH_E2E=1."]); assert.equal(spawn.calls.filter((call) => call.command === "npx" && call.args[0] === "playwright").length, 0); }); it("detects authenticated E2E credentials", () => { assert.equal(hasRequiredAuthEnv({ env: {} }), false); assert.equal(hasRequiredAuthEnv({ env: { E2E_TENANT_EMAIL: "user@example.test" } }), false); assert.equal(hasRequiredAuthEnv({ env: { E2E_TENANT_EMAIL: "user@example.test", E2E_TENANT_PASSWORD: "secret" } }), true); }); it("fails before running Playwright when readiness E2E inputs are incomplete", () => { const spawn = recordingSpawn({ npx: ({ args }) => { if (args[0] === "--no-install") { return { status: 0, stdout: "Version 1.59.1", stderr: "" }; } return { status: 0, stdout: "", stderr: "" }; }, pnpm: () => ({ status: 0, stdout: "", stderr: "" }), curl: () => ({ status: 0, stdout: "200", stderr: "" }), }); const stdout = captureLines(); const outcome = runPlaywrightA11y({ env: { E2E_BASE_URL: "https://staging.example.test", E2E_TENANT_EMAIL: "user@example.test", E2E_TENANT_PASSWORD: "secret", REQUIRE_E2E_READINESS: "1", }, spawn, stdout, }); assert.deepEqual(outcome, { status: "fail", reason: "readiness-env-missing", exitCode: 1 }); assert.match(stdout.lines[0], /E2E readiness env missing:/); assert.match(stdout.lines[0], /E2E_REGISTRATION_EXPECTS_EMAIL_VERIFICATION/); assert.match(stdout.lines[0], /E2E_TENANT_DASHBOARD_PATH/); assert.match(stdout.lines[0], /E2E_TENANT_SETTINGS_ACCOUNT_PATH/); assert.match(stdout.lines[0], /E2E_TENANT_SETTINGS_PROFILE_PATH/); assert.match(stdout.lines[0], /E2E_TENANT_SUBSCRIPTION_PATH/); assert.match(stdout.lines[0], /E2E_TENANT_MEMBERS_PATH/); assert.match(stdout.lines[0], /E2E_TENANT_ROLES_AND_PERMISSIONS_PATH/); assert.match(stdout.lines[0], /E2E_TENANT_NOTIFICATIONS_PATH/); assert.match(stdout.lines[0], /E2E_TENANT_LOGS_PATH/); assert.match(stdout.lines[0], /E2E_TENANT_LOG_EVENTS_PATH/); assert.match(stdout.lines[0], /E2E_TENANT_AUDIT_EXPORT_PATH/); assert.match(stdout.lines[0], /E2E_TENANT_PRIVACY_PATH/); assert.match(stdout.lines[0], /E2E_TENANT_CHATBOT_PATH/); assert.match(stdout.lines[0], /E2E_TENANT_AI_USAGE_PATH/); assert.match(stdout.lines[0], /E2E_TENANT_API_PATH/); assert.match(stdout.lines[0], /E2E_TENANT_API_KEYS_PATH/); assert.match(stdout.lines[0], /E2E_TENANT_API_DOCS_PATH/); assert.match(stdout.lines[0], /E2E_TENANT_API_LOGS_PATH/); assert.match(stdout.lines[0], /E2E_TENANT_POLICIES_PATH/); assert.match(stdout.lines[0], /E2E_TENANT_PORTAL_ANALYTICS_PATH/); assert.match(stdout.lines[0], /E2E_TENANT_PORTAL_SETTINGS_PATH/); assert.match(stdout.lines[0], /E2E_PLUGIN_SETTINGS_PATH/); assert.match(stdout.lines[0], /E2E_PLUGIN_READONLY_EMAIL/); assert.match(stdout.lines[0], /E2E_PLUGIN_READONLY_PASSWORD/); assert.match(stdout.lines[0], /E2E_WORKFLOW_ENGINE_PATH/); assert.match(stdout.lines[0], /E2E_WORKFLOW_BUILDER_PATH/); assert.match(stdout.lines[0], /E2E_WORKFLOW_RUN_API_PATH/); assert.match(stdout.lines[0], /E2E_WORKFLOW_RUN_MANUAL_PATH/); assert.match(stdout.lines[0], /E2E_WORKFLOW_WEBHOOK_BUILDER_PATH/); assert.match(stdout.lines[0], /E2E_WORKFLOW_WEBHOOK_RUN_MANUAL_PATH/); assert.match(stdout.lines[0], /E2E_WORKFLOW_WAITING_BUILDER_PATH/); assert.match(stdout.lines[0], /E2E_WORKFLOW_WAITING_RUN_MANUAL_PATH/); assert.match(stdout.lines[0], /E2E_WORKFLOW_WAITING_RUN_API_PATH/); assert.match(stdout.lines[0], /E2E_WORKFLOW_WAITING_EXECUTIONS_PATH/); assert.match(stdout.lines[0], /E2E_WORKFLOW_WAITING_EXECUTION_ID/); assert.match(stdout.lines[0], /PLUGIN_BINARY_BASE_PATH/); assert.doesNotMatch(stdout.lines[0], /E2E_TENANT_SUBSCRIPTION_SUCCESS_PATH/); assert.doesNotMatch(stdout.lines[0], /E2E_ALLOW_WORKFLOW_RUN=1/); assert.doesNotMatch(stdout.lines[0], /E2E_ALLOW_REGISTRATION_CREATE=1/); assert.equal(spawn.calls.filter((call) => call.command === "npx" && call.args[0] === "playwright").length, 0); }); it("accepts the complete readiness E2E env contract", () => { assert.deepEqual( missingReadinessEnv({ env: { E2E_TENANT_EMAIL: "user@example.test", E2E_TENANT_PASSWORD: "secret", E2E_REGISTRATION_EXPECTS_EMAIL_VERIFICATION: "0", E2E_TENANT_DASHBOARD_PATH: "/app/acme/dashboard", E2E_TENANT_SETTINGS_ACCOUNT_PATH: "/app/acme/settings/account", E2E_TENANT_SETTINGS_PROFILE_PATH: "/app/acme/settings/profile", E2E_TENANT_SUBSCRIPTION_PATH: "/app/acme/settings/subscription", E2E_TENANT_MEMBERS_PATH: "/app/acme/settings/members", E2E_TENANT_ROLES_AND_PERMISSIONS_PATH: "/app/acme/settings/roles-and-permissions", E2E_TENANT_NOTIFICATIONS_PATH: "/app/acme/settings/notifications", E2E_TENANT_LOGS_PATH: "/app/acme/settings/logs", E2E_TENANT_LOG_EVENTS_PATH: "/app/acme/settings/logs/events", E2E_TENANT_AUDIT_EXPORT_PATH: "/app/acme/settings/audit-export", E2E_TENANT_PRIVACY_PATH: "/app/acme/settings/privacy", E2E_TENANT_CHATBOT_PATH: "/app/acme/settings/chatbot", E2E_TENANT_AI_USAGE_PATH: "/app/acme/settings/ai-usage", E2E_TENANT_API_PATH: "/app/acme/settings/api", E2E_TENANT_API_KEYS_PATH: "/app/acme/settings/api/keys", E2E_TENANT_API_DOCS_PATH: "/app/acme/settings/api/docs", E2E_TENANT_API_LOGS_PATH: "/app/acme/settings/api/logs", E2E_TENANT_POLICIES_PATH: "/app/acme/settings/policies", E2E_TENANT_PORTAL_ANALYTICS_PATH: "/app/acme/portals/readiness/analytics", E2E_TENANT_PORTAL_SETTINGS_PATH: "/app/acme/portals/readiness/settings", E2E_ADMIN_EMAIL_SEQUENCES_PATH: "/admin/email-sequences", E2E_PLUGIN_SETTINGS_PATH: "/app/acme/settings/plugins/plugin-1", E2E_PLUGIN_READONLY_EMAIL: "plugin-readonly@example.test", E2E_PLUGIN_READONLY_PASSWORD: "readonly-secret", E2E_WORKFLOW_ENGINE_PATH: "/app/acme/workflows", E2E_WORKFLOW_BUILDER_PATH: "/app/acme/workflows/wf-1/builder", E2E_WORKFLOW_RUN_API_PATH: "/app/acme/workflows/wf-1/run/api", E2E_WORKFLOW_RUN_MANUAL_PATH: "/app/acme/workflows/wf-1/run", E2E_WORKFLOW_WEBHOOK_BUILDER_PATH: "/app/acme/workflows/wf-webhook/builder", E2E_WORKFLOW_WEBHOOK_RUN_MANUAL_PATH: "/app/acme/workflows/wf-webhook/run", E2E_WORKFLOW_WAITING_BUILDER_PATH: "/app/acme/workflows/wf-waiting/builder", E2E_WORKFLOW_WAITING_RUN_MANUAL_PATH: "/app/acme/workflows/wf-waiting/run", E2E_WORKFLOW_WAITING_RUN_API_PATH: "/app/acme/workflows/wf-waiting/run/api", E2E_WORKFLOW_WAITING_EXECUTIONS_PATH: "/app/acme/workflows/wf-waiting/executions", E2E_WORKFLOW_WAITING_EXECUTION_ID: "wfe-waiting-1", PLUGIN_BINARY_BASE_PATH: "/tmp/e2e-plugins", }, }), [] ); }); it("rejects whitespace-only readiness values before Playwright starts", () => { assert.deepEqual( missingReadinessEnv({ env: completeReadinessEnv({ E2E_TENANT_DASHBOARD_PATH: " ", E2E_PLUGIN_SETTINGS_PATH: "\n\t", E2E_WORKFLOW_RUN_MANUAL_PATH: "", }), }), ["E2E_TENANT_DASHBOARD_PATH", "E2E_PLUGIN_SETTINGS_PATH", "E2E_WORKFLOW_RUN_MANUAL_PATH"] ); }); it("keeps subscription success optional for normal readiness lanes", () => { const env = completeReadinessEnv(); assert.deepEqual(missingReadinessEnv({ env }), []); assert.deepEqual(missingSubscriptionSuccessReadinessEnv({ env }), []); }); it("requires readiness and mobile dashboard follow-through env when subscription success strict mode is enabled", () => { assert.deepEqual( missingSubscriptionSuccessReadinessEnv({ env: { E2E_REQUIRE_SUBSCRIPTION_SUCCESS: "1" }, }), ["E2E_TENANT_SUBSCRIPTION_SUCCESS_PATH", "E2E_TENANT_DASHBOARD_PATH", "REQUIRE_E2E_READINESS=1", "E2E_BROWSER_MATRIX=1"] ); assert.deepEqual( missingSubscriptionSuccessReadinessEnv({ env: completeReadinessEnv({ E2E_REQUIRE_SUBSCRIPTION_SUCCESS: "1", E2E_TENANT_SUBSCRIPTION_SUCCESS_PATH: "/subscribe/acme/cs_test_123/success", }), }), [] ); }); it("does not allow subscription success strict mode outside the readiness mobile matrix", () => { assert.deepEqual( missingSubscriptionSuccessReadinessEnv({ env: { E2E_REQUIRE_SUBSCRIPTION_SUCCESS: "1", E2E_TENANT_SUBSCRIPTION_SUCCESS_PATH: "/subscribe/acme/cs_test_123/success", E2E_TENANT_DASHBOARD_PATH: "/app/acme/dashboard", }, }), ["REQUIRE_E2E_READINESS=1", "E2E_BROWSER_MATRIX=1"] ); }); it("requires strict a11y, real workflow execution, and the mobile browser matrix for readiness lanes", () => { assert.deepEqual( missingReadinessModeEnv({ env: { E2E_A11Y_STRICT: "1", }, }), ["E2E_BROWSER_MATRIX=1", "E2E_ALLOW_WORKFLOW_RUN=1"] ); assert.deepEqual( missingReadinessModeEnv({ env: { E2E_A11Y_STRICT: "1", E2E_BROWSER_MATRIX: "1", E2E_ALLOW_WORKFLOW_RUN: "1", }, }), [] ); }); it("requires core mutating opt-ins for readiness lanes", () => { assert.deepEqual( missingReadinessMutatingOptInEnv({ env: { E2E_ALLOW_REGISTRATION_CREATE: "1", E2E_ALLOW_ACCOUNT_CREATE: "1", }, }), [ "E2E_ALLOW_NO_TENANT_ACCOUNT_CREATE=1", "E2E_ALLOW_PLUGIN_LIFECYCLE_MUTATION=1", "E2E_ALLOW_PLUGIN_SETTINGS_WRITE=1", ] ); assert.deepEqual( missingReadinessMutatingOptInEnv({ env: { E2E_ALLOW_REGISTRATION_CREATE: "1", E2E_ALLOW_ACCOUNT_CREATE: "1", E2E_ALLOW_NO_TENANT_ACCOUNT_CREATE: "1", E2E_ALLOW_PLUGIN_LIFECYCLE_MUTATION: "1", E2E_ALLOW_PLUGIN_SETTINGS_WRITE: "1", }, }), [] ); }); it("requires no-tenant credentials whenever no-tenant account creation is enabled", () => { assert.deepEqual(missingNoTenantAccountCreateEnv({ env: {} }), []); assert.deepEqual( missingNoTenantAccountCreateEnv({ env: { E2E_ALLOW_NO_TENANT_ACCOUNT_CREATE: "1" }, }), ["E2E_NO_TENANT_EMAIL", "E2E_NO_TENANT_PASSWORD"] ); assert.deepEqual( missingNoTenantAccountCreateEnv({ env: { E2E_ALLOW_NO_TENANT_ACCOUNT_CREATE: "1", E2E_NO_TENANT_EMAIL: "no-tenant@example.test", E2E_NO_TENANT_PASSWORD: "NoTenantPass123!", }, }), [] ); }); it("fails before running Playwright when no-tenant account creation is enabled without credentials", () => { const spawn = recordingSpawn({ npx: ({ args }) => { if (args[0] === "--no-install") { return { status: 0, stdout: "Version 1.59.1", stderr: "" }; } return { status: 0, stdout: "", stderr: "" }; }, pnpm: () => ({ status: 0, stdout: "", stderr: "" }), curl: () => ({ status: 0, stdout: "200", stderr: "" }), }); const stdout = captureLines(); const outcome = runPlaywrightA11y({ env: { E2E_BASE_URL: "https://staging.example.test", E2E_ALLOW_NO_TENANT_ACCOUNT_CREATE: "1", }, spawn, stdout, }); assert.deepEqual(outcome, { status: "fail", reason: "no-tenant-account-create-env-missing", exitCode: 1 }); assert.deepEqual(stdout.lines, [ "FAIL: E2E no-tenant account creation env missing: E2E_NO_TENANT_EMAIL, E2E_NO_TENANT_PASSWORD while E2E_ALLOW_NO_TENANT_ACCOUNT_CREATE=1.", ]); assert.equal(spawn.calls.length, 0); }); it("fails before running Playwright when readiness mode is not strict/mobile", () => { const spawn = recordingSpawn({ npx: ({ args }) => { if (args[0] === "--no-install") { return { status: 0, stdout: "Version 1.59.1", stderr: "" }; } return { status: 0, stdout: "", stderr: "" }; }, pnpm: () => ({ status: 0, stdout: "", stderr: "" }), curl: () => ({ status: 0, stdout: "200", stderr: "" }), }); const stdout = captureLines(); const outcome = runPlaywrightA11y({ env: { E2E_BASE_URL: "https://staging.example.test", E2E_TENANT_EMAIL: "user@example.test", E2E_TENANT_PASSWORD: "secret", E2E_REGISTRATION_EXPECTS_EMAIL_VERIFICATION: "0", E2E_TENANT_DASHBOARD_PATH: "/app/acme/dashboard", E2E_TENANT_SETTINGS_ACCOUNT_PATH: "/app/acme/settings/account", E2E_TENANT_SETTINGS_PROFILE_PATH: "/app/acme/settings/profile", E2E_TENANT_SUBSCRIPTION_PATH: "/app/acme/settings/subscription", E2E_TENANT_MEMBERS_PATH: "/app/acme/settings/members", E2E_TENANT_ROLES_AND_PERMISSIONS_PATH: "/app/acme/settings/roles-and-permissions", E2E_TENANT_NOTIFICATIONS_PATH: "/app/acme/settings/notifications", E2E_TENANT_LOGS_PATH: "/app/acme/settings/logs", E2E_TENANT_LOG_EVENTS_PATH: "/app/acme/settings/logs/events", E2E_TENANT_AUDIT_EXPORT_PATH: "/app/acme/settings/audit-export", E2E_TENANT_PRIVACY_PATH: "/app/acme/settings/privacy", E2E_TENANT_CHATBOT_PATH: "/app/acme/settings/chatbot", E2E_TENANT_AI_USAGE_PATH: "/app/acme/settings/ai-usage", E2E_TENANT_API_PATH: "/app/acme/settings/api", E2E_TENANT_API_KEYS_PATH: "/app/acme/settings/api/keys", E2E_TENANT_API_DOCS_PATH: "/app/acme/settings/api/docs", E2E_TENANT_API_LOGS_PATH: "/app/acme/settings/api/logs", E2E_TENANT_POLICIES_PATH: "/app/acme/settings/policies", E2E_TENANT_PORTAL_ANALYTICS_PATH: "/app/acme/portals/readiness/analytics", E2E_TENANT_PORTAL_SETTINGS_PATH: "/app/acme/portals/readiness/settings", E2E_ADMIN_EMAIL_SEQUENCES_PATH: "/admin/email-sequences", E2E_PLUGIN_SETTINGS_PATH: "/app/acme/settings/plugins/plugin-1", E2E_PLUGIN_READONLY_EMAIL: "plugin-readonly@example.test", E2E_PLUGIN_READONLY_PASSWORD: "readonly-secret", E2E_WORKFLOW_ENGINE_PATH: "/app/acme/workflows", E2E_WORKFLOW_BUILDER_PATH: "/app/acme/workflows/wf-1/builder", E2E_WORKFLOW_RUN_API_PATH: "/app/acme/workflows/wf-1/run/api", E2E_WORKFLOW_RUN_MANUAL_PATH: "/app/acme/workflows/wf-1/run", E2E_WORKFLOW_WEBHOOK_BUILDER_PATH: "/app/acme/workflows/wf-webhook/builder", E2E_WORKFLOW_WEBHOOK_RUN_MANUAL_PATH: "/app/acme/workflows/wf-webhook/run", E2E_WORKFLOW_WAITING_BUILDER_PATH: "/app/acme/workflows/wf-waiting/builder", E2E_WORKFLOW_WAITING_RUN_MANUAL_PATH: "/app/acme/workflows/wf-waiting/run", E2E_WORKFLOW_WAITING_RUN_API_PATH: "/app/acme/workflows/wf-waiting/run/api", E2E_WORKFLOW_WAITING_EXECUTIONS_PATH: "/app/acme/workflows/wf-waiting/executions", E2E_WORKFLOW_WAITING_EXECUTION_ID: "wfe-waiting-1", PLUGIN_BINARY_BASE_PATH: "/tmp/e2e-plugins", REQUIRE_E2E_READINESS: "1", }, spawn, stdout, }); assert.deepEqual(outcome, { status: "fail", reason: "readiness-mode-missing", exitCode: 1 }); assert.deepEqual(stdout.lines, ["FAIL: E2E readiness mode missing: E2E_A11Y_STRICT=1, E2E_BROWSER_MATRIX=1, E2E_ALLOW_WORKFLOW_RUN=1."]); assert.equal(spawn.calls.filter((call) => call.command === "pnpm" && call.args[0] === "exec").length, 0); }); it("does not require mutating opt-ins for normal non-mutating readiness lanes", () => { const spawn = recordingSpawn({ npx: ({ args }) => { if (args[0] === "--no-install") { return { status: 0, stdout: "Version 1.59.1", stderr: "" }; } return { status: 0, stdout: "", stderr: "" }; }, pnpm: () => ({ status: 0, stdout: "", stderr: "" }), curl: () => ({ status: 0, stdout: "200", stderr: "" }), }); const stdout = captureLines(); const outcome = runPlaywrightA11y({ env: completeReadinessEnv({ E2E_ALLOW_REGISTRATION_CREATE: undefined, E2E_ALLOW_ACCOUNT_CREATE: undefined, E2E_ALLOW_NO_TENANT_ACCOUNT_CREATE: undefined, E2E_ALLOW_PLUGIN_LIFECYCLE_MUTATION: undefined, E2E_ALLOW_PLUGIN_SETTINGS_WRITE: undefined, }), spawn, stdout, }); assert.deepEqual(outcome, { status: "pass", reason: "ok", exitCode: 0 }); assert.equal(spawn.calls.filter((call) => call.command === "pnpm" && call.args[0] === "exec").length, 1); }); it("fails before running Playwright when mutating readiness opt-ins are missing", () => { const spawn = recordingSpawn({ npx: ({ args }) => { if (args[0] === "--no-install") { return { status: 0, stdout: "Version 1.59.1", stderr: "" }; } return { status: 0, stdout: "", stderr: "" }; }, pnpm: () => ({ status: 0, stdout: "", stderr: "" }), curl: () => ({ status: 0, stdout: "200", stderr: "" }), }); const stdout = captureLines(); const outcome = runPlaywrightA11y({ env: completeReadinessEnv({ E2E_ALLOW_REGISTRATION_CREATE: undefined, E2E_ALLOW_ACCOUNT_CREATE: undefined, E2E_ALLOW_NO_TENANT_ACCOUNT_CREATE: undefined, E2E_ALLOW_PLUGIN_LIFECYCLE_MUTATION: undefined, E2E_ALLOW_PLUGIN_SETTINGS_WRITE: undefined, REQUIRE_E2E_MUTATING_READINESS: "1", }), spawn, stdout, }); assert.deepEqual(outcome, { status: "fail", reason: "readiness-mutating-opt-in-missing", exitCode: 1 }); assert.deepEqual(stdout.lines, [ "FAIL: E2E readiness mutating opt-in missing: E2E_ALLOW_REGISTRATION_CREATE=1, E2E_ALLOW_ACCOUNT_CREATE=1, E2E_ALLOW_NO_TENANT_ACCOUNT_CREATE=1, E2E_ALLOW_PLUGIN_LIFECYCLE_MUTATION=1, E2E_ALLOW_PLUGIN_SETTINGS_WRITE=1.", ]); assert.equal(spawn.calls.filter((call) => call.command === "pnpm" && call.args[0] === "exec").length, 0); }); it("fails before running Playwright when subscription success strict mode is missing its path", () => { const spawn = recordingSpawn({ npx: ({ args }) => { if (args[0] === "--no-install") { return { status: 0, stdout: "Version 1.59.1", stderr: "" }; } return { status: 0, stdout: "", stderr: "" }; }, pnpm: () => ({ status: 0, stdout: "", stderr: "" }), curl: () => ({ status: 0, stdout: "200", stderr: "" }), }); const stdout = captureLines(); const outcome = runPlaywrightA11y({ env: completeReadinessEnv({ E2E_REQUIRE_SUBSCRIPTION_SUCCESS: "1" }), spawn, stdout, }); assert.deepEqual(outcome, { status: "fail", reason: "subscription-success-readiness-env-missing", exitCode: 1 }); assert.deepEqual(stdout.lines, [ "FAIL: E2E subscription success readiness env missing: E2E_TENANT_SUBSCRIPTION_SUCCESS_PATH while E2E_REQUIRE_SUBSCRIPTION_SUCCESS=1.", ]); assert.equal(spawn.calls.filter((call) => call.command === "pnpm" && call.args[0] === "exec").length, 0); }); it("fails before running Playwright when real workflow webhook execution lacks its target contract", () => { const spawn = recordingSpawn({}); const stdout = captureLines(); assert.deepEqual( missingWorkflowWebhookRunReadinessEnv({ env: { E2E_ALLOW_WORKFLOW_WEBHOOK_RUN: "1" }, }), [ "E2E_TENANT_EMAIL", "E2E_TENANT_PASSWORD", "E2E_WORKFLOW_WEBHOOK_BUILDER_PATH", "E2E_WORKFLOW_WEBHOOK_RUN_MANUAL_PATH", "E2E_WORKFLOW_WEBHOOK_TARGET_URL", ] ); assert.deepEqual( missingWorkflowWebhookRunReadinessEnv({ env: completeReadinessEnv({ E2E_ALLOW_WORKFLOW_WEBHOOK_RUN: "1", E2E_WORKFLOW_WEBHOOK_TARGET_URL: "https://hooks.example.test/readiness", }), }), [] ); const outcome = runPlaywrightA11y({ env: completeReadinessEnv({ E2E_ALLOW_WORKFLOW_WEBHOOK_RUN: "1", E2E_WORKFLOW_WEBHOOK_TARGET_URL: "", }), spawn, stdout, }); assert.deepEqual(outcome, { status: "fail", reason: "workflow-webhook-run-readiness-env-missing", exitCode: 1 }); assert.deepEqual(stdout.lines, [ "FAIL: E2E workflow webhook run readiness env missing: E2E_WORKFLOW_WEBHOOK_TARGET_URL while E2E_ALLOW_WORKFLOW_WEBHOOK_RUN=1.", ]); assert.equal(spawn.calls.length, 0); }); it("fails before running Playwright when workflow outbox-drain readiness is misconfigured", () => { const spawn = recordingSpawn({}); const stdout = captureLines(); assert.deepEqual( missingWorkflowOutboxDrainReadinessEnv({ env: { E2E_REQUIRE_WORKFLOW_OUTBOX_DRAIN: "1", E2E_WORKFLOW_OUTBOX_DRAIN_EXPECTED_STATUS: "done" }, }), [ "E2E_TENANT_EMAIL", "E2E_TENANT_PASSWORD", "E2E_WORKFLOW_RUN_MANUAL_PATH", "E2E_WORKFLOW_OUTBOX_DRAIN_EXPECTED_STATUS=success|error", ] ); assert.deepEqual( missingWorkflowOutboxDrainReadinessEnv({ env: completeReadinessEnv({ E2E_REQUIRE_WORKFLOW_OUTBOX_DRAIN: "1", E2E_WORKFLOW_OUTBOX_DRAIN_EXPECTED_STATUS: "error", }), }), [] ); const outcome = runPlaywrightA11y({ env: completeReadinessEnv({ E2E_REQUIRE_WORKFLOW_OUTBOX_DRAIN: "1", E2E_WORKFLOW_OUTBOX_DRAIN_EXPECTED_STATUS: "done", }), spawn, stdout, }); assert.deepEqual(outcome, { status: "fail", reason: "workflow-outbox-drain-readiness-env-missing", exitCode: 1 }); assert.deepEqual(stdout.lines, [ "FAIL: E2E workflow outbox-drain readiness env missing: E2E_WORKFLOW_OUTBOX_DRAIN_EXPECTED_STATUS=success|error while E2E_REQUIRE_WORKFLOW_OUTBOX_DRAIN=1.", ]); assert.equal(spawn.calls.length, 0); }); it("static contract keeps subscription success strict mode explicit", () => { const runnerSource = readFileSync("scripts/run-playwright-a11y.mjs", "utf8"); const subscriptionSource = readFileSync("tests/e2e/subscription-smoke.spec.ts", "utf8"); const readinessDocs = readFileSync("docs/testing/e2e-readiness.md", "utf8"); assert.match(runnerSource, /E2E_REQUIRE_SUBSCRIPTION_SUCCESS/u); assert.match(runnerSource, /E2E_TENANT_SUBSCRIPTION_SUCCESS_PATH/u); assert.match(subscriptionSource, /E2E_REQUIRE_SUBSCRIPTION_SUCCESS/u); assert.match( subscriptionSource, /Subscription checkout success smoke requires E2E_TENANT_SUBSCRIPTION_SUCCESS_PATH while E2E_REQUIRE_SUBSCRIPTION_SUCCESS=1/u ); assert.match(subscriptionSource, /follows checkout success return into the tenant dashboard on mobile when strict mode is enabled/u); assert.match(subscriptionSource, /await expectTenantDashboard\(page\)/u); assert.match(readinessDocs, /Normal\s+readiness runs stay non-mutating and do not require\s+`E2E_TENANT_SUBSCRIPTION_SUCCESS_PATH`/u); assert.match(readinessDocs, /`E2E_REQUIRE_SUBSCRIPTION_SUCCESS=1`/u); }); it("requires plugin settings and workflow fixtures separately from mutating opt-ins", () => { assert.deepEqual( missingReadinessEnv({ env: { E2E_TENANT_EMAIL: "user@example.test", E2E_TENANT_PASSWORD: "secret", E2E_TENANT_DASHBOARD_PATH: "/app/acme/dashboard", E2E_TENANT_SUBSCRIPTION_PATH: "/app/acme/settings/subscription", E2E_WORKFLOW_RUN_MANUAL_PATH: "/app/acme/workflows/wf-1/run", E2E_WORKFLOW_WEBHOOK_RUN_MANUAL_PATH: "/app/acme/workflows/wf-webhook/run", PLUGIN_BINARY_BASE_PATH: "/tmp/e2e-plugins", }, }), [ "E2E_REGISTRATION_EXPECTS_EMAIL_VERIFICATION", "E2E_TENANT_SETTINGS_ACCOUNT_PATH", "E2E_TENANT_SETTINGS_PROFILE_PATH", "E2E_TENANT_MEMBERS_PATH", "E2E_TENANT_ROLES_AND_PERMISSIONS_PATH", "E2E_TENANT_NOTIFICATIONS_PATH", "E2E_TENANT_LOGS_PATH", "E2E_TENANT_LOG_EVENTS_PATH", "E2E_TENANT_AUDIT_EXPORT_PATH", "E2E_TENANT_PRIVACY_PATH", "E2E_TENANT_CHATBOT_PATH", "E2E_TENANT_AI_USAGE_PATH", "E2E_TENANT_API_PATH", "E2E_TENANT_API_KEYS_PATH", "E2E_TENANT_API_DOCS_PATH", "E2E_TENANT_API_LOGS_PATH", "E2E_TENANT_POLICIES_PATH", "E2E_TENANT_PORTAL_ANALYTICS_PATH", "E2E_TENANT_PORTAL_SETTINGS_PATH", "E2E_ADMIN_EMAIL_SEQUENCES_PATH", "E2E_PLUGIN_SETTINGS_PATH", "E2E_PLUGIN_READONLY_EMAIL", "E2E_PLUGIN_READONLY_PASSWORD", "E2E_WORKFLOW_ENGINE_PATH", "E2E_WORKFLOW_BUILDER_PATH", "E2E_WORKFLOW_RUN_API_PATH", "E2E_WORKFLOW_WEBHOOK_BUILDER_PATH", "E2E_WORKFLOW_WAITING_BUILDER_PATH", "E2E_WORKFLOW_WAITING_RUN_MANUAL_PATH", "E2E_WORKFLOW_WAITING_RUN_API_PATH", "E2E_WORKFLOW_WAITING_EXECUTIONS_PATH", "E2E_WORKFLOW_WAITING_EXECUTION_ID", ] ); }); it("rejects invalid explicit registration email verification readiness assertions", () => { assert.deepEqual( missingReadinessEnv({ env: completeReadinessEnv({ E2E_REGISTRATION_EXPECTS_EMAIL_VERIFICATION: "yes", }), }), ["E2E_REGISTRATION_EXPECTS_EMAIL_VERIFICATION=0|1"] ); }); it("keeps persistent plugin lifecycle E2E flows behind explicit opt-in", () => { const source = readFileSync( "tests/e2e/plugin-settings.mobile-a11y.spec.ts", "utf8" ); assert.match(source, /skipOrFailWhenE2eOptInMissing/u); assert.match(source, /E2E_ALLOW_PLUGIN_LIFECYCLE_MUTATION/u); assert.match(source, /E2E_ALLOW_PLUGIN_SETTINGS_WRITE/u); assert.match( source, /test\("capability grant and revoke persist for the seeded readiness plugin"[\s\S]*?skipUnlessPluginLifecycleMutationAllowed\("capability grant\/revoke persistence flow"\)/u ); assert.match( source, /test\("lifecycle controls persist enable and disable state for the seeded lifecycle plugin"[\s\S]*?skipUnlessPluginLifecycleMutationAllowed\("enable\/disable persistence flow"\)/u ); }); it("keeps mutating registration and account E2E flows readiness-aware behind explicit opt-ins", () => { const source = readFileSync( "tests/e2e/registration-account-dashboard.mobile-a11y.spec.ts", "utf8" ); assert.match(source, /skipOrFailWhenE2eOptInMissing\("E2E_ALLOW_REGISTRATION_CREATE"/u); assert.match(source, /skipOrFailWhenE2eOptInMissing\("E2E_ALLOW_ACCOUNT_CREATE"/u); assert.match(source, /skipOrFailWhenE2eOptInMissing\("E2E_ALLOW_NO_TENANT_ACCOUNT_CREATE"/u); assert.doesNotMatch(source, /test\.skip\(process\.env\.E2E_ALLOW_(?:REGISTRATION_CREATE|ACCOUNT_CREATE|NO_TENANT_ACCOUNT_CREATE)/u); }); it("keeps the local mutating E2E readiness lane explicit and documented", () => { const packageJson = JSON.parse(readFileSync("package.json", "utf8")); const script = packageJson.scripts["verify:e2e-mutating-readiness:local"]; const docs = readFileSync("docs/testing/e2e-readiness.md", "utf8"); const requiredFlags = [ "REQUIRE_E2E_MUTATING_READINESS=1", "E2E_ALLOW_REGISTRATION_CREATE=1", "E2E_ALLOW_ACCOUNT_CREATE=1", "E2E_ALLOW_NO_TENANT_ACCOUNT_CREATE=1", "E2E_ALLOW_PLUGIN_LIFECYCLE_MUTATION=1", "E2E_ALLOW_PLUGIN_SETTINGS_WRITE=1", ]; assert.equal(typeof script, "string"); assert.match(script, /pnpm run verify:e2e-a11y/u); assert.match(docs, /verify:e2e-mutating-readiness:local/u); for (const flag of requiredFlags) { assert.match(script, new RegExp(flag, "u")); assert.match(docs, new RegExp(flag, "u")); } assert.match(docs, /E2E_NO_TENANT_EMAIL/u); assert.match(docs, /E2E_NO_TENANT_PASSWORD/u); }); it("keeps the local worker-drain E2E readiness lane explicit and documented", () => { const packageJson = JSON.parse(readFileSync("package.json", "utf8")); const script = packageJson.scripts["verify:e2e-mutating-readiness:worker-local"]; const docs = readFileSync("docs/testing/e2e-readiness.md", "utf8"); assert.equal(typeof script, "string"); assert.match(script, /E2E_REQUIRE_WORKFLOW_OUTBOX_DRAIN=1/u); assert.match(script, /pnpm run verify:e2e-mutating-readiness:local/u); assert.match(docs, /verify:e2e-mutating-readiness:worker-local/u); assert.match(docs, /E2E_REQUIRE_WORKFLOW_OUTBOX_DRAIN=1/u); assert.match(docs, /WorkflowExecution\.status/u); }); it("keeps real workflow webhook E2E runs behind explicit opt-in and target URL", () => { const source = readFileSync( "tests/e2e/workflow-builder-run.mobile-a11y.spec.ts", "utf8" ); assert.match(source, /E2E_ALLOW_WORKFLOW_WEBHOOK_RUN/u); assert.match(source, /E2E_WORKFLOW_WEBHOOK_TARGET_URL/u); assert.match(source, /E2E_WORKFLOW_WEBHOOK_BUILDER_PATH/u); assert.match(source, /E2E_WORKFLOW_WEBHOOK_RUN_MANUAL_PATH/u); assert.match(source, /E2E workflow webhook run opt-in missing/u); assert.match( source, /if \(allowWorkflowWebhookRun\)[\s\S]*?requireWorkflowWebhookRunReadiness\(\)[\s\S]*?else[\s\S]*?skipOrFailWhenE2eInputsMissing/u ); assert.match( source, /if \(allowWorkflowWebhookRun\)[\s\S]*?workflowWebhookTargetUrl![\s\S]*?else[\s\S]*?interceptCurrentRoutePost/u ); }); it("runs Playwright when runtime and target are reachable", () => { const spawn = recordingSpawn({ npx: ({ args }) => { if (args[0] === "--no-install") { return { status: 0, stdout: "Version 1.59.1", stderr: "" }; } return { status: 0, stdout: "", stderr: "" }; }, pnpm: () => ({ status: 0, stdout: "", stderr: "" }), curl: () => ({ status: 0, stdout: "200", stderr: "" }), }); const stdout = captureLines(); const outcome = runPlaywrightA11y({ env: { E2E_BASE_URL: "https://staging.example.test" }, spawn, stdout, }); assert.deepEqual(outcome, { status: "pass", reason: "ok", exitCode: 0 }); const runCall = spawn.calls.find((call) => call.command === "pnpm" && call.args[0] === "exec"); assert.ok(runCall, "expected playwright test to be invoked"); assert.deepEqual(runCall.args, ["exec", "playwright", "test", "--config=playwright.config.ts"]); assert.deepEqual(runCall.options, { stdio: "inherit" }); }); it("returns the Playwright exit status when the suite fails", () => { const spawn = recordingSpawn({ npx: ({ args }) => { if (args[0] === "--no-install") { return { status: 0, stdout: "Version 1.59.1", stderr: "" }; } return { status: 0, stdout: "", stderr: "" }; }, pnpm: () => ({ status: 3, stdout: "", stderr: "failed" }), curl: () => ({ status: 0, stdout: "200", stderr: "" }), }); const outcome = runPlaywrightA11y({ env: {}, spawn, stdout: captureLines() }); assert.deepEqual(outcome, { status: "fail", reason: "non-zero-exit", exitCode: 3 }); }); it("treats a valid curl status body as reachable", () => { const spawn = recordingSpawn({ curl: () => ({ status: 0, stdout: "503", stderr: "" }), }); assert.equal(isUrlReachable("https://degraded.example.test", { spawn }), true); }); it("treats server errors as unreachable in strict readiness mode", () => { const spawn = recordingSpawn({ npx: ({ args }) => { if (args[0] === "--no-install") { return { status: 0, stdout: "Version 1.59.1", stderr: "" }; } return { status: 0, stdout: "", stderr: "" }; }, curl: () => ({ status: 0, stdout: "503", stderr: "" }), }); const stdout = captureLines(); assert.equal(isUrlReachable("https://degraded.example.test", { spawn, allowServerErrors: false }), false); const outcome = runPlaywrightA11y({ env: { E2E_BASE_URL: "https://degraded.example.test", REQUIRE_E2E_A11Y: "1" }, spawn, stdout, }); assert.deepEqual(outcome, { status: "fail", reason: "target-unreachable", exitCode: 1 }); assert.deepEqual(stdout.lines, ["FAIL: Target URL https://degraded.example.test not reachable while REQUIRE_E2E_A11Y=1."]); assert.equal(spawn.calls.filter((call) => call.command === "pnpm").length, 0); }); });