import { createRequire } from "node:module"; import { randomUUID } from "node:crypto"; import { execFileSync } from "node:child_process"; import { mkdir } from "node:fs/promises"; import { fileURLToPath } from "node:url"; const require = createRequire(process.env.PLAYWRIGHT_REQUIRE_FROM ?? import.meta.url); const { chromium } = require("playwright"); const outputDirectory = new URL("./screenshots/", import.meta.url); const webURL = process.env.VISUAL_WEB_URL ?? "http://localhost:3100"; const webHostPattern = new RegExp(new URL(webURL).host.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")); const oidcURLPattern = new RegExp(process.env.VISUAL_OIDC_URL_PATTERN ?? "localhost:58180"); const username = process.env.VISUAL_USERNAME ?? "owner"; const password = process.env.VISUAL_PASSWORD ?? "LocalOnly123!"; const contextID = randomUUID(); const contextPublicID = randomUUID(); const conversationID = randomUUID(); const conversationPublicID = randomUUID(); const jobID = randomUUID(); const jobPublicID = randomUUID(); const jobAggregateID = randomUUID(); const issueOpenID = randomUUID(); const issueOpenPublicID = randomUUID(); const issueProgressID = randomUUID(); const issueProgressPublicID = randomUUID(); const issueResolvedID = randomUUID(); const issueResolvedPublicID = randomUUID(); const issueVerifiedID = randomUUID(); const issueVerifiedPublicID = randomUUID(); const issueClosedID = randomUUID(); const issueClosedPublicID = randomUUID(); const accessReviewID = randomUUID(); const accessReviewPublicID = randomUUID(); await mkdir(outputDirectory, { recursive: true }); function psql(statement) { return execFileSync("docker", ["compose", "exec", "-T", "postgres", "psql", "-v", "ON_ERROR_STOP=1", "-U", "voice", "-d", "voice_platform", "-Atc", statement], { cwd: process.cwd(), encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim(); } function cleanup() { psql(`BEGIN; DELETE FROM integration_issue WHERE id IN ('${issueOpenID}'::uuid,'${issueProgressID}'::uuid,'${issueResolvedID}'::uuid,'${issueVerifiedID}'::uuid,'${issueClosedID}'::uuid); DELETE FROM outbox_event WHERE id='${jobID}'::uuid; DELETE FROM ops_sensitive_access_request WHERE conversation_id='${conversationID}'::uuid; DELETE FROM conversation_state_history WHERE conversation_id='${conversationID}'::uuid; DELETE FROM conversation WHERE id='${conversationID}'::uuid; DELETE FROM context_snapshot WHERE id='${contextID}'::uuid; COMMIT;`); } psql(`BEGIN; INSERT INTO context_snapshot(id,public_id,tenant_id,subject_id,profile_version,consent_snapshot_id,memory_versions,prompt_bundle_version,engine_mode,content_digest,sanitized_summary,preparation_status) VALUES('${contextID}'::uuid,'${contextPublicID}'::uuid,'10000000-0000-0000-0000-000000000001'::uuid,'10000000-0000-0000-0000-000000000401'::uuid,1,'10000000-0000-0000-0000-000000000701'::uuid,'[]'::jsonb,'visual-sensitive-request-v1','s2s_hybrid','1111111111111111111111111111111111111111111111111111111111111111','运营敏感访问申请页面夹具','READY'); INSERT INTO conversation(id,public_id,tenant_id,household_id,subject_id,device_id,consent_snapshot_id,context_snapshot_id,provider_task_ref,engine_mode,retention_mode,status,allocation_expires_at,started_at,ended_at,stop_reason) VALUES('${conversationID}'::uuid,'${conversationPublicID}'::uuid,'10000000-0000-0000-0000-000000000001'::uuid,'10000000-0000-0000-0000-000000000201'::uuid,'10000000-0000-0000-0000-000000000401'::uuid,'10000000-0000-0000-0000-000000000501'::uuid,'10000000-0000-0000-0000-000000000701'::uuid,'${contextID}'::uuid,'visual-sensitive-${conversationPublicID}','s2s_hybrid','transcript_only','ROOM_ISSUED',now()+interval '5 minutes',now()-interval '2 minutes',NULL,NULL); INSERT INTO conversation_state_history(conversation_id,from_status,to_status,reason,source,occurred_at) VALUES('${conversationID}'::uuid,NULL,'ROOM_ISSUED','visual fixture','platform',now()-interval '2 minutes'); INSERT INTO outbox_event(id,public_id,tenant_id,aggregate_type,aggregate_id,event_type,payload,status,attempt_count,last_error_code,dead_at,payload_hash) VALUES('${jobID}'::uuid,'${jobPublicID}'::uuid,'10000000-0000-0000-0000-000000000001'::uuid,'visual_control','${jobAggregateID}'::uuid,'platform.noop','{}'::jsonb,'dead',8,'VISUAL_DEPENDENCY_FAILURE',now(),repeat('0',64)); INSERT INTO integration_issue(id,public_id,tenant_id,phenomenon,severity,device_id,conversation_id,occurred_at,request_id,responsible_party,status,resolution_result,root_cause,fixed_version,regression_conclusion,regression_evidence,created_by,updated_by,version) VALUES ('${issueOpenID}'::uuid,'${issueOpenPublicID}'::uuid,'10000000-0000-0000-0000-000000000001'::uuid,'页面流转夹具:待处理问题','MEDIUM','10000000-0000-0000-0000-000000000501'::uuid,'${conversationID}'::uuid,now()-interval '5 minutes','visual-issue-open','硬件团队','OPEN',NULL,NULL,NULL,NULL,NULL,'10000000-0000-0000-0000-000000000101'::uuid,'10000000-0000-0000-0000-000000000101'::uuid,3), ('${issueProgressID}'::uuid,'${issueProgressPublicID}'::uuid,'10000000-0000-0000-0000-000000000001'::uuid,'页面流转夹具:处理中问题','MEDIUM','10000000-0000-0000-0000-000000000501'::uuid,'${conversationID}'::uuid,now()-interval '4 minutes','visual-issue-progress','Agent研发组','IN_PROGRESS',NULL,NULL,NULL,NULL,NULL,'10000000-0000-0000-0000-000000000101'::uuid,'10000000-0000-0000-0000-000000000101'::uuid,4), ('${issueResolvedID}'::uuid,'${issueResolvedPublicID}'::uuid,'10000000-0000-0000-0000-000000000001'::uuid,'页面流转夹具:待回归问题','LOW','10000000-0000-0000-0000-000000000501'::uuid,'${conversationID}'::uuid,now()-interval '3 minutes','visual-issue-resolved','云端研发组','RESOLVED','已修复状态映射','状态映射遗漏','0.56.0-rc.1',NULL,NULL,'10000000-0000-0000-0000-000000000101'::uuid,'10000000-0000-0000-0000-000000000101'::uuid,5), ('${issueVerifiedID}'::uuid,'${issueVerifiedPublicID}'::uuid,'10000000-0000-0000-0000-000000000001'::uuid,'页面流转夹具:已验证问题','LOW','10000000-0000-0000-0000-000000000501'::uuid,'${conversationID}'::uuid,now()-interval '2 minutes','visual-issue-verified','云端研发组','VERIFIED','已修复状态映射','状态映射遗漏','0.56.0-rc.1','连续验证3次均未复现','请求 visual-regression-001','10000000-0000-0000-0000-000000000101'::uuid,'10000000-0000-0000-0000-000000000101'::uuid,6), ('${issueClosedID}'::uuid,'${issueClosedPublicID}'::uuid,'10000000-0000-0000-0000-000000000001'::uuid,'页面流转夹具:已关闭问题','LOW','10000000-0000-0000-0000-000000000501'::uuid,'${conversationID}'::uuid,now()-interval '1 minute','visual-issue-closed','云端研发组','CLOSED','已修复状态映射','状态映射遗漏','0.56.0-rc.1','连续验证3次均未复现','请求 visual-regression-002','10000000-0000-0000-0000-000000000101'::uuid,'10000000-0000-0000-0000-000000000101'::uuid,7); INSERT INTO ops_sensitive_access_request(id,public_id,tenant_id,conversation_id,requester_user_id,capabilities,reason,requested_expires_at,status,version) VALUES('${accessReviewID}'::uuid,'${accessReviewPublicID}'::uuid,'10000000-0000-0000-0000-000000000001'::uuid,'${conversationID}'::uuid,'10000000-0000-0000-0000-000000000102'::uuid,ARRAY['RECORDING_PLAY','TRANSCRIPT_READ'],'页面审批夹具:核对转写时间轴和原录音片段',now()+interval '1 hour','PENDING',4); COMMIT;`); const browser = await chromium.launch({ headless: true, executablePath: process.env.CHROME_PATH ?? "C:/Program Files/Google/Chrome/Application/chrome.exe" }); const page = await browser.newPage({ viewport: { width: 1440, height: 1100 }, deviceScaleFactor: 1 }); const consoleErrors = []; const failedRequests = []; const accessMutations = []; const controlMutations = []; const issueMutations = []; page.on("console", (message) => { if (message.type() === "error") consoleErrors.push(message.text()); }); page.on("request", (request) => { if (request.method() === "POST" && /\/api\/v1\/ops\/sensitive-access-requests(\/|$)/.test(request.url())) accessMutations.push(`${request.method()} ${request.url()}`); if (request.method() === "POST" && /\/api\/v1\/ops\/diagnostics\/(conversations|devices|jobs|bundles)(\/|$)/.test(request.url())) controlMutations.push(`${request.method()} ${request.url()}`); if (request.method() === "PATCH" && /\/api\/v1\/ops\/integration-issues\//.test(request.url())) issueMutations.push(`${request.method()} ${request.url()}`); }); page.on("requestfailed", (request) => { const failure = request.failure()?.errorText ?? "failed"; const requestURL = new URL(request.url()); if (request.method() === "GET" && requestURL.pathname === "/api/v1/events" && failure.includes("ERR_ABORTED")) return; failedRequests.push(`${request.method()} ${request.url()} ${failure}`); }); try { await page.goto(`${webURL}/?workspace=diagnostics`, { waitUntil: "networkidle" }); await page.getByRole("button", { name: "登录研发环境" }).click(); await page.waitForURL(oidcURLPattern); await page.locator("#username").fill(username); await page.locator("#password").fill(password); await page.locator("#kc-login").click(); await page.waitForURL(webHostPattern, { timeout: 15000 }); await page.getByRole("heading", { name: "设备与通话联调" }).waitFor(); await page.getByLabel("检索字段").selectOption("conversation_id"); await page.getByLabel("精确编号").fill(conversationPublicID); await page.getByRole("button", { name: "查询", exact: true }).click(); const resultCard = page.locator(".diagnostic-card").filter({ hasText: conversationPublicID }).first(); await resultCard.waitFor(); await page.getByRole("button", { name: "导出脱敏诊断包" }).click(); const bundleForm = page.getByRole("form", { name: "脱敏诊断包导出" }); await bundleForm.waitFor(); const bundleTargetBound = (await bundleForm.textContent())?.includes(conversationPublicID) === true && (await bundleForm.textContent())?.includes("通话编号") === true; const bundleEmptyReasonDisabled = await bundleForm.getByRole("button", { name: "生成并下载" }).isDisabled(); await bundleForm.getByLabel("导出原因").fill("用于验证当前联调记录的脱敏字段和状态关联"); const bundleCompletedEnabled = await bundleForm.getByRole("button", { name: "生成并下载" }).isEnabled(); await bundleForm.getByRole("button", { name: "取消" }).click(); const bundleCancelClosedForm = await bundleForm.count() === 0; const controlForm = page.getByRole("form", { name: "受控联调操作" }); await resultCard.getByRole("button", { name: "刷新配置" }).click(); await controlForm.waitFor(); const refreshEmptyReasonDisabled = await controlForm.getByRole("button", { name: "刷新设备配置" }).isDisabled(); const refreshTargetBound = (await controlForm.textContent())?.includes("10000000-0000-0000-0000-000000000511") === true; await controlForm.getByLabel("操作原因").fill("设备已在线,核对配置版本后重新触发拉取"); const refreshCompletedEnabled = await controlForm.getByRole("button", { name: "刷新设备配置" }).isEnabled(); await controlForm.getByRole("button", { name: "取消" }).click(); await resultCard.getByRole("button", { name: "状态对账" }).click(); await controlForm.waitFor(); const reconcileTargetBound = (await controlForm.textContent())?.includes(conversationPublicID) === true; await controlForm.getByLabel("操作原因").fill("云端与供应商任务状态需要重新核对"); const reconcileCompletedEnabled = await controlForm.getByRole("button", { name: "执行状态对账" }).isEnabled(); await controlForm.getByRole("button", { name: "取消" }).click(); await resultCard.getByRole("button", { name: "安全停止" }).click(); await controlForm.waitFor(); await controlForm.getByLabel("操作原因").fill("联调异常已复现,停止当前夹具通话"); const stopBlockedBeforeAcknowledgement = await controlForm.getByRole("button", { name: "安全停止通话" }).isDisabled(); await controlForm.getByLabel("我确认停止操作只针对上方指定通话,并已核对当前状态").check(); const stopEnabledAfterAcknowledgement = await controlForm.getByRole("button", { name: "安全停止通话" }).isEnabled(); await controlForm.getByRole("button", { name: "取消" }).click(); await resultCard.getByRole("button", { name: "吊销设备" }).click(); await controlForm.waitFor(); await controlForm.getByLabel("操作原因").fill("仅验证吊销确认门禁,不执行实际吊销"); const revokeBlockedBeforeAcknowledgement = await controlForm.getByRole("button", { name: "吊销设备身份" }).isDisabled(); await controlForm.getByLabel("我确认吊销后该设备的后续签名请求会被拒绝").check(); const revokeEnabledAfterAcknowledgement = await controlForm.getByRole("button", { name: "吊销设备身份" }).isEnabled(); await page.screenshot({ path: fileURLToPath(new URL("ops-controlled-diagnostic-action.png", outputDirectory)), fullPage: true }); await controlForm.getByRole("button", { name: "取消" }).click(); const controlCancelClosedForm = await controlForm.count() === 0; await page.getByRole("button", { name: "刷新任务" }).click(); const jobCard = page.locator(".diagnostic-card").filter({ hasText: "platform.noop" }).filter({ hasText: "visual_control" }).first(); await jobCard.waitFor(); await jobCard.getByRole("button", { name: "受控重试" }).click(); const retryForm = page.getByRole("form", { name: "死信任务受控重试" }); await retryForm.waitFor(); const retryTargetBound = (await retryForm.textContent())?.includes(jobPublicID) === true && (await retryForm.textContent())?.includes("VISUAL_DEPENDENCY_FAILURE") === true; const retryEmptyReasonDisabled = await retryForm.getByRole("button", { name: "确认受控重试" }).isDisabled(); await retryForm.getByLabel("重试原因").fill("依赖恢复情况已复核,本次仅验证页面门禁,不提交重试"); const retryBlockedBeforeAcknowledgement = await retryForm.getByRole("button", { name: "确认受控重试" }).isDisabled(); await retryForm.getByLabel("我已确认根因或依赖问题已经处理,并理解失败后任务仍可能再次进入死信").check(); const retryEnabledAfterAcknowledgement = await retryForm.getByRole("button", { name: "确认受控重试" }).isEnabled(); await page.screenshot({ path: fileURLToPath(new URL("ops-diagnostic-retry-and-export.png", outputDirectory)), fullPage: true }); await retryForm.getByRole("button", { name: "取消" }).click(); const retryCancelClosedForm = await retryForm.count() === 0; await page.getByLabel("问题状态筛选").selectOption(""); await page.waitForTimeout(400); await page.getByRole("button", { name: "刷新清单" }).click(); const openIssueCard = page.locator(".integration-issue-card").filter({ hasText: "页面流转夹具:待处理问题" }); const progressIssueCard = page.locator(".integration-issue-card").filter({ hasText: "页面流转夹具:处理中问题" }); const resolvedIssueCard = page.locator(".integration-issue-card").filter({ hasText: "页面流转夹具:待回归问题" }); const verifiedIssueCard = page.locator(".integration-issue-card").filter({ hasText: "页面流转夹具:已验证问题" }); const closedIssueCard = page.locator(".integration-issue-card").filter({ hasText: "页面流转夹具:已关闭问题" }); await Promise.all([openIssueCard.waitFor(), progressIssueCard.waitFor(), resolvedIssueCard.waitFor(), verifiedIssueCard.waitFor(), closedIssueCard.waitFor()]); const issueForm = page.getByRole("form", { name: "联调问题流转编辑" }); await openIssueCard.getByRole("button", { name: "调整级别" }).click(); await issueForm.waitFor(); const severityTargetBound = (await issueForm.textContent())?.includes(issueOpenPublicID) === true && (await issueForm.textContent())?.includes("ETag版本 3") === true; const sameSeverityDisabled = await issueForm.getByRole("button", { name: "保存级别" }).isDisabled(); await issueForm.getByLabel("严重级别").selectOption("CRITICAL"); const changedSeverityEnabled = await issueForm.getByRole("button", { name: "保存级别" }).isEnabled(); await issueForm.getByRole("button", { name: "取消" }).click(); await openIssueCard.getByRole("button", { name: "接手处理" }).click(); await issueForm.getByLabel("接手责任方").fill(""); const takeEmptyPartyDisabled = await issueForm.getByRole("button", { name: "确认接手" }).isDisabled(); await issueForm.getByLabel("接手责任方").fill("联调值班组"); const takeCompletedEnabled = await issueForm.getByRole("button", { name: "确认接手" }).isEnabled(); await issueForm.getByRole("button", { name: "取消" }).click(); await progressIssueCard.getByRole("button", { name: "登记解决" }).click(); const resolveEmptyDisabled = await issueForm.getByRole("button", { name: "提交解决记录" }).isDisabled(); await issueForm.getByLabel("根因结论").fill("设备状态映射缺少一个稳定分支"); await issueForm.getByLabel("修复版本或不可变构建标识").fill("0.56.0-rc.2"); await issueForm.getByLabel("解决结果").fill("补齐映射并完成本地复核"); const resolveCompletedEnabled = await issueForm.getByRole("button", { name: "提交解决记录" }).isEnabled(); await issueForm.getByRole("button", { name: "取消" }).click(); await resolvedIssueCard.getByRole("button", { name: "登记回归" }).click(); const verifyEmptyDisabled = await issueForm.getByRole("button", { name: "提交回归记录" }).isDisabled(); await issueForm.getByLabel("脱敏回归证据").fill("请求 visual-regression-003,连续执行3次"); await issueForm.getByLabel("回归结论").fill("三次结果一致,原问题未再复现"); const verifyCompletedEnabled = await issueForm.getByRole("button", { name: "提交回归记录" }).isEnabled(); await issueForm.getByRole("button", { name: "取消" }).click(); await verifiedIssueCard.getByRole("button", { name: "关闭问题" }).click(); const closeBlockedBeforeAcknowledgement = await issueForm.getByRole("button", { name: "确认关闭" }).isDisabled(); await issueForm.getByLabel("我已复核根因、修复版本、解决结果及回归证据,同意关闭该问题").check(); const closeEnabledAfterAcknowledgement = await issueForm.getByRole("button", { name: "确认关闭" }).isEnabled(); await page.screenshot({ path: fileURLToPath(new URL("ops-integration-issue-workflow.png", outputDirectory)), fullPage: true }); await issueForm.getByRole("button", { name: "取消" }).click(); await closedIssueCard.getByRole("button", { name: "重新打开" }).click(); await issueForm.getByLabel("重新处理责任方").fill(""); const reopenEmptyPartyDisabled = await issueForm.getByRole("button", { name: "重新打开" }).isDisabled(); await issueForm.getByLabel("重新处理责任方").fill("回归复核组"); const reopenCompletedEnabled = await issueForm.getByRole("button", { name: "重新打开" }).isEnabled(); await issueForm.getByRole("button", { name: "取消" }).click(); const issueCancelClosedForm = await issueForm.count() === 0; await page.getByRole("button", { name: "刷新申请" }).click(); const accessReviewCard = page.locator(".diagnostic-card").filter({ hasText: "页面审批夹具:核对转写时间轴和原录音片段" }); await accessReviewCard.waitFor(); await accessReviewCard.getByRole("button", { name: "批准" }).click(); const reviewForm = page.getByRole("form", { name: "临时敏感访问审批" }); await reviewForm.waitFor(); const approvalText = await reviewForm.textContent(); const approvalTargetBound = approvalText?.includes(accessReviewPublicID) === true && approvalText?.includes("10000000-0000-0000-0000-000000000112") === true && approvalText?.includes("读取最终字幕") === true && approvalText?.includes("播放原录音") === true && approvalText?.includes("版本 4") === true; const approvalEmptyReasonDisabled = await reviewForm.getByRole("button", { name: "确认批准" }).isDisabled(); await reviewForm.getByLabel("批准依据").fill("已复核单次通话、最小能力、问题范围和一小时有效期"); const approvalBlockedBeforeAcknowledgement = await reviewForm.getByRole("button", { name: "确认批准" }).isDisabled(); await reviewForm.getByLabel("我确认申请人不是本人,已复核单次通话、最小能力和到期时间,批准后只有原申请人可在有效期内使用").check(); const approvalEnabledAfterAcknowledgement = await reviewForm.getByRole("button", { name: "确认批准" }).isEnabled(); await page.screenshot({ path: fileURLToPath(new URL("ops-sensitive-access-review.png", outputDirectory)), fullPage: true }); await reviewForm.getByRole("button", { name: "取消" }).click(); await accessReviewCard.getByRole("button", { name: "拒绝" }).click(); const rejectionTargetBound = (await reviewForm.textContent())?.includes(accessReviewPublicID) === true && (await reviewForm.textContent())?.includes("终止本次申请") === true; const rejectionEmptyReasonDisabled = await reviewForm.getByRole("button", { name: "确认拒绝" }).isDisabled(); await reviewForm.getByLabel("拒绝原因").fill("申请包含原录音播放,但当前排障说明不足以支持该能力"); const rejectionCompletedEnabled = await reviewForm.getByRole("button", { name: "确认拒绝" }).isEnabled(); await reviewForm.getByRole("button", { name: "取消" }).click(); const reviewCancelClosedForm = await reviewForm.count() === 0; await resultCard.getByRole("button", { name: "申请临时敏感访问" }).click(); const form = page.getByRole("form", { name: "临时敏感访问申请" }); await form.waitFor(); const submit = form.getByRole("button", { name: "提交审批" }); const emptyReasonDisabled = await submit.isDisabled(); const transcript = form.getByLabel("读取本次通话最终字幕"); const transcriptMandatory = await transcript.isChecked() && await transcript.isDisabled(); const recording = form.getByLabel("同时申请本次通话原录音播放"); const recordingInitiallyOptional = !(await recording.isChecked()); await form.getByLabel("排障理由").fill("核对本次转写时间轴与设备错误码是否一致"); await recording.check(); await form.getByLabel("有效期").selectOption("240"); const completedFormEnabled = await submit.isEnabled(); const fourHourSelected = await form.getByLabel("有效期").inputValue() === "240"; await page.screenshot({ path: fileURLToPath(new URL("ops-sensitive-access-request.png", outputDirectory)), fullPage: true }); await form.getByRole("button", { name: "取消" }).click(); const cancelClosedForm = await form.count() === 0; const overflow = await page.evaluate(() => [...document.querySelectorAll("body *")] .filter((element) => element instanceof HTMLElement && element.scrollWidth > element.clientWidth + 2 && getComputedStyle(element).overflowX === "visible") .slice(0, 20) .map((element) => `${element.tagName}.${element.className}: ${element.clientWidth}/${element.scrollWidth}`)); const result = { bundleTargetBound, bundleEmptyReasonDisabled, bundleCompletedEnabled, bundleCancelClosedForm, refreshEmptyReasonDisabled, refreshTargetBound, refreshCompletedEnabled, reconcileTargetBound, reconcileCompletedEnabled, stopBlockedBeforeAcknowledgement, stopEnabledAfterAcknowledgement, revokeBlockedBeforeAcknowledgement, revokeEnabledAfterAcknowledgement, controlCancelClosedForm, retryTargetBound, retryEmptyReasonDisabled, retryBlockedBeforeAcknowledgement, retryEnabledAfterAcknowledgement, retryCancelClosedForm, severityTargetBound, sameSeverityDisabled, changedSeverityEnabled, takeEmptyPartyDisabled, takeCompletedEnabled, resolveEmptyDisabled, resolveCompletedEnabled, verifyEmptyDisabled, verifyCompletedEnabled, closeBlockedBeforeAcknowledgement, closeEnabledAfterAcknowledgement, reopenEmptyPartyDisabled, reopenCompletedEnabled, issueCancelClosedForm, approvalTargetBound, approvalEmptyReasonDisabled, approvalBlockedBeforeAcknowledgement, approvalEnabledAfterAcknowledgement, rejectionTargetBound, rejectionEmptyReasonDisabled, rejectionCompletedEnabled, reviewCancelClosedForm, emptyReasonDisabled, transcriptMandatory, recordingInitiallyOptional, completedFormEnabled, fourHourSelected, cancelClosedForm, controlMutations, issueMutations, accessMutations, overflow, consoleErrors, failedRequests }; console.log(JSON.stringify(result, null, 2)); if (!bundleTargetBound || !bundleEmptyReasonDisabled || !bundleCompletedEnabled || !bundleCancelClosedForm || !refreshEmptyReasonDisabled || !refreshTargetBound || !refreshCompletedEnabled || !reconcileTargetBound || !reconcileCompletedEnabled || !stopBlockedBeforeAcknowledgement || !stopEnabledAfterAcknowledgement || !revokeBlockedBeforeAcknowledgement || !revokeEnabledAfterAcknowledgement || !controlCancelClosedForm || !retryTargetBound || !retryEmptyReasonDisabled || !retryBlockedBeforeAcknowledgement || !retryEnabledAfterAcknowledgement || !retryCancelClosedForm || !severityTargetBound || !sameSeverityDisabled || !changedSeverityEnabled || !takeEmptyPartyDisabled || !takeCompletedEnabled || !resolveEmptyDisabled || !resolveCompletedEnabled || !verifyEmptyDisabled || !verifyCompletedEnabled || !closeBlockedBeforeAcknowledgement || !closeEnabledAfterAcknowledgement || !reopenEmptyPartyDisabled || !reopenCompletedEnabled || !issueCancelClosedForm || !approvalTargetBound || !approvalEmptyReasonDisabled || !approvalBlockedBeforeAcknowledgement || !approvalEnabledAfterAcknowledgement || !rejectionTargetBound || !rejectionEmptyReasonDisabled || !rejectionCompletedEnabled || !reviewCancelClosedForm || !emptyReasonDisabled || !transcriptMandatory || !recordingInitiallyOptional || !completedFormEnabled || !fourHourSelected || !cancelClosedForm || controlMutations.length || issueMutations.length || accessMutations.length || overflow.length || consoleErrors.length || failedRequests.length) { throw new Error("Ops sensitive access request visual smoke failed"); } } finally { await browser.close(); cleanup(); }