Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
test
autotest-playwright-web-spd
Commits
79a08ff4
Commit
79a08ff4
authored
Sep 18, 2026
by
liguangyu06
Browse files
修复报表表头 strict mode、列设置关面板超时及汇总/排序定位,避免夜间全量被脚本误杀。
parent
35fe36af
Changes
87
Expand all
Hide whitespace changes
Inline
Side-by-side
core/column-header-match.util.ts
View file @
79a08ff4
...
@@ -6,7 +6,6 @@ const COLUMN_HEADER_ALIAS_GROUPS: readonly (readonly string[])[] = [
...
@@ -6,7 +6,6 @@ const COLUMN_HEADER_ALIAS_GROUPS: readonly (readonly string[])[] = [
[
'
院区名称
'
,
'
院区
'
],
[
'
院区名称
'
,
'
院区
'
],
[
'
27位医保编码
'
,
'
医保编码
'
,
'
医保码
'
],
[
'
27位医保编码
'
,
'
医保编码
'
,
'
医保码
'
],
[
'
医保单件名称
'
,
'
单件名称
'
,
'
医保名称
'
],
[
'
医保单件名称
'
,
'
单件名称
'
,
'
医保名称
'
],
[
'
数量
'
,
'
净入数量
'
,
'
净出数量
'
,
'
入库数量
'
,
'
出库数量
'
,
'
成本数量
'
],
[
'
HIS编码
'
,
'
HIS码
'
,
'
His编码
'
],
[
'
HIS编码
'
,
'
HIS码
'
,
'
His编码
'
],
[
'
结算单标签
'
,
'
标签
'
],
[
'
结算单标签
'
,
'
标签
'
],
[
'
产品编号
'
,
'
产品编码
'
,
'
物资编码
'
,
'
商品编码
'
],
[
'
产品编号
'
,
'
产品编码
'
,
'
物资编码
'
,
'
商品编码
'
],
...
@@ -18,10 +17,7 @@ function aliasTokensFor(columnName: string): string[] {
...
@@ -18,10 +17,7 @@ function aliasTokensFor(columnName: string): string[] {
const
normalized
=
columnName
.
replace
(
/
\s
+/g
,
''
).
trim
();
const
normalized
=
columnName
.
replace
(
/
\s
+/g
,
''
).
trim
();
const
out
:
string
[]
=
[];
const
out
:
string
[]
=
[];
for
(
const
group
of
COLUMN_HEADER_ALIAS_GROUPS
)
{
for
(
const
group
of
COLUMN_HEADER_ALIAS_GROUPS
)
{
const
hit
=
group
.
some
((
alias
)
=>
{
const
hit
=
group
.
some
((
alias
)
=>
alias
.
replace
(
/
\s
+/g
,
''
)
===
normalized
);
const
a
=
alias
.
replace
(
/
\s
+/g
,
''
);
return
a
===
normalized
||
a
.
includes
(
normalized
)
||
normalized
.
includes
(
a
);
});
if
(
hit
)
{
if
(
hit
)
{
for
(
const
alias
of
group
)
{
for
(
const
alias
of
group
)
{
const
a
=
alias
.
replace
(
/
\s
+/g
,
''
).
trim
();
const
a
=
alias
.
replace
(
/
\s
+/g
,
''
).
trim
();
...
...
data/ana-chg.data.ts
View file @
79a08ff4
...
@@ -110,6 +110,15 @@ export const anaChgData: CenterReportPageData & {
...
@@ -110,6 +110,15 @@ export const anaChgData: CenterReportPageData & {
comboSamplePickKeys
:
[
'
field
'
,
'
productName
'
,
'
spec
'
,
'
supplierName
'
,
'
field2
'
,
'
consumableType
'
],
comboSamplePickKeys
:
[
'
field
'
,
'
productName
'
,
'
spec
'
,
'
supplierName
'
,
'
field2
'
,
'
consumableType
'
],
comboSampleMaxRowScan
:
5
,
comboSampleMaxRowScan
:
5
,
drawerFields
:
anaChgComboDrawerFields
,
drawerFields
:
anaChgComboDrawerFields
,
firstRowSummaryMatch
:
{
metrics
:
[
{
key
:
'
field8
'
,
label
:
'
选中总数量
'
,
summaryLabels
:
[
'
选中总数量
'
]
},
{
key
:
'
field9
'
,
label
:
'
选中总差额
'
,
summaryLabels
:
[
'
选中总差额
'
]
},
],
requiredKey
:
'
productName
'
,
fields
:
anaChgComboQuickFields
,
footerKeywords
:
[
'
选中总数量
'
,
'
选中总差额
'
,
'
合计
'
],
},
};
};
export
const
anaChgSortCases
=
buildSortColumnCases
(
'
STAT-ACH
'
,
anaChgSortColumns
,
10
);
export
const
anaChgSortCases
=
buildSortColumnCases
(
'
STAT-ACH
'
,
anaChgSortColumns
,
10
);
data/center-report-net-out.data.ts
View file @
79a08ff4
...
@@ -24,7 +24,6 @@ export const centerReportNetOutSortColumns = [
...
@@ -24,7 +24,6 @@ export const centerReportNetOutSortColumns = [
'
科室名称
'
,
'
科室名称
'
,
'
产品编码
'
,
'
产品编码
'
,
'
产品名称
'
,
'
产品名称
'
,
'
规格型号
'
,
'
单位
'
,
'
单位
'
,
'
耗材类型
'
,
'
耗材类型
'
,
'
厂家
'
,
'
厂家
'
,
...
...
data/center-report-shared.types.ts
View file @
79a08ff4
...
@@ -26,6 +26,8 @@ export type CenterReportPageData = {
...
@@ -26,6 +26,8 @@ export type CenterReportPageData = {
sortColumns
?:
readonly
string
[];
sortColumns
?:
readonly
string
[];
sortCasePrefix
?:
string
;
sortCasePrefix
?:
string
;
sortCaseStartIndex
?:
number
;
sortCaseStartIndex
?:
number
;
/** 列排序前需勾选的维度(如「产品批号」依赖「区分批号」) */
sortColumnPrerequisites
?:
Readonly
<
Record
<
string
,
readonly
string
[]
>>
;
mockNotExistProduct
:
string
;
mockNotExistProduct
:
string
;
mockNotExistCode
?:
string
;
mockNotExistCode
?:
string
;
mockNotExistMaterial
?:
string
;
mockNotExistMaterial
?:
string
;
...
...
data/cost-fin-in.data.ts
View file @
79a08ff4
...
@@ -44,6 +44,7 @@ export const costFinInData: CenterReportPageData = {
...
@@ -44,6 +44,7 @@ export const costFinInData: CenterReportPageData = {
hasExpandRow
:
false
,
hasExpandRow
:
false
,
hasBatchPrint
:
false
,
hasBatchPrint
:
false
,
hasToolbarPrint
:
true
,
hasToolbarPrint
:
true
,
printRequiresDetailSelection
:
true
,
hasFilterToggle
:
false
,
hasFilterToggle
:
false
,
exportTaskName
:
'
财务入库单
'
,
exportTaskName
:
'
财务入库单
'
,
exportDirectDownload
:
false
,
exportDirectDownload
:
false
,
...
...
data/cost-finance-psi.data.ts
View file @
79a08ff4
...
@@ -66,7 +66,6 @@ export const costFinancePsiSortColumns = [
...
@@ -66,7 +66,6 @@ export const costFinancePsiSortColumns = [
'
产品名称
'
,
'
产品名称
'
,
'
规格型号
'
,
'
规格型号
'
,
'
产品编号
'
,
'
产品编号
'
,
'
生产厂家
'
,
'
耗材类型
'
,
'
耗材类型
'
,
'
单位
'
,
'
单位
'
,
'
期初数量
'
,
'
期初数量
'
,
...
...
data/cost-product-rank.data.ts
View file @
79a08ff4
...
@@ -37,11 +37,11 @@ export const costProductRankDetailHeaders = ['科室名称', '成本数量', '
...
@@ -37,11 +37,11 @@ export const costProductRankDetailHeaders = ['科室名称', '成本数量', '
export
const
costProductRankComboQuickFields
:
readonly
DeptQuickFieldDef
[]
=
[
export
const
costProductRankComboQuickFields
:
readonly
DeptQuickFieldDef
[]
=
[
{
key
:
'
statMonth
'
,
label
:
'
统计月份
'
,
type
:
'
date
'
},
{
key
:
'
statMonth
'
,
label
:
'
统计月份
'
,
type
:
'
date
'
},
{
key
:
'
campus
'
,
label
:
'
院区
'
,
type
:
'
select
'
},
{
key
:
'
campus
'
,
label
:
'
院区
'
,
type
:
'
select
'
},
{
key
:
'
consumableType
'
,
label
:
'
耗材类型
'
,
type
:
'
select
'
},
{
key
:
'
consumableCategory
'
,
label
:
'
耗材分类
'
,
type
:
'
select
'
},
];
];
export
const
costProductRankComboDrawerFields
:
readonly
CenterReportDrawerField
[]
=
[
export
const
costProductRankComboDrawerFields
:
readonly
CenterReportDrawerField
[]
=
[
{
key
:
'
consumableType
'
,
type
:
'
select
'
,
label
:
'
耗材类型
'
},
{
key
:
'
consumableCategory
'
,
type
:
'
select
'
,
label
:
'
耗材分类
'
},
{
key
:
'
isKeySupervised
'
,
type
:
'
select
'
,
label
:
'
是否重点监管
'
},
{
key
:
'
isKeySupervised
'
,
type
:
'
select
'
,
label
:
'
是否重点监管
'
},
];
];
...
...
data/dept-report-out.data.ts
View file @
79a08ff4
...
@@ -51,7 +51,7 @@ export const deptReportOutData: CenterReportPageData = {
...
@@ -51,7 +51,7 @@ export const deptReportOutData: CenterReportPageData = {
exportDirectDownload
:
false
,
exportDirectDownload
:
false
,
exportSelectFirstRow
:
false
,
exportSelectFirstRow
:
false
,
exportQueryFromSample
:
true
,
exportQueryFromSample
:
true
,
comboSampleScrollColumns
:
[
'
结算方式
'
,
'
单据形态
'
,
'
批号
'
,
'
科室名称
'
,
'
单号
'
,
'
进院供应商名称
'
],
comboSampleScrollColumns
:
[
'
产品编号
'
,
'
产品名称
'
,
'
结算方式
'
,
'
单据形态
'
,
'
批号
'
,
'
科室名称
'
,
'
单号
'
,
'
进院供应商名称
'
],
comboSamplePickKeys
:
[
'
productName
'
,
'
accountDate
'
,
'
billType
'
,
'
deptName
'
,
'
dept
'
,
'
orderNo
'
,
'
settlement
'
,
'
billMode
'
,
'
batchNo
'
],
comboSamplePickKeys
:
[
'
productName
'
,
'
accountDate
'
,
'
billType
'
,
'
deptName
'
,
'
dept
'
,
'
orderNo
'
,
'
settlement
'
,
'
billMode
'
,
'
batchNo
'
],
comboSampleFieldAliases
:
{
dept
:
'
deptName
'
},
comboSampleFieldAliases
:
{
dept
:
'
deptName
'
},
comboSampleMaxRowScan
:
5
,
comboSampleMaxRowScan
:
5
,
...
...
data/dept-report-turnover.data.ts
View file @
79a08ff4
...
@@ -38,6 +38,9 @@ export const deptReportTurnoverData: CenterReportPageData = {
...
@@ -38,6 +38,9 @@ export const deptReportTurnoverData: CenterReportPageData = {
sortCasePrefix
:
'
STAT-DTR
'
,
sortCasePrefix
:
'
STAT-DTR
'
,
sortCaseStartIndex
:
6
,
sortCaseStartIndex
:
6
,
mockNotExistProduct
:
'
__NOT_EXIST_PRODUCT__99999
'
,
mockNotExistProduct
:
'
__NOT_EXIST_PRODUCT__99999
'
,
horizontalScrollAnchorColumn
:
'
产品编号
'
,
horizontalScrollTargetColumn
:
'
库存周转率
'
,
horizontalScrollDragDelta
:
320
,
paginationPageSizeFrom
:
'
50 条/页
'
,
paginationPageSizeFrom
:
'
50 条/页
'
,
paginationPageSizeTo
:
'
100 条/页
'
,
paginationPageSizeTo
:
'
100 条/页
'
,
sampleRowIndex
:
0
,
sampleRowIndex
:
0
,
...
...
data/invoice-settle.data.ts
View file @
79a08ff4
...
@@ -33,7 +33,7 @@ export const invoiceSettleComboAssertKeys = ['supplierName', 'field4'] as const;
...
@@ -33,7 +33,7 @@ export const invoiceSettleComboAssertKeys = ['supplierName', 'field4'] as const;
export
const
invoiceSettleDomainQuickFields
:
readonly
DeptQuickFieldDef
[]
=
[
export
const
invoiceSettleDomainQuickFields
:
readonly
DeptQuickFieldDef
[]
=
[
{
key
:
'
field
'
,
label
:
'
结算月份
'
,
type
:
'
date
'
},
{
key
:
'
field
'
,
label
:
'
结算月份
'
,
type
:
'
date
'
},
{
key
:
'
supplierName
'
,
label
:
'
进院供应商
名称
'
,
type
:
'
select
'
},
{
key
:
'
supplierName
'
,
label
:
'
进院供应商
'
,
type
:
'
select
'
},
];
];
export
const
invoiceSettleDomainAssertKeys
=
[
'
supplierName
'
,
'
field4
'
]
as
const
;
export
const
invoiceSettleDomainAssertKeys
=
[
'
supplierName
'
,
'
field4
'
]
as
const
;
...
@@ -84,8 +84,8 @@ export const invoiceSettleData: CenterReportPageData & {
...
@@ -84,8 +84,8 @@ export const invoiceSettleData: CenterReportPageData & {
exportQueryFromSample
:
true
,
exportQueryFromSample
:
true
,
columnSettingsToggleCandidates
:
[
'
线上线下
'
],
columnSettingsToggleCandidates
:
[
'
线上线下
'
],
comboSampleScrollColumns
:
[
'
院区名称
'
],
comboSampleScrollColumns
:
[
'
结算月份
'
,
'
进院供应商
'
,
'
院区名称
'
],
comboSamplePickKeys
:
[
'
supplierName
'
,
'
field4
'
,
'
isVolume
'
,
'
field2
'
],
comboSamplePickKeys
:
[
'
field
'
,
'
supplierName
'
,
'
field4
'
,
'
isVolume
'
,
'
field2
'
],
drawerFields
:
invoiceSettleComboDrawerFields
,
drawerFields
:
invoiceSettleComboDrawerFields
,
};
};
...
...
data/pol-consumer.data.ts
View file @
79a08ff4
...
@@ -103,7 +103,7 @@ export const polConsumerData: CenterReportPageData & {
...
@@ -103,7 +103,7 @@ export const polConsumerData: CenterReportPageData & {
},
},
horizontalScrollAnchorColumn
:
'
消耗日期
'
,
horizontalScrollAnchorColumn
:
'
消耗日期
'
,
horizontalScrollTargetColumn
:
'
带量项目合同号
'
,
horizontalScrollTargetColumn
:
'
完成数量
'
,
horizontalScrollDragDelta
:
320
,
horizontalScrollDragDelta
:
320
,
mockNotExistProduct
:
'
__NOT_EXIST_PRODUCT__99999
'
,
mockNotExistProduct
:
'
__NOT_EXIST_PRODUCT__99999
'
,
mockFieldLabel
:
'
带量项目
'
,
mockFieldLabel
:
'
带量项目
'
,
...
...
data/recon-purchase-entry.data.ts
View file @
79a08ff4
...
@@ -55,6 +55,9 @@ export const reconPurchaseEntryData: CenterReportPageData = {
...
@@ -55,6 +55,9 @@ export const reconPurchaseEntryData: CenterReportPageData = {
sortColumns
:
reconPurchaseEntrySortColumns
,
sortColumns
:
reconPurchaseEntrySortColumns
,
sortCasePrefix
:
'
STAT-RPE
'
,
sortCasePrefix
:
'
STAT-RPE
'
,
sortCaseStartIndex
:
16
,
sortCaseStartIndex
:
16
,
sortColumnPrerequisites
:
{
产品批号
:
[
'
区分批号
'
],
},
hasAdvancedFilter
:
true
,
hasAdvancedFilter
:
true
,
hasExport
:
true
,
hasExport
:
true
,
hasExpandRow
:
false
,
hasExpandRow
:
false
,
...
@@ -69,7 +72,8 @@ export const reconPurchaseEntryData: CenterReportPageData = {
...
@@ -69,7 +72,8 @@ export const reconPurchaseEntryData: CenterReportPageData = {
horizontalScrollAnchorColumn
:
'
产品名称
'
,
horizontalScrollAnchorColumn
:
'
产品名称
'
,
horizontalScrollTargetColumn
:
'
产品类型
'
,
horizontalScrollTargetColumn
:
'
产品类型
'
,
horizontalScrollDragDelta
:
320
,
horizontalScrollDragDelta
:
320
,
comboSamplePickKeys
:
[
'
productName
'
,
'
statDate
'
,
'
supplierName
'
,
'
subSupplierName
'
],
comboSamplePickKeys
:
[
'
productName
'
,
'
statDate
'
,
'
supplierName
'
,
'
subSupplierName
'
,
'
inboundQty
'
],
comboSampleScrollColumns
:
[
'
采购入库数量
'
,
'
产品类型
'
],
drawerFields
:
reconPurchaseEntryComboDrawerFields
,
drawerFields
:
reconPurchaseEntryComboDrawerFields
,
firstRowSummaryMatch
:
{
firstRowSummaryMatch
:
{
metrics
:
[
metrics
:
[
...
...
data/warn-detain.data.ts
View file @
79a08ff4
...
@@ -72,7 +72,7 @@ export const warnDetainData: CenterReportPageData & {
...
@@ -72,7 +72,7 @@ export const warnDetainData: CenterReportPageData & {
},
},
horizontalScrollAnchorColumn
:
'
院区名称
'
,
horizontalScrollAnchorColumn
:
'
院区名称
'
,
horizontalScrollTargetColumn
:
'
院区名称
'
,
horizontalScrollTargetColumn
:
'
待发数量
'
,
horizontalScrollDragDelta
:
320
,
horizontalScrollDragDelta
:
320
,
mockNotExistProduct
:
'
__NOT_EXIST_PRODUCT__99999
'
,
mockNotExistProduct
:
'
__NOT_EXIST_PRODUCT__99999
'
,
mockFieldLabel
:
'
产品名称
'
,
mockFieldLabel
:
'
产品名称
'
,
...
...
docs/jenkins.md
View file @
79a08ff4
...
@@ -9,7 +9,7 @@
...
@@ -9,7 +9,7 @@
| 任务 | 套件 | 建议 cron | 说明 |
| 任务 | 套件 | 建议 cron | 说明 |
|------|------|-----------|------|
|------|------|-----------|------|
|
`spd-ui-smoke`
|
`smoke`
|
`H 8-18 * * 1-5`
| 工作时段冒烟:全部报表模块已打
`@smoke`
的用例 |
|
`spd-ui-smoke`
|
`smoke`
|
`H 8-18 * * 1-5`
| 工作时段冒烟:全部报表模块已打
`@smoke`
的用例 |
|
`spd-ui-nightly`
|
`nightly`
|
`H 2 * *
*`
| 夜间主 spec 回归,不含
`@full`
、不含调试
`*.stat-*.spec.ts`
|
|
`spd-ui-nightly`
/
`SPD`
|
`nightly`
/
`full`
|
`H 2
3
* *
1,3,5`
| 周一、三、五
**23 点**
回归(Jenkins 任务
`SPD`
当前按此时段跑 full)
|
|
`spd-ui-full`
|
`full`
|
`H 3 * * 0`
| 周末含全列排序,最慢 |
|
`spd-ui-full`
|
`full`
|
`H 3 * * 0`
| 周末含全列排序,最慢 |
同一套
`Jenkinsfile`
用参数
`SUITE`
区分即可;定时任务在 Jenkins 里「Build periodically」分别写 cron。
同一套
`Jenkinsfile`
用参数
`SUITE`
区分即可;定时任务在 Jenkins 里「Build periodically」分别写 cron。
...
@@ -84,7 +84,7 @@ npm run test:spd:shard
...
@@ -84,7 +84,7 @@ npm run test:spd:shard
| Jenkins 任务名 | 默认
`SUITE`
| Build periodically | 建议参数 |
| Jenkins 任务名 | 默认
`SUITE`
| Build periodically | 建议参数 |
|----------------|--------------|--------------------|----------|
|----------------|--------------|--------------------|----------|
|
`spd-ui-smoke`
|
`smoke`
|
`H 8-18 * * 1-5`
|
`WORKERS=3`
`SHARDS=1`
|
|
`spd-ui-smoke`
|
`smoke`
|
`H 8-18 * * 1-5`
|
`WORKERS=3`
`SHARDS=1`
|
|
`spd-ui-nightly`
|
`nightly`
|
`H 2 * *
*`
|
`WORKERS=2`
`SHARDS=2`
|
|
`spd-ui-nightly`
/
`SPD`
|
`nightly`
/
`full`
|
`H 2
3
* *
1,3,5`
| 周一、三、五 23 点;
`WORKERS=2`
`SHARDS=2`
|
|
`spd-ui-full`
|
`full`
|
`H 3 * * 0`
|
`WORKERS=2`
`SHARDS=2`
,勾选
`RUN_FULL`
|
|
`spd-ui-full`
|
`full`
|
`H 3 * * 0`
|
`WORKERS=2`
`SHARDS=2`
,勾选
`RUN_FULL`
|
每个任务:
每个任务:
...
...
locators/spd/center-report-entry.locator.ts
View file @
79a08ff4
...
@@ -88,19 +88,41 @@ export class CenterReportEntryLocators {
...
@@ -88,19 +88,41 @@ export class CenterReportEntryLocators {
}
}
tableHeaderCells
():
Locator
{
tableHeaderCells
():
Locator
{
return
this
.
report
.
locator
(
'
.ant-table-wrapper
'
).
first
().
locator
(
'
.ant-table-thead tr
'
).
last
().
locator
(
'
th
'
);
return
this
.
visibleThead
().
locator
(
'
tr
'
).
last
().
locator
(
'
th
'
);
}
/**
* 可见 sticky 表头。宽表会在 body / fixed 区再克隆 thead,
* `.ant-table-thead tr`.last() 会命中测宽空行或克隆列,waitFor 触发 strict mode。
*/
visibleThead
():
Locator
{
const
wrapper
=
this
.
report
.
locator
(
'
.ant-table-wrapper
'
).
first
();
return
wrapper
.
locator
(
'
.ant-table-container > .ant-table-header .ant-table-thead
'
)
.
or
(
wrapper
.
locator
(
'
.ant-table-header .ant-table-thead
'
))
.
or
(
wrapper
.
locator
(
'
.ant-table-content > table > .ant-table-thead
'
))
.
or
(
wrapper
.
locator
(
'
.ant-table-thead
'
))
.
first
();
}
}
/** 指定列的表头单元格;每条分支先 .first(),避免 or() 在多匹配 waitFor 时 strict mode。 */
columnHeaderCell
(
columnName
:
string
):
Locator
{
columnHeaderCell
(
columnName
:
string
):
Locator
{
const
thead
=
this
.
report
.
locator
(
'
.ant-table-wrapper
'
).
first
().
locator
(
'
.ant-table-thead
tr
'
).
last
();
const
thead
=
this
.
visibleThead
().
locator
(
'
tr
'
).
last
();
const
byTitle
=
thead
const
byTitle
=
thead
.
locator
(
'
th:visible
'
)
.
locator
(
'
th
'
)
.
filter
({
.
filter
({
has
:
thead
.
locator
(
'
.ant-table-column-title
'
).
getByText
(
columnName
,
{
exact
:
true
})
})
has
:
this
.
report
.
locator
(
'
.ant-table-column-title
'
).
getByText
(
columnName
,
{
exact
:
true
}),
.
first
();
})
const
bySorter
=
thead
.
filter
({
has
:
this
.
report
.
locator
(
'
.ant-table-column-sorter
'
)
});
.
locator
(
'
th
'
)
const
byRole
=
this
.
report
.
getByRole
(
'
columnheader
'
,
{
name
:
columnName
,
exact
:
true
});
.
filter
({
has
:
thead
.
locator
(
'
.ant-table-column-title
'
).
getByText
(
columnName
,
{
exact
:
true
})
})
return
byTitle
.
or
(
byRole
).
first
();
.
filter
({
has
:
thead
.
locator
(
'
.ant-table-column-sorter
'
)
})
.
first
();
const
byRole
=
this
.
report
.
locator
(
'
.ant-table-wrapper
'
)
.
first
()
.
getByRole
(
'
columnheader
'
,
{
name
:
columnName
,
exact
:
true
})
.
first
();
return
byTitle
.
or
(
bySorter
).
or
(
byRole
).
first
();
}
}
columnSorter
(
columnName
:
string
):
Locator
{
columnSorter
(
columnName
:
string
):
Locator
{
...
@@ -146,14 +168,21 @@ export class CenterReportEntryLocators {
...
@@ -146,14 +168,21 @@ export class CenterReportEntryLocators {
}
}
subTableRow
(
rowIndex
=
0
):
Locator
{
subTableRow
(
rowIndex
=
0
):
Locator
{
return
this
.
expandedRow
.
locator
(
'
.ant-table tbody tr
'
).
nth
(
rowIndex
);
return
this
.
expandedRow
.
locator
(
'
.ant-table tbody tr.ant-table-row:not(.ant-table-measure-row)
'
)
.
nth
(
rowIndex
);
}
}
subTableViewButton
(
rowIndex
=
0
):
Locator
{
subTableViewButton
(
rowIndex
=
0
):
Locator
{
const
row
=
this
.
subTableRow
(
rowIndex
);
const
row
=
this
.
subTableRow
(
rowIndex
);
return
row
const
fixedRightRow
=
this
.
expandedRow
.
getByRole
(
'
button
'
,
{
name
:
'
查看
'
})
.
locator
(
'
.ant-table-fixed-right tbody tr.ant-table-row:not(.ant-table-measure-row)
'
)
.
or
(
row
.
getByRole
(
'
link
'
,
{
name
:
'
查看
'
}))
.
nth
(
rowIndex
);
.
first
();
const
inRow
=
(
host
:
Locator
)
=>
host
.
getByRole
(
'
button
'
,
{
name
:
/查
\s
*看/
})
.
or
(
host
.
getByRole
(
'
link
'
,
{
name
:
/查
\s
*看/
}))
.
or
(
host
.
locator
(
'
a, button, span, .ant-btn
'
).
filter
({
hasText
:
/查
\s
*看/
}));
return
inRow
(
fixedRightRow
).
or
(
inRow
(
row
)).
first
();
}
}
}
}
locators/spd/center-report-shared.locator.ts
View file @
79a08ff4
...
@@ -39,7 +39,6 @@ export class CenterReportSharedLocators {
...
@@ -39,7 +39,6 @@ export class CenterReportSharedLocators {
readonly
tableBody
:
Locator
;
readonly
tableBody
:
Locator
;
readonly
dataRows
:
Locator
;
readonly
dataRows
:
Locator
;
sortDataRows
:
Locator
;
sortDataRows
:
Locator
;
readonly
paginationTotal
:
Locator
;
readonly
drawerTitle
:
Locator
;
readonly
drawerTitle
:
Locator
;
readonly
drawerFilterBtn
:
Locator
;
readonly
drawerFilterBtn
:
Locator
;
readonly
drawerResetBtn
:
Locator
;
readonly
drawerResetBtn
:
Locator
;
...
@@ -50,6 +49,7 @@ export class CenterReportSharedLocators {
...
@@ -50,6 +49,7 @@ export class CenterReportSharedLocators {
readonly
tableWrapperIndex
:
number
;
readonly
tableWrapperIndex
:
number
;
readonly
detailTableWrapperIndex
:
number
;
readonly
detailTableWrapperIndex
:
number
;
sortTableWrapperIndex
:
number
;
sortTableWrapperIndex
:
number
;
paginationTableWrapperIndex
:
number
;
readonly
detailDataRows
:
Locator
;
readonly
detailDataRows
:
Locator
;
constructor
(
page
:
Page
,
options
:
CenterReportLocatorOptions
)
{
constructor
(
page
:
Page
,
options
:
CenterReportLocatorOptions
)
{
...
@@ -57,6 +57,7 @@ export class CenterReportSharedLocators {
...
@@ -57,6 +57,7 @@ export class CenterReportSharedLocators {
this
.
tableWrapperIndex
=
options
.
tableWrapperIndex
??
0
;
this
.
tableWrapperIndex
=
options
.
tableWrapperIndex
??
0
;
this
.
detailTableWrapperIndex
=
options
.
detailTableWrapperIndex
??
this
.
tableWrapperIndex
;
this
.
detailTableWrapperIndex
=
options
.
detailTableWrapperIndex
??
this
.
tableWrapperIndex
;
this
.
sortTableWrapperIndex
=
options
.
sortTableWrapperIndex
??
this
.
tableWrapperIndex
;
this
.
sortTableWrapperIndex
=
options
.
sortTableWrapperIndex
??
this
.
tableWrapperIndex
;
this
.
paginationTableWrapperIndex
=
this
.
tableWrapperIndex
;
this
.
productName
=
this
.
report
.
locator
(
options
.
productNameSelector
).
first
();
this
.
productName
=
this
.
report
.
locator
(
options
.
productNameSelector
).
first
();
this
.
goodsCode
=
options
.
goodsCodeSelector
this
.
goodsCode
=
options
.
goodsCodeSelector
?
this
.
report
.
locator
(
options
.
goodsCodeSelector
).
first
()
?
this
.
report
.
locator
(
options
.
goodsCodeSelector
).
first
()
...
@@ -112,7 +113,6 @@ export class CenterReportSharedLocators {
...
@@ -112,7 +113,6 @@ export class CenterReportSharedLocators {
'
.ant-table-scroll .ant-table-body table tbody > tr.ant-table-row
'
,
'
.ant-table-scroll .ant-table-body table tbody > tr.ant-table-row
'
,
].
join
(
'
,
'
),
].
join
(
'
,
'
),
);
);
this
.
paginationTotal
=
this
.
report
.
locator
(
'
.ant-pagination-total-text
'
).
first
();
this
.
drawerTitle
=
this
.
report
.
locator
(
'
.ant-drawer-open .ant-drawer-title
'
);
this
.
drawerTitle
=
this
.
report
.
locator
(
'
.ant-drawer-open .ant-drawer-title
'
);
this
.
drawerFilterBtn
=
this
.
report
.
getByRole
(
'
button
'
,
{
name
:
'
筛 选
'
});
this
.
drawerFilterBtn
=
this
.
report
.
getByRole
(
'
button
'
,
{
name
:
'
筛 选
'
});
this
.
drawerResetBtn
=
this
.
report
.
locator
(
'
.ant-drawer-footer
'
).
getByRole
(
'
button
'
,
{
name
:
'
重 置
'
});
this
.
drawerResetBtn
=
this
.
report
.
locator
(
'
.ant-drawer-footer
'
).
getByRole
(
'
button
'
,
{
name
:
'
重 置
'
});
...
@@ -241,6 +241,24 @@ export class CenterReportSharedLocators {
...
@@ -241,6 +241,24 @@ export class CenterReportSharedLocators {
);
);
}
}
bindPaginationTable
(
index
:
number
):
void
{
this
.
paginationTableWrapperIndex
=
index
;
}
/** 按 tableWrapper 定位对应 ProTable 底部分页,避免左右双表互相抢页码。 */
paginationHost
():
Locator
{
const
wrapper
=
this
.
report
.
locator
(
'
.ant-table-wrapper
'
).
nth
(
this
.
paginationTableWrapperIndex
);
return
wrapper
.
locator
(
'
xpath=ancestor::*[contains(@class,"ant-pro-table")][1]//ul[contains(@class,"ant-pagination")]
'
)
.
first
()
.
or
(
wrapper
.
locator
(
'
xpath=following::ul[contains(@class,"ant-pagination")][1]
'
))
.
or
(
this
.
report
.
locator
(
'
.ant-pagination
'
).
nth
(
this
.
paginationTableWrapperIndex
));
}
get
paginationTotal
():
Locator
{
return
this
.
paginationHost
().
locator
(
'
.ant-pagination-total-text
'
).
first
();
}
private
sortTableWrapper
():
Locator
{
private
sortTableWrapper
():
Locator
{
return
this
.
report
.
locator
(
'
.ant-table-wrapper
'
).
nth
(
this
.
sortTableWrapperIndex
);
return
this
.
report
.
locator
(
'
.ant-table-wrapper
'
).
nth
(
this
.
sortTableWrapperIndex
);
}
}
...
@@ -257,17 +275,16 @@ export class CenterReportSharedLocators {
...
@@ -257,17 +275,16 @@ export class CenterReportSharedLocators {
let
chain
:
Locator
|
undefined
;
let
chain
:
Locator
|
undefined
;
const
append
=
(
loc
:
Locator
)
=>
{
const
append
=
(
loc
:
Locator
)
=>
{
chain
=
chain
?
chain
.
or
(
loc
)
:
loc
;
const
unique
=
loc
.
first
();
chain
=
chain
?
chain
.
or
(
unique
)
:
unique
;
};
};
append
(
thead
.
locator
(
'
th
:visible
'
).
filter
({
has
:
thead
.
getByText
(
columnName
,
{
exact
:
true
})
}));
append
(
thead
.
locator
(
'
th
'
).
filter
({
has
:
thead
.
getByText
(
columnName
,
{
exact
:
true
})
}));
append
(
withSorter
(
thead
.
locator
(
'
th
:visible
'
).
filter
({
has
:
thead
.
getByText
(
columnName
,
{
exact
:
true
})
})));
append
(
withSorter
(
thead
.
locator
(
'
th
'
).
filter
({
has
:
thead
.
getByText
(
columnName
,
{
exact
:
true
})
})));
append
(
append
(
withSorter
(
withSorter
(
thead
.
locator
(
'
th:visible
'
).
filter
({
thead
.
locator
(
'
th
'
).
filter
({
has
:
this
.
report
has
:
thead
.
locator
(
'
.ant-table-column-title
'
).
getByText
(
columnName
,
{
exact
:
true
}),
.
locator
(
'
.ant-table-column-title
'
)
.
getByText
(
columnName
,
{
exact
:
true
}),
}),
}),
),
),
);
);
...
@@ -283,11 +300,11 @@ export class CenterReportSharedLocators {
...
@@ -283,11 +300,11 @@ export class CenterReportSharedLocators {
for
(
const
token
of
tokens
)
{
for
(
const
token
of
tokens
)
{
const
normalizedFull
=
columnName
.
replace
(
/
\s
+/g
,
''
);
const
normalizedFull
=
columnName
.
replace
(
/
\s
+/g
,
''
);
if
(
token
===
normalizedFull
)
continue
;
if
(
token
===
normalizedFull
)
continue
;
append
(
withSorter
(
thead
.
locator
(
'
th
:visible
'
).
filter
({
hasText
:
token
})));
append
(
withSorter
(
thead
.
locator
(
'
th
'
).
filter
({
hasText
:
token
})));
append
(
append
(
withSorter
(
withSorter
(
thead
.
locator
(
'
th
:visible
'
).
filter
({
thead
.
locator
(
'
th
'
).
filter
({
has
:
th
is
.
report
.
locator
(
'
.ant-table-column-title
'
).
filter
({
hasText
:
token
}),
has
:
th
ead
.
locator
(
'
.ant-table-column-title
'
).
filter
({
hasText
:
token
}),
}),
}),
),
),
);
);
...
@@ -347,11 +364,11 @@ export class CenterReportSharedLocators {
...
@@ -347,11 +364,11 @@ export class CenterReportSharedLocators {
}
}
paginationItem
(
pageNum
:
number
):
Locator
{
paginationItem
(
pageNum
:
number
):
Locator
{
return
this
.
report
.
locator
(
`.ant-pagination-item-
${
pageNum
}
`
);
return
this
.
paginationHost
()
.
locator
(
`.ant-pagination-item-
${
pageNum
}
`
);
}
}
paginationActiveItem
():
Locator
{
paginationActiveItem
():
Locator
{
return
this
.
report
.
locator
(
'
.ant-pagination-item-active
'
);
return
this
.
paginationHost
()
.
locator
(
'
.ant-pagination-item-active
'
)
.
first
()
;
}
}
expandedSubTableHeader
(
name
:
string
):
Locator
{
expandedSubTableHeader
(
name
:
string
):
Locator
{
...
@@ -359,7 +376,9 @@ export class CenterReportSharedLocators {
...
@@ -359,7 +376,9 @@ export class CenterReportSharedLocators {
}
}
subTableRow
(
rowIndex
=
0
):
Locator
{
subTableRow
(
rowIndex
=
0
):
Locator
{
return
this
.
expandedRow
.
locator
(
'
.ant-table tbody tr
'
).
nth
(
rowIndex
);
return
this
.
expandedRow
.
locator
(
'
.ant-table tbody tr.ant-table-row:not(.ant-table-measure-row)
'
)
.
nth
(
rowIndex
);
}
}
subTableRowCheckbox
(
rowIndex
=
0
):
Locator
{
subTableRowCheckbox
(
rowIndex
=
0
):
Locator
{
...
@@ -368,10 +387,14 @@ export class CenterReportSharedLocators {
...
@@ -368,10 +387,14 @@ export class CenterReportSharedLocators {
subTableViewButton
(
rowIndex
=
0
):
Locator
{
subTableViewButton
(
rowIndex
=
0
):
Locator
{
const
row
=
this
.
subTableRow
(
rowIndex
);
const
row
=
this
.
subTableRow
(
rowIndex
);
return
row
const
fixedRightRow
=
this
.
expandedRow
.
getByRole
(
'
button
'
,
{
name
:
'
查看
'
})
.
locator
(
'
.ant-table-fixed-right tbody tr.ant-table-row:not(.ant-table-measure-row)
'
)
.
or
(
row
.
getByRole
(
'
link
'
,
{
name
:
'
查看
'
}))
.
nth
(
rowIndex
);
.
or
(
row
.
locator
(
'
a, span, .ant-btn
'
).
filter
({
hasText
:
/^查看$/
}))
const
inRow
=
(
host
:
Locator
)
=>
.
first
();
host
.
getByRole
(
'
button
'
,
{
name
:
/查
\s
*看/
})
.
or
(
host
.
getByRole
(
'
link
'
,
{
name
:
/查
\s
*看/
}))
.
or
(
host
.
locator
(
'
a, button, span, .ant-btn
'
).
filter
({
hasText
:
/查
\s
*看/
}));
return
inRow
(
fixedRightRow
).
or
(
inRow
(
row
)).
first
();
}
}
}
}
locators/spd/center-report-sheet.locator.ts
View file @
79a08ff4
...
@@ -81,18 +81,41 @@ export class CenterReportSheetLocators {
...
@@ -81,18 +81,41 @@ export class CenterReportSheetLocators {
}
}
tableHeaderCells
():
Locator
{
tableHeaderCells
():
Locator
{
return
this
.
report
.
locator
(
'
.ant-table-wrapper
'
).
first
().
locator
(
'
.ant-table-thead tr
'
).
last
().
locator
(
'
th
'
);
return
this
.
visibleThead
().
locator
(
'
tr
'
).
last
().
locator
(
'
th
'
);
}
/**
* 可见 sticky 表头。宽表会在 body / fixed 区再克隆 thead,
* `.ant-table-thead tr`.last() 会命中测宽空行或克隆列,waitFor 触发 strict mode。
*/
visibleThead
():
Locator
{
const
wrapper
=
this
.
report
.
locator
(
'
.ant-table-wrapper
'
).
first
();
return
wrapper
.
locator
(
'
.ant-table-container > .ant-table-header .ant-table-thead
'
)
.
or
(
wrapper
.
locator
(
'
.ant-table-header .ant-table-thead
'
))
.
or
(
wrapper
.
locator
(
'
.ant-table-content > table > .ant-table-thead
'
))
.
or
(
wrapper
.
locator
(
'
.ant-table-thead
'
))
.
first
();
}
}
/** 指定列的表头单元格
(可见列 + 含排序控件,规避固定列重复表头)
。 */
/** 指定列的表头单元格
;每条分支先 .first(),避免 or() 在多匹配 waitFor 时 strict mode
。 */
columnHeaderCell
(
columnName
:
string
):
Locator
{
columnHeaderCell
(
columnName
:
string
):
Locator
{
const
thead
=
this
.
report
.
locator
(
'
.ant-table-wrapper
'
).
first
().
locator
(
'
.ant-table-thead
tr
'
).
last
();
const
thead
=
this
.
visibleThead
().
locator
(
'
tr
'
).
last
();
const
byTitle
=
thead
const
byTitle
=
thead
.
locator
(
'
th:visible
'
)
.
locator
(
'
th
'
)
.
filter
({
has
:
this
.
report
.
locator
(
'
.ant-table-column-title
'
).
getByText
(
columnName
,
{
exact
:
true
})
})
.
filter
({
has
:
thead
.
locator
(
'
.ant-table-column-title
'
).
getByText
(
columnName
,
{
exact
:
true
})
})
.
filter
({
has
:
this
.
report
.
locator
(
'
.ant-table-column-sorter
'
)
});
.
first
();
const
byRole
=
this
.
report
.
getByRole
(
'
columnheader
'
,
{
name
:
columnName
,
exact
:
true
});
const
bySorter
=
thead
return
byTitle
.
or
(
byRole
).
first
();
.
locator
(
'
th
'
)
.
filter
({
has
:
thead
.
locator
(
'
.ant-table-column-title
'
).
getByText
(
columnName
,
{
exact
:
true
})
})
.
filter
({
has
:
thead
.
locator
(
'
.ant-table-column-sorter
'
)
})
.
first
();
const
byRole
=
this
.
report
.
locator
(
'
.ant-table-wrapper
'
)
.
first
()
.
getByRole
(
'
columnheader
'
,
{
name
:
columnName
,
exact
:
true
})
.
first
();
return
byTitle
.
or
(
bySorter
).
or
(
byRole
).
first
();
}
}
/** 指定列的排序按钮(▲▼ 区域,见 ant-table-column-sorter)。 */
/** 指定列的排序按钮(▲▼ 区域,见 ant-table-column-sorter)。 */
...
...
pages/spd/ana-chg.page.ts
View file @
79a08ff4
import
{
expect
,
type
Page
}
from
'
@playwright/test
'
;
import
{
expect
,
type
Page
}
from
'
@playwright/test
'
;
import
{
anaChgData
}
from
'
../../data/ana-chg.data
'
;
import
{
anaChgData
}
from
'
../../data/ana-chg.data
'
;
import
{
expectNumbersClose
,
parseReportNumber
,
}
from
'
./helpers/report-summary.helper
'
;
import
{
readSummaryMetrics
}
from
'
./helpers/report-summary-match.helper
'
;
import
{
ReconCostReportSharedPage
}
from
'
./recon-cost-report-shared.page
'
;
import
{
ReconCostReportSharedPage
}
from
'
./recon-cost-report-shared.page
'
;
export
class
AnaChgPage
extends
ReconCostReportSharedPage
{
export
class
AnaChgPage
extends
ReconCostReportSharedPage
{
...
@@ -17,35 +12,15 @@ export class AnaChgPage extends ReconCostReportSharedPage {
...
@@ -17,35 +12,15 @@ export class AnaChgPage extends ReconCostReportSharedPage {
* STAT-ACH-007:勾选首行后,明细「数量/总差额」与底部「选中总数量/选中总差额」一致。
* STAT-ACH-007:勾选首行后,明细「数量/总差额」与底部「选中总数量/选中总差额」一致。
*/
*/
async
expectSelectedSummaryMatchesFirstRow
(
rowIndex
=
this
.
data
.
sampleRowIndex
):
Promise
<
void
>
{
async
expectSelectedSummaryMatchesFirstRow
(
rowIndex
=
this
.
data
.
sampleRowIndex
):
Promise
<
void
>
{
const
cfg
=
this
.
data
.
firstRowSummaryMatch
;
expect
(
cfg
,
'
未配置 firstRowSummaryMatch,无法做选中汇总勾稽
'
).
toBeTruthy
();
if
(
!
cfg
)
return
;
await
this
.
waitForTableReady
();
await
this
.
waitForTableReady
();
const
rowCount
=
await
this
.
locators
.
dataRows
.
count
();
expect
(
await
this
.
locators
.
dataRows
.
count
(),
'
主表应至少有 1 条数据以便勾选
'
).
toBeGreaterThan
(
0
);
expect
(
rowCount
,
'
主表应至少有 1 条数据以便勾选
'
).
toBeGreaterThan
(
0
);
await
this
.
checkMainTableRow
(
rowIndex
);
await
this
.
checkMainTableRow
(
rowIndex
);
const
sample
=
await
this
.
extractSampleRow
(
rowIndex
);
await
this
.
assertVisibleRowsMatchFooter
(
cfg
.
metrics
,
{
rowIndexes
:
[
rowIndex
]
});
const
expectedQty
=
parseReportNumber
(
this
.
getSampleValue
(
sample
,
'
field8
'
));
const
expectedDiff
=
parseReportNumber
(
this
.
getSampleValue
(
sample
,
'
field9
'
));
await
expect
.
poll
(
async
()
=>
{
const
summary
=
await
readSummaryMetrics
(
this
.
locators
.
report
.
locator
(
'
body
'
),
[
'
选中总数量
'
,
'
选中总差额
'
,
]);
return
Math
.
abs
(
summary
[
'
选中总数量
'
]
-
expectedQty
)
<=
0.01
*
Math
.
max
(
Math
.
abs
(
expectedQty
),
1
)
&&
Math
.
abs
(
summary
[
'
选中总差额
'
]
-
expectedDiff
)
<=
0.01
*
Math
.
max
(
Math
.
abs
(
expectedDiff
),
1
);
},
{
timeout
:
15
_000
,
message
:
'
勾选后底部选中汇总未与明细数量/总差额一致
'
},
)
.
toBe
(
true
);
const
summary
=
await
readSummaryMetrics
(
this
.
locators
.
report
.
locator
(
'
body
'
),
[
'
选中总数量
'
,
'
选中总差额
'
,
]);
expectNumbersClose
(
summary
[
'
选中总数量
'
],
expectedQty
,
0.01
,
'
选中总数量
'
);
expectNumbersClose
(
summary
[
'
选中总差额
'
],
expectedDiff
,
0.01
,
'
选中总差额
'
);
}
}
}
}
...
...
pages/spd/center-report-entry.page.ts
View file @
79a08ff4
...
@@ -11,9 +11,10 @@ import { BasePage } from '../../core/base.page';
...
@@ -11,9 +11,10 @@ import { BasePage } from '../../core/base.page';
import
{
columnHeaderMatchTokens
}
from
'
../../core/column-header-match.util
'
;
import
{
columnHeaderMatchTokens
}
from
'
../../core/column-header-match.util
'
;
import
{
CenterReportEntryLocators
}
from
'
../../locators/spd/center-report-entry.locator
'
;
import
{
CenterReportEntryLocators
}
from
'
../../locators/spd/center-report-entry.locator
'
;
import
{
DrawerFormControls
}
from
'
./helpers/drawer-form-controls.helper
'
;
import
{
DrawerFormControls
}
from
'
./helpers/drawer-form-controls.helper
'
;
import
{
ColumnSortControls
}
from
'
./helpers/column-sort.helper
'
;
import
{
ColumnSortControls
,
clickColumnSortControl
}
from
'
./helpers/column-sort.helper
'
;
import
{
import
{
ColumnSettingsControls
,
ColumnSettingsControls
,
executeColumnSettingsToggleRestore
,
findUsableColumnSettingsTrigger
,
findUsableColumnSettingsTrigger
,
revealColumnSettingsTriggerByScroll
,
revealColumnSettingsTriggerByScroll
,
}
from
'
./helpers/column-settings.helper
'
;
}
from
'
./helpers/column-settings.helper
'
;
...
@@ -68,7 +69,7 @@ export class CenterReportEntryPage extends BasePage {
...
@@ -68,7 +69,7 @@ export class CenterReportEntryPage extends BasePage {
columnSorter
:
(
columnName
)
=>
this
.
locators
.
columnSorter
(
columnName
),
columnSorter
:
(
columnName
)
=>
this
.
locators
.
columnSorter
(
columnName
),
columnSorterUp
:
(
columnName
)
=>
this
.
locators
.
columnSorterUp
(
columnName
),
columnSorterUp
:
(
columnName
)
=>
this
.
locators
.
columnSorterUp
(
columnName
),
columnSorterDown
:
(
columnName
)
=>
this
.
locators
.
columnSorterDown
(
columnName
),
columnSorterDown
:
(
columnName
)
=>
this
.
locators
.
columnSorterDown
(
columnName
),
clickColumnSort
:
(
columnName
)
=>
this
.
clickColumnSort
(
columnName
),
clickColumnSort
:
(
columnName
,
order
)
=>
this
.
clickColumnSort
(
columnName
,
order
),
getFirstRowText
:
()
=>
this
.
getFirstRowText
(),
getFirstRowText
:
()
=>
this
.
getFirstRowText
(),
getColumnValues
:
(
columnName
,
maxRows
)
=>
this
.
getColumnValues
(
columnName
,
maxRows
),
getColumnValues
:
(
columnName
,
maxRows
)
=>
this
.
getColumnValues
(
columnName
,
maxRows
),
getRowSignatures
:
(
maxRows
)
=>
this
.
getRowSignatures
(
maxRows
),
getRowSignatures
:
(
maxRows
)
=>
this
.
getRowSignatures
(
maxRows
),
...
@@ -668,8 +669,20 @@ export class CenterReportEntryPage extends BasePage {
...
@@ -668,8 +669,20 @@ export class CenterReportEntryPage extends BasePage {
async
clickSubTableViewDetail
(
rowIndex
=
0
):
Promise
<
string
>
{
async
clickSubTableViewDetail
(
rowIndex
=
0
):
Promise
<
string
>
{
const
orderNo
=
await
this
.
getSubTableInboundOrderNo
(
rowIndex
);
const
orderNo
=
await
this
.
getSubTableInboundOrderNo
(
rowIndex
);
const
expanded
=
this
.
locators
.
expandedRow
;
const
scrollHosts
=
expanded
.
locator
(
'
.ant-table-body, .ant-table-content, .ant-table-scroll
'
);
const
hostCount
=
await
scrollHosts
.
count
();
for
(
let
i
=
0
;
i
<
hostCount
;
i
+=
1
)
{
await
scrollHosts
.
nth
(
i
)
.
evaluate
((
el
)
=>
{
(
el
as
HTMLElement
).
scrollLeft
=
(
el
as
HTMLElement
).
scrollWidth
;
})
.
catch
(()
=>
undefined
);
}
const
viewBtn
=
this
.
locators
.
subTableViewButton
(
rowIndex
);
const
viewBtn
=
this
.
locators
.
subTableViewButton
(
rowIndex
);
await
expect
(
viewBtn
).
toBeVisible
();
await
viewBtn
.
scrollIntoViewIfNeeded
().
catch
(()
=>
undefined
);
await
expect
(
viewBtn
,
'
子表「查看」按钮应可见
'
).
toBeVisible
({
timeout
:
10
_000
});
await
this
.
click
(
viewBtn
,
'
点击子表查看
'
);
await
this
.
click
(
viewBtn
,
'
点击子表查看
'
);
return
orderNo
;
return
orderNo
;
}
}
...
@@ -888,19 +901,43 @@ export class CenterReportEntryPage extends BasePage {
...
@@ -888,19 +901,43 @@ export class CenterReportEntryPage extends BasePage {
async
isColumnSortable
(
columnName
:
string
):
Promise
<
boolean
>
{
async
isColumnSortable
(
columnName
:
string
):
Promise
<
boolean
>
{
await
this
.
scrollColumnIntoView
(
columnName
);
await
this
.
scrollColumnIntoView
(
columnName
);
const
sorter
=
this
.
locators
.
columnSorter
(
columnName
);
const
sorter
=
this
.
locators
.
columnSorter
(
columnName
);
const
sortable
=
(
await
sorter
.
count
())
>
0
&&
(
await
sorter
.
isVisible
());
if
((
await
sorter
.
count
())
>
0
)
{
if
(
!
sortable
)
{
return
true
;
}
const
header
=
this
.
locators
.
columnHeaderCell
(
columnName
);
const
hasSorter
=
await
header
.
evaluate
((
el
)
=>
{
const
th
=
((
el
as
HTMLElement
).
closest
(
'
th
'
)
??
el
)
as
HTMLElement
;
return
Boolean
(
th
.
querySelector
(
'
.ant-table-column-sorter
'
)
||
th
.
classList
.
contains
(
'
ant-table-column-has-sorters
'
),
);
})
.
catch
(()
=>
false
);
if
(
!
hasSorter
)
{
await
this
.
assertPageHealthy
(
`列「
${
columnName
}
」不可排序`
);
await
this
.
assertPageHealthy
(
`列「
${
columnName
}
」不可排序`
);
}
}
return
sortable
;
return
hasSorter
;
}
}
async
clickColumnSort
(
columnName
:
string
):
Promise
<
void
>
{
async
clickColumnSort
(
columnName
:
string
,
order
?:
'
ascend
'
|
'
descend
'
):
Promise
<
void
>
{
await
this
.
scrollColumnIntoView
(
columnName
);
await
this
.
scrollColumnIntoView
(
columnName
);
const
header
=
this
.
locators
.
columnHeaderCell
(
columnName
);
const
sorter
=
this
.
locators
.
columnSorter
(
columnName
);
const
sorter
=
this
.
locators
.
columnSorter
(
columnName
);
await
this
.
waitVisible
(
sorter
,
15
_000
);
if
((
await
sorter
.
count
())
>
0
)
{
await
test
.
step
(
`点击
${
columnName
}
列排序`
,
async
()
=>
{
await
sorter
.
waitFor
({
state
:
'
attached
'
,
timeout
:
15
_000
}).
catch
(()
=>
undefined
);
await
sorter
.
click
({
force
:
true
});
}
else
{
await
this
.
waitVisible
(
header
,
15
_000
);
}
const
label
=
order
===
'
descend
'
?
'
降序
'
:
order
===
'
ascend
'
?
'
升序
'
:
'
排序
'
;
await
test
.
step
(
`点击
${
columnName
}
列
${
label
}
`
,
async
()
=>
{
await
clickColumnSortControl
({
header
,
sorter
,
up
:
this
.
locators
.
columnSorterUp
(
columnName
),
down
:
this
.
locators
.
columnSorterDown
(
columnName
),
order
,
});
});
});
await
this
.
locators
.
report
.
locator
(
'
.ant-spin-spinning
'
).
waitFor
({
state
:
'
hidden
'
,
timeout
:
30
_000
}).
catch
(()
=>
undefined
);
await
this
.
locators
.
report
.
locator
(
'
.ant-spin-spinning
'
).
waitFor
({
state
:
'
hidden
'
,
timeout
:
30
_000
}).
catch
(()
=>
undefined
);
}
}
...
@@ -940,26 +977,32 @@ export class CenterReportEntryPage extends BasePage {
...
@@ -940,26 +977,32 @@ export class CenterReportEntryPage extends BasePage {
}
}
async
openColumnSettings
():
Promise
<
void
>
{
async
openColumnSettings
():
Promise
<
void
>
{
await
this
.
closeColumnSettingsPanel
();
const
panel
=
this
.
locators
.
columnSettingsPanel
();
await
this
.
locators
.
columnSettingsPanel
().
waitFor
({
state
:
'
hidden
'
,
timeout
:
3
_000
}).
catch
(()
=>
undefined
);
if
(
await
panel
.
isVisible
().
catch
(()
=>
false
))
{
await
revealColumnSettingsTriggerByScroll
({
return
;
scroll
:
this
.
tableScrollLayoutControls
,
}
tableWrapper
:
this
.
locators
.
report
.
locator
(
'
.ant-table-wrapper
'
).
first
(),
const
triggerCandidates
=
[
this
.
locators
.
columnSettingsTrigger
];
triggerCandidates
:
[
this
.
locators
.
columnSettingsTrigger
],
let
trigger
=
await
findUsableColumnSettingsTrigger
(
triggerCandidates
);
horizontalScrollTargetColumn
:
centerReportEntryData
.
horizontalScrollTargetColumn
,
if
(
!
trigger
)
{
horizontalScrollDragDelta
:
centerReportEntryData
.
horizontalScrollDragDelta
,
await
revealColumnSettingsTriggerByScroll
({
scrollColumnIntoView
:
async
(
column
)
=>
{
scroll
:
this
.
tableScrollLayoutControls
,
await
this
.
locators
.
tableHeader
(
column
).
scrollIntoViewIfNeeded
().
catch
(()
=>
undefined
);
tableWrapper
:
this
.
locators
.
report
.
locator
(
'
.ant-table-wrapper
'
).
first
(),
},
triggerCandidates
,
});
horizontalScrollTargetColumn
:
centerReportEntryData
.
horizontalScrollTargetColumn
,
if
(
!
(
await
findUsableColumnSettingsTrigger
([
this
.
locators
.
columnSettingsTrigger
])))
{
horizontalScrollDragDelta
:
centerReportEntryData
.
horizontalScrollDragDelta
,
scrollColumnIntoView
:
async
(
column
)
=>
{
await
this
.
locators
.
tableHeader
(
column
).
scrollIntoViewIfNeeded
().
catch
(()
=>
undefined
);
},
});
trigger
=
await
findUsableColumnSettingsTrigger
(
triggerCandidates
);
}
if
(
!
trigger
)
{
await
this
.
guardedSkip
(
'
列设置齿轮不可见
'
);
await
this
.
guardedSkip
(
'
列设置齿轮不可见
'
);
}
}
await
this
.
waitVisible
(
this
.
locators
.
columnSettingsTrigger
,
15
_000
);
await
test
.
step
(
'
打开列设置
'
,
async
()
=>
{
await
test
.
step
(
'
打开列设置
'
,
async
()
=>
{
await
t
his
.
locators
.
columnSettingsT
rigger
.
click
({
force
:
true
});
await
trigger
!
.
click
({
force
:
true
});
});
});
await
this
.
waitVisible
(
this
.
locators
.
columnSettingsP
anel
()
,
10
_000
);
await
this
.
waitVisible
(
p
anel
,
10
_000
);
}
}
async
expectColumnSettingsPanel
():
Promise
<
void
>
{
async
expectColumnSettingsPanel
():
Promise
<
void
>
{
...
@@ -1010,6 +1053,19 @@ export class CenterReportEntryPage extends BasePage {
...
@@ -1010,6 +1053,19 @@ export class CenterReportEntryPage extends BasePage {
return
centerReportEntryData
.
columnSettingsToggleCandidates
[
0
];
return
centerReportEntryData
.
columnSettingsToggleCandidates
[
0
];
}
}
/** 场景:取消勾选非核心列后表头隐藏,再勾选后表头恢复。 */
async
executeColumnSettingsToggleRestoreTest
():
Promise
<
void
>
{
await
executeColumnSettingsToggleRestore
({
pickToggleColumnName
:
()
=>
this
.
pickToggleColumnName
(),
openColumnSettings
:
()
=>
this
.
openColumnSettings
(),
setColumnVisibleInSettings
:
(
name
,
visible
)
=>
this
.
setColumnVisibleInSettings
(
name
,
visible
),
closeColumnSettingsPanel
:
()
=>
this
.
closeColumnSettingsPanel
(),
expectTableHeaderVisible
:
(
name
,
visible
)
=>
this
.
expectTableHeaderVisible
(
name
,
visible
),
expectSettingsCheckboxChecked
:
(
name
,
checked
)
=>
this
.
expectSettingsCheckboxChecked
(
name
,
checked
),
});
}
async
expectPaginationTotal
():
Promise
<
void
>
{
async
expectPaginationTotal
():
Promise
<
void
>
{
await
expect
(
this
.
locators
.
paginationTotal
).
toHaveText
(
/共
\s
+
\d
+
\s
+条/
);
await
expect
(
this
.
locators
.
paginationTotal
).
toHaveText
(
/共
\s
+
\d
+
\s
+条/
);
}
}
...
...
pages/spd/center-report-shared.page.ts
View file @
79a08ff4
This diff is collapsed.
Click to expand it.
Prev
1
2
3
4
5
Next
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment