refactor(tests): 优化组件导入路径和输入框处理逻辑,增强代码可读性
This commit is contained in:
parent
e55b84e3cc
commit
135718a8c3
@ -1,4 +1,4 @@
|
||||
import { NumberInput } from '@/pages/components/numberInput';
|
||||
import { PopupContent } from '@/pages/components/popupContent';
|
||||
import { NumberInput } from './numberInput';
|
||||
import { PopupContent } from './popupContent';
|
||||
|
||||
export { NumberInput, PopupContent };
|
||||
|
||||
@ -3,12 +3,13 @@ import { Locator, Page } from '@playwright/test';
|
||||
export class NumberInput {
|
||||
private readonly page: Page;
|
||||
private readonly popupLocator: Locator;
|
||||
private readonly inputLocator: Locator;
|
||||
private readonly inputLocators: { [key: string]: Locator } = {};
|
||||
private readonly confirmButtonLocator: Locator;
|
||||
private readonly delButtonLocator: Locator;
|
||||
private readonly delAllButtonLocator: Locator;
|
||||
private readonly pointInputLocator: Locator;
|
||||
private readonly commonInputLocator: Locator;
|
||||
// private readonly inputLocator: Locator;
|
||||
// private readonly pointInputLocator: Locator;
|
||||
// private readonly commonInputLocator: Locator;
|
||||
|
||||
/**
|
||||
* 数字键盘组件
|
||||
@ -17,41 +18,60 @@ export class NumberInput {
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
this.popupLocator = this.page.locator('div.popup_content');
|
||||
this.commonInputLocator = this.popupLocator.getByPlaceholder('');
|
||||
this.inputLocator = this.popupLocator.getByPlaceholder('请输入内容');
|
||||
this.pointInputLocator = this.popupLocator.getByPlaceholder('请输入积分');
|
||||
this.inputLocators = {
|
||||
common: this.popupLocator.getByPlaceholder(''),
|
||||
normal: this.popupLocator.getByPlaceholder('请输入内容'),
|
||||
point: this.popupLocator.getByPlaceholder('请输入积分'),
|
||||
};
|
||||
// this.commonInputLocator = this.popupLocator.getByPlaceholder('');
|
||||
// this.inputLocator = this.popupLocator.getByPlaceholder('请输入内容');
|
||||
// this.pointInputLocator = this.popupLocator.getByPlaceholder('请输入积分');
|
||||
this.confirmButtonLocator = this.popupLocator.locator('button.sure');
|
||||
this.delButtonLocator = this.popupLocator.locator('button.del');
|
||||
this.delAllButtonLocator = this.popupLocator.locator('button.delAll');
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置值
|
||||
* @param type 输入框类型 (common, normal, point)
|
||||
* @param value 输入值
|
||||
*/
|
||||
async setValue(type: 'common' | 'normal' | 'point', value: number | string): Promise<void> {
|
||||
const locator = this.inputLocators[type];
|
||||
if (!locator) {
|
||||
throw new Error(`Invalid input type: ${type}`);
|
||||
}
|
||||
await locator.fill(value.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置通用值
|
||||
*/
|
||||
async setCommonValue(value: number): Promise<void> {
|
||||
await this.commonInputLocator.fill(value.toString());
|
||||
}
|
||||
// async setCommonValue(value: number): Promise<void> {
|
||||
// await this.commonInputLocator.fill(value.toString());
|
||||
// }
|
||||
|
||||
/**
|
||||
* 设置值
|
||||
*/
|
||||
async setValue(value: number): Promise<void> {
|
||||
await this.inputLocator.fill(value.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置文本
|
||||
*/
|
||||
async setString(value: string): Promise<void> {
|
||||
await this.inputLocator.fill(value);
|
||||
}
|
||||
// async setValue(value: number): Promise<void> {
|
||||
// await this.inputLocator.fill(value.toString());
|
||||
// }
|
||||
|
||||
/**
|
||||
* 设置积分值
|
||||
* @param value
|
||||
*/
|
||||
async setPointValue(value: number): Promise<void> {
|
||||
await this.pointInputLocator.fill(value.toString());
|
||||
// async setPointValue(value: number): Promise<void> {
|
||||
// await this.pointInputLocator.fill(value.toString());
|
||||
// }
|
||||
|
||||
/**
|
||||
* 设置文本
|
||||
*/
|
||||
async setString(value: string): Promise<void> {
|
||||
// await this.inputLocator.fill(value);
|
||||
await this.inputLocators.normal.fill(value);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -14,20 +14,23 @@ export class CustomerAnalysisPage {
|
||||
|
||||
/**
|
||||
* 跳转到子页面
|
||||
* @param {string} subPageName
|
||||
* - 项目余量分析
|
||||
* - 套餐消耗升单分析
|
||||
* - 顾客项目分析
|
||||
* @param {string} subPageName - 子页面名称,支持以下选项:
|
||||
* - "项目余量分析"
|
||||
* - "套餐消耗升单分析"
|
||||
* - "顾客项目分析"
|
||||
*/
|
||||
gotoSubPage = async (subPageName: string) => {
|
||||
if (!this.subPages.some(({ name }) => name === subPageName)) {
|
||||
// 输入验证
|
||||
if (!subPageName || typeof subPageName !== 'string') {
|
||||
throw new Error('Invalid subPageName parameter');
|
||||
}
|
||||
|
||||
// 异常处理
|
||||
if (!this.subPages || !this.subPages.some(({ name }) => name === subPageName)) {
|
||||
throw new Error(`${subPageName} is not a valid sub page name`);
|
||||
}
|
||||
const $dropDown = this.page
|
||||
.locator('.top_tab .tab_item', {
|
||||
hasText: '顾客分析',
|
||||
})
|
||||
.locator('.ant-dropdown-link');
|
||||
|
||||
const $dropDown = this.page.locator('.top_tab .tab_item', { hasText: '顾客分析' }).locator('.ant-dropdown-link');
|
||||
|
||||
await $dropDown.click();
|
||||
await this.page.getByRole('menuitem', { name: subPageName }).click();
|
||||
|
||||
@ -8,7 +8,12 @@ export class CustomerDetailsPage {
|
||||
*/
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
this.subPages = [{ name: '基本资料' }, { name: '流水' }, { name: '动态' }, { name: '日志' }];
|
||||
this.subPages = [
|
||||
{ name: '基本资料' },
|
||||
{ name: '流水' },
|
||||
{ name: '动态' },
|
||||
{ name: '日志' }
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -20,12 +25,22 @@ export class CustomerDetailsPage {
|
||||
* - 日志
|
||||
*/
|
||||
gotoSubPage = async (subPageName: string) => {
|
||||
if (!this.subPages.findIndex(e => e.name === subPageName)) {
|
||||
// 标准化输入字符串,去除前后空格并统一为小写
|
||||
const normalizedSubPageName = subPageName.trim().toLowerCase();
|
||||
|
||||
// 检查子页面是否存在
|
||||
if (!this.subPages.some(e => e.name.trim().toLowerCase() === normalizedSubPageName)) {
|
||||
throw new Error(`${subPageName} is not in the subPages list`);
|
||||
}
|
||||
const $subPage = this.page.getByRole('tab', { name: subPageName });
|
||||
await $subPage.click();
|
||||
await expect($subPage).toHaveClass(/active/);
|
||||
await this.page.waitForLoadState();
|
||||
|
||||
try {
|
||||
// 获取子页面元素并点击
|
||||
const $subPage = this.page.getByRole('tab', { name: subPageName });
|
||||
await $subPage.click();
|
||||
await expect($subPage).toHaveClass(/active/);
|
||||
} catch (error) {
|
||||
// 捕获并抛出更明确的错误信息
|
||||
throw new Error(`Failed to navigate to ${subPageName}: ${error.message}`);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -60,8 +60,14 @@ export class CustomerPage {
|
||||
* - 服务日志
|
||||
*/
|
||||
gotoSubPage = async (subPageName: string) => {
|
||||
// 输入验证
|
||||
if (!subPageName || typeof subPageName !== 'string' || subPageName.trim() === '') {
|
||||
throw new Error('子页面名称不能为空或无效');
|
||||
}
|
||||
|
||||
const subPage = this.subPages.find(e => e.name === subPageName);
|
||||
if (!subPage) {
|
||||
console.error(`子页面 ${subPageName} 不存在`);
|
||||
throw new Error(`子页面 ${subPageName} 不存在`);
|
||||
}
|
||||
|
||||
@ -69,18 +75,24 @@ export class CustomerPage {
|
||||
|
||||
await $subPageTab.waitFor();
|
||||
|
||||
const classAttribute = await $subPageTab.getAttribute('class', { timeout: 5000 });
|
||||
if (classAttribute && classAttribute.includes('active')) {
|
||||
return;
|
||||
try {
|
||||
const classAttribute = await $subPageTab.getAttribute('class', { timeout: 5000 });
|
||||
if (classAttribute && classAttribute.includes('active')) {
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`获取子页面 ${subPageName} 的 class 属性超时`);
|
||||
throw new Error(`获取子页面 ${subPageName} 的 class 属性超时`);
|
||||
}
|
||||
|
||||
await Promise.all([
|
||||
expect(async () => {
|
||||
await $subPageTab.click();
|
||||
await expect($subPageTab).toHaveClass(/active/);
|
||||
}).toPass(),
|
||||
waitSpecifyApiLoad(this.page, subPage.url),
|
||||
]);
|
||||
try {
|
||||
await $subPageTab.click();
|
||||
await expect($subPageTab).toHaveClass(/active/, { timeout: 5000 });
|
||||
await waitSpecifyApiLoad(this.page, subPage.url);
|
||||
} catch (error) {
|
||||
console.error(`点击子页面 ${subPageName} 或等待 API 加载失败`);
|
||||
throw new Error(`点击子页面 ${subPageName} 或等待 API 加载失败`);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Locator, type Page } from '@playwright/test';
|
||||
import { waitSpecifyApiLoad } from '@/utils/utils.js';
|
||||
import { waitSpecifyApiLoad } from '@/utils/utils';
|
||||
|
||||
export class MarketingInviteGuestsPage {
|
||||
page: Page;
|
||||
|
||||
@ -280,9 +280,17 @@ test.describe('挂单', () => {
|
||||
await page.getByText('已过期 / 删除单据').click();
|
||||
await page.getByText('警告:已过期服务无法取单结算,请至收银台处理').waitFor();
|
||||
await $slidingMenu.locator('div.item_box').first().waitFor();
|
||||
await expect($slidingMenu.locator('div.item_box').first().getByRole('button', { name: /^取\s单$/ })).not.toBeVisible();
|
||||
await expect(
|
||||
$slidingMenu
|
||||
.locator('div.item_box')
|
||||
.first()
|
||||
.getByRole('button', { name: /^取\s单$/ }),
|
||||
).not.toBeVisible();
|
||||
|
||||
const $delete = $slidingMenu.locator('div.item_box').first().locator('.comment > div:nth-child(2) > .touchIcon');
|
||||
const $delete = $slidingMenu
|
||||
.locator('div.item_box')
|
||||
.first()
|
||||
.locator('.comment > div:nth-child(2) > .touchIcon');
|
||||
await $delete.click();
|
||||
await page.getByPlaceholder('请输入1-100个字符备注内容').click();
|
||||
await page.getByPlaceholder('请输入1-100个字符备注内容').fill('测试备注');
|
||||
@ -582,13 +590,13 @@ test.describe('收银-房态', () => {
|
||||
});
|
||||
|
||||
test('占用床位', async ({
|
||||
page,
|
||||
homeNavigation,
|
||||
createCustomer,
|
||||
cashierRoomPage,
|
||||
customerPage,
|
||||
appointmentPage,
|
||||
}) => {
|
||||
page,
|
||||
homeNavigation,
|
||||
createCustomer,
|
||||
cashierRoomPage,
|
||||
customerPage,
|
||||
appointmentPage,
|
||||
}) => {
|
||||
const customer = createCustomer;
|
||||
|
||||
const employee = Employees.FirstShop.Employee_6;
|
||||
@ -872,13 +880,13 @@ test.describe('收银-房态', () => {
|
||||
|
||||
test.describe('收银-开单&结算', () => {
|
||||
test('开单-反结算-撤单', async ({
|
||||
page,
|
||||
homeNavigation,
|
||||
createCustomer,
|
||||
customerPage,
|
||||
wasteBookBusinessRecordPage,
|
||||
numberInput,
|
||||
}) => {
|
||||
page,
|
||||
homeNavigation,
|
||||
createCustomer,
|
||||
customerPage,
|
||||
wasteBookBusinessRecordPage,
|
||||
numberInput,
|
||||
}) => {
|
||||
// 定义一个随机单号
|
||||
const randomBillNo1 = faker.helpers.fromRegExp(/1[3-9][0-9]{8}/);
|
||||
const randomBillNo2 = faker.helpers.fromRegExp(/1[3-9][0-9]{9}/);
|
||||
@ -1179,12 +1187,12 @@ test.describe('收银-开单&结算', () => {
|
||||
});
|
||||
|
||||
test('开卡-使用卡金和赠金-充值卡金', async ({
|
||||
page,
|
||||
homeNavigation,
|
||||
createCustomer,
|
||||
customerPage,
|
||||
numberInput,
|
||||
}) => {
|
||||
page,
|
||||
homeNavigation,
|
||||
createCustomer,
|
||||
customerPage,
|
||||
numberInput,
|
||||
}) => {
|
||||
const c = createCustomer;
|
||||
const username = c.username;
|
||||
const phone = c.phone;
|
||||
@ -1256,7 +1264,7 @@ test.describe('收银-开单&结算', () => {
|
||||
await page.getByText('卡金').nth(4).click();
|
||||
await page.getByRole('button', { name: '增加收款' }).click();
|
||||
// 输入金额
|
||||
await numberInput.setCommonValue(100);
|
||||
await numberInput.setValue('common', 100);
|
||||
await numberInput.confirmValue();
|
||||
// 选择赠送金支付
|
||||
await page.getByText('赠金').nth(2).click();
|
||||
|
||||
@ -2025,7 +2025,7 @@ test.describe('顾客分配', () => {
|
||||
const index = titleList.findIndex(text => text === '现金总额');
|
||||
|
||||
// 拿取前三个顾客的现金总额
|
||||
let amountArray: number[];
|
||||
let amountArray: number[] = new Array(3);
|
||||
for (let i = 0; i < 3; i++) {
|
||||
const amountStr = await amountList.nth(i).locator('td').nth(index).innerText();
|
||||
const amount = convertAmountText(amountStr).amount;
|
||||
@ -2219,7 +2219,7 @@ test.describe('顾客分配', () => {
|
||||
|
||||
test.describe('顾客分析', () => {
|
||||
test('查看顾客项目分析', async ({ page, homeNavigation, createCustomers, customerPage, numberInput }) => {
|
||||
let customers: Customer[];
|
||||
let customers: Customer[] = new Array(2);
|
||||
await test.step('创建两个顾客', async () => {
|
||||
customers = await createCustomers(2);
|
||||
});
|
||||
@ -2227,38 +2227,32 @@ test.describe('顾客分析', () => {
|
||||
const ca = customers[0];
|
||||
const cb = customers[1];
|
||||
|
||||
// 获取姓名、手机号、档案号
|
||||
const usernameA = ca.username;
|
||||
const phoneA = ca.phone;
|
||||
const usernameB = cb.username;
|
||||
const phoneB = cb.phone;
|
||||
|
||||
const ProjectA1 = ProjectName.Projects.Projects_1;
|
||||
const ProjectA1Quantity = 2;
|
||||
const ProjectA2 = ProjectName.Projects.Projects_239;
|
||||
const ProjectA2Quantity = 1;
|
||||
const ProjectA3 = ProjectName.Projects.Projects_2;
|
||||
const ProjectA3Quantity = 2;
|
||||
const ProjectA12Quantity = 1;
|
||||
const projects_a1 = { num: '100012', name: '雪肌晶纯护理', price: 300 };
|
||||
const projects_a1_quantity = 2;
|
||||
const projects_a2 = { num: '100258', name: '出水芙蓉SPA水疗', price: 380 };
|
||||
const projects_a2_quantity = 1;
|
||||
const projects_a3 = { num: '100013', name: '净透驻氧护理', price: 380 };
|
||||
const projects_a3_quantity = 2;
|
||||
const projects_a12_quantity = 1;
|
||||
|
||||
// 顾客A
|
||||
await test.step('顾客A', async () => {
|
||||
await homeNavigation.gotoModule('收银');
|
||||
await page.getByRole('button', { name: /开\s单/ }).click();
|
||||
await customerPage.searchCustomer(phoneA);
|
||||
await customerPage.selectSearchCustomer(usernameA);
|
||||
await customerPage.searchCustomer(ca.phone);
|
||||
await customerPage.selectSearchCustomer(ca.username);
|
||||
|
||||
// 购买项目1-普通,2次
|
||||
await page.getByText(ProjectA1.num).click();
|
||||
await page.getByText(projects_a1.num).click();
|
||||
await page.locator('.edit_txt div:nth-child(2)').first().click();
|
||||
await numberInput.setValue(ProjectA1Quantity);
|
||||
await numberInput.setValue(projects_a1_quantity);
|
||||
await numberInput.confirmValue();
|
||||
|
||||
// 点击面部
|
||||
await page.getByText('面部').click();
|
||||
|
||||
// 购买项目2-普通,1次
|
||||
await page.getByText(ProjectA2.num).click();
|
||||
await page.getByText(projects_a2.num).click();
|
||||
await page.locator('.type_btn').first().click();
|
||||
await page.locator('.type_item', { hasText: '普通' }).click();
|
||||
|
||||
@ -2266,21 +2260,21 @@ test.describe('顾客分析', () => {
|
||||
await page.getByText('护理', { exact: true }).click();
|
||||
|
||||
// 购买项目3-赠送,3次
|
||||
await page.getByText(ProjectA3.num).click();
|
||||
await page.getByText(projects_a3.num).click();
|
||||
await page.locator('.edit_txt div:nth-child(2)').first().click();
|
||||
await numberInput.setValue(ProjectA3Quantity);
|
||||
await numberInput.setValue(projects_a3_quantity);
|
||||
await numberInput.confirmValue();
|
||||
await page.locator('.type_btn').first().click();
|
||||
await page.locator('.type_item', { hasText: '赠送' }).click();
|
||||
|
||||
// 选择组合项目2-项目1,普通
|
||||
await page.getByText(ProjectA1.num).first().click();
|
||||
await page.getByText(projects_a1.num).first().click();
|
||||
await page.locator('.add_btn', { hasText: '设置' }).last().click();
|
||||
await page.getByRole('textbox').fill(ProjectA2.num);
|
||||
await page.getByRole('textbox').fill(projects_a2.num);
|
||||
await page.getByRole('button', { name: /搜\s索/ }).click();
|
||||
await expect(async () => {
|
||||
await page.getByLabel(ProjectA2.name).uncheck();
|
||||
await page.getByLabel(ProjectA2.name).check();
|
||||
await page.getByLabel(projects_a2.name).uncheck();
|
||||
await page.getByLabel(projects_a2.name).check();
|
||||
await page.locator('.menu-item-dot', { hasText: '2' }).first().waitFor({ timeout: 2000 });
|
||||
}).toPass();
|
||||
await page.getByRole('button', { name: '确定选择' }).click();
|
||||
@ -2300,50 +2294,52 @@ test.describe('顾客分析', () => {
|
||||
await page.getByRole('button', { name: /^结\s算$/ }).click();
|
||||
});
|
||||
|
||||
const ProjectB3 = ProjectName.Projects.Projects_2;
|
||||
const ProjectB3Quantity = 20;
|
||||
const ProjectB4 = ProjectName.Projects.Projects_661;
|
||||
const ProjectB4Quantity = 30;
|
||||
const ProjectB5 = ProjectName.Projects.Projects_676;
|
||||
const ProjectB5Quantity = 9;
|
||||
const ProjectB1 = ProjectName.Projects.Projects_1;
|
||||
const ProjectB2 = ProjectName.Projects.Projects_239;
|
||||
const ProjectB12Quantity = 2;
|
||||
const ProjectB34Quantity = 3;
|
||||
const project_b3 = { num: '100013', name: '净透驻氧护理', price: 380 };
|
||||
const project_b3_quantity = 20;
|
||||
|
||||
const project_b4 = { num: '100719', name: '艾灸', price: 0 };
|
||||
const project_b4_quantity = 30;
|
||||
|
||||
const project_b5 = { num: '100735', name: '脱毛', price: 88 };
|
||||
const project_b5_quantity = 9;
|
||||
|
||||
const project_b1 = { num: '100012', name: '雪肌晶纯护理', price: 300 };
|
||||
const project_b2 = { num: '100258', name: '出水芙蓉SPA水疗', Price: 380 };
|
||||
const project_b12_quantity = 2;
|
||||
const project_b34_quantity = 3;
|
||||
|
||||
await test.step('顾客B', async () => {
|
||||
//顾客B
|
||||
await page.reload();
|
||||
await page.getByRole('button', { name: /开\s单/ }).click();
|
||||
await customerPage.searchCustomer(phoneB);
|
||||
await customerPage.selectSearchCustomer(usernameB);
|
||||
await customerPage.searchCustomer(cb.phone);
|
||||
await customerPage.selectSearchCustomer(cb.username);
|
||||
|
||||
// 购买项目3-普通,20次
|
||||
await page.getByText(ProjectB3.num).click();
|
||||
await page.getByText(project_b3.num).click();
|
||||
await page.locator('.edit_txt div:nth-child(2)').first().click();
|
||||
await numberInput.setValue(ProjectB3Quantity);
|
||||
await numberInput.setValue(project_b3_quantity);
|
||||
await numberInput.confirmValue();
|
||||
|
||||
// 点击身体
|
||||
await page.locator('.type_tab_item', { hasText: '身体' }).click();
|
||||
|
||||
// 购买项目4-普通,30次
|
||||
await page.getByText(ProjectB4.num).click();
|
||||
await page.getByText(project_b4.num).click();
|
||||
await page.locator('.edit_txt div:nth-child(2)').first().click();
|
||||
await numberInput.setValue(ProjectB4Quantity);
|
||||
await numberInput.setValue(project_b4_quantity);
|
||||
await numberInput.confirmValue();
|
||||
|
||||
// 购买项目5,9次
|
||||
await page.getByText(ProjectB5.num).click();
|
||||
await page.getByText(project_b5.num).click();
|
||||
await page.locator('.edit_txt div:nth-child(2)').first().click();
|
||||
await numberInput.setValue(ProjectB5Quantity);
|
||||
await numberInput.setValue(project_b5_quantity);
|
||||
await numberInput.confirmValue();
|
||||
|
||||
// 购买项目B1-B2混合,2次
|
||||
await page.locator('.type_tab_item', { hasText: '护理' }).click();
|
||||
await page.getByText(ProjectB1.num).first().click();
|
||||
await page.getByText(project_b1.num).first().click();
|
||||
await page.locator('.add_btn', { hasText: '设置' }).last().click();
|
||||
await page.getByRole('textbox').fill(ProjectB2.num);
|
||||
await page.getByRole('textbox').fill(project_b2.num);
|
||||
await page.getByRole('button', { name: /搜\s索/ }).click();
|
||||
await expect(async () => {
|
||||
await page.locator('.list_box .ant-checkbox-input').click();
|
||||
@ -2352,13 +2348,13 @@ test.describe('顾客分析', () => {
|
||||
await page.getByRole('button', { name: '确定选择' }).click();
|
||||
// 点击选择数量
|
||||
await page.locator('.edit_txt div:nth-child(2)').first().click();
|
||||
await numberInput.setValue(ProjectB12Quantity);
|
||||
await numberInput.setValue(project_b12_quantity);
|
||||
await numberInput.confirmValue();
|
||||
|
||||
// 购买项目B4-B4混合,3次
|
||||
await page.getByText(ProjectB3.num).first().click();
|
||||
await page.getByText(project_b3.num).first().click();
|
||||
await page.locator('.add_btn', { hasText: '设置' }).last().click();
|
||||
await page.getByRole('textbox').fill(ProjectB4.num);
|
||||
await page.getByRole('textbox').fill(project_b4.num);
|
||||
await page.getByRole('button', { name: '搜 索' }).click();
|
||||
await expect(async () => {
|
||||
await page.locator('.list_box .ant-checkbox-input').click();
|
||||
@ -2367,7 +2363,7 @@ test.describe('顾客分析', () => {
|
||||
await page.getByRole('button', { name: '确定选择' }).click();
|
||||
// 点击选择数量
|
||||
await page.locator('.edit_txt div:nth-child(2)').first().click();
|
||||
await numberInput.setValue(ProjectB34Quantity);
|
||||
await numberInput.setValue(project_b34_quantity);
|
||||
await numberInput.confirmValue();
|
||||
|
||||
await page.locator('.commodity_item').last().click();
|
||||
@ -2385,15 +2381,13 @@ test.describe('顾客分析', () => {
|
||||
await page.reload();
|
||||
await homeNavigation.gotoModule('顾客');
|
||||
await customerPage.gotoSubPage('顾客分析');
|
||||
await page
|
||||
.locator('div')
|
||||
.filter({ hasText: /^排序$/ })
|
||||
.nth(1)
|
||||
.click();
|
||||
await page.getByRole('menuitem', { name: '上次到店时间从近到远' }).click();
|
||||
await page.locator('.loading_container').waitFor({ state: 'hidden' });
|
||||
const Customer1A = page.locator('.m-table__body-wrapper tbody tr', { hasText: phoneA });
|
||||
const Customer1B = page.locator('.m-table__body-wrapper tbody tr', { hasText: phoneB });
|
||||
await page.getByText('排序', { exact: true }).click();
|
||||
await Promise.all([
|
||||
page.waitForResponse(res => res.url().includes('analysis') && res.ok()),
|
||||
page.getByRole('menuitem', { name: '上次到店时间从近到远' }).click(),
|
||||
]);
|
||||
const Customer1A = page.locator('.m-table__body-wrapper tbody tr', { hasText: ca.phone });
|
||||
const Customer1B = page.locator('.m-table__body-wrapper tbody tr', { hasText: cb.phone });
|
||||
// 1 查找到顾客A 顾客B
|
||||
await expect(Customer1A).toBeVisible();
|
||||
await expect(Customer1B).toBeVisible();
|
||||
@ -2406,19 +2400,19 @@ test.describe('顾客分析', () => {
|
||||
.locator('.m-table__body-wrapper tbody tr')
|
||||
.allInnerTexts()
|
||||
.then(async text => {
|
||||
return text.findIndex(item => item.includes(phoneB));
|
||||
return text.findIndex(item => item.includes(cb.phone));
|
||||
});
|
||||
|
||||
// 查看各单元格内容
|
||||
// 护理内容
|
||||
await expect.soft(allTr.nth(nowRow).locator('td').nth(2)).toContainText(`${ProjectB3Quantity - 1}`);
|
||||
await expect.soft(allTr.nth(nowRow).locator('td').nth(2)).toContainText(`${project_b3_quantity - 1}`);
|
||||
// 身体内容
|
||||
await expect
|
||||
.soft(allTr.nth(nowRow).locator('td').nth(5))
|
||||
.toContainText(`${ProjectB12Quantity + ProjectB34Quantity}`);
|
||||
.toContainText(`${project_b12_quantity + project_b34_quantity}`);
|
||||
// 组合内容
|
||||
await expect(allTr.nth(nowRow).locator('td').nth(5)).toContainText(
|
||||
`${ProjectB12Quantity + ProjectB34Quantity}`,
|
||||
`${project_b12_quantity + project_b34_quantity}`,
|
||||
);
|
||||
|
||||
const $productName = page.locator('.treat_box .treat_card:nth-child(1) .name_row .auto_desc');
|
||||
@ -2430,67 +2424,67 @@ test.describe('顾客分析', () => {
|
||||
// 点击护理
|
||||
await allTr.nth(nowRow).locator('td').nth(2).click();
|
||||
// 项目名称
|
||||
await expect.soft($productName).toContainText(ProjectB3.name);
|
||||
await expect.soft($productName).toContainText(project_b3.name);
|
||||
// 剩余次数
|
||||
await expect($productResidue).toContainText(`${ProjectB3Quantity - 1}`);
|
||||
await expect($productResidue).toContainText(`${project_b34_quantity - 1}`);
|
||||
// 关闭弹窗
|
||||
await page.locator('.close_icon').last().click();
|
||||
|
||||
// 点击身体
|
||||
await allTr.nth(nowRow).locator('td').nth(4).click();
|
||||
// 项目名称
|
||||
await expect.soft($productName).toContainText(ProjectB4.name);
|
||||
await expect.soft($productName).toContainText(project_b4.name);
|
||||
// 剩余次数
|
||||
await expect.soft($productResidue).toContainText(`${ProjectB4Quantity}`);
|
||||
await expect.soft($productResidue).toContainText(`${project_b4_quantity}`);
|
||||
// 项目名称
|
||||
await expect.soft($productName2).toContainText(ProjectB5.name);
|
||||
await expect.soft($productName2).toContainText(project_b5.name);
|
||||
// 剩余次数
|
||||
await expect.soft($productResidue2).toContainText(`${ProjectB5Quantity}`);
|
||||
await expect.soft($productResidue2).toContainText(`${project_b5_quantity}`);
|
||||
// 关闭弹窗
|
||||
await page.locator('.close_icon').last().click();
|
||||
|
||||
// 点击组合
|
||||
await allTr.nth(nowRow).locator('td').nth(5).click();
|
||||
// 项目名称
|
||||
await expect.soft($productName).toContainText(ProjectB1.name + ',' + ProjectB2.name);
|
||||
await expect.soft($productName).toContainText(project_b1.name + ',' + project_b2.name);
|
||||
// 剩余次数
|
||||
await expect.soft($productResidue).toContainText(`${ProjectB12Quantity}`);
|
||||
await expect.soft($productResidue).toContainText(`${project_b12_quantity}`);
|
||||
// 项目名称
|
||||
await expect.soft($productName2).toContainText(ProjectB3.name + ',' + ProjectB4.name);
|
||||
await expect.soft($productName2).toContainText(project_b3.name + ',' + project_b4.name);
|
||||
// 剩余次数
|
||||
await expect($productResidue2).toContainText(`${ProjectB34Quantity}`);
|
||||
await expect($productResidue2).toContainText(`${project_b34_quantity}`);
|
||||
// 关闭弹窗
|
||||
await page.locator('.close_icon').last().click();
|
||||
|
||||
// 查看顾客A的各单元格内容
|
||||
const allTrA = page.locator('.m-table__body-wrapper tbody tr');
|
||||
const nowRowA = await allTrA.allInnerTexts().then(async text => {
|
||||
return text.findIndex(item => item.includes(phoneA));
|
||||
return text.findIndex(item => item.includes(ca.phone));
|
||||
});
|
||||
// 点击护理
|
||||
await allTrA.nth(nowRowA).locator('td').nth(2).click();
|
||||
// 项目名称
|
||||
await expect.soft($productName).toContainText(ProjectA1.name);
|
||||
await expect.soft($productName).toContainText(projects_a1.name);
|
||||
// 剩余次数
|
||||
await expect($productResidue).toContainText(`${ProjectA1Quantity - 1}`);
|
||||
await expect($productResidue).toContainText(`${projects_a1_quantity - 1}`);
|
||||
// 关闭弹窗
|
||||
await page.locator('.close_icon').last().click();
|
||||
|
||||
// 点击面部
|
||||
await allTrA.nth(nowRowA).locator('td').nth(3).click();
|
||||
// 项目名称
|
||||
await expect.soft($productName).toContainText(ProjectA2.name);
|
||||
await expect.soft($productName).toContainText(projects_a2.name);
|
||||
// 剩余次数
|
||||
await expect($productResidue).toContainText(`${ProjectA2Quantity}`);
|
||||
await expect($productResidue).toContainText(`${projects_a2_quantity}`);
|
||||
// 关闭弹窗
|
||||
await page.locator('.close_icon').last().click();
|
||||
|
||||
// 点击组合
|
||||
await allTrA.nth(nowRowA).locator('td').nth(5).click();
|
||||
// 项目名称
|
||||
await expect.soft($productName).toContainText(ProjectA1.name + ',' + ProjectA2.name);
|
||||
await expect.soft($productName).toContainText(projects_a1.name + ',' + projects_a2.name);
|
||||
// 剩余次数
|
||||
await expect($productResidue).toContainText(`${ProjectA12Quantity}`);
|
||||
await expect($productResidue).toContainText(`${projects_a12_quantity}`);
|
||||
// 关闭弹窗
|
||||
await page.locator('.close_icon').last().click();
|
||||
|
||||
@ -2506,18 +2500,18 @@ test.describe('顾客分析', () => {
|
||||
// 护理内容
|
||||
const allTrAA = page.locator('.m-table__body-wrapper tbody tr');
|
||||
const nowRowAA = await allTrAA.allInnerTexts().then(async text => {
|
||||
return text.findIndex(item => item.includes(phoneA));
|
||||
return text.findIndex(item => item.includes(ca.phone));
|
||||
});
|
||||
// 点击护理
|
||||
await allTrAA.nth(nowRowAA).locator('td').nth(2).click();
|
||||
// 项目名称
|
||||
await expect.soft($productName).toContainText(ProjectA1.name);
|
||||
await expect.soft($productName).toContainText(projects_a1.name);
|
||||
// 剩余次数
|
||||
await expect.soft($productResidue).toContainText(`${ProjectA1Quantity - 1}`);
|
||||
await expect.soft($productResidue).toContainText(`${projects_a1_quantity - 1}`);
|
||||
// 项目名称
|
||||
await expect.soft($productName2).toContainText(ProjectA3.name);
|
||||
await expect.soft($productName2).toContainText(projects_a3.name);
|
||||
// 剩余次数
|
||||
await expect($productResidue2).toContainText(`${ProjectA3Quantity}`);
|
||||
await expect($productResidue2).toContainText(`${projects_a3_quantity}`);
|
||||
// 关闭弹窗
|
||||
await page.locator('.close_icon').last().click();
|
||||
|
||||
|
||||
@ -280,7 +280,7 @@ test.describe('业绩明细表', () => {
|
||||
|
||||
test.describe('项目销耗存表', () => {
|
||||
test('数据校验', async ({ page, createCustomers, homeNavigation, reportPage, customerPage, numberInput }) => {
|
||||
let customers: Customer[];
|
||||
let customers: Customer[] = new Array(2);
|
||||
await test.step('创建两个顾客', async () => {
|
||||
customers = await createCustomers(2);
|
||||
});
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { Page } from "playwright";
|
||||
|
||||
// 解析二维码
|
||||
const decodeImage = require('jimp').read;
|
||||
const { readFile, unlinkSync } = require('fs');
|
||||
@ -95,17 +97,31 @@ export function CleanPunctuation(str) {
|
||||
|
||||
/**
|
||||
* 等待指定接口加载完成
|
||||
* @param {import('@playwright/test').Page} page
|
||||
* @param {string[]} apiArray 接口名称数组
|
||||
* @param {Page} page - Playwright Page 对象
|
||||
* @param {string[]} apiArray - 接口名称数组
|
||||
* @returns Promise<Response[]>
|
||||
*/
|
||||
export const waitSpecifyApiLoad = (page, apiArray) => {
|
||||
if (apiArray === undefined || apiArray.length === 0) {
|
||||
return Promise.resolve([]);
|
||||
export const waitSpecifyApiLoad = async (page: Page, apiArray: string[]): Promise<Response[]> => {
|
||||
// 输入参数检查
|
||||
if (!page || !Array.isArray(apiArray) || apiArray.length === 0 || !apiArray.every(item => typeof item === 'string')) {
|
||||
return [];
|
||||
}
|
||||
return Promise.all(
|
||||
apiArray.map(api => page.waitForResponse(res => res.url().includes(api) && res.status() === 200)),
|
||||
|
||||
// 去重
|
||||
const uniqueApiArray = Array.from(new Set(apiArray));
|
||||
|
||||
// 精确匹配 URL
|
||||
const urlMatchers = uniqueApiArray.map(api => new RegExp(`^.*${api}$`));
|
||||
|
||||
// 等待所有接口加载完成
|
||||
const responses = await Promise.allSettled(
|
||||
urlMatchers.map(matcher => page.waitForResponse(res => matcher.test(res.url()) && res.status() === 200))
|
||||
);
|
||||
|
||||
// 处理结果
|
||||
return responses
|
||||
.filter(response => response.status === 'fulfilled')
|
||||
.map(response => (response as unknown as PromiseFulfilledResult<Response>).value);
|
||||
};
|
||||
|
||||
/**
|
||||
Reference in New Issue
Block a user