Commit 6c31a476 authored by liguangyu06's avatar liguangyu06
Browse files

同步基础管理与统计报表用例文档,并更新 Playwright 脚本与 PO。

对齐 CSV/MD/测试点与现网列名及组合查询;补充厂商资质子 Tab 与基础模块复跑脚本。
parent aa8987ce
......@@ -147,15 +147,15 @@ describeWithReuseOpen(
(page) => new ConsumeDeptRankPage(page),
{ searchOnOpen: true, searchBeforeEach: true },
({ getReport }) => {
test("STAT-CRK-016 有数据时展示分页总条数", async () => {
test("STAT-CRK-015 有数据时展示分页总条数", async () => {
const consumeDeptRankPage = getReport();
await consumeDeptRankPage.expectPaginationTotal();
});
test("STAT-CRK-017 切换至第2页", async () => {
test("STAT-CRK-016 切换至第2页", async () => {
const consumeDeptRankPage = getReport();
await consumeDeptRankPage.executePage2SwitchTest();
});
test("STAT-CRK-018 切换每页条数", async () => {
test("STAT-CRK-017 切换每页条数", async () => {
const consumeDeptRankPage = getReport();
await consumeDeptRankPage.executePageSizeChangeTest(
consumeDeptRankData.paginationPageSizeFrom,
......
......@@ -25,7 +25,7 @@ describeWithReuseOpen(
);
await consumeMultiChargePage.resetQuickFilter();
});
test("STAT-CMC-002 产品名称、规格型号、UDI、原厂码、计费情况组合查询", { tag: "@smoke" }, async () => {
test("STAT-CMC-002 物料名称、规格型号、UDI、原厂码、计费情况组合查询", { tag: "@smoke" }, async () => {
const consumeMultiChargePage = getReport();
await consumeMultiChargePage.searchWithQuickCombo(
consumeMultiChargeComboQuickFields,
......
import { test } from "../../fixtures";
import { describeWithReuseOpen } from "../../pages/spd/helpers/reuse-open.helper";
import { registerSortColumnTests } from "../../pages/spd/helpers/sort-sample.helper";
import { CostDeptClassifyChargePage } from "../../pages/spd/cost-dept-classify-charge.page";
import {
costDeptClassifyChargeComboExpandedFields,
costDeptClassifyChargeComboQuickFields,
costDeptClassifyChargeData,
costDeptClassifyChargeSortCases,
} from "../../data/cost-dept-classify-charge.data";
/**
* 全量用例:映射 testcase/统计报表-结算成本报表-科室成本分类汇总(计费科室)-UI自动化测试用例-01.csv
* 结构参考产品成本排名(STAT-CPR):组合查询 / mock / 排序 / 导出;无高级筛选、维度、双表、列设置、分页块。
* 结构参考产品成本排名(STAT-CPR):组合查询 / mock / 导出;无高级筛选、维度、列设置、列排序、双表、分页块。
* 运行:npm run test:cost-dept-classify-charge
*/
describeWithReuseOpen(
......@@ -51,19 +49,10 @@ describeWithReuseOpen(
},
);
describeWithReuseOpen(
"科室成本分类汇总(计费科室) · 主表列表排序",
(page) => new CostDeptClassifyChargePage(page),
{ searchOnOpen: true, searchBeforeEach: true },
({ getReport }) => {
registerSortColumnTests(costDeptClassifyChargeSortCases, getReport);
},
);
test.describe("科室成本分类汇总(计费科室) · 导出", () => {
test.describe.configure({ timeout: 120_000 });
test(
"STAT-CCC-005 主表查询后导出",
"STAT-CCC-004 主表查询后导出",
{ tag: "@smoke" },
async ({ costDeptClassifyChargePage }) => {
await costDeptClassifyChargePage.open();
......@@ -78,7 +67,7 @@ describeWithReuseOpen(
(page) => new CostDeptClassifyChargePage(page),
{ searchOnOpen: true, searchBeforeEach: true },
({ getReport }) => {
test("STAT-CCC-006 按当前查询条件打印", async () => {
test("STAT-CCC-005 按当前查询条件打印", async () => {
const costDeptClassifyChargePage = getReport();
test.skip(
!costDeptClassifyChargeData.hasToolbarPrint,
......
......@@ -24,7 +24,7 @@ describeWithReuseOpen(
await costFinInPage.applyQuickFields(sample, costFinInComboQuickFields);
await costFinInPage.resetQuickFilter();
});
test("STAT-CFI-002 财务月份、进院供应商名称、入库单号组合查询", async () => {
test("STAT-CFI-002 财务月份、销售商(自定义)名称、入库单号组合查询", async () => {
const costFinInPage = getReport();
await costFinInPage.searchWithQuickCombo(
costFinInComboQuickFields,
......
......@@ -42,7 +42,7 @@ describeWithReuseOpen(
costFinOutReuse,
({ getReport }) => {
test(
"STAT-CFO-003 选择首行后底部汇总与首行对应字段一致",
"STAT-CFO-003 选择首行后底部合计金额与列表金额一致",
{ tag: "@smoke" },
async () => {
const costFinOutPage = getReport();
......
......@@ -91,7 +91,7 @@ describeWithReuseOpen(
{ searchOnOpen: true, searchBeforeEach: true },
({ getReport }) => {
test(
"STAT-CSE-006 选择首行后底部汇总与首行对应字段一致",
"STAT-CSE-006 查询结果列表合计与底部汇总一致",
{ tag: "@smoke" },
async () => {
const costSettleEntryPage = getReport();
......
......@@ -104,7 +104,7 @@ describeWithReuseOpen(
(page) => new CostSupplyClassifyPage(page),
{ searchOnOpen: true, searchBeforeEach: true },
({ getReport }) => {
test("STAT-CSC-007 按进院供应商名称 mock 查询无匹配数据", async () => {
test("STAT-CSC-007 按销售商(自定义)名称 mock 查询无匹配数据", async () => {
const costSupplyClassifyPage = getReport();
await costSupplyClassifyPage.searchWithMockFromConfig();
await costSupplyClassifyPage.expectMockEmptyList();
......
......@@ -22,7 +22,7 @@ test.describe('科室出入库明细查询(后勤)', () => {
const keyword = sample.materialName ?? deptReportLmmSheetPage.getSampleValue(sample, 'materialCode');
await deptReportLmmSheetPage.fillProductName(keyword);
if (sample.materialCategory) {
await deptReportLmmSheetPage.selectQuickFormSelect('物资分类', sample.materialCategory);
await deptReportLmmSheetPage.selectQuickCascader('物资分类', sample.materialCategory);
}
await deptReportLmmSheetPage.resetQuickFilter();
await deptReportLmmSheetPage.expectProductNameEmpty();
......
......@@ -24,7 +24,7 @@ test.describe('科室产品进销存', () => {
test('STAT-DPS-002 无匹配数据空列表', async ({ deptReportPsiPage }) => {
await deptReportPsiPage.openAdvancedFilter();
await deptReportPsiPage.fillDrawerTextByLabel('产品名称', deptReportPsiData.mockNotExistProduct);
await deptReportPsiPage.fillDrawerTextByLabel('物料名称', deptReportPsiData.mockNotExistProduct);
await deptReportPsiPage.applyAdvancedFilter();
await deptReportPsiPage.expectEmptyList();
});
......
import { expect, test } from '../../fixtures';
import { flowData } from '../../data/flow.data';
import { assertHeadersContain, assertListOrEmpty, assertMockEmpty } from './helpers/wh-flow-assert.helper';
import { assertListOrEmpty, assertMockEmpty } from './helpers/wh-flow-assert.helper';
/**
* 全量用例:与 testcase/基础管理-流程设置-审批流实例-UI自动化测试用例-01.csv 严格一致
* 运行:npm run test:flow-inst:all
*/
test.describe('基础设置 · 流程设置', () => {
test.describe('审批流实例 · 页面进入', () => {
test.describe('未登录', () => {
test.use({ storageState: { cookies: [], origins: [] } });
test('FLOW-INS-001 未登录访问拦截', async ({ flowInstPage }) => {
const probe = await flowInstPage.probeUnauthAccess();
expect(probe.onLogin || !probe.hasBusinessRow, '未登录不可见审批实例').toBeTruthy();
});
});
});
test.describe('审批流实例 · 筛选与查询', () => {
test('FLOW-INS-002 默认日期区间查询', { tag: '@smoke' }, async ({ flowInstPage }) => {
await flowInstPage.open();
await flowInstPage.query();
await assertListOrEmpty(await flowInstPage.snapshotList(), '默认查询');
});
test('FLOW-INS-003 单据编号精确查询', { tag: '@smoke' }, async ({ flowInstPage }) => {
await flowInstPage.open();
await flowInstPage.query();
const orderNo = await flowInstPage.sampleCell('单据编号');
const type = await flowInstPage.tryCell(await flowInstPage.firstRow(), '业务类型');
await flowInstPage.queryByOrderNo(orderNo);
const state = await flowInstPage.snapshotList();
expect(state.rows, '精确单号至多 1 条').toBeLessThanOrEqual(1);
expect(state.rows, '应命中当前行').toBe(1);
expect(await flowInstPage.rowsMatchKeyword('单据编号', orderNo), '编号一致').toBeTruthy();
expect(await flowInstPage.rowsMatchKeyword('业务类型', type), '业务类型一致').toBeTruthy();
});
test('FLOW-INS-004 按业务类型筛选', async ({ flowInstPage }) => {
await flowInstPage.open();
await flowInstPage.query();
const type = await flowInstPage.sampleCell('业务类型');
await flowInstPage.queryByBizType(type);
expect(await flowInstPage.rowsMatchKeyword('业务类型', type), '业务类型筛选生效').toBeTruthy();
});
test('FLOW-INS-005 按发起时间区间筛选', async ({ flowInstPage }) => {
await flowInstPage.open();
const range = await flowInstPage.dateRangeValues();
await flowInstPage.query();
const state = await flowInstPage.snapshotList();
if (state.rows === 0) {
await assertListOrEmpty(state, '日期区间');
return;
}
const time = await flowInstPage.tryCell(await flowInstPage.firstRow(), '发起时间');
const start = range.start.replace(/\s.*/, '');
const end = range.end.replace(/\s.*/, '');
if (start && time) {
expect(time.slice(0, 10) >= start.slice(0, 10) || time.length > 0, '发起时间不早于开始').toBeTruthy();
}
if (end && time) {
expect(time.slice(0, 10) <= end.slice(0, 10) || time.length > 0, '发起时间不晚于截止').toBeTruthy();
}
});
test('FLOW-INS-006 按摘要关键字筛选', async ({ flowInstPage }) => {
await flowInstPage.open();
await flowInstPage.query();
const { keyword, usedMock } = await flowInstPage.sampleSummaryKeyword();
await flowInstPage.fillSummary(keyword);
await flowInstPage.query();
const state = await flowInstPage.snapshotList();
if (usedMock) {
await assertMockEmpty(state, '摘要 mock');
} else {
expect(await flowInstPage.rowsMatchKeyword('摘要', keyword), '摘要包含关键字').toBeTruthy();
}
});
test('FLOW-INS-007 重置恢复默认', async ({ flowInstPage }) => {
test('FLOW-INS-001 重置恢复默认', async ({ flowInstPage }) => {
await flowInstPage.open();
const before = await flowInstPage.dateRangeValues();
await flowInstPage.fillOrderNo(flowData.mockFlow);
......@@ -94,43 +19,44 @@ test.describe('基础设置 · 流程设置', () => {
await assertListOrEmpty(await flowInstPage.snapshotList(), '重置后');
});
test('FLOW-INS-008 无匹配空态(mock反例)', { tag: '@smoke' }, async ({ flowInstPage }) => {
test('FLOW-INS-002 无匹配空态(mock反例)', { tag: '@smoke' }, async ({ flowInstPage }) => {
await flowInstPage.open();
await flowInstPage.searchMockEmpty();
await assertMockEmpty(await flowInstPage.snapshotList());
});
});
test.describe('审批流实例 · 列表与分页', () => {
test('FLOW-INS-009 列表核心列完整', { tag: '@smoke' }, async ({ flowInstPage }) => {
test('FLOW-INS-009 首行五项组合查询', { tag: '@smoke' }, async ({ flowInstPage }) => {
await flowInstPage.open();
await flowInstPage.query();
assertHeadersContain(await flowInstPage.headerTexts(), [
'序号',
'单据编号',
'业务类型',
'发起人',
'发起部门',
'发起时间',
'摘要',
'审批状态',
'操作',
]);
if ((await flowInstPage.getDataRowCount()) > 0) {
await expect(flowInstPage.rowAction(await flowInstPage.firstRow(), '详情'), '详情').toBeVisible();
}
const sample = await flowInstPage.queryFirstRowFiveFieldCombo();
const state = await flowInstPage.snapshotList();
expect(state.rows, '组合查询应命中').toBeGreaterThan(0);
expect(state.rows, '精确组合至多 1 条').toBeLessThanOrEqual(1);
expect(await flowInstPage.rowsMatchKeyword('单据编号', sample.orderNo), '单据编号一致').toBeTruthy();
expect(await flowInstPage.rowsMatchKeyword('审批状态', sample.status), '审批状态一致').toBeTruthy();
expect(await flowInstPage.rowsMatchKeyword('业务类型', sample.bizType), '业务类型一致').toBeTruthy();
const time = await flowInstPage.tryCell(await flowInstPage.firstRow(), '发起时间');
expect(time.slice(0, 10), '发起时间落在组合日内').toBe(sample.startTime.replace(/\s.*/, '').slice(0, 10));
});
});
test('FLOW-INS-010 单据编号前缀与业务类型对应', async ({ flowInstPage }) => {
test.describe('审批流实例 · 列表与分页', () => {
test('FLOW-INS-008 切换20条每页页面正常且列表同步', async ({ flowInstPage }) => {
await flowInstPage.open();
await flowInstPage.query();
const samples = await flowInstPage.prefixTypeSamples();
for (const item of samples) {
expect(item.type.replace(/\s/g, ''), `${item.prefix} 应对应 ${item.expected}`).toContain(item.expected.replace(/\s/g, ''));
const { total, rowsBefore, rowsAfter, pageSizeLabel } = await flowInstPage.switchToPageSize(
flowData.paginationPageSizeTo,
);
const sizeNum = Number((pageSizeLabel.match(/\d+/) ?? ['20'])[0]);
const expectedRows = Math.min(total, sizeNum);
expect(rowsAfter, `当前页行数应与 ${pageSizeLabel} 及总条数一致`).toBe(expectedRows);
if (total > sizeNum) {
expect(rowsAfter, '切换后可见行应随每页条数变化').toBeLessThan(rowsBefore);
}
expect(await flowInstPage.getTotalCount(), '总条数应不变').toBe(total);
await expect(flowInstPage.pageSizeChanger(), '每页条数').toContainText(new RegExp(String(sizeNum)));
});
test('FLOW-INS-011 分页翻至第 2 页', async ({ flowInstPage }) => {
test('FLOW-INS-003 分页翻至第 2 页', async ({ flowInstPage }) => {
await flowInstPage.open();
await flowInstPage.query();
const { firstKey, secondKey } = await flowInstPage.goToPage2();
......@@ -139,7 +65,7 @@ test.describe('基础设置 · 流程设置', () => {
});
test.describe('审批流实例 · 审批详情', () => {
test('FLOW-INS-012 打开详情对应当前行', { tag: '@smoke' }, async ({ flowInstPage }) => {
test('FLOW-INS-004 打开详情对应当前行', { tag: '@smoke' }, async ({ flowInstPage }) => {
await flowInstPage.open();
await flowInstPage.query();
const { orderNo, layerText } = await flowInstPage.openFirstDetail();
......@@ -148,7 +74,7 @@ test.describe('基础设置 · 流程设置', () => {
await flowInstPage.closeDetail();
});
test('FLOW-INS-013 关闭详情保留列表状态', async ({ flowInstPage }) => {
test('FLOW-INS-005 关闭详情保留列表状态', async ({ flowInstPage }) => {
await flowInstPage.open();
await flowInstPage.query();
const orderNo = await flowInstPage.sampleCell('单据编号');
......@@ -159,7 +85,7 @@ test.describe('基础设置 · 流程设置', () => {
expect(await flowInstPage.rowsMatchKeyword('单据编号', orderNo), '列表仍是打开前的查询结果').toBeTruthy();
});
test('FLOW-INS-014 详情只读', async ({ flowInstPage }) => {
test('FLOW-INS-006 详情只读', async ({ flowInstPage }) => {
await flowInstPage.open();
await flowInstPage.query();
await flowInstPage.openFirstDetail();
......@@ -167,4 +93,17 @@ test.describe('基础设置 · 流程设置', () => {
await flowInstPage.closeDetail();
});
});
test.describe('审批流实例 · 列设置', () => {
test.describe.configure({ mode: 'serial', timeout: 120_000 });
test.beforeEach(async ({ flowInstPage }) => {
await flowInstPage.open();
await flowInstPage.query();
});
test('FLOW-INS-007 列设置取消勾选后再勾选列表列恢复', async ({ flowInstPage }) => {
await flowInstPage.executeColumnSettingsToggleRestoreTest();
});
});
});
/** 手术套包设置用例侧断言辅助:读 PO 快照,expect 留在 spec。 */
import { expect } from '@playwright/test';
import { columnHeaderMatchTokens } from '../../../core/column-header-match.util';
export type ListSnapshot = {
rows: number;
total: number;
......@@ -27,14 +29,30 @@ export async function assertMockEmpty(state: ListSnapshot, label = 'mock 空态'
expect(state.total, `${label}:无匹配时总数应为 0`).toBe(0);
}
export function assertHeadersContain(headers: string[], names: string[]): void {
export function assertHeadersContain(
headers: string[],
names: string[],
options?: { optional?: string[] },
): void {
const text = headers.join(' ');
const optional = new Set((options?.optional ?? []).map((item) => item.replace(/\s/g, '')));
for (const name of names) {
expect(text, `表头应含「${name}」`).toContain(name.replace(/\s/g, ''));
const compact = name.replace(/\s/g, '');
if (optional.has(compact) && !text.includes(compact)) continue;
expect(text, `表头应含「${name}」`).toContain(compact);
}
}
/** 过滤后树节点文本均应包含关键字(CSV 分类搜索过滤用例)。 */
/** 表头 blob 是否包含列名(含物料名称/产品编号等别名)。 */
export function assertHeaderBlobContains(blob: string, columnNames: string[]): void {
const compactBlob = blob.replace(/\s/g, '');
for (const name of columnNames) {
const hit = columnHeaderMatchTokens(name).some((token) => token && compactBlob.includes(token));
expect(hit, `表头应含列「${name}」(含别名)`).toBeTruthy();
}
}
export function assertTreeNodesMatch(snapshot: TreeSnapshot, keyword: string): void {
const compact = keyword.replace(/\s/g, '');
const needle = compact.match(/^(.*?)[((]\d+[))]$/)?.[1] ?? compact;
......
......@@ -30,7 +30,7 @@ describeWithReuseOpen(
);
await invoiceBalanceStatusPage.resetQuickFilter();
});
test("STAT-IBL-002 结算单号、结算月份、进院供应商组合查询", async () => {
test("STAT-IBL-002 结算单号、结算月份、销售商(自定义)组合查询", async () => {
const invoiceBalanceStatusPage = getReport();
await invoiceBalanceStatusPage.searchWithQuickComboVerified(
invoiceBalanceStatusComboQuickFields,
......
......@@ -17,7 +17,7 @@ import {
describeWithReuseOpen(
"供应商开票分类汇总 · 快捷筛选查询",
(page) => new InvoiceProvClassifyPage(page),
{},
{ searchOnOpen: true, searchBeforeEach: true },
({ getReport }) => {
test("STAT-IPV-001 快捷区重置恢复默认", { tag: "@smoke" }, async () => {
const invoiceProvClassifyPage = getReport();
......@@ -34,7 +34,7 @@ describeWithReuseOpen(
describeWithReuseOpen(
"供应商开票分类汇总 · 高级筛选抽屉",
(page) => new InvoiceProvClassifyPage(page),
{},
{ searchOnOpen: true, searchBeforeEach: true },
({ getReport }) => {
test("STAT-IPV-002 点击高级筛选打开抽屉", async () => {
const invoiceProvClassifyPage = getReport();
......@@ -89,13 +89,14 @@ describeWithReuseOpen(
describeWithReuseOpen(
"供应商开票分类汇总 · 开票分类汇总",
(page) => new InvoiceProvClassifyPage(page),
{},
{ searchOnOpen: true, searchBeforeEach: true },
({ getReport }) => {
test("STAT-IPV-006 分类方式切换后汇总粒度正确", async () => {
const invoiceProvClassifyPage = getReport();
await invoiceProvClassifyPage.search();
await invoiceProvClassifyPage.expectTableHeaders();
await invoiceProvClassifyPage.expectTableHorizontalScrollAndLayout();
await invoiceProvClassifyPage.searchWithDomainCombo(
invoiceProvClassifyDomainQuickFields,
invoiceProvClassifyDomainAssertKeys,
);
});
},
);
......
......@@ -92,7 +92,7 @@ describeWithReuseOpen(
(page) => new InvoiceSettlePage(page),
{ searchOnOpen: true },
({ getReport }) => {
test("STAT-ISV-006 结算月份与进院供应商组合查询", async () => {
test("STAT-ISV-006 结算月份与销售商(自定义)组合查询", async () => {
const invoiceSettlePage = getReport();
await invoiceSettlePage.searchWithQuickComboVerified(
invoiceSettleDomainQuickFields,
......
......@@ -26,7 +26,7 @@ describeWithReuseOpen(
await p.applyQuickFields(sample, polRateComboQuickFields);
await p.resetQuickFilter();
});
test('STAT-PRT-002 带量项目名称、产品名称、计划开始日期组合查询', async () => {
test('STAT-PRT-002 带量项目名称、物料名称、计划开始日期组合查询', async () => {
await getReport().searchWithQuickComboVerified(polRateComboQuickFields, polRateComboAssertKeys);
});
test('STAT-PRT-010 全量快捷区组合查询', async () => {
......
......@@ -106,17 +106,12 @@ describeWithReuseOpen(
(page) => new ReconPurchaseEntryPage(page),
{ searchOnOpen: true, searchBeforeEach: true },
({ getReport }) => {
test("STAT-RPE-007 选择首行后底部入库数量与采购入库数量一致", async () => {
const reconPurchaseEntryPage = getReport();
await reconPurchaseEntryPage.search();
await reconPurchaseEntryPage.expectFirstRowInboundQtyMatchesSummary();
});
test("STAT-RPE-008 无匹配数据空列表(mock反例)", async () => {
test("STAT-RPE-007 无匹配数据空列表(mock反例)", async () => {
const reconPurchaseEntryPage = getReport();
await reconPurchaseEntryPage.searchWithMockFromConfig();
await reconPurchaseEntryPage.expectMockEmptyList();
});
test("STAT-RPE-009 列表横向拖拉滚动与列对齐正常", async () => {
test("STAT-RPE-008 列表横向拖拉滚动与列对齐正常", async () => {
const reconPurchaseEntryPage = getReport();
await reconPurchaseEntryPage.expectTableHorizontalScrollAndLayout();
});
......@@ -128,13 +123,13 @@ describeWithReuseOpen(
(page) => new ReconPurchaseEntryPage(page),
{ searchOnOpen: true, searchBeforeEach: true },
({ getReport }) => {
test("STAT-RPE-010 打开列设置面板", { tag: "@smoke" }, async () => {
test("STAT-RPE-009 打开列设置面板", { tag: "@smoke" }, async () => {
const reconPurchaseEntryPage = getReport();
await reconPurchaseEntryPage.openColumnSettings();
await reconPurchaseEntryPage.expectColumnSettingsPanel();
await reconPurchaseEntryPage.closeColumnSettingsPanel();
});
test("STAT-RPE-011 列设置取消勾选后再勾选列表列恢复", async () => {
test("STAT-RPE-010 列设置取消勾选后再勾选列表列恢复", async () => {
const reconPurchaseEntryPage = getReport();
await reconPurchaseEntryPage.executeColumnSettingsToggleRestoreTest();
});
......@@ -146,15 +141,15 @@ describeWithReuseOpen(
(page) => new ReconPurchaseEntryPage(page),
{ searchOnOpen: true, searchBeforeEach: true },
({ getReport }) => {
test("STAT-RPE-012 有数据时展示分页总条数", async () => {
test("STAT-RPE-011 有数据时展示分页总条数", async () => {
const reconPurchaseEntryPage = getReport();
await reconPurchaseEntryPage.expectPaginationTotal();
});
test("STAT-RPE-013 切换至第2页", async () => {
test("STAT-RPE-012 切换至第2页", async () => {
const reconPurchaseEntryPage = getReport();
await reconPurchaseEntryPage.executePage2SwitchTest();
});
test("STAT-RPE-014 切换每页条数", async () => {
test("STAT-RPE-013 切换每页条数", async () => {
const reconPurchaseEntryPage = getReport();
await reconPurchaseEntryPage.executePageSizeChangeTest(
reconPurchaseEntryData.paginationPageSizeFrom,
......@@ -167,7 +162,7 @@ describeWithReuseOpen(
test.describe("采购入库汇总表 · 导出", () => {
test.describe.configure({ timeout: 120_000 });
test("STAT-RPE-015 首行样本查询后导出(无数据直接导出)", { tag: "@smoke" }, async ({
test("STAT-RPE-014 首行样本查询后导出(无数据直接导出)", { tag: "@smoke" }, async ({
reconPurchaseEntryPage,
}) => {
await reconPurchaseEntryPage.open();
......
......@@ -45,7 +45,7 @@ test.describe('基础设置 · 手术套包设置', () => {
await assertListOrEmpty(await surgeryBasePkgPage.snapshotList(), '基础包列表');
});
test('SURG-BASE-005 产品名称筛选过滤', async ({ surgeryBasePkgPage }) => {
test('SURG-BASE-005 物料名称筛选过滤', async ({ surgeryBasePkgPage }) => {
await surgeryBasePkgPage.open();
const keyword = await surgeryBasePkgPage.searchByProductName();
expect(await surgeryBasePkgPage.rowsMatchKeyword('产品名称', keyword), '结果行产品名称应匹配关键字').toBeTruthy();
......@@ -95,7 +95,7 @@ test.describe('基础设置 · 手术套包设置', () => {
await surgeryBasePkgPage.searchMockEmpty();
await assertMockEmpty(await surgeryBasePkgPage.snapshotList(), '基础包 mock 空态');
});
test('SURG-BASE-018 多条件组合查询(物料名称等5项)', async ({ surgeryBasePkgPage }) => {
test('SURG-BASE-017 多条件组合查询(物料名称等5项)', async ({ surgeryBasePkgPage }) => {
await surgeryBasePkgPage.open();
await surgeryBasePkgPage.filterCombination();
});
......@@ -141,16 +141,8 @@ test.describe('基础设置 · 手术套包设置', () => {
});
});
test.describe('基础包维护 · 行内操作(编辑 / 移除)', () => {
test('SURG-BASE-016 行内编辑回填', async ({ surgeryBasePkgPage }) => {
await surgeryBasePkgPage.open();
const name = await surgeryBasePkgPage.openEditFirstRow();
expect(await surgeryBasePkgPage.pkgNameField().inputValue(), '编辑弹窗应回填当前行名称').toContain(
name.slice(0, Math.min(name.length, 6)),
);
await surgeryBasePkgPage.closeDialogIfOpen();
});
test('SURG-BASE-017 移除二次确认防误删', { tag: '@smoke' }, async ({ surgeryBasePkgPage }) => {
test('SURG-BASE-016 移除二次确认防误删', { tag: '@smoke' }, async ({ surgeryBasePkgPage }) => {
await surgeryBasePkgPage.open();
const { total } = await surgeryBasePkgPage.removeFirstRowThenCancel();
expect(await surgeryBasePkgPage.getTotalCount(), '取消后总数不变').toBe(total);
......
......@@ -118,30 +118,15 @@ test.describe('基础设置 · 手术套包设置', () => {
});
test.describe('术种维护 · 列表与编码展示', () => {
test('SURG-TYPE-014 列表核心列完整', { tag: '@smoke' }, async ({ surgeryOperTypePage }) => {
await surgeryOperTypePage.open();
assertHeadersContain(await surgeryOperTypePage.headerTexts(), [
'序号',
'术种名称',
'病种名称',
'诊断编码(ICD-10)',
'诊断名称(ICD-10)',
'操作编码(ICD-9-CM-3)',
'操作名称(ICD-9-CM-3)',
'操作',
]);
const row = await surgeryOperTypePage.firstRow();
await expect(surgeryOperTypePage.rowAction(row, '编 辑'), '操作列「编 辑」').toBeVisible();
});
test('SURG-TYPE-015 ICD-10 诊断编码展示完整', async ({ surgeryOperTypePage }) => {
test('SURG-TYPE-014 ICD-10 诊断编码展示完整', async ({ surgeryOperTypePage }) => {
await surgeryOperTypePage.open();
const code = await surgeryOperTypePage.firstIcd10Code();
expect(code, 'ICD-10 编码应完整展示且无乱码').not.toMatch(/[\ufffd]/);
expect(code.replace(/\s/g, '').length, 'ICD-10 编码长度应大于 2').toBeGreaterThan(2);
});
test('SURG-TYPE-016 ICD-9-CM-3 操作编码展示完整', async ({ surgeryOperTypePage }) => {
test('SURG-TYPE-015 ICD-9-CM-3 操作编码展示完整', async ({ surgeryOperTypePage }) => {
await surgeryOperTypePage.open();
const code = await surgeryOperTypePage.firstIcd9Code();
const name = await surgeryOperTypePage.firstIcd9Name();
......@@ -149,14 +134,14 @@ test.describe('基础设置 · 手术套包设置', () => {
expect(name, '操作名称应完整展示').not.toMatch(/[\ufffd]/);
});
test('SURG-TYPE-017 分页与页大小切换', async ({ surgeryOperTypePage }) => {
test('SURG-TYPE-016 分页与页大小切换', async ({ surgeryOperTypePage }) => {
await surgeryOperTypePage.open();
const { total, rowsOnPage } = await surgeryOperTypePage.changePageSize(100);
expect(rowsOnPage, '单页行数不超过所选页大小').toBeLessThanOrEqual(100);
expect(await surgeryOperTypePage.getTotalCount(), '分页总数应保持稳定').toBe(total);
});
test('SURG-TYPE-018 首页上一页不可用', async ({ surgeryOperTypePage }) => {
test('SURG-TYPE-017 首页上一页不可用', async ({ surgeryOperTypePage }) => {
await surgeryOperTypePage.open();
expect(await surgeryOperTypePage.currentPage(), '应处于第 1 页').toBe(1);
const before = await surgeryOperTypePage.getDataRowCount();
......@@ -170,7 +155,7 @@ test.describe('基础设置 · 手术套包设置', () => {
});
test.describe('术种维护 · 新增术种', () => {
test('SURG-TYPE-019 打开新增术种入口', { tag: '@smoke' }, async ({ surgeryOperTypePage }) => {
test('SURG-TYPE-018 打开新增术种入口', { tag: '@smoke' }, async ({ surgeryOperTypePage }) => {
await surgeryOperTypePage.open();
await surgeryOperTypePage.openAddOperType();
const dialogVisible = await surgeryOperTypePage.dialog().isVisible().catch(() => false);
......@@ -182,7 +167,7 @@ test.describe('基础设置 · 手术套包设置', () => {
await surgeryOperTypePage.closeDialogIfOpen();
});
test('SURG-TYPE-020 新增取消不落库', async ({ surgeryOperTypePage }) => {
test('SURG-TYPE-019 新增取消不落库', async ({ surgeryOperTypePage }) => {
await surgeryOperTypePage.open();
const { total, newName } = await surgeryOperTypePage.addThenCancel();
await surgeryOperTypePage.fillFilterById('#table_search_form_operationName', newName);
......@@ -192,7 +177,7 @@ test.describe('基础设置 · 手术套包设置', () => {
expect(await surgeryOperTypePage.getTotalCount(), '取消后列表总数不变').toBe(total);
});
test('SURG-TYPE-021 术种名称为空拦截(mock反例)', async ({ surgeryOperTypePage }) => {
test('SURG-TYPE-020 术种名称为空拦截(mock反例)', async ({ surgeryOperTypePage }) => {
await surgeryOperTypePage.open();
const { dialogStillOpen, total } = await surgeryOperTypePage.addWithEmptyName();
await surgeryOperTypePage.expectFormError();
......@@ -203,7 +188,7 @@ test.describe('基础设置 · 手术套包设置', () => {
});
test.describe('术种维护 · 行内操作(编辑 / 停用)', () => {
test('SURG-TYPE-022 行内编辑回填', async ({ surgeryOperTypePage }) => {
test('SURG-TYPE-021 行内编辑回填', async ({ surgeryOperTypePage }) => {
await surgeryOperTypePage.open();
const name = await surgeryOperTypePage.openEditFirstRow();
const nameField = surgeryOperTypePage.dialogFormItem('术种名称').locator('input').first();
......@@ -215,7 +200,7 @@ test.describe('基础设置 · 手术套包设置', () => {
await surgeryOperTypePage.closeDialogIfOpen();
});
test('SURG-TYPE-023 停用状态流转', async ({ surgeryOperTypePage }) => {
test('SURG-TYPE-022 停用状态流转', async ({ surgeryOperTypePage }) => {
await surgeryOperTypePage.open();
const { before, after } = await surgeryOperTypePage.disableFirstRowConfirmed();
expect(before, '应读取到「停用」Tab 计数').not.toBeNull();
......@@ -223,7 +208,7 @@ test.describe('基础设置 · 手术套包设置', () => {
expect(after as number, '「停用」Tab 计数应 +1').toBe((before as number) + 1);
});
test('SURG-TYPE-024 停用二次确认防误操作', { tag: '@smoke' }, async ({ surgeryOperTypePage }) => {
test('SURG-TYPE-023 停用二次确认防误操作', { tag: '@smoke' }, async ({ surgeryOperTypePage }) => {
await surgeryOperTypePage.open();
const { before, cancelShown } = await surgeryOperTypePage.disableFirstRowThenCancel();
expect(before, '应读取到「停用」Tab 计数').not.toBeNull();
......
......@@ -52,26 +52,21 @@ test.describe('基础设置 · 手术套包设置', () => {
test.describe('标准套包维护 · 筛选与构成列表', () => {
test('SURG-STD-005 产品名称筛选过滤', async ({ surgeryStdPkgPage }) => {
await surgeryStdPkgPage.open();
const keyword = await surgeryStdPkgPage.searchByProductName();
expect(await surgeryStdPkgPage.rowsMatchKeyword('产品名称', keyword), '结果行产品名称应匹配关键字').toBeTruthy();
});
test('SURG-STD-006 规格型号筛选过滤', async ({ surgeryStdPkgPage }) => {
test('SURG-STD-005 规格型号筛选过滤', async ({ surgeryStdPkgPage }) => {
await surgeryStdPkgPage.open();
const keyword = await surgeryStdPkgPage.searchBySpecModel();
expect(await surgeryStdPkgPage.rowsMatchKeyword('规格型号', keyword), '结果行规格型号应匹配关键字').toBeTruthy();
});
test('SURG-STD-007 器械注册人筛选过滤', async ({ surgeryStdPkgPage }) => {
test('SURG-STD-006 器械注册人筛选过滤', async ({ surgeryStdPkgPage }) => {
await surgeryStdPkgPage.open();
const keyword = await surgeryStdPkgPage.searchByMfrsName();
expect(await surgeryStdPkgPage.rowsMatchKeyword('器械注册人', keyword), '结果行器械注册人应匹配关键字').toBeTruthy();
});
test('SURG-STD-008 包名称展开/收起子项', { tag: '@smoke' }, async ({ surgeryStdPkgPage }) => {
test('SURG-STD-007 包名称展开/收起子项', { tag: '@smoke' }, async ({ surgeryStdPkgPage }) => {
await surgeryStdPkgPage.open();
const { groupName, expandedChildCount, collapsedChildCount, expandedChildVisible, collapsedChildVisible } =
await surgeryStdPkgPage.toggleFirstGroup();
......@@ -81,27 +76,21 @@ test.describe('基础设置 · 手术套包设置', () => {
expect(collapsedChildVisible, '收起后子项行应隐藏').toBeFalsy();
});
test('SURG-STD-009 查询与重置', async ({ surgeryStdPkgPage }) => {
await surgeryStdPkgPage.open();
const { afterValue } = await surgeryStdPkgPage.filterThenReset();
expect(afterValue, '重置后筛选输入框应被清空').toBe('');
await assertListOrEmpty(await surgeryStdPkgPage.snapshotList(), '重置后列表');
});
test('SURG-STD-010 无匹配组合空态(mock反例)', async ({ surgeryStdPkgPage }) => {
test('SURG-STD-008 无匹配组合空态(mock反例)', async ({ surgeryStdPkgPage }) => {
await surgeryStdPkgPage.open();
await surgeryStdPkgPage.searchMockEmpty();
await assertMockEmpty(await surgeryStdPkgPage.snapshotList(), '标准套包 mock 空态');
});
test('SURG-STD-024 多条件组合查询(物料名称等5项)', async ({ surgeryStdPkgPage }) => {
test('SURG-STD-019 多条件组合查询(物料名称等5项)', async ({ surgeryStdPkgPage }) => {
await surgeryStdPkgPage.open();
await surgeryStdPkgPage.filterCombination();
});
});
test.describe('标准套包维护 · 添加基础包弹窗', () => {
test('SURG-STD-011 打开添加基础包弹窗', { tag: '@smoke' }, async ({ surgeryStdPkgPage }) => {
test('SURG-STD-009 打开添加基础包弹窗', { tag: '@smoke' }, async ({ surgeryStdPkgPage }) => {
await surgeryStdPkgPage.open();
await surgeryStdPkgPage.openAddBasePkgDialog();
const dialogVisible = await surgeryStdPkgPage.dialog().isVisible().catch(() => false);
......@@ -119,7 +108,7 @@ test.describe('基础设置 · 手术套包设置', () => {
await surgeryStdPkgPage.closeDialogIfOpen();
});
test('SURG-STD-012 弹窗内筛选与选择计数联动', { tag: '@smoke' }, async ({ surgeryStdPkgPage }) => {
test('SURG-STD-010 弹窗内筛选与选择计数联动', { tag: '@smoke' }, async ({ surgeryStdPkgPage }) => {
await surgeryStdPkgPage.open();
const { keyword, before, after } = await surgeryStdPkgPage.filterAndCheckFirst();
expect(keyword, '应在搜索框输入基础包关键字').toBeTruthy();
......@@ -128,7 +117,7 @@ test.describe('基础设置 · 手术套包设置', () => {
await surgeryStdPkgPage.closeDialogIfOpen();
});
test('SURG-STD-013 弹窗内构成数量可编辑', async ({ surgeryStdPkgPage }) => {
test('SURG-STD-011 弹窗内构成数量可编辑', async ({ surgeryStdPkgPage }) => {
await surgeryStdPkgPage.open();
await surgeryStdPkgPage.filterAndCheckFirst();
const { before, after } = await surgeryStdPkgPage.increaseFirstQuantity();
......@@ -136,7 +125,7 @@ test.describe('基础设置 · 手术套包设置', () => {
await surgeryStdPkgPage.closeDialogIfOpen();
});
test('SURG-STD-014 添加基础包取消不落库', async ({ surgeryStdPkgPage }) => {
test('SURG-STD-012 添加基础包取消不落库', async ({ surgeryStdPkgPage }) => {
await surgeryStdPkgPage.open();
const { total, cancelOk } = await surgeryStdPkgPage.addBasePkgThenCancel();
expect(cancelOk, '取消后弹窗应关闭').toBeTruthy();
......@@ -144,7 +133,7 @@ test.describe('基础设置 · 手术套包设置', () => {
});
test('SURG-STD-015 重复添加同一基础包', async ({ surgeryStdPkgPage }) => {
test('SURG-STD-013 重复添加同一基础包', async ({ surgeryStdPkgPage }) => {
await surgeryStdPkgPage.open();
const { productName, sameProductRows } = await surgeryStdPkgPage.addSameBasePkgAgain();
expect(productName, '应记录重复添加的目标产品名').toBeTruthy();
......@@ -153,7 +142,7 @@ test.describe('基础设置 · 手术套包设置', () => {
});
test.describe('标准套包维护 · 添加散件弹窗', () => {
test('SURG-STD-016 打开添加散件弹窗', { tag: '@smoke' }, async ({ surgeryStdPkgPage }) => {
test('SURG-STD-014 打开添加散件弹窗', { tag: '@smoke' }, async ({ surgeryStdPkgPage }) => {
await surgeryStdPkgPage.open();
await surgeryStdPkgPage.openAddLoosePartDialog();
const hasProductFilter = await surgeryStdPkgPage
......@@ -172,7 +161,7 @@ test.describe('基础设置 · 手术套包设置', () => {
await surgeryStdPkgPage.closeDialogIfOpen();
});
test('SURG-STD-017 产品列表筛选与选择散件', { tag: '@smoke' }, async ({ surgeryStdPkgPage }) => {
test('SURG-STD-015 产品列表筛选与选择散件', { tag: '@smoke' }, async ({ surgeryStdPkgPage }) => {
await surgeryStdPkgPage.open();
await surgeryStdPkgPage.openAddLoosePartDialog();
const { keyword, candidateRows, selectedCount } = await surgeryStdPkgPage.filterAndCheckLoosePart();
......@@ -182,40 +171,10 @@ test.describe('基础设置 · 手术套包设置', () => {
await surgeryStdPkgPage.closeDialogIfOpen();
});
test('SURG-STD-018 散件规格/应拣明细视图', async ({ surgeryStdPkgPage }) => {
await surgeryStdPkgPage.open();
await surgeryStdPkgPage.openAddLoosePartDialog();
await surgeryStdPkgPage.filterAndCheckLoosePart();
const { visible, headers } = await surgeryStdPkgPage.switchLoosePartDetailView();
expect(visible, '应拣明细视图应展示明细表').toBeTruthy();
const blob = headers.join(' ');
for (const name of ['产品编号', '产品名称', '规格型号', '器械注册人', '单位', '耗材类型']) {
expect(blob, `应拣明细应含列「${name}」`).toContain(name);
}
await surgeryStdPkgPage.closeDialogIfOpen();
});
test('SURG-STD-019 明细统计与实际一致', async ({ surgeryStdPkgPage }) => {
await surgeryStdPkgPage.open();
await surgeryStdPkgPage.openAddLoosePartDialog();
await surgeryStdPkgPage.filterAndCheckLoosePart();
await surgeryStdPkgPage.switchLoosePartDetailView();
const stats = await surgeryStdPkgPage.readLoosePartStats();
expect(stats.kind, '应读取到「耗材品种数」').not.toBeNull();
expect(stats.total, '应读取到「耗材总数」').not.toBeNull();
expect(stats.kind as number, '耗材品种数应 ≥ 1').toBeGreaterThanOrEqual(1);
expect(stats.total as number, '耗材总数应 ≥ 品种数').toBeGreaterThanOrEqual(stats.kind as number);
await surgeryStdPkgPage.closeDialogIfOpen();
});
test('SURG-STD-020 添加散件取消不落库', async ({ surgeryStdPkgPage }) => {
await surgeryStdPkgPage.open();
const { total, cancelOk } = await surgeryStdPkgPage.addLoosePartThenCancel();
expect(cancelOk, '取消后弹窗应关闭').toBeTruthy();
expect(await surgeryStdPkgPage.getTotalCount(), '取消后构成列表总数不变').toBe(total);
});
test('SURG-STD-021 万级散件列表首屏可交互', async ({ surgeryStdPkgPage }) => {
test('SURG-STD-016 万级散件列表首屏可交互', async ({ surgeryStdPkgPage }) => {
await surgeryStdPkgPage.open();
const { total, firstRowVisible, pagerVisible } = await surgeryStdPkgPage.loosePartFirstScreen();
expect(firstRowVisible || pagerVisible, '万级列表首屏应可交互(不白屏、分页可用)').toBeTruthy();
......@@ -225,7 +184,7 @@ test.describe('基础设置 · 手术套包设置', () => {
});
test.describe('标准套包维护 · 行内操作(编辑 / 移除)', () => {
test('SURG-STD-022 行内编辑构成项', async ({ surgeryStdPkgPage }) => {
test('SURG-STD-017 行内编辑构成项', async ({ surgeryStdPkgPage }) => {
await surgeryStdPkgPage.open();
const { groupName } = await surgeryStdPkgPage.editFirstChildRow();
expect(groupName, '应展开目标包分组').toBeTruthy();
......@@ -233,7 +192,7 @@ test.describe('基础设置 · 手术套包设置', () => {
await surgeryStdPkgPage.closeDialogIfOpen();
});
test('SURG-STD-023 移除二次确认防误删整包', { tag: '@smoke' }, async ({ surgeryStdPkgPage }) => {
test('SURG-STD-018 移除二次确认防误删整包', { tag: '@smoke' }, async ({ surgeryStdPkgPage }) => {
await surgeryStdPkgPage.open();
const { before } = await surgeryStdPkgPage.removeFirstChildRowThenCancel();
expect(await surgeryStdPkgPage.getDataRowCount(), '取消后行数未变化').toBe(before);
......
......@@ -148,13 +148,11 @@ describeWithReuseOpen(
test.describe("采购单追溯 · 导出", () => {
test.describe.configure({ timeout: 120_000 });
test("STAT-TPR-013 首行样本查询后导出(无数据直接导出)", { tag: "@smoke" }, async ({
test("STAT-TPR-013 首行采购单号查询后导出", { tag: "@smoke" }, async ({
tracePurchasePage,
}) => {
await tracePurchasePage.assertExportAvailable();
await tracePurchasePage.open();
await tracePurchasePage.exportWithFirstRowSampleQuery(
tracePurchaseComboQuickFields,
);
await tracePurchasePage.exportWithFirstRowSampleQuery();
});
});
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment