This repository has been archived on 2025-04-22. You can view files and clone it, but cannot push or open issues or pull requests.
hlk_autotest/tests/touch/boss_wastebook.spec.ts
2024-12-29 21:51:02 +08:00

1243 lines
60 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// @ts-check
import { test, expect } from '@/fixtures/boss_common.js';
import { faker } from '@faker-js/faker/locale/zh_CN';
import { Customer } from '@/utils/customer';
import { KeepOnlyNumbers } from '@/utils/utils.js';
import fs from 'fs';
import path from 'path';
import { Employees, ProjectName } from '@/fixtures/userconfig.js';
import { staffData } from '@/common/staff';
test.describe('营业记录', () => {
test.beforeEach(async ({ page }) => {
await page.addLocatorHandler(page.getByRole('button', { name: '我知道了' }), async () => {
await page.getByRole('button', { name: '我知道了' }).click();
await expect(page.getByRole('button', { name: '我知道了' })).not.toBeVisible();
await page.reload();
});
await page.addLocatorHandler(page.locator('.ant-notification', { hasText: '反结算成功' }), async () => {
await page.locator('.ant-notification', { hasText: '反结算成功' }).locator('a').click();
await expect(page.locator('.ant-notification', { hasText: '反结算成功' })).not.toBeVisible();
});
});
test('根据条件搜索营业记录', async ({ page, homeNavigation, customerPage, createCustomCustomer }) => {
const customer = new Customer(2, 1);
const project = { num: '100012', name: '雪肌晶纯护理', Price: 300 };
let billNo = '';
await test.step('创建顾客', async () => {
await createCustomCustomer(customer);
});
await test.step('开单结算拿取单号', async () => {
// 进入顾客详情页面
await homeNavigation.gotoModule('顾客');
await customerPage.searchCustomer(customer.phone);
await customerPage.selectSearchCustomer(customer.username);
await customerPage.openCustomerDetail(customer.username, customer.phone);
await page.locator('span').filter({ hasText: '去开单' }).first().click();
await expect(page.locator('div').filter({ hasText: /^结\s算$/ })).toBeVisible();
// 选择项目1
await page.getByText(project.num).click();
await page
.locator('div')
.filter({ hasText: /^结\s算$/ })
.click();
await page.locator('.paymentInfoItem').filter({ hasText: '现金' }).click();
await page.getByLabel('推送消费提醒').uncheck();
await page.getByLabel('结算签字').uncheck();
// 结算
const [response] = await Promise.all([
page.waitForResponse(async res => {
return res.url().includes('/bill') && (await res.json()).code === 'SUCCESS';
}),
page.getByRole('button', { name: /^结\s算$/ }).click(),
]);
const responseBody = await response.json();
billNo = responseBody?.content?.billNo;
});
expect(billNo).not.toBeNull();
const $bill = page.getByRole('cell', { name: billNo }).nth(1);
await test.step('条件搜索', async () => {
await homeNavigation.gotoModule('流水');
await expect(page.getByText('营业记录').first()).toBeVisible();
await page.getByRole('combobox').first().click();
await page.getByRole('option', { name: '购买项目/卖品' }).click();
await page.getByRole('combobox').nth(1).click();
await page.getByRole('option', { name: '已结算' }).click();
await page.getByRole('combobox').nth(2).click();
await page.getByRole('option', { name: '未对单' }).click();
await expect($bill).toBeVisible();
});
await test.step('搜索水单号', async () => {
await page.getByRole('button').click();
await page.getByPlaceholder('输入流水单号搜索').fill(billNo);
await page.locator('.search_btn > svg').click();
await expect($bill).toBeVisible();
});
await test.step('进入水单详情和顾客详情', async () => {
await $bill.click();
await expect(page.locator('li').getByText(billNo)).toBeVisible();
await page
.locator('div')
.filter({ hasText: /^单据明细$/ })
.locator('use')
.click();
await page.locator('.main-table-body_tr').getByText(customer.username).first().click();
await expect(page.getByRole('tabpanel').getByText(customer.username)).toBeVisible();
});
});
test.describe('单据明细', () => {
test.beforeAll(async () => {
const currentFileName = path.basename(__filename);
// 构造快照目录
const snapshotDir = path.resolve('tests/imgs/__screenshots__/touch', currentFileName);
// 如果目录不存在,则创建它
if (!fs.existsSync(snapshotDir)) {
fs.mkdirSync(snapshotDir, { recursive: true });
}
});
test('反结算', async ({ page, homeNavigation, customerPage, createCustomer, numberInput }) => {
// 定义随机单号
let ReceiptNum = faker.helpers.fromRegExp(/1[3-9][0-9]{8}/);
const project_1 = ProjectName.Projects.Projects_2; // 项目
const employee_1 = Employees.FirstShop.Employee_6; // 员工
const project_2 = ProjectName.Projects.Projects_3; // 项目
const employee_2 = Employees.FirstShop.Employee_4; // 员工
// 创建顾客A随机姓名 手机
const customer = createCustomer;
await test.step('开单结算拿取单号', async () => {
// 进入顾客详情页面
await homeNavigation.gotoModule('顾客');
await customerPage.searchCustomer(customer.phone);
await customerPage.selectSearchCustomer(customer.username);
await customerPage.openCustomerDetail(customer.username, customer.phone);
await page.locator('span').filter({ hasText: '去开单' }).first().click();
// 选择项目1
await page.getByText(project_1.num).click();
// 点击添加员工
await page.locator('#buyList').getByRole('button').nth(1).click();
// 选择员工1
await page.locator('.hand_txt .name_txt').getByText(employee_1.name).click();
await page.getByRole('button', { name: /^确\s认$/ }).click();
await page
.locator('div')
.filter({ hasText: /^结\s算$/ })
.click();
// 点击修改单号
await page.locator('.input165').click();
await page.getByPlaceholder('请输入内容').fill(ReceiptNum);
await page.locator('.tools_icon').last().click();
// 点击现金
await page.locator('.paymentInfoItem').filter({ hasText: '现金' }).click();
await page.getByLabel('推送消费提醒').uncheck();
await page.getByLabel('结算签字').uncheck();
await page.getByRole('button', { name: /^结\s算$/ }).click();
await expect(page.locator('.ant-message')).toContainText('结算成功');
});
await test.step('进入流水模块,进行反结算', async () => {
await homeNavigation.gotoModule('流水');
// 点击指定单号
await page
.locator('.m-table__fixed-left .m-table-cell .bill .m-dropdown-link ', {
hasText: ReceiptNum,
})
.click();
// 点击反结算
await page.locator('.oversized', { hasText: '反结算' }).click();
await page.locator('.custom_content').waitFor();
// 删除单据内的项目
await page.locator('.buy_item .buy_name .del_btn').last().click();
// 选择项目C
await page.getByText(project_2.num).click();
await page.locator('#buyList').getByText(project_2.name).click();
// 点击添加员工
await page.locator('#buyList').getByRole('button').nth(1).click();
await page.getByText(employee_2.name).first().click();
// 确认
await page.getByRole('button', { name: /^确\s认$/ }).click();
// 修改数量
await page.locator('.edit_txt div:nth-child(2)').first().click();
await numberInput.setValue(2);
await numberInput.confirmValue();
// 结算
await page
.locator('div')
.filter({ hasText: /^结\s算$/ })
.click();
// 使用银联支付
await page.locator('.paymentInfoItem', { hasText: '银联' }).click();
await page.getByLabel('结算签字').uncheck();
await page.getByLabel('推送消费提醒').uncheck();
await page.getByRole('button', { name: /^结\s算$/ }).click();
await expect(page.locator('.ant-message', { hasText: '结算成功' })).toBeVisible();
await page.addLocatorHandler(page.getByRole('button', { name: '我知道了' }), async () => {
await page.getByRole('button', { name: '我知道了' }).click();
await expect(page.getByRole('button', { name: '我知道了' })).not.toBeVisible();
await page.reload();
await page
.locator('.m-table__fixed-left .m-table-cell .bill .m-dropdown-link ', {
hasText: ReceiptNum,
})
.click();
});
});
await test.step('进入单据明细,查看反结算内容', async () => {
await page.locator('.m-receiptDetail_tip', { hasText: '单据明细' }).waitFor();
// 对比第一个项目
await expect.soft(page.locator('.items_name .name_txt').first()).toContainText(project_2.name);
// 对比员工
await expect
.soft(
page
.locator(
'.m-detailComponent_report .main-table-body_tr:nth-child(1) .billUser_item .userName',
)
.first(),
)
.toContainText(employee_2.name);
// 对比数量
await expect.soft(page.locator('.m-detailComponent-cell .num').last()).toContainText('2');
// 对比总金额
const project1ResultCollect = Number(ProjectName.Projects.Projects_3.Price) * 2 + '';
await expect(page.locator('.m-detailComponent_consume_title .amount')).toContainText(
project1ResultCollect,
);
});
});
test('撤单', async ({ page, homeNavigation, customerPage, createCustomer }) => {
const ReceiptNum = faker.helpers.fromRegExp(/1[3-9][0-9]{8}/); // 随机单号
let OddNumber = page.locator('.m-table__fixed-left .m-table-cell .bill .m-dropdown-link ', {
hasText: ReceiptNum,
});
const project = ProjectName.Projects.Projects_3;
const customer = createCustomer;
await test.step('开单获取单号', async () => {
// 进入顾客详情页面
await homeNavigation.gotoModule('顾客');
await customerPage.searchCustomer(customer.phone);
await customerPage.selectSearchCustomer(customer.username);
await customerPage.openCustomerDetail(customer.username, customer.phone);
await page.locator('span').filter({ hasText: '去开单' }).first().click();
// 选择项目1
await page.getByText(project.num).click();
// 结算
await page
.locator('div')
.filter({ hasText: /^结\s算$/ })
.click();
// 点击修改单号
await page.locator('.input165').click();
// 输入随机单号
await page.getByPlaceholder('请输入内容').fill(ReceiptNum);
// 确认
await page.locator('.tools_icon').last().click();
await page.locator('.paymentInfoItem', { hasText: '现金' }).click();
await page.getByLabel('推送消费提醒').uncheck();
await page.getByLabel('结算签字').uncheck();
await page.getByRole('button', { name: /^结\s算$/ }).click();
await expect(page.locator('.ant-message')).toContainText('结算成功');
});
await test.step('根据单号进行撤单,判断撤单成功', async () => {
// 点击流水
await page.reload();
await homeNavigation.gotoModule('流水');
// 点击下拉框
await page.locator('.ant-dropdown-link > .anticon > svg').first().click();
// 选择营业记录
await page.getByRole('menuitem', { name: '营业记录' }).click();
// 点击指定单号
await page
.locator('.m-table__fixed-left .m-table-cell .bill .m-dropdown-link ', {
hasText: ReceiptNum,
})
.click();
// 点击撤单
await page.locator('.ant-btn', { hasText: '撤单' }).click();
// 点击输入备注
await page.locator('.label_text').last().click();
await page.getByPlaceholder('请输入1-100个字符备注内容').fill('撤单');
await page.locator('.saveCheck').waitFor();
await page.getByRole('button', { name: '确 认' }).click();
// 点击下拉框
await page.locator('.ant-dropdown-link > .anticon > svg').first().click();
// 选择营业记录
await page.getByRole('menuitem', { name: '营业记录' }).click();
// 点击撤单查看
await page.locator('.search_select').first().click();
await page.locator('.ant-select-dropdown-menu-item', { hasText: '已撤单' }).click();
// 判断撤的单子是否还在
await expect(OddNumber).toBeVisible();
});
});
test('补签', async ({ page, homeNavigation, customerPage, createCustomer }) => {
const customer = createCustomer;
const project = { num: '100012', name: '雪肌晶纯护理', Price: 300 };
let billNo = '';
await test.step('开单结算,不勾选签字,拿取单号', async () => {
// 进入顾客详情页面
await homeNavigation.gotoModule('顾客');
await customerPage.searchCustomer(customer.phone);
await customerPage.selectSearchCustomer(customer.username);
await customerPage.openCustomerDetail(customer.username, customer.phone);
await page.locator('span').filter({ hasText: '去开单' }).first().click();
// 选择项目1
await page.getByText(project.num).click();
await page
.locator('div')
.filter({ hasText: /^结\s算$/ })
.click();
await page.locator('.paymentInfoItem').filter({ hasText: '现金' }).click();
await page.getByLabel('推送消费提醒').uncheck();
await page.getByLabel('结算签字').uncheck();
// 结算
const [response] = await Promise.all([
page.waitForResponse(async res => {
return res.url().includes('/bill') && (await res.json()).code === 'SUCCESS';
}),
page.getByRole('button', { name: /^结\s算$/ }).click(),
]);
const responseBody = await response.json();
billNo = responseBody?.content?.billNo;
expect(billNo).not.toBeNull();
});
const $bill = page.getByRole('cell', { name: billNo }).nth(1);
await test.step('进入水单详情进行补签', async () => {
await homeNavigation.gotoModule('流水');
await expect(page.getByText('营业记录').first()).toBeVisible();
await $bill.click();
await expect(page.locator('li').getByText(billNo)).toBeVisible();
await page.getByText('补签').click();
await expect(page.getByText('请签字确认消费')).toBeVisible();
const $canvas = page.locator('canvas').first();
const canvasBoundingBox = await $canvas.boundingBox();
if (canvasBoundingBox) {
const { x, y, width, height } = canvasBoundingBox;
// 模拟鼠标按下操作
await page.mouse.move(x + width / 4, y + height / 2);
await page.mouse.down();
// 模拟签字路径(可以自定义路径)
await page.mouse.move(x + width / 2, y + height / 2);
await page.mouse.move(x + width / 1.5, y + height / 3);
await page.mouse.move(x + width / 1.2, y + height / 1.8);
// 释放鼠标
await page.mouse.up();
} else {
throw new Error('无法找到签字区域');
}
await page.getByRole('button', { name: '签好了' }).click();
await expect(page.locator('li').getByText(billNo)).toBeVisible();
await page.waitForLoadState('load');
const $img = page.locator('.slider_list_item', { has: page.getByText('签名') }).locator('img');
await expect($img).toHaveScreenshot({
threshold: 0.25, // 相似度阈值0.1 表示 10% 以内的差异可以接受)
animations: 'disabled', // 处理有动画的元素
});
});
});
test('查看配方', async ({ page, homeNavigation, customerPage, createCustomer }) => {
const project = { num: '100012', name: '雪肌晶纯护理', Price: 300 };
const customer = createCustomer;
let billNo = '';
let useProductName = '';
await test.step('开单,购买项目并消耗,消耗时选择项目配方', async () => {
// 进入顾客详情页面
await homeNavigation.gotoModule('顾客');
await customerPage.searchCustomer(customer.phone);
await customerPage.selectSearchCustomer(customer.username);
await customerPage.openCustomerDetail(customer.username, customer.phone);
await page.locator('span').filter({ hasText: '去开单' }).first().click();
// 选择项目1
await page.getByText(project.num).click();
await page.locator('.commodity_item').first().click();
// 打开使用区-项目配方
await page.locator('.staff_setting').first().click();
await page.getByLabel('项目配方').check();
await page.getByRole('button', { name: /确\s认/ }).click();
// 选择项目配方
await page.locator('.formula_noData').click();
await expect(async () => {
await page.locator('.list_box').getByRole('checkbox').first().check();
await expect(page.locator('.menu-item-dot').first()).toBeVisible();
}).toPass({ timeout: 30_000 });
useProductName = (await page.locator('.list_box .label').first().innerText()).trim();
await page.getByRole('button', { name: '确定选择' }).click();
await page.locator('input[type="tel"]').fill('1');
await page.getByRole('button', { name: /保\s存/ }).click();
await page
.locator('div')
.filter({ hasText: /^结\s算$/ })
.click();
await page.locator('.paymentInfoItem').filter({ hasText: '现金' }).click();
await page.getByLabel('推送消费提醒').uncheck();
await page.getByLabel('结算签字').uncheck();
// 结算
const [response] = await Promise.all([
page.waitForResponse(async res => {
return res.url().includes('/bill') && (await res.json()).code === 'SUCCESS';
}),
page.getByRole('button', { name: /^结\s算$/ }).click(),
]);
const responseBody = await response.json();
billNo = responseBody?.content?.billNo;
});
expect(billNo).not.toBeNull();
expect(useProductName).not.toBeNull();
await test.step('查看单据明细的配方消耗', async () => {
await homeNavigation.gotoModule('流水');
await page.locator('.m-table-fixed-body').getByText(billNo).first().click();
const $$listItem = page.locator('.slider_list_item');
const $openConsumptionRecord = $$listItem
.filter({
has: page.getByText('开用记录'),
})
.getByText('查看详情');
await $openConsumptionRecord.click();
const $popup = page.locator('.popup_content');
await expect($popup.getByText(useProductName)).toBeVisible();
const useProductNumber = (
await $popup.locator('.main-table-body_tr').first().locator('td').nth(1).innerText()
).trim();
expect(useProductNumber).toBe('1');
});
});
});
});
test.describe('业绩流水', () => {
test('根据条件搜索业绩流水', async ({
page,
customerPage,
homeNavigation,
createCustomer,
wasteBookBusinessRecordPage,
}) => {
const customer = createCustomer;
let billNo = '';
const firstProject = { num: '', name: '' };
const firstGoods = { num: '', name: '' };
await test.step('开单,购买项目、卖品并消耗,消耗购买项目', async () => {
// 进入顾客详情页面
await homeNavigation.gotoModule('顾客');
await customerPage.searchCustomer(customer.phone);
await customerPage.selectSearchCustomer(customer.username);
await customerPage.openCustomerDetail(customer.username, customer.phone);
await page.locator('span').filter({ hasText: '去开单' }).first().click();
await expect(page.locator('div').filter({ hasText: /^结\s算$/ })).toBeVisible();
// 选择项目1
const $firstProject = page.locator('.list_box .project_list').first();
await $firstProject.click();
firstProject.num = await $firstProject.locator('.number').innerText();
firstProject.name = await $firstProject.locator('.title').innerText();
await page.locator('.commodity_item').first().click();
// 选择卖品
await page.getByText('卖品', { exact: true }).click();
await $firstProject.click();
firstGoods.num = await $firstProject.locator('.number').innerText();
firstGoods.name = await $firstProject.locator('.title').innerText();
await page
.locator('div')
.filter({ hasText: /^结\s算$/ })
.click();
await page.locator('.paymentInfoItem').filter({ hasText: '现金' }).click();
await page.getByLabel('推送消费提醒').uncheck();
await page.getByLabel('结算签字').uncheck();
const [response] = await Promise.all([
page.waitForResponse(async res => {
return res.url().includes('/bill') && (await res.json()).code === 'SUCCESS';
}),
page.getByRole('button', { name: /^结\s算$/ }).click(),
]);
await page.getByRole('button', { name: '不寄存' }).click();
const responseBody = await response.json();
billNo = responseBody?.content?.billNo;
});
expect(billNo).not.toBeNull();
expect(firstProject.num).not.toBe('');
expect(firstProject.name).not.toBe('');
expect(firstGoods.num).not.toBe('');
expect(firstGoods.name).not.toBe('');
await test.step('根据筛选条件进行搜索水单', async () => {
await Promise.all([homeNavigation.gotoModule('流水'), page.waitForLoadState()]);
await wasteBookBusinessRecordPage.gotoSubPage('业绩流水');
// 流水单
const $flowChart = page.getByRole('row', { name: billNo, exact: true }).first();
const $projectViewSelect = page
.locator('.com_picker')
.filter({ hasText: '选择' })
.locator('.menu-item-dot')
.first();
const $goodsViewSelect = page
.locator('.com_picker')
.filter({ hasText: '选择卖品' })
.locator('.menu-item-dot')
.first();
await page.getByTitle('全部水单类型').click();
await page.getByRole('option', { name: '购买项目/卖品' }).click();
// 选择项目
await page.locator('span').filter({ hasText: '选择项目' }).getByRole('list').click();
await page.getByRole('textbox', { name: '请输入首字母或关键字检索' }).fill(firstProject.num);
await page.getByRole('button', { name: /搜\s索/ }).click();
await expect(async () => {
await page.getByLabel(firstProject.name).uncheck();
await page.getByLabel(firstProject.name).check();
await expect($projectViewSelect).toBeVisible({ timeout: 2000 });
}).toPass({ timeout: 30_000 });
await page.getByRole('button', { name: '确定选择' }).click();
// 选择卖品
await page.getByTitle('购买项目/卖品').click();
await page.getByRole('option', { name: '全部水单类型' }).click();
await page.getByTitle('全部水单类型').click();
await page.getByRole('option', { name: '购买项目/卖品' }).click();
await page.locator('span').filter({ hasText: '选择卖品' }).getByRole('list').click();
await page.getByRole('textbox').nth(2).fill(firstGoods.num);
await page.getByRole('button', { name: /搜\s索/ }).click();
await expect(async () => {
await page.getByLabel(firstGoods.name).uncheck();
await page.getByLabel(firstGoods.name).check();
await expect($goodsViewSelect).toBeVisible({ timeout: 2000 });
}).toPass({ timeout: 30_000 });
await page.getByRole('button', { name: '确定选择' }).click();
await expect($flowChart).toBeVisible();
await page.getByTitle('购买项目/卖品').click();
await page.getByRole('option', { name: '消耗项目' }).click();
await expect($flowChart).toBeVisible();
await page.getByTitle('消耗项目').click();
await page.getByRole('option', { name: '开卡' }).click();
await expect($flowChart).not.toBeVisible();
await page.getByTitle('开卡').click();
await page.getByRole('option', { name: '充值' }).click();
await expect($flowChart).not.toBeVisible();
await page.getByTitle('充值').click();
await page.getByRole('option', { name: '还款' }).click();
await expect($flowChart).not.toBeVisible();
await page.getByTitle('还款').click();
await page.getByRole('option', { name: '换项目/产品' }).click();
await expect($flowChart).not.toBeVisible();
await page.getByTitle('换项目/产品').click();
await page.getByRole('option', { name: '抹欠款' }).click();
await expect($flowChart).not.toBeVisible();
await page.getByTitle('抹欠款').click();
await page.getByRole('option', { name: '补录' }).click();
await expect($flowChart).not.toBeVisible();
await page.getByTitle('补录').click();
await page.getByRole('option', { name: '跨店帮忙' }).click();
await expect($flowChart).not.toBeVisible();
await page.getByTitle('跨店帮忙').click();
await page.getByRole('option', { name: '会员卡退卡' }).click();
await expect($flowChart).not.toBeVisible();
await page.reload();
await page.getByRole('button').click();
await page.getByPlaceholder('输入流水单号搜索').fill(billNo);
await page.locator('.search_btn > svg').click();
await expect($flowChart).toBeVisible();
});
});
test('查询业绩流水列表明细', async ({ page, homeNavigation, createCustomer, wasteBookBusinessRecordPage }) => {
// 创建顾客A随机姓名 手机
const ca = createCustomer;
const usernameA = ca.username;
const phoneA = ca.phone;
await test.step('开单购买会员卡', async () => {
await homeNavigation.gotoModule('收银');
await page.getByRole('button', { name: /^开\s单$/ }).click();
await page.getByPlaceholder('姓名(拼音首字)、手机号、档案号搜索').fill(phoneA);
await page
.locator('.search_text')
.filter({ hasText: /^搜\s索$/ })
.click();
// 选择会员
await page.locator('.custom_content').getByText(usernameA).click();
await page.locator('.loading_container').waitFor({ state: 'hidden' });
await page.locator('.custom_content').waitFor();
// 点击开卡
const ActivateCards = page.getByRole('button', { name: /^开\s卡$/ });
if (await ActivateCards.isVisible()) {
await page.getByRole('button', { name: /^开\s卡$/ }).click();
} else {
await page.locator('.more').first().click();
await page.getByText('去开卡').click();
}
// 选择会员卡A
await page
.locator('.memberCard_box > .needsclick')
.getByText(/^会员卡$/)
.click();
// 结算
await page.getByRole('button', { name: '去结算' }).click();
// 选择现金支付
await page.getByText('现金').click();
// 取消推送消费提醒
await page.getByLabel('推送消费提醒').uncheck();
// 取消结算签字
await page.getByLabel('结算签字').uncheck();
// 结算
await page.getByRole('button', { name: /^结\s算$/ }).click();
// 会员协议签署确认(需判断 常报错)
try {
await page.locator('.modal_title', { hasText: '会员协议签署确认' }).waitFor();
await page.getByRole('button', { name: /跳\s过/ }).click();
} catch {
console.log('无会员协议签署');
}
await expect(page.locator('.ant-message')).toContainText('结算成功');
});
await test.step('进入顾客详情', async () => {
await page.reload();
await homeNavigation.gotoModule('顾客');
await page.getByPlaceholder('姓名(拼音首字)、手机号、档案号搜索').fill(phoneA);
await page.getByText('搜索', { exact: true }).click();
await page.getByText(usernameA).click();
// 点击进入详情
await page.locator('.user_info_head .user_name', { hasText: usernameA }).last().click();
});
// 定义随机单号
const ReceiptNum = faker.helpers.fromRegExp(/1[3-9][0-9]{8}/);
const Cash = '30';
const CardAmount = '10';
const FreeAmount = '20';
const Arrears = '20';
// 选择员工A
const employee1 = Employees.FirstShop.Employee_6.name;
await test.step('开单消耗项目,选择员工,混合支付,随机单号', async () => {
await page.locator('span').filter({ hasText: '去开单' }).first().click();
await page.getByText(ProjectName.Projects.Projects_17.num).click();
// 点击添加员工
await page.locator('#buyList').getByRole('button').nth(1).click();
await page.locator('.hand_txt .name_txt').getByText(employee1).click();
// 确认
await page.getByRole('button', { name: /^确\s认$/ }).click();
// 消耗该项目1次
await page.locator('.commodity_item').last().click();
// 点击添加员工
await page.locator('.use_item .staff_btn').click();
// 选择员工A
await page.locator('.hand_txt .name_txt').getByText(employee1).click();
// 确认
await page.getByRole('button', { name: /^确\s认$/ }).click();
await page
.locator('div')
.filter({ hasText: /^结 算$/ })
.click();
// 点击修改单号
await page.locator('.input165').click();
// 输入随机单号
await page.getByPlaceholder('请输入内容').fill(ReceiptNum);
// 确认
await page.locator('.tools_icon').last().click();
//点击混合支付
await page.locator('.paytype').first().getByText('混合支付').click();
const rightPaymentInfoItem = page.locator('.right .paymentmain .paymentInfoItem');
//点击卡金
await rightPaymentInfoItem.getByText('卡金', { exact: true }).click();
//增加收款
await page.getByRole('button', { name: '增加收款' }).click();
await page.locator('.money_discount_input').fill(CardAmount);
//确认金额
await page.locator('.sure .tools_icon').click();
//点击赠金
await rightPaymentInfoItem.getByText('赠金', { exact: true }).click();
//增加收款
await page.getByRole('button', { name: '增加收款' }).click();
await page.locator('.money_discount_input').fill(FreeAmount);
//确认金额
await page.locator('.sure .tools_icon').click();
//点击现金
await rightPaymentInfoItem.getByText('现金', { exact: true }).click();
//增加收款
await page.getByRole('button', { name: '增加收款' }).click();
//输入金额
await page.locator('.money_discount_input').fill(Cash);
//确认金额
await page.locator('.sure .tools_icon').click();
//点击欠款
await rightPaymentInfoItem.getByText('欠款', { exact: true }).click();
//增加收款
await page.getByRole('button', { name: '增加收款' }).click();
await page.locator('.money_discount_input').fill(Arrears);
//确认金额
await page.locator('.sure .tools_icon').click();
//取消推送消息提醒
await page.getByLabel('推送消费提醒').uncheck();
//取消结算签字
await page.getByLabel('结算签字').uncheck();
//结算
await page.getByRole('button', { name: /^结\s算$/ }).click();
});
await test.step('进入水单详情页,查看数据', async () => {
// 进入业绩流水
await homeNavigation.gotoModule('流水');
await wasteBookBusinessRecordPage.gotoSubPage('业绩流水');
// 点击搜索水单
await expect(async () => {
await page.getByRole('button').click();
await page.locator('.searchButton .search_input .ant-input').waitFor({ timeout: 2000 });
}).toPass();
await page.locator('.searchButton .search_input .ant-input').fill(ReceiptNum);
await page.locator('.searchButton .search_input .search_btn').click();
await page.locator('.loading_container').waitFor({ state: 'hidden' });
await expect(page.locator('.m-table__fixed-left .m-dropdown-link').first()).toContainText(ReceiptNum);
// 现金业绩
const CashPerformance = KeepOnlyNumbers(
await page
.locator('.m-table__body-wrapper .main-table-body_tr')
.nth(1)
.locator('.is-right')
.first()
.innerText(),
);
const Cashs = Number(Cash) * 0.8 + '';
console.log('现金业绩' + CashPerformance);
// 划卡业绩
const CardPerformance = KeepOnlyNumbers(
await page
.locator('.m-table__body-wrapper .main-table-body_tr')
.nth(1)
.locator('.is-right')
.nth(1)
.innerText(),
);
console.log('划卡业绩' + CardPerformance);
// 划赠金业绩
const FreePerformance = KeepOnlyNumbers(
await page
.locator('.m-table__body-wrapper .main-table-body_tr')
.nth(1)
.locator('.is-right')
.nth(2)
.innerText(),
);
console.log('赠金业绩' + FreePerformance);
// 消耗业绩
const ExpendPerformance = KeepOnlyNumbers(
await page
.locator('.m-table__body-wrapper .main-table-body_tr')
.nth(0)
.locator('.is-right')
.nth(4)
.innerText(),
);
const ProjectPrice = ProjectName.Projects.Projects_17.Price; // 项目价格
const ProjectPrices = Number(ProjectPrice) * 0.8 + ''; // 会员卡打8折
console.log('消耗业绩' + ExpendPerformance);
// 消耗 员工
const ExpendEmployee = await page
.locator('.m-table__body-wrapper .main-table-body_tr')
.nth(0)
.locator('.billUser span')
.last()
.innerText();
console.log('消耗 员工' + ExpendEmployee);
// 购买 员工
const BuyEmployee = await page
.locator('.m-table__body-wrapper .main-table-body_tr')
.nth(1)
.locator('.billUser span')
.last()
.innerText();
console.log('购买 员工' + BuyEmployee);
expect(CashPerformance).toBe(Cashs); // 现金业绩
expect(CardPerformance).toBe(CardAmount); // 划卡业绩
expect(FreePerformance).toBe(FreeAmount); // 划赠金业绩
expect(ExpendPerformance).toBe(ProjectPrices); // 消耗业绩
expect(ExpendEmployee).toBe(employee1); // 消耗 员工
expect(BuyEmployee).toBe(employee1); // 购买 员工
});
});
});
test.describe('对账流水', () => {
test('根据条件搜索对账流水', async ({ page, homeNavigation, createCustomer, wasteBookBusinessRecordPage }) => {
const customer = createCustomer;
const project = { no: '100018', name: '苹果精萃护理', shortName: '精萃护理', price: '980' };
let billNo: string;
await test.step('选择顾客开单,结算使用银联、支付宝、微信、欠款、现金', async () => {
await homeNavigation.gotoModule('收银');
await page.getByRole('button', { name: /开\s单/ }).click();
await page.getByPlaceholder('姓名(拼音首字)、手机号、档案号搜索').fill(customer.phone);
await page.locator('.ant-input-suffix', { hasText: '搜索' }).click();
await page.locator('.member_list .phone', { hasText: customer.phone }).click();
await page.locator('.project_list .number', { hasText: project.no }).click();
await page.locator('.pay_btn', { hasText: /^结\s算$/ }).click();
await page.getByLabel('推送消费提醒').uncheck();
await page.getByLabel('结算签字').uncheck();
const rightPaymentInfoItem = page.locator('.right .paymentmain .paymentInfoItem');
const leftPaymentInfoItem = page.locator('.left .paymentmain .paymentInfoItem');
page.locator('.left .paymentmain .paymentInfoItem').filter({
hasText: '混合支付',
});
await leftPaymentInfoItem.filter({ hasText: '混合支付' }).click();
// 银联
await rightPaymentInfoItem.filter({ hasText: '银联' }).click();
await page.getByRole('button', { name: '增加收款' }).click();
await page.locator('.popup_content input').fill('1');
await page.locator('.number_tr').nth(2).getByRole('button').nth(3).click();
// 支付宝
await rightPaymentInfoItem.filter({ hasText: '支付宝' }).click();
await page.getByRole('button', { name: '增加收款' }).click();
await page.locator('.popup_content input').fill('1');
await page.locator('.number_tr').nth(2).getByRole('button').nth(3).click();
// 微信
await rightPaymentInfoItem.filter({ hasText: '微信' }).click();
await page.getByRole('button', { name: '增加收款' }).click();
await page.locator('.popup_content input').fill('1');
await page.locator('.number_tr').nth(2).getByRole('button').nth(3).click();
// 欠款
await rightPaymentInfoItem.filter({ hasText: '欠款' }).click();
await page.getByRole('button', { name: '增加收款' }).click();
await page.locator('.popup_content input').fill('1');
await page.locator('.number_tr').nth(2).getByRole('button').nth(3).click();
// 现金
await rightPaymentInfoItem.filter({ hasText: '现金' }).first().click();
await page.getByRole('button', { name: '增加收款' }).click();
await page.locator('.number_tr').nth(2).getByRole('button').nth(3).click();
// 等待 /bill 请求完成并获取流水单号
const [response] = await Promise.all([
page.waitForResponse(async res => {
return res.url().includes('/bill') && res.status() === 200;
}),
page.getByRole('button', { name: /结\s算/ }).click(),
]);
const responseBody = await response.json();
billNo = responseBody?.content?.billNo;
expect(billNo).not.toBeNull();
});
await test.step('根据筛选条件进行搜索水单', async () => {
await Promise.all([homeNavigation.gotoModule('流水'), page.waitForLoadState()]);
await wasteBookBusinessRecordPage.gotoSubPage('对账流水');
// 流水单
const $flowChart = page.getByRole('cell', { name: billNo, exact: true }).first();
await page.getByTitle('全部水单类型').click();
await page.getByTitle('全部记账流水').click();
await page.getByRole('option', { name: '有记账无收款流水' }).click();
await expect($flowChart).toBeVisible();
await page.getByTitle('全部水单类型').click();
await page.getByRole('option', { name: '购买项目/卖品' }).click();
await expect($flowChart).toBeVisible();
await page.getByTitle('购买项目/卖品').click();
await page.getByRole('option', { name: '开卡' }).click();
await expect($flowChart).not.toBeVisible();
await page.getByTitle('开卡').click();
await page.getByRole('option', { name: '充值' }).click();
await expect($flowChart).not.toBeVisible();
await page.getByTitle('充值').click();
await page.getByRole('option', { name: '全部水单类型' }).click();
await expect($flowChart).toBeVisible();
await page.getByTitle('全部支付方式').click();
await page.getByRole('option', { name: '现金' }).click();
await expect($flowChart).toBeVisible();
await page.getByTitle('现金').click();
await page.getByRole('option', { name: '银联' }).click();
await expect($flowChart).toBeVisible();
await page.getByTitle('银联').click();
await page.getByRole('option', { name: '微信' }).click();
await expect($flowChart).toBeVisible();
await page.getByTitle('微信').click();
await page.getByRole('option', { name: '支付宝' }).click();
await expect($flowChart).toBeVisible();
await page.reload();
await page.getByRole('button').click();
await page.getByPlaceholder('输入流水单号搜索').fill(billNo);
await page.locator('.search_btn > svg').click();
await expect($flowChart).toBeVisible();
});
});
test('对账流水只展示现金、支付宝、银联、微信', async ({ page, homeNavigation, createCustomer }) => {
const project = { no: '100018', name: '苹果精萃护理', shortName: '精萃护理', price: '980' };
const customer = createCustomer;
let billNo:string;
await test.step('选择顾客开单,结算使用银联、支付宝、微信、欠款、现金', async () => {
await homeNavigation.gotoModule('收银');
await page.getByRole('button', { name: /开\s单/ }).click();
await page.getByPlaceholder('姓名(拼音首字)、手机号、档案号搜索').fill(customer.phone);
await page.locator('.ant-input-suffix', { hasText: '搜索' }).click();
await page.locator('.member_list .phone', { hasText: customer.phone }).click();
await page.locator('.project_list .number', { hasText: project.no }).click();
await page.locator('.pay_btn', { hasText: /^结\s算$/ }).click();
await page.getByLabel('推送消费提醒').uncheck();
await page.getByLabel('结算签字').uncheck();
const rightPaymentInfoItem = page.locator('.right .paymentmain .paymentInfoItem');
const leftPaymentInfoItem = page.locator('.left .paymentmain .paymentInfoItem');
page.locator('.left .paymentmain .paymentInfoItem').filter({
hasText: '混合支付',
});
await leftPaymentInfoItem.filter({ hasText: '混合支付' }).click();
// 银联
await rightPaymentInfoItem.filter({ hasText: '银联' }).click();
await page.getByRole('button', { name: '增加收款' }).click();
await page.locator('.popup_content input').fill('1');
await page.locator('.number_tr').nth(2).getByRole('button').nth(3).click();
// 支付宝
await rightPaymentInfoItem.filter({ hasText: '支付宝' }).click();
await page.getByRole('button', { name: '增加收款' }).click();
await page.locator('.popup_content input').fill('1');
await page.locator('.number_tr').nth(2).getByRole('button').nth(3).click();
// 微信
await rightPaymentInfoItem.filter({ hasText: '微信' }).click();
await page.getByRole('button', { name: '增加收款' }).click();
await page.locator('.popup_content input').fill('1');
await page.locator('.number_tr').nth(2).getByRole('button').nth(3).click();
// 欠款
await rightPaymentInfoItem.filter({ hasText: '欠款' }).click();
await page.getByRole('button', { name: '增加收款' }).click();
await page.locator('.popup_content input').fill('1');
await page.locator('.number_tr').nth(2).getByRole('button').nth(3).click();
// 现金
await rightPaymentInfoItem.filter({ hasText: '现金' }).first().click();
await page.getByRole('button', { name: '增加收款' }).click();
await page.locator('.number_tr').nth(2).getByRole('button').nth(3).click();
// 等待 /bill 请求完成并获取流水单号
const [response] = await Promise.all([
page.waitForResponse(async res => {
return res.url().includes('/bill') && res.status() === 200;
}),
page.getByRole('button', { name: /结\s算/ }).click(),
]);
const responseBody = await response.json();
billNo = responseBody?.content?.billNo;
expect(billNo).not.toBeNull();
});
await test.step('进入流水-对账流水', async () => {
// 进入流水模块
await homeNavigation.gotoModule('流水');
await page.locator('.ant-dropdown-link', { hasText: '营业记录' }).click();
await Promise.all([
await page.getByRole('menuitem', { name: '对账流水' }).click(),
await page.waitForResponse(
response => response.url().includes('/payment_flow') && response.status() === 200,
),
]);
// 拿取现金列的列数
let index: number;
const thLocator = page.locator('.m-table__header tr').last().locator('th');
const headers = await thLocator.allInnerTexts();
index = headers.findIndex(headerText => headerText.includes('支付方式'));
if (index !== -1) {
console.log(`"支付方式" 列是第 ${index + 1}`);
} else {
throw new Error('没有找到支付方式列');
}
const paymentArray = (
await page
.locator('.main-table-body_tr ', { hasText: billNo })
.locator(`td:nth-child(${index + 1})`)
.allInnerTexts()
).map(i => i.trim());
console.log(paymentArray);
expect.soft(paymentArray).toContain('银联');
expect.soft(paymentArray).toContain('现金');
expect.soft(paymentArray).toContain('支付宝');
expect.soft(paymentArray).toContain('微信');
expect.soft(paymentArray).toContain('微信');
expect(paymentArray).not.toContain('欠款');
});
});
});
test.describe('日结单', () => {
/**
* 获取员工列的各项数据
* @param {import('@playwright/test').Page} page
* @param {number} index 员工列
* @param {{ 'name': string, 'lastPrice': number, 'price': number }[]} data 员工数据
*/
async function getColumnPrice(page, index, data) {
const columnName = ['现金', '消耗', '划卡', '客数', '客次', '拓客', '留客', '项目数', '卖品', '总耗业绩'];
for (const name of columnName) {
const price = await page
.locator('.m-table__body-wrapper tr', { hasText: name })
.locator('td')
.nth(index)
.locator('.hlknum')
.innerText();
console.log(`${name} -- ${price}`);
const item = data.find(item => item.name === name);
if (!item) {
throw new Error(`没有找到 ${name} 数据`);
}
item.lastPrice = item.price;
item.price = price.trim() === '--' ? 0 : Number(price);
}
}
test('根据条件搜索日结单', async ({ page, homeNavigation }) => {
const employee_1 = staffData.firstStore.firstSector.employee_2;
const employee_2 = staffData.firstStore.secondSector.employee_2;
const firstSectorName = staffData.firstStore.firstSector.name;
const secondSectorName = staffData.firstStore.secondSector.name;
await test.step('进入日结单模块', async () => {
await homeNavigation.gotoModule('流水');
await page.getByText('日结单').first().click();
await expect(page.getByText('查看更多汇总数据')).toBeVisible();
await expect(page.getByRole('cell', { name: employee_1.name })).toBeVisible();
await expect(page.getByRole('cell', { name: employee_2.name })).toBeVisible();
});
await test.step('切换到一部门查看员工A', async () => {
await page.locator('.shop-picker-store > .icon > svg').click();
await page.getByLabel(firstSectorName).check();
await page.getByRole('button', { name: /保\s存/ }).click();
await expect(page.getByRole('cell', { name: employee_1.name })).toBeVisible();
await expect(page.getByRole('cell', { name: employee_2.name })).not.toBeVisible();
});
await test.step('切换到二部门查看员工B', async () => {
await page.locator('.shop-picker-store > .icon > svg').click();
await page.getByLabel(secondSectorName).check();
await page.getByRole('button', { name: /保\s存/ }).click();
await expect(page.getByRole('cell', { name: employee_1.name })).not.toBeVisible();
await expect(page.getByRole('cell', { name: employee_2.name })).toBeVisible();
});
});
test('查询日结单明细', async ({ page, homeNavigation, createCustomer }) => {
// 使用的员工
const employee = staffData.firstStore.firstSector.employee_1;
const project = { no: '100018', name: '苹果精萃护理', shortName: '精萃护理', price: 980 };
// 当前员工的日结单数据初始值
const employeeData = [
{ name: '现金', price: 0, lastPrice: 0 },
{
name: '消耗',
price: 0,
lastPrice: 0,
},
{ name: '划卡', price: 0, lastPrice: 0 },
{
name: '客数',
price: 0,
lastPrice: 0,
},
{ name: '客次', price: 0, lastPrice: 0 },
{
name: '拓客',
price: 0,
lastPrice: 0,
},
{ name: '留客', price: 0, lastPrice: 0 },
{
name: '项目数',
price: 0,
lastPrice: 0,
},
{ name: '卖品', price: 0, lastPrice: 0 },
{ name: '总耗业绩', price: 0, lastPrice: 0 },
];
const customer = createCustomer;
// 拿取员工列的列数
let index;
await test.step('进入流水-日结单,获取员工数据', async () => {
await homeNavigation.gotoModule('流水');
await page.locator('.top_tab').getByText('日结单').first().click();
await page
.getByRole('row', {
name: '现金',
exact: true,
})
.locator('div')
.nth(1)
.waitFor();
const thLocator = page.locator('.m-table__header-wrapper tr').last().locator('th');
await thLocator.last().waitFor();
const headers = await thLocator.allInnerTexts();
index = headers.findIndex(headerText => {
return headerText.includes(employee.name) && headerText.includes(String(employee.id));
});
if (index !== -1) {
console.log(`"${employee.name}" 列是第 ${index + 1}`);
} else {
throw new Error(`没有找到${employee.name}, ${employee.id}`);
}
// 获取员工各个行的值
await getColumnPrice(page, index, employeeData);
});
await test.step('开单结算,选择员工', async () => {
await homeNavigation.gotoModule('收银');
await page.getByRole('button', { name: /开\s单/ }).click();
await page.getByPlaceholder('姓名(拼音首字)、手机号、档案号搜索').fill(customer.phone);
await page.locator('.ant-input-suffix', { hasText: '搜索' }).click();
await page.locator('.member_list .phone', { hasText: customer.phone }).click();
// 购买并消费项目A
await page.locator('.project_list .number', { hasText: project.no }).click();
await page.locator('#shoppingCart .commodity_list li').first().click();
// 购买项目选择员工A
await page.locator('.buy_item').first().locator('.buy_staff').getByRole('button').click();
await page
.locator('.check_row', {
hasText: employee.name,
})
.getByRole('checkbox')
.check();
await page.getByRole('button', { name: /确\s认/ }).click();
// 消耗项目选择员工A
await page.locator('.use_item').first().locator('.use_staff').getByRole('button').click();
await page
.locator('.check_row', {
hasText: employee.name,
})
.getByRole('checkbox')
.check();
await page.getByRole('button', { name: /确\s认/ }).click();
await page.locator('.pay_btn', { hasText: /^结\s算$/ }).click();
// 去使用现金结算
await page.getByLabel('推送消费提醒').uncheck();
await page.getByLabel('结算签字').uncheck();
await page.locator('.left .paymentInfoItem', { hasText: '现金' }).click();
await page.getByRole('button', { name: /结\s算/ }).click();
});
await test.step('进入流水-日结单,比较员工数据变化', async () => {
await homeNavigation.gotoModule('流水');
await page.locator('.top_tab').getByText('日结单').first().click();
await page
.getByRole('row', {
name: '现金',
exact: true,
})
.locator('div')
.nth(1)
.waitFor();
await getColumnPrice(page, index, employeeData);
// 购买0.5
const checks = [
{ name: '现金', expected: project.price * 0.5 },
{
name: '消耗',
expected: project.price * 0.6,
},
{ name: '客数', expected: 1 },
{ name: '客次', expected: 1 },
{
name: '拓客',
expected: 1,
},
{ name: '留客', expected: 0 },
{ name: '项目数', expected: 1 },
{
name: '卖品',
expected: 0,
},
{ name: '总耗业绩', expected: project.price * 0.6 },
];
checks.forEach((check, index) => {
const item = employeeData.find(i => i.name === check.name);
if (!item) {
throw new Error(`没有找到 ${check.name} 数据`);
}
if (index < checks.length - 1) {
expect.soft(parseFloat((item.price - item.lastPrice).toFixed(2))).toBe(check.expected);
} else {
expect(parseFloat((item.price - item.lastPrice).toFixed(2))).toBe(check.expected);
}
});
});
});
});