| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- import { test, expect } from '../fixtures/auth';
- import type { Page } from '@playwright/test';
- /**
- * B-02 遗留现场扩展复测(阶段 4 / N-2 前置):
- * 在已验证"详情 API + 详情页可加载"之上,补齐 列表 / 时间线 / 状态一致性 三项。
- */
- const SCENES = [
- { id: 4, flow: '796353842065477', code: 'EX-20260414-0002', label: '阶段2 Approve 半提交' },
- { id: 29, flow: '796458502344773', code: 'EX-20260414-0003-RJ', label: '阶段3 Reject 半提交' },
- ] as const;
- async function token(page: Page) {
- return page.evaluate(() => {
- for (let i = 0; i < localStorage.length; i++) {
- const k = localStorage.key(i)!;
- if (/access-token$/i.test(k) && !/x-access-token$/i.test(k)) {
- const raw = localStorage.getItem(k)!;
- try {
- const v = JSON.parse(raw);
- return typeof v === 'string' ? v : v?.value ?? raw;
- } catch {
- return raw;
- }
- }
- }
- return null;
- });
- }
- async function api(page: Page, url: string) {
- const t = await token(page);
- const base = new URL(page.url()).origin;
- const resp = await page.request.get(`${base}${url}`, {
- headers: { Authorization: `Bearer ${t!}` },
- });
- return { status: resp.status(), json: resp.ok() ? ((await resp.json()) as any) : null };
- }
- test.describe('B-02 遗留现场扩展复测', () => {
- for (const s of SCENES) {
- test(`id=${s.id} 详情/时间线/列表三侧一致`, async ({ authedPage }) => {
- await authedPage.goto('/#/aidop/s8/exceptions', { waitUntil: 'domcontentloaded' });
- await authedPage.waitForLoadState('networkidle', { timeout: 15_000 }).catch(() => {});
- // 1) 详情 API
- const detail = await api(
- authedPage,
- `/api/aidop/s8/exceptions/${s.id}?tenantId=1&factoryId=1`,
- );
- expect(detail.status).toBe(200);
- const d = detail.json?.data ?? detail.json;
- test.info().annotations.push({
- type: 'detail',
- description: JSON.stringify({
- code: d.code ?? d.exceptionCode,
- status: d.status,
- activeFlow: d.activeFlowInstanceId ?? d.ActiveFlowInstanceId,
- }),
- });
- expect(String(d.activeFlowInstanceId ?? d.ActiveFlowInstanceId ?? '')).toBe(s.flow);
- expect(String(d.status ?? '')).not.toMatch(/CLOSED|CANCELED|已关闭|已取消/);
- // 2) 时间线 API
- const tl = await api(authedPage, `/api/aidop/s8/exceptions/${s.id}/timeline`);
- expect(tl.status, '时间线接口应返回 200').toBe(200);
- const tlData = tl.json?.data ?? tl.json;
- const tlArr = Array.isArray(tlData) ? tlData : (tlData?.items ?? tlData?.list ?? []);
- test.info().annotations.push({
- type: 'timeline',
- description: `length=${tlArr.length}; first=${JSON.stringify(tlArr[0] ?? null).slice(0, 200)}`,
- });
- expect(tlArr.length, '时间线至少应有一条记录').toBeGreaterThan(0);
- // 3) 列表接口:按 code 过滤定位行
- const listResp = await api(
- authedPage,
- `/api/aidop/s8/exceptions?page=1&pageSize=50&tenantId=1&factoryId=1`,
- );
- expect(listResp.status).toBe(200);
- const listData = listResp.json?.data ?? listResp.json;
- const rows: any[] = listData?.list ?? listData?.items ?? listData?.rows ?? [];
- const hit = rows.find(
- (r) => String(r.id) === String(s.id) || r.code === s.code || r.exceptionCode === s.code,
- );
- test.info().annotations.push({
- type: 'list',
- description: hit
- ? `found code=${hit.code ?? hit.exceptionCode} status=${hit.status}`
- : `total=${rows.length}, not in first page`,
- });
- // 不强断言必须在第 1 页(数据量变化可能让它翻页),仅要求接口可达
- if (hit) {
- expect(String(hit.status ?? '')).toBe(String(d.status ?? ''));
- }
- // 4) 详情页 URL 可达
- await authedPage.goto(`/#/aidop/s8/exceptions/${s.id}`, {
- waitUntil: 'domcontentloaded',
- });
- await authedPage.waitForLoadState('networkidle', { timeout: 12_000 }).catch(() => {});
- const errBanner = authedPage.locator('text=/页面加载失败|未找到|Error:/').first();
- expect(await errBanner.isVisible().catch(() => false)).toBeFalsy();
- });
- }
- });
|