280 lines
26 KiB
JavaScript
280 lines
26 KiB
JavaScript
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();
|
|
}
|