Commit 297e887d authored by liguangyu06's avatar liguangyu06
Browse files

修复基础管理列设置误点顶栏齿轮,统一触发器解析与面板定位。

parent d14afcfe
......@@ -22,9 +22,10 @@ export const basicHospitalData = {
mockOutOfRangeDate: '1999-01-01',
writeDisabledReason: '环境禁止写:SKIP_BASIC_WRITE=1',
paginationPageSizeTo: '20 条/页',
noticeColumnSettingsToggleCandidates: ['发布科室'] as const,
branchColumnSettingsToggleCandidates: ['院区简称'] as const,
financeColumnSettingsToggleCandidates: ['备注'] as const,
noticeColumnSettingsToggleCandidates: ['发布科室', '发布人', '是否置顶'] as const,
// 与列表实际表头对齐(环境未必有「院区简称」「备注」勾选项)
branchColumnSettingsToggleCandidates: ['院区地址', '院区编号', '状态'] as const,
financeColumnSettingsToggleCandidates: ['自动结算日期', '开始日期', '结束日期'] as const,
} as const;
export function isBasicWriteAllowed(): boolean {
......
......@@ -60,9 +60,10 @@ export class BasicUserSharedLocators {
}
columnSettingsPanel(): Locator {
// 与 pages/spd/helpers/column-settings.helper.ts 的 COLUMN_SETTINGS_PANEL_TEXT_RE 保持一致
return this.page
.locator('.ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: '字段设置' })
.locator('.ant-popover.cloumn-list:visible, .ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: /字段设置|列展示|列设置/ })
.first();
}
......
......@@ -133,8 +133,8 @@ export class CenterReportEntryLocators {
columnSettingsPanel(): Locator {
return this.report
.locator('.ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: '字段设置' })
.locator('.ant-popover.cloumn-list:visible, .ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: /字段设置|列展示|列设置/ })
.first();
}
......
......@@ -133,8 +133,8 @@ export class CenterReportSheetLocators {
/** 列设置弹出面板(含「列展示」「字段设置」)。 */
columnSettingsPanel(): Locator {
return this.report
.locator('.ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: '字段设置' })
.locator('.ant-popover.cloumn-list:visible, .ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: /字段设置|列展示|列设置/ })
.first();
}
......
import { expect, type Locator, type Page } from '@playwright/test';
import { userData, uniqLogin } from '../../data/user.data';
import { COLUMN_SETTINGS_TRIGGER_CSS } from '../../locators/spd/center-report-shared.locator';
import { BasicUserLocators } from '../../locators/spd/basic-user.locator';
import { BasicUserSharedPage, type UserMeta } from './basic-user-shared.page';
import {
ColumnSettingsControls,
executeColumnSettingsToggleRestore,
findUsableColumnSettingsTrigger,
resolveUsableColumnSettingsTrigger,
} from './helpers/column-settings.helper';
export type UserSample = {
......@@ -295,27 +294,20 @@ export class BasicUserPage extends BasicUserSharedPage {
}
private async resolveColumnSettingsTrigger(): Promise<Locator> {
const triggers = this.page.locator(COLUMN_SETTINGS_TRIGGER_CSS);
const triggerCount = await triggers.count();
const candidates: Locator[] = [];
for (let i = 0; i < Math.min(triggerCount, 4); i += 1) {
candidates.push(triggers.nth(i));
}
if (candidates.length === 0) {
candidates.push(this.locators.columnSettingsTrigger);
}
let trigger = await findUsableColumnSettingsTrigger(candidates);
if (!trigger) {
await this.locators.tableWrapper.scrollIntoViewIfNeeded().catch(() => undefined);
const body = this.locators.tableWrapper.locator('.ant-table-body').first();
await body
.evaluate((el) => {
(el as HTMLElement).scrollLeft = (el as HTMLElement).scrollWidth;
})
.catch(() => undefined);
await this.waitSettle(200);
trigger = await findUsableColumnSettingsTrigger(candidates);
}
const trigger = await resolveUsableColumnSettingsTrigger({
root: this.page,
tableWrapper: this.locators.tableWrapper,
afterScroll: async () => {
await this.locators.tableWrapper.scrollIntoViewIfNeeded().catch(() => undefined);
const body = this.locators.tableWrapper.locator('.ant-table-body').first();
await body
.evaluate((el) => {
(el as HTMLElement).scrollLeft = (el as HTMLElement).scrollWidth;
})
.catch(() => undefined);
await this.waitSettle(200);
},
});
if (!trigger) {
await this.skipWhenDataInsufficient('列设置齿轮不可见');
}
......@@ -350,6 +342,20 @@ export class BasicUserPage extends BasicUserSharedPage {
return name;
}
}
await this.openColumnSettings();
const wrappers = this.locators.columnSettingsPanel().locator('.ant-checkbox-wrapper');
const count = await wrappers.count();
const core = /^(序号|序号列|操作|查看|全选|字段设置|列展示|列设置|行高|分散|中等|紧凑|紧簇|显示|表格设置|重置)$/;
for (let i = 0; i < count; i += 1) {
const raw = ((await wrappers.nth(i).innerText()) ?? '').replace(/\s+/g, '').trim();
if (!raw || core.test(raw)) continue;
const checkbox = wrappers.nth(i).locator('input[type="checkbox"]').first();
if (!(await checkbox.isChecked().catch(() => false))) continue;
await this.closeColumnSettingsPanel();
return raw;
}
await this.closeColumnSettingsPanel();
await this.skipWhenDataInsufficient('列设置中无可 toggle 的已勾选列');
return userData.columnSettingsToggleCandidates[0];
}
......
import { expect, type Locator, type Page } from '@playwright/test';
import { flowData } from '../../data/flow.data';
import { COLUMN_SETTINGS_TRIGGER_CSS } from '../../locators/spd/center-report-shared.locator';
import { FlowInstLocators } from '../../locators/spd/flow-inst.locator';
import {
ColumnSettingsControls,
executeColumnSettingsToggleRestore,
findUsableColumnSettingsTrigger,
isColumnSettingsTriggerUsable,
resolveUsableColumnSettingsTrigger,
} from './helpers/column-settings.helper';
import { WhFlowSharedPage } from './wh-flow-shared.page';
......@@ -48,8 +46,8 @@ export class FlowInstPage extends WhFlowSharedPage {
columnSettingsPanel(): Locator {
return this.page
.locator('.ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: /字段设置|列展示/ })
.locator('.ant-popover.cloumn-list:visible, .ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: /字段设置|列展示|列设置/ })
.first();
}
......@@ -65,29 +63,19 @@ export class FlowInstPage extends WhFlowSharedPage {
}
async resolveColumnSettingsTrigger(): Promise<Locator> {
const settings = this.page.locator(COLUMN_SETTINGS_TRIGGER_CSS);
const candidates: Locator[] = [];
const count = await settings.count();
for (let i = 0; i < count; i += 1) {
const loc = settings.nth(i);
const box = await loc.boundingBox().catch(() => null);
if (box && box.y > 120) {
candidates.push(loc);
}
}
if (candidates.length === 0) {
candidates.push(this.tableWrapper().locator(COLUMN_SETTINGS_TRIGGER_CSS).first());
}
let trigger = await findUsableColumnSettingsTrigger(candidates);
if (!trigger) {
for (let i = 0; i < count; i += 1) {
const loc = settings.nth(i);
if (await isColumnSettingsTriggerUsable(loc)) {
trigger = loc;
break;
}
}
}
const trigger = await resolveUsableColumnSettingsTrigger({
root: this.page,
tableWrapper: this.tableWrapper(),
afterScroll: async () => {
const body = this.tableWrapper().locator('.ant-table-body').first();
await body
.evaluate((el) => {
(el as HTMLElement).scrollLeft = (el as HTMLElement).scrollWidth;
})
.catch(() => undefined);
await this.waitSettle(200);
},
});
if (!trigger) {
await this.skipWhenDataInsufficient('列设置齿轮不可见');
}
......@@ -122,6 +110,20 @@ export class FlowInstPage extends WhFlowSharedPage {
return name;
}
}
await this.openColumnSettings();
const wrappers = this.columnSettingsPanel().locator('.ant-checkbox-wrapper');
const count = await wrappers.count();
const core = /^(序号|序号列|操作|查看|全选|字段设置|列展示|列设置|行高|分散|中等|紧凑|紧簇|显示|表格设置|重置)$/;
for (let i = 0; i < count; i += 1) {
const raw = ((await wrappers.nth(i).innerText()) ?? '').replace(/\s+/g, '').trim();
if (!raw || core.test(raw)) continue;
const checkbox = wrappers.nth(i).locator('input[type="checkbox"]').first();
if (!(await checkbox.isChecked().catch(() => false))) continue;
await this.closeColumnSettingsPanel();
return raw;
}
await this.closeColumnSettingsPanel();
await this.skipWhenDataInsufficient('列设置中无可 toggle 的已勾选列');
return flowData.columnSettingsToggleCandidates[0];
}
......
import { test, type Locator } from '@playwright/test';
import { test, type FrameLocator, type Locator, type Page } from '@playwright/test';
import { COLUMN_SETTINGS_TRIGGER_CSS } from '../../../locators/spd/center-report-shared.locator';
import type { TableScrollLayoutControls } from './table-scroll-layout.helper';
/** ProTable 列设置浮层文案(各环境可能是字段设置/列展示/列设置)。 */
export const COLUMN_SETTINGS_PANEL_TEXT_RE = /字段设置|列展示|列设置/;
export type ColumnSettingsRoot = Page | FrameLocator | Locator;
/** 统一列设置面板 Locator,避免各页漏写「列设置」。 */
export function columnSettingsPanelLocator(root: ColumnSettingsRoot): Locator {
return root
.locator('.ant-popover.cloumn-list:visible, .ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: COLUMN_SETTINGS_PANEL_TEXT_RE })
.first();
}
/**
* 收集列设置齿轮候选:优先 ProTable 工具栏,再收内容区(y>minY),排除顶栏壳页 setting。
*/
export async function collectColumnSettingsTriggerCandidates(options: {
root: ColumnSettingsRoot;
tableWrapper?: Locator;
triggerCss?: string;
minY?: number;
}): Promise<Locator[]> {
const triggerCss = options.triggerCss ?? COLUMN_SETTINGS_TRIGGER_CSS;
const minY = options.minY ?? 120;
const { root, tableWrapper } = options;
const candidates: Locator[] = [];
const toolbar = root.locator('.ant-pro-table-list-toolbar').first();
const toolbarItem = toolbar.locator(`.ant-pro-table-list-toolbar-setting-item, ${triggerCss}`);
const toolbarCount = await toolbarItem.count().catch(() => 0);
for (let i = 0; i < toolbarCount; i += 1) {
candidates.push(toolbarItem.nth(i));
}
const settings = root.locator(triggerCss);
const count = await settings.count();
for (let i = 0; i < count; i += 1) {
const loc = settings.nth(i);
const box = await loc.boundingBox().catch(() => null);
if (box && box.y > minY) {
candidates.push(loc);
}
}
if (candidates.length === 0 && tableWrapper) {
candidates.push(tableWrapper.locator(triggerCss).first());
}
if (candidates.length === 0) {
for (let i = 0; i < count; i += 1) {
candidates.push(settings.nth(i));
}
}
return candidates;
}
/** 解析可用列设置齿轮:候选收集 → chrome 过滤 → 必要时横滚重试。 */
export async function resolveUsableColumnSettingsTrigger(options: {
root: ColumnSettingsRoot;
tableWrapper?: Locator;
triggerCss?: string;
afterScroll?: () => Promise<void>;
}): Promise<Locator | undefined> {
let candidates = await collectColumnSettingsTriggerCandidates(options);
let trigger = await findUsableColumnSettingsTrigger(candidates);
if (!trigger && options.afterScroll) {
await options.afterScroll();
candidates = await collectColumnSettingsTriggerCandidates(options);
trigger = await findUsableColumnSettingsTrigger(candidates);
}
if (!trigger) {
const settings = options.root.locator(options.triggerCss ?? COLUMN_SETTINGS_TRIGGER_CSS);
const fallback: Locator[] = [];
const count = await settings.count();
for (let i = 0; i < count; i += 1) {
fallback.push(settings.nth(i));
}
trigger = await findUsableColumnSettingsTrigger(fallback);
}
return trigger;
}
/** 列设置齿轮是否可点击(可见或已有盒模型,宽表下常被 overflow 裁切)。 */
export async function isColumnSettingsTriggerUsable(loc: Locator): Promise<boolean> {
if ((await loc.count().catch(() => 0)) === 0) {
......@@ -15,16 +97,57 @@ export async function isColumnSettingsTriggerUsable(loc: Locator): Promise<boole
return !!(box && box.width > 0 && box.height > 0);
}
/** 从候选 Locator 中找到第一个可用的列设置齿轮。 */
/**
* SPD 壳顶栏也有 setting 图标;点它不会打开 ProTable「字段设置」面板。
* 排除 header / 主题设置,并优先 list-toolbar 内的齿轮。
*/
export async function isChromeHeaderSettingsTrigger(loc: Locator): Promise<boolean> {
return loc
.evaluate((el) => {
const node = el as HTMLElement;
if (node.closest('.ant-layout-header, .theme-setting, .ant-pro-global-header, .ant-layout-sider')) {
return true;
}
if (node.closest('.ant-pro-table-list-toolbar, .ant-pro-table, .ant-table-wrapper, main')) {
return false;
}
const top = node.getBoundingClientRect().top;
return top >= 0 && top < 96;
})
.catch(() => false);
}
async function isToolbarColumnSettingsTrigger(loc: Locator): Promise<boolean> {
return loc
.evaluate((el) => {
const node = el as HTMLElement;
const cls = (node.className || '').toString().toLowerCase();
if (cls.includes('list-toolbar-setting-item')) return true;
return Boolean(node.closest('.ant-pro-table-list-toolbar-setting-item, .ant-pro-table-list-toolbar'));
})
.catch(() => false);
}
/** 从候选 Locator 中找到第一个可用的列设置齿轮(跳过壳页顶栏 setting)。 */
export async function findUsableColumnSettingsTrigger(
candidates: readonly Locator[],
): Promise<Locator | undefined> {
const usable: Locator[] = [];
for (const loc of candidates) {
if (await isColumnSettingsTriggerUsable(loc)) {
return loc.first();
const first = loc.first();
if (await isChromeHeaderSettingsTrigger(first)) {
continue;
}
if (await isColumnSettingsTriggerUsable(first)) {
usable.push(first);
}
}
for (const loc of usable) {
if (await isToolbarColumnSettingsTrigger(loc)) {
return loc;
}
}
return undefined;
return usable[0];
}
export type RevealColumnSettingsTriggerOptions = {
......
import { expect, test, type FrameLocator, type Locator, type Page } from '@playwright/test';
import { COLUMN_SETTINGS_TRIGGER_CSS } from '../../../locators/spd/center-report-shared.locator';
import {
ColumnSettingsControls,
columnSettingsPanelLocator,
executeColumnSettingsToggleRestore,
findUsableColumnSettingsTrigger,
isColumnSettingsTriggerUsable,
resolveUsableColumnSettingsTrigger,
} from './column-settings.helper';
import { expectColumnSortByDom } from './column-sort.helper';
......@@ -37,11 +36,7 @@ export class SpdProTableListControls {
}
columnSettingsPanel(): Locator {
return this.deps
.listScope()
.locator('.ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: /字段设置|列展示/ })
.first();
return columnSettingsPanelLocator(this.deps.listScope());
}
columnSettingsCheckboxRow(label: string): Locator {
......@@ -60,36 +55,19 @@ export class SpdProTableListControls {
}
async resolveColumnSettingsTrigger(): Promise<Locator> {
const scope = this.deps.listScope();
const settings = scope.locator(COLUMN_SETTINGS_TRIGGER_CSS);
const candidates: Locator[] = [];
const count = await settings.count();
for (let i = 0; i < count; i += 1) {
candidates.push(settings.nth(i));
}
if (candidates.length === 0) {
candidates.push(this.tableWrapper().locator(COLUMN_SETTINGS_TRIGGER_CSS).first());
}
let trigger = await findUsableColumnSettingsTrigger(candidates);
if (!trigger) {
await this.tableWrapper().scrollIntoViewIfNeeded().catch(() => undefined);
const body = this.tableWrapper().locator('.ant-table-body').first();
await body
.evaluate((el) => {
(el as HTMLElement).scrollLeft = (el as HTMLElement).scrollWidth;
})
.catch(() => undefined);
trigger = await findUsableColumnSettingsTrigger(candidates);
}
if (!trigger) {
for (let i = 0; i < count; i += 1) {
const loc = settings.nth(i);
if (await isColumnSettingsTriggerUsable(loc)) {
trigger = loc;
break;
}
}
}
const trigger = await resolveUsableColumnSettingsTrigger({
root: this.deps.listScope(),
tableWrapper: this.tableWrapper(),
afterScroll: async () => {
await this.tableWrapper().scrollIntoViewIfNeeded().catch(() => undefined);
const body = this.tableWrapper().locator('.ant-table-body').first();
await body
.evaluate((el) => {
(el as HTMLElement).scrollLeft = (el as HTMLElement).scrollWidth;
})
.catch(() => undefined);
},
});
if (!trigger) {
await this.deps.skipWhen('列设置齿轮不可见');
}
......@@ -119,6 +97,22 @@ export class SpdProTableListControls {
if (this.deps.columnSettingsToggleCandidates.length === 0) {
await this.deps.skipWhen('未配置 columnSettingsToggleCandidates');
}
// 候选列当前未展示:打开列设置,挑一个已勾选且非核心列
await this.openColumnSettings();
const wrappers = this.columnSettingsPanel().locator('.ant-checkbox-wrapper');
const count = await wrappers.count();
const core = /^(序号|序号列|操作|查看|全选|字段设置|列展示|列设置|行高|分散|中等|紧凑|紧簇|显示|表格设置|重置)$/;
for (let i = 0; i < count; i += 1) {
const raw = ((await wrappers.nth(i).innerText()) ?? '').replace(/\s+/g, '').trim();
if (!raw || core.test(raw)) continue;
const checkbox = wrappers.nth(i).locator('input[type="checkbox"]').first();
if (!(await checkbox.isChecked().catch(() => false))) continue;
await this.closeColumnSettingsPanel();
return raw;
}
await this.closeColumnSettingsPanel();
await this.deps.skipWhen('列设置中无可 toggle 的已勾选列');
return this.deps.columnSettingsToggleCandidates[0]!;
}
......
......@@ -3,12 +3,11 @@ import { expect, type Locator, type Page } from '@playwright/test';
import { normalizeSampleCellValue } from '../../core/table-data-column.util';
import { vendorAuthFinalData } from '../../data/vendor-auth-final.data';
import { vendorData } from '../../data/vendor.data';
import { COLUMN_SETTINGS_TRIGGER_CSS } from '../../locators/spd/center-report-shared.locator';
import { VendorAuditPage, type VendorAuthOpenOptions } from './vendor-audit.page';
import {
ColumnSettingsControls,
executeColumnSettingsToggleRestore,
findUsableColumnSettingsTrigger,
resolveUsableColumnSettingsTrigger,
} from './helpers/column-settings.helper';
export class VendorAuthFinalPage extends VendorAuditPage {
......@@ -44,8 +43,8 @@ export class VendorAuthFinalPage extends VendorAuditPage {
columnSettingsPanel(): Locator {
return this.page
.locator('.ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: /字段设置|列展示/ })
.locator('.ant-popover.cloumn-list:visible, .ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: /字段设置|列展示|列设置/ })
.first();
}
......@@ -145,18 +144,18 @@ export class VendorAuthFinalPage extends VendorAuditPage {
}
async resolveColumnSettingsTrigger(): Promise<Locator> {
const settings = this.page.locator(COLUMN_SETTINGS_TRIGGER_CSS);
const candidates: Locator[] = [];
const count = await settings.count();
for (let i = 0; i < count; i += 1) {
const loc = settings.nth(i);
const box = await loc.boundingBox().catch(() => null);
if (box && box.y > 120) candidates.push(loc);
}
if (candidates.length === 0) {
candidates.push(this.tableWrapper().locator(COLUMN_SETTINGS_TRIGGER_CSS).first());
}
let trigger = await findUsableColumnSettingsTrigger(candidates);
const trigger = await resolveUsableColumnSettingsTrigger({
root: this.page,
tableWrapper: this.tableWrapper(),
afterScroll: async () => {
const body = this.tableWrapper().locator('.ant-table-body').first();
await body
.evaluate((el) => {
(el as HTMLElement).scrollLeft = (el as HTMLElement).scrollWidth;
})
.catch(() => undefined);
},
});
if (!trigger) {
await this.skipWhenDataInsufficient('列设置齿轮不可见');
}
......
......@@ -3,13 +3,11 @@ import { expect, type Locator, type Page } from '@playwright/test';
import { normalizeSampleCellValue } from '../../core/table-data-column.util';
import { vendorAuthFirstData } from '../../data/vendor-auth-first.data';
import { vendorData } from '../../data/vendor.data';
import { COLUMN_SETTINGS_TRIGGER_CSS } from '../../locators/spd/center-report-shared.locator';
import { VendorAuditPage, type VendorAuthOpenOptions } from './vendor-audit.page';
import {
ColumnSettingsControls,
executeColumnSettingsToggleRestore,
findUsableColumnSettingsTrigger,
isColumnSettingsTriggerUsable,
resolveUsableColumnSettingsTrigger,
} from './helpers/column-settings.helper';
/** 授权变更初审。 */
......@@ -42,8 +40,8 @@ export class VendorAuthFirstPage extends VendorAuditPage {
columnSettingsPanel(): Locator {
return this.page
.locator('.ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: /字段设置|列展示/ })
.locator('.ant-popover.cloumn-list:visible, .ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: /字段设置|列展示|列设置/ })
.first();
}
......@@ -165,18 +163,18 @@ export class VendorAuthFirstPage extends VendorAuditPage {
}
async resolveColumnSettingsTrigger(): Promise<Locator> {
const settings = this.page.locator(COLUMN_SETTINGS_TRIGGER_CSS);
const candidates: Locator[] = [];
const count = await settings.count();
for (let i = 0; i < count; i += 1) {
const loc = settings.nth(i);
const box = await loc.boundingBox().catch(() => null);
if (box && box.y > 120) candidates.push(loc);
}
if (candidates.length === 0) {
candidates.push(this.tableWrapper().locator(COLUMN_SETTINGS_TRIGGER_CSS).first());
}
let trigger = await findUsableColumnSettingsTrigger(candidates);
const trigger = await resolveUsableColumnSettingsTrigger({
root: this.page,
tableWrapper: this.tableWrapper(),
afterScroll: async () => {
const body = this.tableWrapper().locator('.ant-table-body').first();
await body
.evaluate((el) => {
(el as HTMLElement).scrollLeft = (el as HTMLElement).scrollWidth;
})
.catch(() => undefined);
},
});
if (!trigger) {
await this.skipWhenDataInsufficient('列设置齿轮不可见');
}
......
......@@ -4,12 +4,11 @@ import { type FilterScope } from '../../core/base.page';
import { normalizeSampleCellValue } from '../../core/table-data-column.util';
import { vendorCertDiffData } from '../../data/vendor-cert-diff.data';
import { vendorData } from '../../data/vendor.data';
import { COLUMN_SETTINGS_TRIGGER_CSS } from '../../locators/spd/center-report-shared.locator';
import { VendorAuditPage, type VendorAuthOpenOptions } from './vendor-audit.page';
import {
ColumnSettingsControls,
executeColumnSettingsToggleRestore,
findUsableColumnSettingsTrigger,
resolveUsableColumnSettingsTrigger,
} from './helpers/column-settings.helper';
import { skipIfInsufficientForPage2 } from './helpers/pagination-page2.helper';
......@@ -147,8 +146,8 @@ export class VendorCertDiffPage extends VendorAuditPage {
columnSettingsPanel(): Locator {
return this.page
.locator('.ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: /字段设置|列展示/ })
.locator('.ant-popover.cloumn-list:visible, .ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: /字段设置|列展示|列设置/ })
.first();
}
......@@ -287,18 +286,19 @@ export class VendorCertDiffPage extends VendorAuditPage {
}
async resolveColumnSettingsTrigger(): Promise<Locator> {
const settings = this.filterScope().locator(COLUMN_SETTINGS_TRIGGER_CSS);
const candidates: Locator[] = [];
const count = await settings.count();
for (let i = 0; i < count; i += 1) {
const loc = settings.nth(i);
const box = await loc.boundingBox().catch(() => null);
if (box && box.y > 120) candidates.push(loc);
}
if (candidates.length === 0) {
candidates.push(this.tableWrapper().locator(COLUMN_SETTINGS_TRIGGER_CSS).first());
}
let trigger = await findUsableColumnSettingsTrigger(candidates);
const trigger = await resolveUsableColumnSettingsTrigger({
root: this.filterScope(),
tableWrapper: this.tableWrapper(),
afterScroll: async () => {
const body = this.tableWrapper().locator('.ant-table-body').first();
await body
.evaluate((el) => {
(el as HTMLElement).scrollLeft = (el as HTMLElement).scrollWidth;
})
.catch(() => undefined);
await this.waitSettle(200);
},
});
if (!trigger) {
await this.skipWhenDataInsufficient('列设置齿轮不可见');
}
......
......@@ -3,12 +3,11 @@ import { expect, type Locator, type Page } from '@playwright/test';
import { normalizeSampleCellValue } from '../../core/table-data-column.util';
import { vendorCertFinalData } from '../../data/vendor-cert-final.data';
import { vendorData } from '../../data/vendor.data';
import { COLUMN_SETTINGS_TRIGGER_CSS } from '../../locators/spd/center-report-shared.locator';
import { VendorAuditPage, type VendorAuthOpenOptions } from './vendor-audit.page';
import {
ColumnSettingsControls,
executeColumnSettingsToggleRestore,
findUsableColumnSettingsTrigger,
resolveUsableColumnSettingsTrigger,
} from './helpers/column-settings.helper';
/** 注册证变更终审。 */
......@@ -41,8 +40,8 @@ export class VendorCertFinalPage extends VendorAuditPage {
columnSettingsPanel(): Locator {
return this.page
.locator('.ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: /字段设置|列展示/ })
.locator('.ant-popover.cloumn-list:visible, .ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: /字段设置|列展示|列设置/ })
.first();
}
......@@ -151,18 +150,18 @@ export class VendorCertFinalPage extends VendorAuditPage {
}
async resolveColumnSettingsTrigger(): Promise<Locator> {
const settings = this.page.locator(COLUMN_SETTINGS_TRIGGER_CSS);
const candidates: Locator[] = [];
const count = await settings.count();
for (let i = 0; i < count; i += 1) {
const loc = settings.nth(i);
const box = await loc.boundingBox().catch(() => null);
if (box && box.y > 120) candidates.push(loc);
}
if (candidates.length === 0) {
candidates.push(this.tableWrapper().locator(COLUMN_SETTINGS_TRIGGER_CSS).first());
}
let trigger = await findUsableColumnSettingsTrigger(candidates);
const trigger = await resolveUsableColumnSettingsTrigger({
root: this.page,
tableWrapper: this.tableWrapper(),
afterScroll: async () => {
const body = this.tableWrapper().locator('.ant-table-body').first();
await body
.evaluate((el) => {
(el as HTMLElement).scrollLeft = (el as HTMLElement).scrollWidth;
})
.catch(() => undefined);
},
});
if (!trigger) {
await this.skipWhenDataInsufficient('列设置齿轮不可见');
}
......
......@@ -3,12 +3,11 @@ import { expect, type Locator, type Page } from '@playwright/test';
import { normalizeSampleCellValue } from '../../core/table-data-column.util';
import { vendorCertFirstData } from '../../data/vendor-cert-first.data';
import { vendorData } from '../../data/vendor.data';
import { COLUMN_SETTINGS_TRIGGER_CSS } from '../../locators/spd/center-report-shared.locator';
import { VendorAuditPage, type VendorAuthOpenOptions } from './vendor-audit.page';
import {
ColumnSettingsControls,
executeColumnSettingsToggleRestore,
findUsableColumnSettingsTrigger,
resolveUsableColumnSettingsTrigger,
} from './helpers/column-settings.helper';
/** 注册证变更初审。 */
......@@ -41,8 +40,8 @@ export class VendorCertFirstPage extends VendorAuditPage {
columnSettingsPanel(): Locator {
return this.page
.locator('.ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: /字段设置|列展示/ })
.locator('.ant-popover.cloumn-list:visible, .ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: /字段设置|列展示|列设置/ })
.first();
}
......@@ -151,18 +150,18 @@ export class VendorCertFirstPage extends VendorAuditPage {
}
async resolveColumnSettingsTrigger(): Promise<Locator> {
const settings = this.page.locator(COLUMN_SETTINGS_TRIGGER_CSS);
const candidates: Locator[] = [];
const count = await settings.count();
for (let i = 0; i < count; i += 1) {
const loc = settings.nth(i);
const box = await loc.boundingBox().catch(() => null);
if (box && box.y > 120) candidates.push(loc);
}
if (candidates.length === 0) {
candidates.push(this.tableWrapper().locator(COLUMN_SETTINGS_TRIGGER_CSS).first());
}
let trigger = await findUsableColumnSettingsTrigger(candidates);
const trigger = await resolveUsableColumnSettingsTrigger({
root: this.page,
tableWrapper: this.tableWrapper(),
afterScroll: async () => {
const body = this.tableWrapper().locator('.ant-table-body').first();
await body
.evaluate((el) => {
(el as HTMLElement).scrollLeft = (el as HTMLElement).scrollWidth;
})
.catch(() => undefined);
},
});
if (!trigger) {
await this.skipWhenDataInsufficient('列设置齿轮不可见');
}
......
......@@ -2,13 +2,11 @@ import { expect, type Locator, type Page } from '@playwright/test';
import { vendorEvalIndicatorData } from '../../data/vendor-eval-indicator.data';
import { vendorData } from '../../data/vendor.data';
import { COLUMN_SETTINGS_TRIGGER_CSS } from '../../locators/spd/center-report-shared.locator';
import { VendorSharedPage } from './vendor-shared.page';
import {
ColumnSettingsControls,
executeColumnSettingsToggleRestore,
findUsableColumnSettingsTrigger,
isColumnSettingsTriggerUsable,
resolveUsableColumnSettingsTrigger,
} from './helpers/column-settings.helper';
import { expectColumnSortByDom, hasDomSortableColumn } from './helpers/column-sort.helper';
......@@ -42,8 +40,8 @@ export class VendorEvalIndicatorPage extends VendorSharedPage {
columnSettingsPanel(): Locator {
return this.page
.locator('.ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: /字段设置|列展示/ })
.locator('.ant-popover.cloumn-list:visible, .ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: /字段设置|列展示|列设置/ })
.first();
}
......@@ -86,39 +84,19 @@ export class VendorEvalIndicatorPage extends VendorSharedPage {
}
async resolveColumnSettingsTrigger(): Promise<Locator> {
const settings = this.page.locator(COLUMN_SETTINGS_TRIGGER_CSS);
const candidates: Locator[] = [];
const count = await settings.count();
for (let i = 0; i < count; i += 1) {
const loc = settings.nth(i);
const box = await loc.boundingBox().catch(() => null);
if (box && box.y > 120) {
candidates.push(loc);
}
}
if (candidates.length === 0) {
candidates.push(this.tableWrapper().locator(COLUMN_SETTINGS_TRIGGER_CSS).first());
}
let trigger = await findUsableColumnSettingsTrigger(candidates);
if (!trigger) {
const body = this.tableWrapper().locator('.ant-table-body').first();
await body
.evaluate((el) => {
(el as HTMLElement).scrollLeft = (el as HTMLElement).scrollWidth;
})
.catch(() => undefined);
await this.waitSettle(200);
trigger = await findUsableColumnSettingsTrigger(candidates);
}
if (!trigger) {
for (let i = 0; i < count; i += 1) {
const loc = settings.nth(i);
if (await isColumnSettingsTriggerUsable(loc)) {
trigger = loc;
break;
}
}
}
const trigger = await resolveUsableColumnSettingsTrigger({
root: this.page,
tableWrapper: this.tableWrapper(),
afterScroll: async () => {
const body = this.tableWrapper().locator('.ant-table-body').first();
await body
.evaluate((el) => {
(el as HTMLElement).scrollLeft = (el as HTMLElement).scrollWidth;
})
.catch(() => undefined);
await this.waitSettle(200);
},
});
if (!trigger) {
await this.skipWhenDataInsufficient('列设置齿轮不可见');
}
......
......@@ -3,13 +3,11 @@ import { expect, type Locator, type Page } from '@playwright/test';
import { normalizeSampleCellValue } from '../../core/table-data-column.util';
import { vendorEvalSchemeExpandedFilterLabels } from '../../data/vendor-eval-scheme.data';
import { vendorData } from '../../data/vendor.data';
import { COLUMN_SETTINGS_TRIGGER_CSS } from '../../locators/spd/center-report-shared.locator';
import { VendorSharedPage } from './vendor-shared.page';
import {
ColumnSettingsControls,
executeColumnSettingsToggleRestore,
findUsableColumnSettingsTrigger,
isColumnSettingsTriggerUsable,
resolveUsableColumnSettingsTrigger,
} from './helpers/column-settings.helper';
import { expectColumnSortByDom, hasDomSortableColumn } from './helpers/column-sort.helper';
......@@ -39,8 +37,8 @@ export class VendorEvalSchemePage extends VendorSharedPage {
columnSettingsPanel(): Locator {
return this.page
.locator('.ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: /字段设置|列展示/ })
.locator('.ant-popover.cloumn-list:visible, .ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: /字段设置|列展示|列设置/ })
.first();
}
......@@ -56,39 +54,19 @@ export class VendorEvalSchemePage extends VendorSharedPage {
}
async resolveColumnSettingsTrigger(): Promise<Locator> {
const settings = this.page.locator(COLUMN_SETTINGS_TRIGGER_CSS);
const candidates: Locator[] = [];
const count = await settings.count();
for (let i = 0; i < count; i += 1) {
const loc = settings.nth(i);
const box = await loc.boundingBox().catch(() => null);
if (box && box.y > 120) {
candidates.push(loc);
}
}
if (candidates.length === 0) {
candidates.push(this.tableWrapper().locator(COLUMN_SETTINGS_TRIGGER_CSS).first());
}
let trigger = await findUsableColumnSettingsTrigger(candidates);
if (!trigger) {
const body = this.tableWrapper().locator('.ant-table-body').first();
await body
.evaluate((el) => {
(el as HTMLElement).scrollLeft = (el as HTMLElement).scrollWidth;
})
.catch(() => undefined);
await this.waitSettle(200);
trigger = await findUsableColumnSettingsTrigger(candidates);
}
if (!trigger) {
for (let i = 0; i < count; i += 1) {
const loc = settings.nth(i);
if (await isColumnSettingsTriggerUsable(loc)) {
trigger = loc;
break;
}
}
}
const trigger = await resolveUsableColumnSettingsTrigger({
root: this.page,
tableWrapper: this.tableWrapper(),
afterScroll: async () => {
const body = this.tableWrapper().locator('.ant-table-body').first();
await body
.evaluate((el) => {
(el as HTMLElement).scrollLeft = (el as HTMLElement).scrollWidth;
})
.catch(() => undefined);
await this.waitSettle(200);
},
});
if (!trigger) {
await this.skipWhenDataInsufficient('列设置齿轮不可见');
}
......
......@@ -10,13 +10,11 @@ import {
} from '../../data/vendor-qual-tab-cases';
import { subTabsForMainTab } from '../../data/vendor-qual-subtabs.data';
import { vendorData } from '../../data/vendor.data';
import { COLUMN_SETTINGS_TRIGGER_CSS } from '../../locators/spd/center-report-shared.locator';
import { VendorSharedPage } from './vendor-shared.page';
import {
ColumnSettingsControls,
executeColumnSettingsToggleRestore,
findUsableColumnSettingsTrigger,
isColumnSettingsTriggerUsable,
resolveUsableColumnSettingsTrigger,
} from './helpers/column-settings.helper';
import { executeExportReport } from './helpers/export-report.helper';
......@@ -62,8 +60,8 @@ export class VendorQualPage extends VendorSharedPage {
columnSettingsPanel(): Locator {
return this.page
.locator('.ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: /字段设置|列展示/ })
.locator('.ant-popover.cloumn-list:visible, .ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: /字段设置|列展示|列设置/ })
.first();
}
......@@ -719,39 +717,19 @@ export class VendorQualPage extends VendorSharedPage {
}
async resolveColumnSettingsTrigger(): Promise<Locator> {
const settings = this.page.locator(COLUMN_SETTINGS_TRIGGER_CSS);
const candidates: Locator[] = [];
const count = await settings.count();
for (let i = 0; i < count; i += 1) {
const loc = settings.nth(i);
const box = await loc.boundingBox().catch(() => null);
if (box && box.y > 120) {
candidates.push(loc);
}
}
if (candidates.length === 0) {
candidates.push(this.tableWrapper().locator(COLUMN_SETTINGS_TRIGGER_CSS).first());
}
let trigger = await findUsableColumnSettingsTrigger(candidates);
if (!trigger) {
const body = this.tableWrapper().locator('.ant-table-body').first();
await body
.evaluate((el) => {
(el as HTMLElement).scrollLeft = (el as HTMLElement).scrollWidth;
})
.catch(() => undefined);
await this.waitSettle(200);
trigger = await findUsableColumnSettingsTrigger(candidates);
}
if (!trigger) {
for (let i = 0; i < count; i += 1) {
const loc = settings.nth(i);
if (await isColumnSettingsTriggerUsable(loc)) {
trigger = loc;
break;
}
}
}
const trigger = await resolveUsableColumnSettingsTrigger({
root: this.page,
tableWrapper: this.tableWrapper(),
afterScroll: async () => {
const body = this.tableWrapper().locator('.ant-table-body').first();
await body
.evaluate((el) => {
(el as HTMLElement).scrollLeft = (el as HTMLElement).scrollWidth;
})
.catch(() => undefined);
await this.waitSettle(200);
},
});
if (!trigger) {
await this.skipWhenDataInsufficient('列设置齿轮不可见');
}
......
......@@ -2,14 +2,12 @@ import { expect, type Locator, type Page } from '@playwright/test';
import { normalizeSampleCellValue } from '../../core/table-data-column.util';
import { vendorData } from '../../data/vendor.data';
import { COLUMN_SETTINGS_TRIGGER_CSS } from '../../locators/spd/center-report-shared.locator';
import type { VendorQualPage } from './vendor-qual.page';
import { VendorSharedPage } from './vendor-shared.page';
import {
ColumnSettingsControls,
executeColumnSettingsToggleRestore,
findUsableColumnSettingsTrigger,
isColumnSettingsTriggerUsable,
resolveUsableColumnSettingsTrigger,
} from './helpers/column-settings.helper';
/** 厂商查询:动作与取数;断言在 tests/spd/vendor-query.spec.ts。 */
......@@ -38,8 +36,8 @@ export class VendorQueryPage extends VendorSharedPage {
columnSettingsPanel(): Locator {
return this.page
.locator('.ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: /字段设置|列展示/ })
.locator('.ant-popover.cloumn-list:visible, .ant-popover:visible, .ant-dropdown:visible')
.filter({ hasText: /字段设置|列展示|列设置/ })
.first();
}
......@@ -55,40 +53,19 @@ export class VendorQueryPage extends VendorSharedPage {
}
async resolveColumnSettingsTrigger(): Promise<Locator> {
// column-height 为表格密度(分散/中等/紧凑),非列设置;列设置为 anticon-setting(列表工具栏)。
const settings = this.page.locator(COLUMN_SETTINGS_TRIGGER_CSS);
const candidates: Locator[] = [];
const count = await settings.count();
for (let i = 0; i < count; i += 1) {
const loc = settings.nth(i);
const box = await loc.boundingBox().catch(() => null);
if (box && box.y > 120) {
candidates.push(loc);
}
}
if (candidates.length === 0) {
candidates.push(this.tableWrapper().locator(COLUMN_SETTINGS_TRIGGER_CSS).first());
}
let trigger = await findUsableColumnSettingsTrigger(candidates);
if (!trigger) {
const body = this.tableWrapper().locator('.ant-table-body').first();
await body
.evaluate((el) => {
(el as HTMLElement).scrollLeft = (el as HTMLElement).scrollWidth;
})
.catch(() => undefined);
await this.waitSettle(200);
trigger = await findUsableColumnSettingsTrigger(candidates);
}
if (!trigger) {
for (let i = 0; i < count; i += 1) {
const loc = settings.nth(i);
if (await isColumnSettingsTriggerUsable(loc)) {
trigger = loc;
break;
}
}
}
const trigger = await resolveUsableColumnSettingsTrigger({
root: this.page,
tableWrapper: this.tableWrapper(),
afterScroll: async () => {
const body = this.tableWrapper().locator('.ant-table-body').first();
await body
.evaluate((el) => {
(el as HTMLElement).scrollLeft = (el as HTMLElement).scrollWidth;
})
.catch(() => undefined);
await this.waitSettle(200);
},
});
if (!trigger) {
await this.skipWhenDataInsufficient('列设置齿轮不可见');
}
......@@ -123,6 +100,20 @@ export class VendorQueryPage extends VendorSharedPage {
return name;
}
}
await this.openColumnSettings();
const wrappers = this.columnSettingsPanel().locator('.ant-checkbox-wrapper');
const count = await wrappers.count();
const core = /^(序号|序号列|操作|查看|全选|字段设置|列展示|列设置|行高|分散|中等|紧凑|紧簇|显示|表格设置|重置)$/;
for (let i = 0; i < count; i += 1) {
const raw = ((await wrappers.nth(i).innerText()) ?? '').replace(/\s+/g, '').trim();
if (!raw || core.test(raw)) continue;
const checkbox = wrappers.nth(i).locator('input[type="checkbox"]').first();
if (!(await checkbox.isChecked().catch(() => false))) continue;
await this.closeColumnSettingsPanel();
return raw;
}
await this.closeColumnSettingsPanel();
await this.skipWhenDataInsufficient('列设置中无可 toggle 的已勾选列');
return vendorData.columnSettingsToggleCandidates[0];
}
......
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