// @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 { waitSpecifyApiLoad, convertAmountText, waitStable } from '@/utils/utils.js'; import { Employees, ProjectName } from '@/common/userconfig'; import path from 'path'; import fs from 'fs'; import { HomeNavigation } from '@/pages/homeNavigationPage.js'; import { CustomerPage } from '@/pages/customer/customerPage.js'; test.describe('顾客通用', () => { test.describe('快捷查询', () => { test('精准查询', async ({ page, homeNavigation, createCustomCustomer, customerPage }) => { let historySet = new Set(); const customer = new Customer(1, 1, { archive: 'ABC' + faker.string.alpha(3), employees: [ { name: '周慧', level: '咨询师', }, ], }); await createCustomCustomer(customer); // 去创建顾客 const username = customer.username; const phone = customer.phone; const archive = customer.archive; await test.step('根据名字第一个字符进行搜索', async () => { await homeNavigation.gotoModule('顾客'); const searchStr = username.substring(0, Math.ceil(username.length / 2)); await customerPage.searchCustomer(searchStr); await page.locator('.alertBox .close').waitFor(); // 判断顾客存在 await expect(page.locator('.custom_content', { hasText: username })).toBeVisible(); // 添加到搜索历史 historySet.add(searchStr); await page.locator('.alertBox .close .anticon-close').click(); }); await test.step('根据手机号进行搜索', async () => { await customerPage.searchCustomer(phone); await page.locator('.alertBox .close').waitFor(); // 判断顾客存在 await expect(page.locator('.custom_content', { hasText: username })).toBeVisible(); // 添加到搜索历史 historySet.add(phone); await page.locator('.alertBox .close .anticon-close').click(); }); await test.step('根据档案号进行搜索', async () => { await customerPage.searchCustomer(archive); await page.locator('.alertBox .close').waitFor(); // 判断顾客存在 await expect(page.locator('.custom_content', { hasText: username })).toBeVisible(); // 添加到搜索历史 historySet.add(archive); await page.locator('.alertBox .close .anticon-close').click(); }); await test.step('查询搜索历史', async () => { await page.getByPlaceholder('姓名(拼音首字)、手机号、档案号搜索').click(); await page.locator('.historyALertBox_title', { hasText: '搜索历史' }).waitFor(); // 判断搜索历史是否存在 await expect(page.locator('.historyMemberList_item')).toContainText([...historySet].reverse()); }); }); test('顾客概要', async ({ page, homeNavigation, createCustomCustomer, customerPage, tablePage }) => { const customer = new Customer(1, 1, { archive: 'ABC' + faker.string.alpha(3), employees: [ { name: '周慧', level: '咨询师', }, ], }); await createCustomCustomer(customer); // 第一个顾客 const $firstCustomer = tablePage.fixedLeftTable.locator('tr td:nth-child(2)').locator('.name ').first(); await test.step('选择部门一,查看顾客详情', async () => { await homeNavigation.gotoModule('顾客'); await page.locator('.shop-picker-store').click(); await page.getByLabel('医美部').uncheck(); await page.getByLabel('美容部').check(); await page.getByRole('button', { name: /保\s存/ }).click(); // 点击会员 await page.locator('.sub_icon').first().click(); await page.locator('.m-table__icon__warp').waitFor({ state: 'hidden' }); // 打开顾客详情 await $firstCustomer.click(); await page.locator('.basic_box .base_info').first().waitFor(); // 判断该会员所属部门是否有美容部 await expect(page.locator('.basic_box .item_txt1', { hasText: '美容部' })).toBeVisible(); // 关闭基础资料 await customerPage.closeCustomerDetail(); await page.locator('.store_mark').click(); await page.locator('.store_mark').waitFor({ state: 'hidden' }); }); await test.step('选择员工,查看顾客详情', async () => { await page.locator('.shop-picker-store').click(); await page.getByLabel('医美部').uncheck(); await page.getByLabel('美容部').uncheck(); await page.getByLabel('周慧').check(); await page.getByRole('button', { name: /保\s存/ }).click(); // 点击潜客 await page.locator('.sub_icon').nth(3).click(); // 打开顾客详情 await $firstCustomer.click(); await expect(page.locator('.employees_txt')).toContainText('周慧'); }); }); test('顾客分配', async ({ page, homeNavigation, createCustomCustomer, customerPage, tablePage }) => { const customer = new Customer(1, 1, { archive: 'ABC' + faker.string.alpha(3), employees: [ { name: '周慧', level: '咨询师', }, ], }); await createCustomCustomer(customer); // 第一个顾客 const $firstCustomer = tablePage.fixedLeftTable.locator('tr td:nth-child(2)').locator('.name ').first(); await test.step('顾客分配', async () => { await homeNavigation.gotoModule('顾客'); await customerPage.gotoSubPage('顾客分配'); await page.locator('.assign_info').waitFor(); // 点击左上角门店 await page.locator('.shop-picker-store').click(); await page.locator('.shopSelect_title', { hasText: '选择查询对象' }).waitFor(); // 员工不可见 await expect(page.locator('.shopSelect_small_title', { hasText: '员工' })).not.toBeVisible(); // 选择美容部 await page.getByLabel('医美部').uncheck(); await page.getByLabel('美容部').check(); await page.getByRole('button', { name: /保\s存/ }).click(); // 打开顾客详情 await $firstCustomer.click(); await page.locator('.basic_box .base_info').first().waitFor(); // 判断该会员所属部门是否有美容部 await expect(page.locator('.basic_box .item_txt1', { hasText: '美容部' })).toBeVisible(); }); }); test('顾客动态', async ({ page, homeNavigation, createCustomCustomer, customerPage, tablePage }) => { const customer = new Customer(1, 1, { archive: 'ABC' + faker.string.alpha(3), employees: [ { name: '周慧', level: '咨询师', }, ], }); await createCustomCustomer(customer); // 第一个顾客 const $firstCustomer = tablePage.fixedLeftTable.locator('tr td:nth-child(2)').locator('.name ').first(); await test.step('选择部门一,查看顾客详情', async () => { await homeNavigation.gotoModule('顾客'); await customerPage.gotoSubPage('顾客动态'); await page.locator('.shop-picker-store').click(); await page.getByLabel('医美部').uncheck(); await page.getByLabel('美容部').check(); await page.getByRole('button', { name: /保\s存/ }).click(); await $firstCustomer.click(); await page.locator('.basic_box .base_info').first().waitFor(); await expect(page.locator('.basic_box .item_txt1', { hasText: '美容部' })).toBeVisible(); await page.locator('.close_icons').click(); await page.locator('.basic_box .base_info').waitFor({ state: 'hidden' }); }); await test.step('选择部门一的员工,查看顾客详情', async () => { await page.locator('.shop-picker-store').click(); await page.getByLabel('医美部').uncheck(); await page.getByLabel('美容部').uncheck(); await page.getByLabel('周慧').check(); await page.getByRole('button', { name: /保\s存/ }).click(); // 打开顾客详情 await $firstCustomer.click(); // 判断分配员工 await expect(page.locator('.employees_txt')).toContainText('周慧'); }); }); test('顾客分析', async ({ page, homeNavigation, createCustomCustomer, customerPage, tablePage }) => { const customer = new Customer(1, 1, { archive: 'ABC' + faker.string.alpha(3), employees: [ { name: '周慧', level: '咨询师', }, ], }); await createCustomCustomer(customer); // 第一个顾客 const $firstCustomer = tablePage.fixedLeftTable.locator('tr td:nth-child(2)').locator('.name ').first(); await test.step('选择部门一,查看顾客详情', async () => { await homeNavigation.gotoModule('顾客'); await customerPage.gotoSubPage('顾客分析'); await page.locator('.shop-picker-store').click(); await page.getByLabel('医美部').uncheck(); await page.getByLabel('美容部').check(); await page.getByRole('button', { name: /保\s存/ }).click(); // 打开顾客详情 await $firstCustomer.click(); await page.locator('.basic_box .base_info').first().waitFor(); await expect(page.locator('.basic_box .item_txt1', { hasText: '美容部' })).toBeVisible(); await page.locator('.close_icons').click(); await expect(page.locator('.basic_box .base_info')).not.toBeVisible(); }); await test.step('选择部门一的员工,查看顾客详情', async () => { await page.locator('.shop-picker-store').click(); await page.getByLabel('医美部').uncheck(); await page.getByLabel('美容部').uncheck(); await page.getByLabel('周慧').check(); await page.getByRole('button', { name: /保\s存/ }).click(); // 打开顾客详情 await $firstCustomer.click(); // 判断分配员工 await expect(page.locator('.employees_txt')).toContainText('周慧'); }); }); }); test.describe('高级查询', () => { const customer = new Customer(1, 1, { archive: 'ABC' + faker.string.alpha(3), employees: [ { name: '周慧', level: '咨询师', }, ], source: 5, }); /**@type {import('playwright').BrowserContext} */ let browserContext; /**@type {import('playwright').Page} */ let page; let homeNavigation; let customerPage; test.beforeAll(async ({ browser, baseURL }) => { browserContext = await browser.newContext(); page = await browserContext.newPage(); if (!baseURL) throw new Error('baseURL is required'); await page.goto(baseURL); await page.waitForLoadState('networkidle'); await page.reload(); await page.getByRole('button', { name: /开\s单/ }).waitFor(); homeNavigation = new HomeNavigation(page); customerPage = new CustomerPage(page); await homeNavigation.gotoModule('顾客'); await customerPage.createCustomer(customer); await homeNavigation.gotoModule('收银'); // 给会员开卡 await page.getByRole('button', { name: /^开\s单$/ }).click(); await customerPage.searchCustomer(customer.phone); await customerPage.selectSearchCustomer(customer.username); await page.locator('.number_service').waitFor(); await page.getByRole('button', { name: /^开\s卡$/ }).click(); // 选择会员卡A await page.locator('.memberCard_box > .needsclick').getByText('会员卡A').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(); await page.getByRole('button', { name: /跳\s过/ }).click(); await page.getByRole('button', { name: '转寄存' }).click(); await page.getByRole('button', { name: /^确\s认$/ }).click(); // 关闭收银界面 await page.locator('use').first().click(); }); test.afterAll(async () => { homeNavigation = new HomeNavigation(page); customerPage = new CustomerPage(page); await homeNavigation.gotoModule('顾客'); await customerPage.setInvalidCustomer(customer); await page.close(); await browserContext.close(); }); test('组合查询', async ({ page, homeNavigation }) => { await test.step('搜索关键字-姓', async () => { // 点击顾客 await homeNavigation.gotoModule('顾客'); await page.locator('.ant-btn-default', { hasText: /^高\s级$/ }).click(); await page.locator('.shopSelect_title', { hasText: '顾客高级查询' }).waitFor(); // 根据所属门店点击右边搜索框 await page .locator('.item_sub') .filter({ has: page.locator('.item_name', { hasText: '所属门店' }) }) .locator('.item_val') .click(); // 通过点击两次全选达到所有门店不在选中状态 await page .locator('.comPicker_btn', { hasText: /^全\s选$/ }) .first() .click(); await expect(page.locator('.ant-checkbox-wrapper-checked', { hasText: 'AT测试一店' })).toBeVisible(); await page .locator('.comPicker_btn', { hasText: /^全\s选$/ }) .first() .click(); await expect( page.locator('.ant-checkbox-wrapper-checked', { hasText: 'AT测试一店' }), ).not.toBeVisible(); // 选择门店一店 await page.locator('.label_checkbox', { hasText: 'AT测试一店' }).click(); await expect(page.locator('.ant-checkbox-wrapper-checked', { hasText: 'AT测试一店' })).toBeVisible(); await page.locator('.ant-btn-primary', { hasText: '确定选择' }).first().click(); // 搜索关键字'王' await page.getByPlaceholder('姓名(拼音首字)、手机号、档案号搜索').fill(customer.username[0]); // 选择拥有会员卡A await page .locator('.item_sub') .filter({ has: page.locator('.item_name', { hasText: '拥有的会员卡' }) }) .locator('.item_val') .click(); await page.locator('.check_box_container', { hasText: '会员卡A' }).click(); await expect(page.locator('.ant-checkbox-wrapper-checked', { hasText: '会员卡A' })).toBeVisible(); await page.locator('.ant-btn-primary', { hasText: '确定选择' }).nth(5).click(); // 点击搜索 await page.locator('.ant-btn-block').click(); await expect(page.locator('.m-table__fixed-left tbody tr', { hasText: customer.phone })).toBeVisible(); }); }); test('保存查询', async ({ page, homeNavigation }) => { await test.step('搜索关键字-姓', async () => { // 点击顾客 await homeNavigation.gotoModule('顾客'); await page.locator('.ant-btn-default', { hasText: /^高\s级$/ }).click(); await page.locator('.shopSelect_title', { hasText: '顾客高级查询' }).waitFor(); // 点击两次全选确保所有门店默认未选 await page .locator('.item_sub') .filter({ has: page.locator('.item_name', { hasText: '所属门店' }) }) .locator('.item_val') .click(); await page .locator('.comPicker_btn', { hasText: /^全\s选$/ }) .first() .click(); // 判断某个门店被选中 await expect(page.locator('.ant-checkbox-wrapper-checked', { hasText: 'AT测试一店' })).toBeVisible(); await page .locator('.comPicker_btn', { hasText: /^全\s选$/ }) .first() .click(); // 判断门店未被选中 await expect( page.locator('.ant-checkbox-wrapper-checked', { hasText: 'AT测试一店' }), ).not.toBeVisible(); await page.locator('.label_checkbox', { hasText: 'AT测试一店' }).click(); // 确认选中一店 await expect(page.locator('.ant-checkbox-wrapper-checked', { hasText: 'AT测试一店' })).toBeVisible(); await page.locator('.ant-btn-primary', { hasText: '确定选择' }).first().click(); // 搜索关键字 王 await page.getByPlaceholder('姓名(拼音首字)、手机号、档案号搜索').fill(customer.username[0]); await page .locator('.item_sub') .filter({ has: page.locator('.item_name', { hasText: '拥有的会员卡' }) }) .locator('.item_val') .click(); await page.locator('.check_box_container', { hasText: '会员卡A' }).click(); // 拥有会员卡A await expect(page.locator('.ant-checkbox-wrapper-checked', { hasText: '会员卡A' })).toBeVisible(); await page.locator('.ant-btn-primary', { hasText: '确定选择' }).nth(5).click(); // 点击搜索 await page.locator('.ant-btn-block').click(); await expect(page.locator('.m-table__fixed-left tbody tr', { hasText: customer.phone })).toBeVisible(); }); await test.step('保存查询', async () => { const identificationA = faker.person.fullName(); const identificationB = faker.person.fullName(); await page.locator('.item-btns', { hasText: '保存查询' }).waitFor(); await page.locator('.item-btns', { hasText: '保存查询' }).click(); await page.locator('.modal_header').waitFor(); await page.getByPlaceholder('请输入名称').fill(identificationA); await expect(async () => { await page.locator('.ant-btn-primary').last().click(); await expect(page.locator('.ant-modal-content')).not.toBeVisible({ timeout: 5000, }); }).toPass(); // 操作成功 await expect(page.locator('.ant-message', { hasText: '操作成功' })).toBeVisible(); await page.locator('.item-btns', { hasText: '保存查询' }).waitFor(); await page.locator('.item-btns', { hasText: '保存查询' }).click(); await page.locator('.modal_header').waitFor(); await page.getByPlaceholder('请输入名称').fill(identificationB); await page.locator('.search_tip').click(); await expect(async () => { await page.locator('.ant-btn-primary').last().click(); await expect(page.locator('.ant-modal-content')).not.toBeVisible({ timeout: 5000, }); }).toPass(); // 操作成功 await expect(page.locator('.ant-message', { hasText: '操作成功' })).toBeVisible(); // 点击高级搜索旁边三个点 await page.locator('.ant-btn-default .anticon').click(); await page.locator('.ant-tabs-tab').first().waitFor(); await page.locator('.ant-tabs-tab', { hasText: '保存的搜索器' }).click(); await page.locator('.tools_items .item').first().waitFor(); await page.locator('.tools_items .item', { hasText: identificationA }).click(); // 判断点击该搜索器是否能搜到该会员 await expect(page.locator('.m-table__fixed-left tbody tr', { hasText: customer.phone })).toBeVisible(); // 点击高级搜索旁边三个点 await page.locator('.ant-btn-default .anticon').click(); await page.locator('.tools_items .item').first().waitFor(); // 判断该搜索器有没有手机标识 const phoneLogo = page .locator('.tools_items .item') .filter({ has: page.locator('.tool_name', { hasText: identificationB }) }) .locator('.item_icon'); await expect(phoneLogo).toBeVisible(); }); await test.step('删除保存的搜索器', async () => { // 点击高级搜索旁边三个点 上一步停留在了这里面不需要点 await page.locator('.ant-tabs-tab', { hasText: '保存的搜索器' }).click(); await page.locator('.tools_items .item').first().waitFor(); // 点击右上角设置齿轮 await page.locator('.edit_btn').click(); // 等待保存搜索的右上角叉叉按钮出现 await page.locator('.del_btn').first().click(); // 点击完成 await page.locator('.btn_ok').click(); // 操作成功 await expect(page.locator('.ant-message', { hasText: '操作成功' })).toBeVisible(); }); }); test('使用历史查询', async ({ page, homeNavigation, createCustomCustomer, customerPage }) => { await test.step('搜索关键字-姓', async () => { // 点击顾客 await homeNavigation.gotoModule('顾客'); await page.locator('.ant-btn-default', { hasText: /^高\s级$/ }).click(); await page.locator('.shopSelect_title', { hasText: '顾客高级查询' }).waitFor(); // 点击两次全选确保所有门店默认未选 await page .locator('.item_sub') .filter({ has: page.locator('.item_name', { hasText: '所属门店' }) }) .locator('.item_val') .click(); await page .locator('.comPicker_btn', { hasText: /^全\s选$/ }) .first() .click(); // 判断某个门店被选中 await expect(page.locator('.ant-checkbox-wrapper-checked', { hasText: 'AT测试一店' })).toBeVisible(); await page .locator('.comPicker_btn', { hasText: /^全\s选$/ }) .first() .click(); // 判断门店未被选中 await expect( page.locator('.ant-checkbox-wrapper-checked', { hasText: 'AT测试一店' }), ).not.toBeVisible(); await page.locator('.label_checkbox', { hasText: 'AT测试一店' }).click(); // 确认选中一店 await expect(page.locator('.ant-checkbox-wrapper-checked', { hasText: 'AT测试一店' })).toBeVisible(); await page.locator('.ant-btn-primary', { hasText: '确定选择' }).first().click(); // 搜索关键字 A await page.getByPlaceholder('姓名(拼音首字)、手机号、档案号搜索').fill(customer.username[0]); // 拥有会员卡A await page .locator('.item_sub') .filter({ has: page.locator('.item_name', { hasText: '拥有的会员卡' }) }) .locator('.item_val') .click(); await page.locator('.check_box_container', { hasText: '会员卡A' }).click(); await expect(page.locator('.ant-checkbox-wrapper-checked', { hasText: '会员卡A' })).toBeVisible(); await page.locator('.ant-btn-primary', { hasText: '确定选择' }).nth(5).click(); // 点击搜索 await page.locator('.ant-btn-block').click(); await expect(page.locator('.m-table__fixed-left tbody tr', { hasText: customer.phone })).toBeVisible(); }); await test.step('历史查询', async () => { // 点击高级搜索旁边三个点 await page.locator('.ant-btn-default .anticon').click(); await page.locator('.ant-tabs-tab').first().waitFor(); await page.locator('.ant-tabs-tab', { hasText: '历史搜索' }).click(); await page.locator('.ant-tabs-tab-active', { hasText: '历史搜索' }).first().waitFor(); const $history = page .locator('.search_list_ul .text', { hasText: `门店:AT测试一店;关键字${customer.username[0]};` }) .first(); await $history.click(); // 判断点击该搜索器是否能搜到该会员 await expect(page.locator('.m-table__fixed-left tbody tr', { hasText: customer.phone })).toBeVisible(); }); }); test('快捷搜索', async ({ page, homeNavigation }) => { // 进入顾客列表 await homeNavigation.gotoModule('顾客'); // 点击高级搜索旁边三个点 await page.locator('.ant-btn-default .anticon').click(); await page.locator('.ant-tabs-tab').first().waitFor(); await page.locator('.ant-tabs-tab', { hasText: '快捷搜索' }).click(); await page.locator('.ant-tabs-tab-active', { hasText: '快捷搜索' }).first().waitFor(); await page .locator('.class_tag') .first() .locator('.class_list', { hasText: /^会员$/ }) .click(); await expect(page.locator('.selected', { hasText: /^会员$/ }).first()).toBeVisible(); await page .locator('.ant-btn-lg', { hasText: /^搜\s索$/ }) .last() .click(); // 判断是否有会员标识 const identification = page .locator('.m-table__fixed-left .m-table__body tbody tr') .first() .locator('td .icon_style', { hasText: '会' }); await expect(identification).toBeVisible(); }); }); test('顾客分页', async ({ page, homeNavigation }) => { // 进入顾客界面 await homeNavigation.gotoModule('顾客'); // 点击潜客 await page.locator('.sub_icon').nth(3).click(); // 获取第一页会员信息 await page.locator('.m-table-pagination .dec').waitFor(); const member = page.locator('.m-table__fixed-left tbody tr'); const pagePhone1 = await member.locator('td .user_info_body').first().innerText(); // 点击第下一页 await page.locator('.ant-pagination-next').click(); // 获取第二页会员信息 await page.locator('.m-table-pagination .dec').waitFor(); const pagePhone2 = await member.locator('td .user_info_body').first().innerText(); // 点击第下一页 await page.locator('.ant-pagination-next').click(); // 获取第三页会员信息 await page.locator('.m-table-pagination .dec').waitFor(); const pagePhone3 = await member.locator('td .user_info_body').first().innerText(); expect(pagePhone1).not.toBe(pagePhone2); expect(pagePhone1).not.toBe(pagePhone3); expect(pagePhone2).not.toBe(pagePhone3); }); }); test.describe('顾客动态', () => { test('新增事项', async ({ page, homeNavigation, createCustomer, customerPage }) => { const customer = createCustomer; const today = new Date().getDate(); // 获取今日的天数 const customerTr = page.locator('.m-table__body-wrapper tbody tr', { hasText: customer.phone, }); const customerTd = customerTr.locator('td .cell'); await test.step('搜索顾客存在', async () => { // 进入顾客页面 await homeNavigation.gotoModule('顾客'); // 跳转到顾客动态 await customerPage.gotoSubPage('顾客动态'); await customerPage.searchCustomer(customer.phone); await customerPage.selectSearchCustomer(customer.username); await expect(page.locator('.m-table__fixed-left').getByText(customer.username)).toBeVisible(); }); await test.step('切换时间为上月,新增事项', async () => { await page.locator('.ant_date').getByPlaceholder('开始日期').click(); await page.getByRole('button', { name: /^上\s月$/ }).click(); // 选择上月第一天 await customerTd.first().click(); // 过去时间不可新增事项! await expect(page.locator('.ant-message', { hasText: '过去时间不可新增事项!' })).toBeVisible(); }); await test.step('切换时间为本月,新增事项', async () => { await page.locator('.ant_date').getByPlaceholder('开始日期').click(); await page.getByRole('button', { name: /^本\s月$/ }).click(); // 选择本月第today天(当天) await customerTd.nth(today - 1).click(); await page.locator('.action .shopSelect_title', { hasText: '新增事项' }).waitFor(); await page.locator('label', { hasText: '电话回访' }).click(); await page.getByPlaceholder('请输入1-100个字符的备注内容').fill('今日新增待办事项'); await page.getByRole('button', { name: '确认添加' }).click(); await expect(customerTd.nth(today - 1).locator('.cell-warp—td')).toBeVisible(); await expect(page.locator('.ant-message', { hasText: '操作成功' })).toBeVisible(); }); await test.step('查看今日事项,删除事项', async () => { // 打开今日事项 await customerTd.nth(today - 1).click(); await expect(page.locator('.remark_area span')).toContainText('今日新增待办事项'); await expect( page .locator('.item') .filter({ has: page.locator('.name', { hasText: '事项状态' }) }) .locator('.status'), ).toContainText('已完成'); // 删除事项 await page.locator('.action').getByRole('button', { name: '删除' }).click(); await page .locator('.popup_content') .getByRole('button', { name: /^确\s认$/ }) .click(); await expect(customerTd.nth(today - 1).locator('.cell-warp—td')).not.toBeVisible(); await expect(page.locator('.ant-message', { hasText: '操作成功' })).toBeVisible(); await customerTd.nth(today - 1).click(); await expect(page.locator('.action .shopSelect_title')).toContainText('新增事项'); // 关闭弹窗 await page.locator('.action > div > div > .shopSelect_box > .shopSelect_heard > .close > svg').click(); }); await test.step('新增明日事项,查看事项', async () => { // 选择本月第today天的明天(明天) await customerTd.nth(today).click(); await page.locator('.action .shopSelect_title', { hasText: '新增事项' }).waitFor(); await page.locator('label', { hasText: '电话回访' }).click(); await page.getByPlaceholder('请输入1-100个字符的备注内容').fill('新增明日待办事项'); await page.getByRole('button', { name: '确认添加' }).click(); await expect(customerTd.nth(today).locator('.cell-warp—td')).toBeVisible(); await expect(page.locator('.ant-message', { hasText: '操作成功' })).toBeVisible(); // 打开明日事项 await customerTd.nth(today).click(); await page.locator('.action .shopSelect_title', { hasText: '电话回访' }).waitFor(); await expect(page.locator('.remark_area span')).toContainText('新增明日待办事项'); await expect( page .locator('.item') .filter({ has: page.locator('.name', { hasText: '事项状态' }) }) .locator('.status'), ).toContainText('待完成'); }); }); test('完成事项', async ({ page, homeNavigation, createCustomer }) => { const customer = createCustomer; // 事项状态 let statusText; // 当前顾客处于第几行,默认第一行 let nowRow = 0; // 获取当前月份 const nowMonth = new Date().getMonth(); // 获取今日的天数 const today = new Date().getDate(); // 进入顾客动态 await homeNavigation.gotoModule('顾客'); await page.locator('.top_tab').getByText('顾客动态').click(); await page.getByText('图标注释').waitFor(); // 根据手机号进行搜索 await page.getByPlaceholder('姓名(拼音首字)、手机号、档案号搜索').fill(customer.phone); await page.locator('.ant-input-suffix .search_btn').getByText('搜索', { exact: true }).click(); await page.locator('.alertBox .close').waitFor(); await page.locator('.custom_content', { hasText: customer.username }).click(); // 设置生日 await page.locator('.m-table__fixed-left').getByText(customer.username).click(); await page.locator('.person_info .user_name .edit_icon').click(); await page.locator('.birth_content', { hasText: '日期' }).click(); // 选择日 await page .getByRole('listbox') .first() .getByRole('option') .nth(today - 1) .click(); // 选择月 await page.getByRole('listbox').last().getByRole('option').nth(nowMonth).click(); await page.getByRole('button', { name: /^确\s认$/ }).click(); await page.getByRole('button', { name: /^保\s存$/ }).click(); await expect(page.locator('.ant-message', { hasText: '修改成功' })).toBeVisible(); await page.locator('.close_icons svg').click(); // 切换时间为本月 await page.locator('.ant_date').getByPlaceholder('开始日期').click(); await page.getByRole('button', { name: /^本\s月$/ }).click(); // 选择本月第today天(当天) const allTr = page.locator('.m-table__body-wrapper tbody tr'); await allTr .nth(nowRow) .locator('td .cell') .nth(today - 1) .click(); await page.getByRole('button', { name: '完成该事项' }).click(); await page.getByPlaceholder('这里显示的回访完成后的反馈内容').fill('测试完成该事项'); await page.getByRole('button', { name: /^提\s交$/ }).click(); await expect(page.locator('.ant-message', { hasText: '操作成功' })).toBeVisible(); const $statusText = page .locator('.item') .filter({ has: page.locator('.name', { hasText: '事项状态' }) }) .locator('.status'); await expect($statusText).toContainText('已完成'); }); test('排序', async ({ page, homeNavigation, customerPage }) => { const customerTrList = page.locator('.m-table-fixed-body tbody > tr'); const consumeTotalList = page.locator('.consume_total'); const amountTotalLocator = consumeTotalList.locator('.total_').filter({ hasText: '现金总额' }); const lastTimeArrivalLocator = consumeTotalList.locator('.consume_list').filter({ hasText: '上次到店' }); const closeMemberBoxLocator = page.locator('.close_icons'); const sortToolLocator = page.locator('.table_tools').getByText('排序'); let amountTotal, previousAmountTotal; let lastTimeArrival, previousLastTimeArrival; let tmp; await test.step('上次到店时间', async () => { await homeNavigation.gotoModule('顾客'); await customerPage.gotoSubPage('顾客动态'); await sortToolLocator.click(); await page.getByRole('menuitem', { name: '上次到店时间从远到近' }).click(); await customerTrList.nth(0).waitFor(); await customerTrList.nth(0).locator('.name').click(); tmp = await lastTimeArrivalLocator.locator('.detail_txt').innerText(); lastTimeArrival = tmp.includes('--') ? 0 : Number(tmp); previousLastTimeArrival = lastTimeArrival; await closeMemberBoxLocator.click(); await sortToolLocator.click(); await page.getByRole('menuitem', { name: '上次到店时间从近到远' }).click(); await customerTrList.nth(0).waitFor(); await customerTrList.nth(0).locator('.name').click(); tmp = await lastTimeArrivalLocator.locator('.detail_txt').innerText(); lastTimeArrival = tmp.includes('--') ? 0 : Number(tmp); previousLastTimeArrival = lastTimeArrival; await closeMemberBoxLocator.click(); expect(lastTimeArrival).toBeGreaterThanOrEqual(previousLastTimeArrival); }); await test.step('现金总额', async () => { await sortToolLocator.click(); await page.getByRole('menuitem', { name: '现金总额从多到少' }).click(); await customerTrList.nth(0).waitFor(); await customerTrList.nth(0).locator('.name').click(); tmp = await amountTotalLocator.locator('.total_num').innerText(); amountTotal = Number(tmp); previousAmountTotal = amountTotal; await closeMemberBoxLocator.click(); await sortToolLocator.click(); await page.getByRole('menuitem', { name: '现金总额从多到少' }).click(); await customerTrList.nth(0).waitFor(); await customerTrList.nth(0).locator('.name').click(); tmp = await amountTotalLocator.locator('.total_num').innerText(); amountTotal = Number(tmp); previousAmountTotal = amountTotal; await closeMemberBoxLocator.click(); expect(amountTotal).toBeLessThanOrEqual(previousAmountTotal); }); }); }); test.describe('顾客详情', () => { test('修改顾客资料(标签、档案、到店周期、备注)', async ({ page, homeNavigation, customerPage, createCustomer, }) => { const customer = createCustomer; const infoBox = page.locator('.info_box'); await test.step('设置顾客标签', async () => { await homeNavigation.gotoModule('顾客'); await customerPage.searchCustomer(customer.phone); await customerPage.selectSearchCustomer(customer.username); await customerPage.openCustomerDetail(customer.username, customer.phone); const noSignLocator = infoBox.getByText('暂未添加标签'); await expect(noSignLocator).toBeVisible(); await infoBox.locator('.sign i').click(); await expect(page.getByRole('button', { name: '移除所有选中' })).toBeVisible(); const signSelectLocator = page.getByRole('treeitem', { name: '顾客六期管理' }); await signSelectLocator.getByText('问题期').click(); await signSelectLocator.getByText('铺垫期').click(); await page.getByRole('button', { name: /确\s认/ }).click(); await expect(page.locator('.ant-message', { hasText: '修改成功' })).toBeVisible(); await expect(noSignLocator).not.toBeVisible(); await expect(page.locator('.sign_txt')).toContainText(['问题期', '铺垫期']); }); await test.step('设置档案', async () => { const infoBox = page.locator('.info_box'); const popupLocator = page.locator('.popup_content'); const titlePopup = popupLocator.locator('.title_box'); const rightPopup = popupLocator.locator('.right_item_box'); const archiveContent = faker.string.fromCharacters('编辑档案', 8); const editArchive = page.locator('.box', { hasText: '编辑顾客档案' }); const archivesLocator = infoBox.getByText('档案完成度'); await expect(archivesLocator).toBeVisible(); await infoBox.locator('.file_box .edit_icon').click(); await expect(titlePopup.getByText('定制顾客档案', { exact: true })).toBeVisible(); await rightPopup.locator('.edit_icon').click(); await editArchive .locator('.item', { hasText: '基本描述信息' }) .getByPlaceholder('请输入1-500个字符备注内容') .fill(archiveContent); await editArchive.getByRole('button', { name: /保\s存/ }).click(); await expect(page.locator('.ant-message', { hasText: '操作成功' })).toBeVisible(); // 打开档案编辑页面 await expect(archivesLocator).toBeVisible(); await infoBox.locator('.file_box .edit_icon').click(); await expect(rightPopup).toContainText(archiveContent); await page.locator('.title > .close_icon > svg > use').click(); }); await test.step('修改到店周期', async () => { const storeCycleDay = '0'; // 到店周期实际值 const expectStoreCycleDay = '3'; // 到店周期期望值 const consumeList = infoBox.locator('.consume_list'); const storeCycle = consumeList.filter({ has: page.getByText('到店周期', { exact: true }), }); await storeCycle.waitFor(); const storeCycleText = storeCycle.locator('.detail_txt'); await expect(storeCycleText).toHaveText('0'); await storeCycle.locator('.edit_icon').click(); await page.getByPlaceholder('请输入天数').fill(expectStoreCycleDay); await page.locator('.number_box').getByRole('button').nth(11).click(); await expect(page.locator('.ant-message', { hasText: '修改成功' })).toBeVisible(); // 原来的值消失 await expect(storeCycleText.filter({ hasText: storeCycleDay })).not.toBeVisible(); // 更改为期望值显示 await expect(storeCycleText.filter({ hasText: expectStoreCycleDay })).toBeVisible(); }); await test.step('修改备注', async () => { const popupLocator = page.locator('.popup_content'); const remark = faker.string.fromCharacters('修改备注', 8); const baseInfo = page.locator('.base_info .base_info_list'); const remarkLocator = baseInfo.filter({ has: page.getByText('备注', { exact: true }) }); await expect(async () => { await remarkLocator.locator('.edit_icon').click(); await popupLocator.getByPlaceholder('请输入1-100个字符备注内容').fill(remark); await page.getByRole('button', { name: /保\s存/ }).click(); await expect(page.locator('.ant-message', { hasText: '修改成功' })).toBeVisible(); await expect(remarkLocator).toContainText(remark, { timeout: 3_000 }); }).toPass(); }); }); test('在顾客详情页面开卡', async ({ page, homeNavigation, customerPage, createCustomer }) => { const customer = createCustomer; const card = page.locator('.has_card .membercard_box', { hasText: '原价卡' }); 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('.info_package') .getByRole('button', { name: /开\s卡/ }) .click(); await page.locator('.openCard_box', { hasText: '会员卡购买' }).waitFor(); await page.locator('.openCard_box .memberCard_box', { hasText: '原价卡' }).click(); await page.locator('.remark', { hasText: '可输入卡备注' }).click(); await page.getByPlaceholder('请输入1-100个字符备注内容').fill('测试顾客详情页面开卡'); await page.getByRole('button', { name: /确\s认/ }).click(); await page.getByRole('button', { name: '去结算' }).click(); await page.getByLabel('推送消费提醒').uncheck(); await page.getByLabel('结算签字').uncheck(); await page.locator('.paytype .paymentInfoItem', { hasText: '现金' }).click(); await page.getByRole('button', { name: /结\s算/ }).click(); await page.locator('.popup_content', { hasText: '会员协议签署确认' }).waitFor(); await page.getByRole('button', { name: /跳\s过/ }).click(); // 判断会员卡存在 await expect(card.locator('.other_row .comment_item')).toHaveText('测试顾客详情页面开卡'); }); }); test('操作会员卡', async ({ page, homeNavigation, customerPage, createCustomer }) => { const cardInfo = { name: '原价卡', gold: 5000, bonus: 3000 }; const card = page.locator('.has_card .membercard_box', { hasText: cardInfo.name }); const customer = createCustomer; await test.step('开卡', async () => { await homeNavigation.gotoModule('收银'); await page.getByRole('button', { name: /开\s单/ }).click(); await customerPage.searchCustomer(customer.phone); await customerPage.selectSearchCustomer(customer.username); await page.getByRole('button', { name: /开\s卡/ }).click(); // 会员卡定位器 const $card = page.locator('.openCard_box .memberCard_box', { hasText: cardInfo.name }); await $card.click(); // 判断卡金、赠金符合预期值 await expect($card.locator('.balance.needsclick')).toContainText(`${cardInfo.gold}`); await expect($card.locator('.bonus.needsclick')).toContainText(`${cardInfo.bonus}`); // 备注会员卡,进行结算 await page.locator('.remark', { hasText: '可输入卡备注' }).click(); await page.getByPlaceholder('请输入1-100个字符备注内容').fill('测试操作会员卡'); await page.getByRole('button', { name: /确\s认/ }).click(); await page.getByRole('button', { name: '去结算' }).click(); await page.getByLabel('推送消费提醒').uncheck(); await page.getByLabel('结算签字').uncheck(); await page.locator('.paytype .paymentInfoItem', { hasText: '现金' }).click(); await page.getByRole('button', { name: /结\s算/ }).click(); await page.getByRole('button', { name: /跳\s过/ }).click(); await expect(page.locator('.ant-message', { hasText: '结算成功' })).toBeVisible(); // 返回首页 await page.locator('.anticon > svg').first().click(); // 进入顾客详情页面,判断会员卡存在 await homeNavigation.gotoModule('顾客'); await customerPage.searchCustomer(customer.phone); await customerPage.selectSearchCustomer(customer.username); await customerPage.openCustomerDetail(customer.username, customer.phone); // 判断会员卡存在 await expect(card.locator('.other_row .comment_item')).toHaveText('测试操作会员卡'); }); const modifiedCardGold = cardInfo.gold + 1000; await test.step('修改卡金', async () => { await page.locator('.card_control_btn .more').click(); await page.getByRole('menuitem', { name: '修改卡金' }).click(); await page.getByPlaceholder('请输入内容@.').fill(`${modifiedCardGold}`); // 点击确认按钮 await page.locator('.number_tr').nth(2).getByRole('button').nth(3).click(); await page.getByPlaceholder('请输入1-100个字符备注内容').fill('测试修改卡金'); await page.getByRole('button', { name: /确\s认/ }).click(); await expect(page.locator('.ant-message', { hasText: '操作成功' })).toBeVisible(); await expect(card.locator('.balances')).toContainText(`${modifiedCardGold}`); }); const modifiedCardBonus = cardInfo.bonus + 1000; await test.step('修改赠送金', async () => { await page.locator('.card_control_btn .more').click(); await page.getByRole('menuitem', { name: '修改赠送金' }).click(); await page.getByPlaceholder('请输入内容@.').fill(`${modifiedCardBonus}`); // 点击确认按钮 await page.locator('.number_tr').nth(2).getByRole('button').nth(3).click(); await page.getByPlaceholder('请输入1-100个字符备注内容').fill('测试修改赠金'); await page.getByRole('button', { name: /确\s认/ }).click(); await expect(card.locator('.bonuses')).toContainText(`${modifiedCardBonus}`); }); // 随机卡号card**** const modifiedCardNo = faker.helpers.fromRegExp(/card[0-9]{4}/); await test.step('修改卡号', async () => { await page.locator('.card_control_btn .more').click(); await page.getByRole('menuitem', { name: '修改卡号' }).click(); await page.getByPlaceholder('请输入新卡号').fill(modifiedCardNo); await page.getByRole('button', { name: /确\s认/ }).click(); // 判断卡号修改成功 await expect(card.locator('.number_row .numebr')).toContainText(modifiedCardNo); }); await test.step('修改有效期,会员卡左上角展示有效期提示“剩1天过期”', async () => { await page.locator('.card_control_btn .more').click(); await page.getByRole('menuitem', { name: '修改有效期' }).click(); await page.getByPlaceholder('选择日期').click(); await page .locator('span') .filter({ hasText: /^今天$/ }) .click(); await page.getByRole('button', { name: /确\s认/ }).click(); // 剩1天过期 await expect(card.locator('.expireDay_box')).toContainText('剩1天'); }); await test.step('删除会员卡', async () => { await page.locator('.card_control_btn .more').click(); await page.getByRole('menuitem', { name: '删除卡' }).click(); await page.getByRole('button', { name: /确\s认/ }).click(); await page.getByPlaceholder('请输入1-100个字符备注内容').fill('测试删除会员卡'); await page.getByRole('button', { name: /确\s认/ }).click(); await expect(card).not.toBeVisible(); await page.getByText('未使用').click(); await page.locator('.ant-select-dropdown').getByRole('option', { name: '已删除' }).click(); await expect(card.locator('.card_name .overTime_tag').last()).toContainText('已删'); }); }); test('操作套餐', async ({ page, homeNavigation, customerPage, createCustomer }) => { let billNo: string; const date = new Date(); const currentYear = date.getFullYear(); const currentMonth = date.getMonth() + 1; const currentDay = date.getDate(); const dayStr = currentDay >= 10 ? `${currentDay}` : `0${currentDay}`; // 套餐的名称 const $setMeal = page.getByText('护理修护全套'); // 套餐的所有项目 const $$treatCard = page.locator('.treat_card').filter({ has: $setMeal }); const customer = createCustomer; await test.step('开单买[护理修护全套]', async () => { await homeNavigation.gotoModule('收银'); await page.getByRole('button', { name: /开\s单/ }).click(); await page.getByPlaceholder('姓名(拼音首字)、手机号、档案号搜索').fill(customer.phone); await page.getByText('搜索', { exact: true }).click(); await page.locator('.member_list_li').filter({ hasText: customer.phone }).click(); await page.getByText('套餐').click(); await page.getByText('护理修护全套').last().click(); await page.getByText(/结\s算/).click(); await page.locator('.paymentInfoItem').first().click(); await page.getByLabel('推送消费提醒').uncheck(); await page.getByLabel('结算签字').uncheck(); await page.locator('.paytype .paymentInfoItem', { hasText: '现金' }).click(); await page.getByRole('button', { name: /结\s算/ }).click(); await page.locator('.popup_content', { hasText: '会员协议签署确认' }).waitFor(); // 结算 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(); await page.getByRole('button', { name: '不寄存' }).click(); }); 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 test.step('查看套餐消耗记录', async () => { await page.locator('label').filter({ hasText: '套餐' }).click(); await expect($setMeal).toBeVisible(); await $$treatCard.first().locator('svg').last().click(); await page.getByText('消耗记录').click(); await expect(page.getByText(billNo).last()).toBeVisible(); await page .locator('div') .filter({ hasText: /^消耗记录$/ }) .locator('use') .click(); }); await test.step('冻结有效期-解冻有效期', async () => { // 冻结日期 const freezeStr = `${currentYear}-${currentMonth}-${dayStr}冻结`; // 冻结有效期 await $$treatCard.first().locator('svg').last().click(); await page.getByText('冻结有效期').click(); await Promise.all([page.getByRole('button', { name: /确\s认/ }).click(), page.waitForLoadState()]); await expect(page.locator('.ant-message')).toContainText('修改成功'); await expect($$treatCard.first().locator('.deadline_row span')).toContainText(freezeStr); // 解冻有效期 await expect(async () => { await $$treatCard.first().locator('svg').last().click(); await page.getByText('解冻有效期').click({ timeout: 2000 }); await expect($$treatCard.first().locator('.deadline_row span')).not.toContainText(freezeStr, { timeout: 2000, }); }).toPass(); }); }); test('查看流水', async ({ page, homeNavigation, createCustomer, customerPage, numberInput }) => { const remark = '测试查看流水' + faker.string.numeric(3); // 当前备注 const project = { no: '100018', name: '苹果精萃护理', shortName: '精萃护理', price: 980 }; const goods = { no: 'aa100001', name: '家居搭配护理套', shortName: '', price: 3980 }; const cardInfo = { name: '原价卡', gold: 5000, bonus: 3000 }; // 预期的支付明细 const paymentDetail = [ { method: '卡金', amount: 1000 }, { method: '赠金', amount: 1000 }, { method: '积分', amount: 1000 }, { method: '欠款', amount: 1000 }, { method: '优惠券', amount: 10 }, { method: '现金', amount: 950 }, ]; 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.getByRole('button', { name: /开\s卡/ }).click(); // 会员卡定位器 const $card = page.locator('.openCard_box .memberCard_box', { hasText: cardInfo.name }); await $card.click(); // 判断卡金、赠金符合预期值 await expect($card.locator('.balance.needsclick')).toContainText(`${cardInfo.gold}`); await expect($card.locator('.bonus.needsclick')).toContainText(`${cardInfo.bonus}`); await page.getByRole('button', { name: '去结算' }).click(); await page.getByLabel('推送消费提醒').uncheck(); await page.getByLabel('结算签字').uncheck(); await page.locator('.paytype .paymentInfoItem', { hasText: '现金' }).click(); await page.getByRole('button', { name: /结\s算/ }).click(); await page.getByRole('button', { name: /跳\s过/ }).click(); // 判断会员卡存在 const card = page.locator('.has_card .membercard_box', { hasText: cardInfo.name }); await expect(card).toBeVisible(); }); await test.step('赠送1000积分,1积分兑换1元', async () => { await page.getByRole('tab', { name: '流水' }).click(); await page.locator('.label_text', { hasText: '积分记录' }).click(); await page.getByRole('button', { name: /^赠\s送$/ }).click(); const point = paymentDetail.find(e => e.method === '积分')?.amount ?? 0; await numberInput.setPointValue(point); await numberInput.confirmValue(); await page.locator('.popup_content', { hasText: '赠送积分备注' }).waitFor(); await page.getByPlaceholder('请输入1-100个字符备注内容').fill(remark); await page.locator('.popup_content input[type=radio]').click(); await page.getByRole('button', { name: /确\s认/ }).click(); }); let billNo: string; await test.step('购买项目并消耗,购买卖品并结算,结算使用优惠券、卡金、赠金、欠款、积分,拿取单号', async () => { // 左右两侧的支付方式定位器 const rightPaymentInfoItem = page.locator('.right .paymentmain .paymentInfoItem'); const leftPaymentInfoItem = page.locator('.left .paymentmain .paymentInfoItem'); await page.locator('.right_util .goto_pay_cash', { hasText: '去开单' }).click(); // 购买项目并消耗,价格980 await page.locator('.project_list .number', { hasText: project.no }).click(); await page.locator('#shoppingCart .commodity_list li').first().click(); // 购买卖品并结算,价格3980 await page.locator('.float_tab .item', { hasText: '卖品' }).click(); await page.locator('.project_list .number', { hasText: goods.no }).click(); await page.locator('.pay_btn', { hasText: /结\s算/ }).click(); // 赠送优惠券,价格10 await page.locator('.payMain .left .body .row', { hasText: '优惠券抵扣' }).click(); await page.getByRole('button', { name: '赠送优惠券' }).click(); await page.locator('.popup_content', { hasText: '选择优惠券' }).waitFor(); await page .locator('.popup_content .list .item', { hasText: '定额10元券' }) .locator('input[type="checkbox"]') .click(); await page .locator('.popup_content') .getByRole('button', { name: /^确\s定$/ }) .click(); // 使用优惠券 await page.locator('.m_sliding_menu .body .box').first().locator('input[type="checkbox"]').check(); await page.getByRole('button', { name: '确认选择' }).click(); await leftPaymentInfoItem.filter({ hasText: '混合支付' }).click(); await rightPaymentInfoItem.filter({ hasText: '卡金' }).click(); await page.getByRole('button', { name: '增加收款' }).click(); await numberInput.setCommonValue(paymentDetail.find(e => e.method === '卡金')?.amount ?? 0); await numberInput.confirmValue(); await rightPaymentInfoItem.filter({ hasText: '赠金' }).click(); await page.getByRole('button', { name: '增加收款' }).click(); await numberInput.setCommonValue(paymentDetail.find(e => e.method === '赠金')?.amount ?? 0); await numberInput.confirmValue(); await rightPaymentInfoItem.filter({ hasText: '欠款' }).click(); await page.getByRole('button', { name: '增加收款' }).click(); await numberInput.setCommonValue(paymentDetail.find(e => e.method === '欠款')?.amount ?? 0); await numberInput.confirmValue(); await rightPaymentInfoItem.filter({ hasText: '积分' }).click(); await page.getByRole('button', { name: '增加收款' }).click(); await numberInput.setCommonValue(paymentDetail.find(e => e.method === '积分')?.amount ?? 0); await numberInput.confirmValue(); await rightPaymentInfoItem.filter({ hasText: '现金' }).first().click(); await page.getByRole('button', { name: '增加收款' }).click(); await numberInput.confirmValue(); 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(); await page.getByRole('button', { name: '不寄存' }).click(); }); const consumeTrLocator = page.locator('.consume_table .m-table__body tr'); const billNoLocator = consumeTrLocator.locator('.bill_no', { hasText: billNo }); const billTrLocator = consumeTrLocator.filter({ has: page.locator('.bill_no', { hasText: 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.getByRole('tab', { name: '流水' }).click(); }); // 消费记录区域 const consume = page.locator('.m-detailComponent_warp'); // 购买区 const consumeBuy = consume.locator('.m-detailComponent_item').nth(0); // 支付明细 const consumeDetail = consume.locator('.m-detailComponent_consume'); await test.step('查看购买记录和单据明细', async () => { // 购买记录 await page.locator('.label_text', { hasText: '购买记录' }).click(); await expect(billNoLocator).toBeVisible(); await billNoLocator.click(); await consumeBuy.locator('.main-table-body_tr').last().waitFor(); // 项目简称、卖品名称 await expect(consumeBuy.locator('.main-table-body_tr')).toContainText([project.name, goods.name]); // 总金额 await expect(consumeDetail.locator('.amount')).toContainText(`${project.price + goods.price}`); // 欠款金额 await expect(consumeDetail.locator('.overdraft')).toContainText( `${paymentDetail.find(e => e.method === '欠款')?.amount}`, ); await expect(consumeDetail.locator('.m-detailComponent_consume_detail > div')).toContainText([ `优惠券¥${paymentDetail.find(e => e.method === '优惠券')?.amount}`, `卡金¥${paymentDetail.find(e => e.method === '卡金')?.amount}`, `赠金¥${paymentDetail.find(e => e.method === '赠金')?.amount}`, `积分¥${paymentDetail.find(e => e.method === '积分')?.amount}`, `现金¥${paymentDetail.find(e => e.method === '现金')?.amount}`, ]); await page .locator('div') .filter({ hasText: /^单据明细$/ }) .locator('i') .click(); }); await test.step('查看赠送记录', async () => { await page.locator('.label_text', { hasText: '赠送记录' }).click(); await expect(billNoLocator).not.toBeVisible(); }); await test.step('查看消耗记录', async () => { // 消耗记录 await page.locator('.label_text', { hasText: '消耗记录' }).click(); // 单据明细 await expect.soft(billNoLocator).toBeVisible(); // 项目简称 await expect.soft(billTrLocator.first().locator('.consume_shortname')).toContainText(project.shortName); await expect.soft(billTrLocator.first().locator('.num')).toContainText('1'); await expect(billTrLocator.first().locator('.price')).toContainText(`${project.price}`); }); await test.step('查看退换记录', async () => { // 退换记录 await page.locator('.label_text', { hasText: '退换记录' }).click(); await expect(billNoLocator).not.toBeVisible(); }); await test.step('查看会员卡记录', async () => { await page.locator('.label_text', { hasText: '会员卡记录' }).click(); await page.getByRole('cell', { name: '单号' }).waitFor(); const row = consumeTrLocator .filter({ has: page.locator('td', { hasText: '消费' }), }) .filter({ has: page.locator('td', { hasText: billNo }), }); // 卡金 await expect(row.locator('td').nth(4)).toContainText( `${paymentDetail.find(e => e.method === '卡金')?.amount}`, ); // 赠金 await expect(row.locator('td').nth(5)).toContainText( `${paymentDetail.find(e => e.method === '赠金')?.amount}`, ); }); await test.step('查看积分记录', async () => { await page.locator('.label_text', { hasText: '积分记录' }).click(); await expect( consumeTrLocator .filter({ has: page.locator('td', { hasText: '线下抵扣' }) }) .locator('td') .nth(1), ).toContainText(`${paymentDetail.find(e => e.method === '积分')?.amount}`); }); await test.step('查看优惠券记录', async () => { await page.locator('.label_text', { hasText: '优惠券记录' }).click(); const pointLocator = consumeTrLocator .filter({ has: page.locator('td', { hasText: '定额10元券' }) }) .filter({ has: page.locator('td', { hasText: '已使用' }) }) .filter({ has: page.locator('td', { hasText: /¥\s4960/ }) }); await expect(pointLocator).toBeVisible(); }); await test.step('查看卖品记录', async () => { await page.locator('.label_text', { hasText: '卖品记录' }).click(); const productLocator = consumeTrLocator .filter({ has: page.locator('td', { hasText: billNo }) }) .filter({ has: page.locator('td', { hasText: '购买' }) }) .filter({ has: page.locator('td', { hasText: goods.name }) }); await expect(productLocator).toBeVisible(); }); await test.step('查看欠还款记录,并且还款', async () => { await page.locator('.label_text', { hasText: '欠还款记录' }).click(); const paybackLocator = page .locator('.reimbursement_list') .filter({ has: page.locator('.reimbursement_order', { hasText: billNo }), }) .first(); // 还款存在 await expect(paybackLocator).toBeVisible(); // 进行还款 await paybackLocator.getByRole('button', { name: /^还\s款$/ }).click(); await page.getByText('现金', { exact: true }).click(); // 结算 await page.getByRole('button', { name: /^结\s算$/ }).click(); await expect(paybackLocator.filter({ hasText: '已清' })).toBeVisible(); }); }); test('查看动态', async ({ page, homeNavigation, createCustomer, customerPage, customerDetailsPage }) => { const customer = createCustomer; const date = new Date(); const currentYear = date.getFullYear(); const currentMonth = date.getMonth() + 1; const currentDay = date.getDate(); /**@type {string} */ let billNo = ''; await test.step('开单拿取单号', async () => { await homeNavigation.gotoModule('收银'); await page.getByRole('button', { name: /开\s单/ }).click(); await page.getByPlaceholder('姓名(拼音首字)、手机号、档案号搜索').fill(customer.phone); await page.getByText('搜索', { exact: true }).click(); await page.locator('.member_list_li').filter({ hasText: customer.phone }).click(); await page.locator('.list_box .project_list').first().click(); await page .locator('.pay_btn') .filter({ hasText: /^结\s算$/ }) .click(); //取消推送消息提醒 await page.getByLabel('推送消费提醒').uncheck(); //取消结算签字 await page.getByLabel('结算签字').uncheck(); await page.locator('.paymentInfoItem').first().click(); // 结算 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(), ]); billNo = (await response.json())?.content?.billNo; expect(billNo).not.toBeNull(); }); 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 test.step('查看日动态', async () => { // 日历列表 const $$calendarList = page.locator('.calendar_list').filter({ has: page.getByText(`${currentYear}年${currentMonth.toString().padStart(2, '0')}月`, { exact: true, }), }); // 当前日期的动态 const $$dayForDynamics = $$calendarList .getByTitle(`${currentMonth}月${currentDay}日`) .getByRole('listitem') .locator('div'); // 进入顾客详情动态页面 await customerDetailsPage.gotoSubPage('动态'); await expect($$dayForDynamics.first()).toBeInViewport(); await $$dayForDynamics.first().click(); await page.getByRole('button', { name: '查看消费详情' }).click(); await expect(page.getByText(billNo)).toBeVisible(); await page .locator('div') .filter({ hasText: /^单据明细$/ }) .locator('svg') .click(); await page.locator('.shopSelect_heard > .close > svg').first().click(); }); // 今年所有月份的动态 const $$dynamic = page.locator('.calendar_year_list', { hasText: `${currentYear}` }).locator('.dynamic_list'); // 当前月份的动态 const $currentForMonthDynamic = $$dynamic.filter({ has: page.locator('.month_box', { hasText: `${currentMonth}` }), }); await test.step('查看月动态-缩略', async () => { await page .locator('div') .filter({ hasText: /^日月$/ }) .getByRole('switch') .click(); await expect(page.getByText('月', { exact: true })).toHaveClass('selected_btn'); await expect(async () => { await $currentForMonthDynamic.click(); await expect(page.getByRole('tabpanel').getByText(billNo)).toBeVisible(); }).toPass(); await page.locator('.action_detail > .container > .m_sliding_menu > .box > .top > .anticon').click(); }); await test.step('查看月动态-日期', async () => { await page .locator('div') .filter({ hasText: /^缩略日期$/ }) .getByRole('switch') .click(); await expect(page.getByText('日期', { exact: true })).toHaveClass('selected_btn'); await $currentForMonthDynamic.filter({ hasText: `${currentDay}` }).click(); await expect(page.getByRole('tabpanel').getByText(billNo)).toBeVisible(); }); }); test('日志-添加-修改-删除', async ({ page, homeNavigation, customerPage, createCustomer }) => { const customer = createCustomer; let logContent = '测试添加日志成功'; let lastLogContent = ''; // 日志列表 const $$journal = page.locator('.journal_list'); // 日志填写框 const $input = page.getByPlaceholder('请输入1-500个字符护理内容'); 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 test.step('添加日志', async () => { await page.getByRole('tab', { name: '日志' }).click(); await page.getByRole('button', { name: '添加日志' }).click(); await $input.fill(logContent); await page.getByRole('button', { name: /确\s认/ }).click(); // 在顾客A的顾客详情页面 -》日志查看刚才添加的日志 await expect($$journal.first()).toContainText(logContent); }); lastLogContent = logContent; logContent = '修改日志'; await test.step('修改日志', async () => { await $$journal.first().locator('.title a').click(); await page.getByRole('menuitem', { name: '编辑' }).click(); await $input.waitFor(); const currentLogContent = await $input.inputValue(); expect(currentLogContent).toBe(lastLogContent); await $input.fill(logContent); await page.getByRole('button', { name: /确\s认/ }).click(); await expect($$journal.first()).toContainText(logContent); }); await test.step('删除日志', async () => { await expect($$journal.first()).toContainText(logContent); await $$journal.first().locator('.title a').click(); await page.getByRole('menuitem', { name: '删除' }).click(); await page.getByRole('button', { name: /确\s认/ }).click(); await expect($$journal.first()).not.toBeVisible(); }); }); }); test.describe('顾客概要', () => { test('顾客列表展示', async ({ page, homeNavigation }) => { // 定义会员数据 let TotalCash2; let TotalCash3; let ConsumptionFrequency2; let ConsumptionFrequency3; let LastArrivalTime2; let LastArrivalTime3; let LastConsumptionTime2; let LastConsumptionTime3; let FirstConsumptionTime2; let FirstConsumptionTime3; let RegistrationTime2; let RegistrationTime3; // 进入顾客界面 await homeNavigation.gotoModule('顾客'); // 点击会员列表下拉框 await page.locator('.sub_icon').first().click(); // 现金总额 await page.locator('.m-table-cell-sort').filter({ hasText: '现金总额' }).click(); // 点击最后一页 const endPage = await page.locator('.m-table-pagination li').count(); await page .locator('.m-table-pagination li') .nth(endPage - 3) .click(); // 顾客数量 const memberquantity = await page.locator('.main-table-body_tr').count(); console.log('最后一页' + memberquantity); await test.step('倒数三个对比正数三个的现金总额', async () => { const $$cash = page.locator('.main-table-body_tr .is-right:nth-child(12)'); const TotalCash1 = await $$cash.nth(-1).innerText(); if (memberquantity === 1) { await page.locator('.ant-pagination-item-link').first().click(); TotalCash2 = await $$cash.nth(-1).innerText(); TotalCash3 = await $$cash.nth(-2).innerText(); } if (memberquantity === 2) { TotalCash2 = await $$cash.nth(-2).innerText(); await page.locator('.ant-pagination-item-link').first().click(); TotalCash3 = await $$cash.nth(-1).innerText(); } if (memberquantity > 2) { TotalCash2 = await $$cash.nth(-2).innerText(); TotalCash3 = await $$cash.nth(-3).innerText(); } // 点击现金总额排序 await page.locator('.m-table-cell-sort').filter({ hasText: '现金总额' }).click(); await expect($$cash.nth(0)).toContainText(TotalCash1); await expect($$cash.nth(1)).toContainText(TotalCash2); await expect($$cash.nth(2)).toContainText(TotalCash3); }); await test.step('倒数三个对比正数三个的消费次数', async () => { await page.locator('.m-table-cell-sort').filter({ hasText: '消费次数' }).click(); const $consumptionFrequency = page.locator('.main-table-body_tr .is-right:nth-child(13)'); // 点击最后一页 await page .locator('.m-table-pagination li') .nth(endPage - 3) .click(); await expect(page.locator('.m-table__icon__warp')).toBeHidden(); const ConsumptionFrequency1 = await $consumptionFrequency.nth(-1).innerText(); if (memberquantity === 1) { await page.locator('.ant-pagination-item-link').first().click(); ConsumptionFrequency2 = await $consumptionFrequency.nth(-1).innerText(); ConsumptionFrequency3 = await $consumptionFrequency.nth(-2).innerText(); } if (memberquantity === 2) { ConsumptionFrequency2 = await $consumptionFrequency.nth(-2).innerText(); await page.locator('.ant-pagination-item-link').first().click(); ConsumptionFrequency3 = await $consumptionFrequency.nth(-1).innerText(); } if (memberquantity > 2) { ConsumptionFrequency2 = await page .locator('.main-table-body_tr .is-right:nth-child(13)') .nth(-2) .innerText(); ConsumptionFrequency3 = await page .locator('.main-table-body_tr .is-right:nth-child(13)') .nth(-3) .innerText(); } await page.locator('.m-table-cell-sort').filter({ hasText: '消费次数' }).click(); await expect(page.locator('.main-table-body_tr .is-right:nth-child(13)').nth(0)).toBeVisible(); await expect($consumptionFrequency.nth(0)).toContainText(ConsumptionFrequency1); await expect($consumptionFrequency.nth(1)).toContainText(ConsumptionFrequency2); await expect($consumptionFrequency.nth(2)).toContainText(ConsumptionFrequency3); }); await test.step('倒数三个对比正数三个的上次到店时间', async () => { await page.locator('.m-table-cell-sort').filter({ hasText: '上次到店时间' }).click(); // 点击最后一页 await page .locator('.m-table-pagination li') .nth(endPage - 3) .click(); await expect(page.locator('.m-table__icon__warp')).toBeHidden(); const $$lastArrivalTime = page.locator('.main-table-body_tr .is-center:nth-child(15)'); const LastArrivalTime1 = await $$lastArrivalTime.nth(-1).innerText(); if (memberquantity === 1) { await page.locator('.ant-pagination-item-link').first().click(); LastArrivalTime2 = await $$lastArrivalTime.nth(-1).innerText(); LastArrivalTime3 = await $$lastArrivalTime.nth(-2).innerText(); } if (memberquantity === 2) { LastArrivalTime2 = await $$lastArrivalTime.nth(-2).innerText(); await page.locator('.ant-pagination-item-link').first().click(); LastArrivalTime3 = await $$lastArrivalTime.nth(-1).innerText(); } if (memberquantity > 2) { LastArrivalTime2 = await $$lastArrivalTime.nth(-2).innerText(); LastArrivalTime3 = await $$lastArrivalTime.nth(-3).innerText(); } await page.locator('.m-table-cell-sort').filter({ hasText: '上次到店时间' }).click(); await expect($$lastArrivalTime.nth(0)).toContainText(LastArrivalTime1); await expect($$lastArrivalTime.nth(1)).toContainText(LastArrivalTime2); await expect($$lastArrivalTime.nth(2)).toContainText(LastArrivalTime3); }); await test.step('倒数三个对比正数三个的上次消费时间', async () => { await page.locator('.m-table-cell-sort').filter({ hasText: '上次消费时间' }).click(); // 点击最后一页 await page .locator('.m-table-pagination li') .nth(endPage - 3) .click(); await expect(page.locator('.m-table__icon__warp')).toBeHidden(); // 上次消费时间定位器 const $$lastConsumptionTime = page.locator('.main-table-body_tr .is-center:nth-child(16)'); const LastConsumptionTime1 = await $$lastConsumptionTime.nth(-1).innerText(); if (memberquantity === 1) { await page.locator('.ant-pagination-item-link').first().click(); LastConsumptionTime2 = await $$lastConsumptionTime.nth(-1).innerText(); LastConsumptionTime3 = await $$lastConsumptionTime.nth(-2).innerText(); } if (memberquantity === 2) { LastConsumptionTime2 = await $$lastConsumptionTime.nth(-2).innerText(); await page.locator('.ant-pagination-item-link').first().click(); LastConsumptionTime3 = await $$lastConsumptionTime.nth(-1).innerText(); } if (memberquantity > 2) { LastConsumptionTime2 = await $$lastConsumptionTime.nth(-2).innerText(); LastConsumptionTime3 = await $$lastConsumptionTime.nth(-3).innerText(); } await page.locator('.m-table-cell-sort').filter({ hasText: '上次消费时间' }).click(); await expect($$lastConsumptionTime.nth(0)).toContainText(LastConsumptionTime1); await expect($$lastConsumptionTime.nth(1)).toContainText(LastConsumptionTime2); await expect($$lastConsumptionTime.nth(2)).toContainText(LastConsumptionTime3); }); await test.step('倒数三个对比正数三个的首次消费时间', async () => { await page.locator('.m-table-cell-sort').filter({ hasText: '首次消费时间' }).click(); // 点击最后一页 await page .locator('.m-table-pagination li') .nth(endPage - 3) .click(); await expect(page.locator('.m-table__icon__warp')).toBeHidden(); // 首次消费时间定位器 const $$firstConsumptionTime = page.locator('.main-table-body_tr .is-center:nth-child(17)'); const FirstConsumptionTime1 = await $$firstConsumptionTime.nth(-1).innerText(); if (memberquantity === 1) { await page.locator('.ant-pagination-item-link').first().click(); FirstConsumptionTime2 = await $$firstConsumptionTime.nth(-1).innerText(); FirstConsumptionTime3 = await $$firstConsumptionTime.nth(-2).innerText(); } if (memberquantity === 2) { FirstConsumptionTime2 = await $$firstConsumptionTime.nth(-2).innerText(); await page.locator('.ant-pagination-item-link').first().click(); FirstConsumptionTime3 = await $$firstConsumptionTime.nth(-1).innerText(); } if (memberquantity > 2) { FirstConsumptionTime2 = await $$firstConsumptionTime.nth(-2).innerText(); FirstConsumptionTime3 = await $$firstConsumptionTime.nth(-3).innerText(); } await page.locator('.m-table-cell-sort').filter({ hasText: '首次消费时间' }).click(); await expect($$firstConsumptionTime.nth(0)).toContainText(FirstConsumptionTime1); await expect($$firstConsumptionTime.nth(1)).toContainText(FirstConsumptionTime2); await expect($$firstConsumptionTime.nth(2)).toContainText(FirstConsumptionTime3); }); await test.step('倒数三个对比正数三个的注册时间', async () => { // 注册时间 await page.locator('.m-table-cell-sort').filter({ hasText: '注册时间' }).click(); // 点击最后一页 await page .locator('.m-table-pagination li') .nth(endPage - 3) .click(); await expect(page.locator('.m-table__icon__warp')).toBeHidden(); // 注册时间定位器 const $$registrationTime = page.locator('.main-table-body_tr .is-center:nth-child(18)'); const RegistrationTime1 = await $$registrationTime.nth(-1).innerText(); if (memberquantity === 1) { await page.locator('.ant-pagination-item-link').first().click(); RegistrationTime2 = await $$registrationTime.nth(-1).innerText(); RegistrationTime3 = await $$registrationTime.nth(-2).innerText(); } if (memberquantity === 2) { RegistrationTime2 = await $$registrationTime.nth(-2).innerText(); await page.locator('.ant-pagination-item-link').first().click(); RegistrationTime3 = await $$registrationTime.nth(-1).innerText(); } if (memberquantity > 2) { RegistrationTime2 = await $$registrationTime.nth(-2).innerText(); RegistrationTime3 = await $$registrationTime.nth(-3).innerText(); } await page.locator('.m-table-cell-sort').filter({ hasText: '注册时间' }).click(); await expect($$registrationTime.nth(0)).toContainText(RegistrationTime1); await expect($$registrationTime.nth(1)).toContainText(RegistrationTime2); await expect($$registrationTime.nth(2)).toContainText(RegistrationTime3); }); }); test('待办展示', async ({ page, homeNavigation, createCustomCustomer }) => { const date = new Date(); const currentYear = date.getFullYear(); const currentMonth = date.getMonth() + 1; const currentDay = date.getDate(); const customer = new Customer(1, 1, { birthday: { year: currentYear, month: currentMonth, day: currentDay }, }); const todoLocator = page.locator('.member-side', { hasText: '待办事项' }); const todoListLocator = todoLocator.locator('.action_item'); const customerTodo = todoListLocator.filter({ has: page.getByText(customer.username) }); const showTodoLocator = page.locator('.shopSelect_box', { hasText: '事项状态' }); // 创建顾客,并且设置了顾客生日为今日 await createCustomCustomer(customer); // 进入顾客模块 await homeNavigation.gotoModule('顾客'); // 待办列表存在 await expect(todoLocator).toBeVisible(); // 打开顾客的生日待办事项 await customerTodo.getByText('生日提醒', { exact: true }).click(); // 判断待办事项正确展示 await expect(showTodoLocator).toContainText('生日提醒'); await expect(showTodoLocator).toContainText(customer.username); }); test.skip('表显示配置', async ({ page, homeNavigation }) => { // 进入顾客界面 await homeNavigation.gotoModule('顾客'); // 点击潜客 await page.locator('.sub_icon').nth(3).click(); // 点击更多 await page.locator('.more', { hasText: '更多' }).waitFor(); await page.locator('.more', { hasText: '更多' }).click(); // 等待表显示配置 await page.locator('.title', { hasText: '表显示配置' }).waitFor(); // 关闭档案号、项目的显示开关 await page .locator('.sortList .list-session') .filter({ has: page.locator('.name', { hasText: /^档案号$/ }) }) .locator('.ant-switch') .click(); const SwitchA = page .locator('.sortList .list-session') .filter({ has: page.locator('.name', { hasText: /^档案号$/ }) }) .locator('.ant-switch-checked'); // 判断开关已关闭 await expect(SwitchA).not.toBeVisible(); await page .locator('.sortList .list-session') .filter({ has: page.locator('.name', { hasText: /^项目$/ }) }) .locator('.ant-switch') .click(); const SwitchB = page .locator('.sortList .list-session') .filter({ has: page.locator('.name', { hasText: /^项目$/ }) }) .locator('.ant-switch-checked'); // 判断开关已关闭 await expect(SwitchB).not.toBeVisible(); // 确认 await page.locator('.ant-btn-primary', { hasText: /^确\s认$/ }).click(); // 遍历标题 项目 档案号不存在 const allTrB = page.locator('.m-table__header-wrapper thead th'); const archivesB = allTrB.locator('.m-table-cell', { hasText: /^档案号$/ }); const ProjectB = allTrB.locator('.m-table-cell', { hasText: /^项目$/ }); await expect(archivesB).not.toBeVisible(); await expect(ProjectB).not.toBeVisible(); // 点击更多 await page.locator('.more', { hasText: '更多' }).click(); // 等待表显示配置 await page.locator('.title', { hasText: '表显示配置' }).waitFor(); // 关闭档案号、项目的显示开关 await page .locator('.sortList .list-session') .filter({ has: page.locator('.name', { hasText: /^档案号$/ }) }) .locator('.ant-switch') .click(); const SwitchC = page .locator('.sortList .list-session') .filter({ has: page.locator('.name', { hasText: /^档案号$/ }) }) .locator('.ant-switch-checked'); // 判断开关已打开 await expect(SwitchC).toBeVisible(); await page .locator('.sortList .list-session') .filter({ has: page.locator('.name', { hasText: /^项目$/ }) }) .locator('.ant-switch') .click(); const SwitchD = page .locator('.sortList .list-session') .filter({ has: page.locator('.name', { hasText: /^项目$/ }) }) .locator('.ant-switch-checked'); // 判断开关已打开 await expect(SwitchD).toBeVisible(); // 确认 await page.locator('.ant-btn-primary', { hasText: /^确\s认$/ }).click(); // 遍历标题 项目 档案号存在 const allTrA = page.locator('.m-table__header-wrapper thead th'); const archivesA = allTrA.locator('.m-table-cell', { hasText: /^档案号$/ }); const ProjectA = allTrA.locator('.m-table-cell', { hasText: /^项目$/ }); await expect(archivesA).toBeVisible(); await expect(ProjectA).toBeVisible(); // 点击更多 await page.locator('.more', { hasText: '更多' }).click(); // 等待表显示配置 await page.locator('.title', { hasText: '表显示配置' }).waitFor(); const sortArchives = page .locator('.sortList .list-session') .filter({ has: page.locator('.name', { hasText: /^档案号$/ }) }) .locator('.sort'); const sortItem = page .locator('.sortList .list-session') .filter({ has: page.locator('.name', { hasText: /^项目$/ }) }) .locator('.sort'); // 边界框 const boundaryArchives = await sortArchives.boundingBox(); const boundaryItem = await sortItem.boundingBox(); if (!boundaryArchives || !boundaryItem) { throw new Error('获取边界框失败'); } const ArchivesX = boundaryArchives.x + boundaryArchives.width / 2; const ArchivesY = boundaryArchives.y + boundaryArchives.height / 2; const ItemX = boundaryItem.x + boundaryItem.width / 2; const ItemY = boundaryItem.y + boundaryItem.height / 2; await expect(async () => { // 拖动项目到档案号的位置 await page.mouse.move(ItemX, ItemY); await page.mouse.down(); await page.waitForTimeout(2000); await page.mouse.move(ArchivesX, ArchivesY); await page.mouse.up(); expect(await page.locator('.sortList .list-session .name').first().innerText()).toBe('项目'); }).toPass(); await expect(async () => { // 拖动项目到档案号的位置 await page.mouse.move(ItemX, ItemY); await page.mouse.down(); await page.waitForTimeout(2000); await page.mouse.move(ArchivesX, ArchivesY); await page.mouse.up(); expect(await page.locator('.sortList .list-session .name').first().innerText()).toBe('档案号'); }).toPass(); }); test.skip('导出表格', async ({ page, homeNavigation }) => { // 进入顾客界面 await homeNavigation.gotoModule('顾客'); // 点击潜客 await page.locator('.sub_icon').nth(3).click(); // 点击更多 await page.locator('.more', { hasText: '更多' }).waitFor(); await page.locator('.more', { hasText: '更多' }).click(); // 等待表显示配置 await page.locator('.title', { hasText: '表显示配置' }).waitFor(); const downloadPromise = page.waitForEvent('download'); // 点击导出数据 await page.locator('.a-modal-export', { hasText: '导出数据' }).click(); // 等待报表导出 await page.locator('.m-exportModal_title', { hasText: '报表导出' }).waitFor(); // 确认 await page.locator('.m-exportModal_button', { hasText: /^确\s认$/ }).click(); const download = await downloadPromise; // 获取下载的文件名 const fileName = download.suggestedFilename(); // 指定保存下载文件的路径 const downloadPath = path.join(__dirname, `@/imgs/${fileName}`); // 保存下载的文件 await download.saveAs(downloadPath); // 验证文件是否成功保存 const fileExists = fs.existsSync(downloadPath); expect(fileExists).toBeTruthy(); }); }); test.describe('顾客分配', () => { test('顾客列表展示', async ({ page, homeNavigation, customerPage }) => { await test.step('查看总人数和页脚总人数一致', async () => { await homeNavigation.gotoModule('顾客'); await customerPage.gotoSubPage('顾客分配'); const headTotalLocator = page.locator('.info_item', { hasText: '总人数' }); await waitStable(headTotalLocator); const paginationLocator = page.locator('.m-table-pagination .dec'); await paginationLocator.waitFor(); const paginationMatch = (await paginationLocator.innerText()).match(/共计([0-9]+)/); const paginationTotal = paginationMatch ? paginationMatch[1] : '0'; const headTotal = await headTotalLocator.locator('.info_number').innerText(); expect.soft(headTotal).toBe(paginationTotal); }); await test.step('按照现金总额排序查看列表', async () => { const amountTotalLocator = page.locator('.m-table__header-wrapper th', { hasText: '现金总额', }); // 顺序和倒序的按钮 const amountTotalOrder = amountTotalLocator.locator('.m-table-sort i').last(); const amountTotalReverseOrder = amountTotalLocator.locator('.m-table-sort i').first(); const amountList = page.locator('.m-table__body-wrapper .main-table-body_tr'); // 查看从高到底的排序 await amountTotalOrder.click(); await expect(amountTotalOrder).toHaveClass(/on/); await amountList.first().waitFor(); // 拿取现金总额列的index const titleListLocator = page.locator('.m-table__header-wrapper tr').first().locator('th'); const titleList = await titleListLocator.allInnerTexts(); const index = titleList.findIndex(text => text === '现金总额'); // 拿取前三个顾客的现金总额 let amountArray: number[]; for (let i = 0; i < 3; i++) { const amountStr = await amountList.nth(i).locator('td').nth(index).innerText(); const amount = convertAmountText(amountStr).amount; amountArray.push(amount); } // 金额按照从高到低排列 expect(amountArray[0]).toBeGreaterThanOrEqual(amountArray[1]); expect(amountArray[1]).toBeGreaterThanOrEqual(amountArray[2]); // 查看从低到高的排序 await amountTotalReverseOrder.click(); await expect(amountTotalOrder).toHaveClass(/on/); await amountList.first().waitFor(); amountArray = []; let amountStr = await amountList.nth(0).locator('td').nth(index).innerText(); amountArray.push(convertAmountText(amountStr).amount); // 跳转到倒数第一页,拿取最后三个顾客的现金总额 const paginationLiLocator = page.locator('.m-table-pagination ul li'); const paginationLiCount = await paginationLiLocator.count(); await paginationLiLocator.nth(paginationLiCount - 3).click(); amountStr = await amountList.nth(0).locator('td').nth(index).innerText(); amountArray.push(convertAmountText(amountStr).amount); // 金额按照从高到低排列 expect(amountArray[0]).toBeLessThanOrEqual(amountArray[1]); }); }); test.skip('表显示配置', async ({ page, homeNavigation }) => { await page.reload(); // 跟分配师一样不重进不加载某些内容 // 进入顾客界面 await homeNavigation.gotoModule('顾客'); // 点击顾客分配 await page.locator('.tab_item', { hasText: '顾客分配' }).first().click(); await page.locator('.assign_info').waitFor(); // 点击更多 await page.locator('.more', { hasText: '更多' }).waitFor(); await page.locator('.more', { hasText: '更多' }).click(); // 等待表显示配置 await page.locator('.title', { hasText: '表显示配置' }).waitFor(); // 关闭档案号、项目的显示开关 await page .locator('.sortList .list-session') .filter({ has: page.locator('.name', { hasText: /^咨询师$/ }) }) .locator('.ant-switch') .click(); const SwitchA = page .locator('.sortList .list-session') .filter({ has: page.locator('.name', { hasText: /^咨询师$/ }) }) .locator('.ant-switch-checked'); // 判断开关已关闭 await expect(SwitchA).not.toBeVisible(); await page .locator('.sortList .list-session') .filter({ has: page.locator('.name', { hasText: /^医生$/ }) }) .locator('.ant-switch') .click(); const SwitchB = page .locator('.sortList .list-session') .filter({ has: page.locator('.name', { hasText: /^医生$/ }) }) .locator('.ant-switch-checked'); // 判断开关已关闭 await expect(SwitchB).not.toBeVisible(); // 确认 await page.locator('.ant-btn-primary', { hasText: /^确\s认$/ }).click(); // 遍历标题 项目 档案号不存在 const allTrB = page.locator('.m-table__header-wrapper thead th'); const archivesB = allTrB.locator('.m-table-cell', { hasText: /^咨询师$/ }); const ProjectB = allTrB.locator('.m-table-cell', { hasText: /^医生$/ }); await expect(archivesB).not.toBeVisible(); await expect(ProjectB).not.toBeVisible(); // 点击更多 await page.locator('.more', { hasText: '更多' }).click(); // 等待表显示配置 await page.locator('.title', { hasText: '表显示配置' }).waitFor(); // 关闭档案号、项目的显示开关 await page .locator('.sortList .list-session') .filter({ has: page.locator('.name', { hasText: /^咨询师$/ }) }) .locator('.ant-switch') .click(); const SwitchC = page .locator('.sortList .list-session') .filter({ has: page.locator('.name', { hasText: /^咨询师$/ }) }) .locator('.ant-switch-checked'); // 判断开关已打开 await expect(SwitchC).toBeVisible(); await page .locator('.sortList .list-session') .filter({ has: page.locator('.name', { hasText: /^医生$/ }) }) .locator('.ant-switch') .click(); const SwitchD = page .locator('.sortList .list-session') .filter({ has: page.locator('.name', { hasText: /^医生$/ }) }) .locator('.ant-switch-checked'); // 判断开关已打开 await expect(SwitchD).toBeVisible(); // 确认 await page.locator('.ant-btn-primary', { hasText: /^确\s认$/ }).click(); // 遍历标题 项目 档案号存在 const allTrA = page.locator('.m-table__header-wrapper thead th'); const archivesA = allTrA.locator('.m-table-cell', { hasText: /^咨询师$/ }); const ProjectA = allTrA.locator('.m-table-cell', { hasText: /^医生$/ }); await expect(archivesA).toBeVisible(); await expect(ProjectA).toBeVisible(); // 点击更多 await page.locator('.more', { hasText: '更多' }).click(); // 等待表显示配置 await page.locator('.title', { hasText: '表显示配置' }).waitFor(); const sortArchives = page .locator('.sortList .list-session') .filter({ has: page.locator('.name', { hasText: /^咨询师$/ }) }) .locator('.sort'); const sortItem = page .locator('.sortList .list-session') .filter({ has: page.locator('.name', { hasText: /^医生$/ }) }) .locator('.sort'); // 边界框 const boundaryArchives = await sortArchives.boundingBox(); const boundaryItem = await sortItem.boundingBox(); if (!boundaryArchives || !boundaryItem) { throw new Error('获取边界框失败'); } const ArchivesX = boundaryArchives.x + boundaryArchives.width / 2; const ArchivesY = boundaryArchives.y + boundaryArchives.height / 2; const ItemX = boundaryItem.x + boundaryItem.width / 2; const ItemY = boundaryItem.y + boundaryItem.height / 2; await expect(async () => { // 拖动项目到档案号的位置 await page.mouse.move(ItemX, ItemY); await page.mouse.down(); await page.waitForTimeout(2000); await page.mouse.move(ArchivesX, ArchivesY); await page.mouse.up(); expect(await page.locator('.sortList .list-session .name').first().innerText()).toBe('医生'); }).toPass(); await expect(async () => { // 拖动项目到档案号的位置 await page.mouse.move(ItemX, ItemY); await page.mouse.down(); await page.waitForTimeout(2000); await page.mouse.move(ArchivesX, ArchivesY); await page.mouse.up(); expect(await page.locator('.sortList .list-session .name').first().innerText()).toBe('咨询师'); }).toPass(); }); test.skip('导出表格', async ({ page, homeNavigation }) => { // 进入顾客界面 await homeNavigation.gotoModule('顾客'); // 点击顾客分配 await page.locator('.tab_item', { hasText: '顾客分配' }).click(); await page.locator('.assign_side').waitFor(); // 点击更多 await page.locator('.more', { hasText: '更多' }).waitFor(); await page.locator('.more', { hasText: '更多' }).click(); // 等待表显示配置 await page.locator('.title', { hasText: '表显示配置' }).waitFor(); const downloadPromise = page.waitForEvent('download'); // 点击导出数据 await page.locator('.a-modal-export', { hasText: '导出数据' }).click(); // 等待报表导出 await page.locator('.m-exportModal_title', { hasText: '报表导出' }).waitFor(); // 确认 await page.locator('.m-exportModal_button', { hasText: /^确\s认$/ }).click(); const download = await downloadPromise; // 获取下载的文件名 const fileName = download.suggestedFilename(); // 指定保存下载文件的路径 const downloadPath = path.join(__dirname, `@/imgs/${fileName}`); // 保存下载的文件 await download.saveAs(downloadPath); // 验证文件是否成功保存 const fileExists = fs.existsSync(downloadPath); expect(fileExists).toBeTruthy(); }); }); test.describe('顾客分析', () => { test('查看顾客项目分析', async ({ page, homeNavigation, createCustomers, customerPage, numberInput }) => { let customers: Customer[]; await test.step('创建两个顾客', async () => { customers = await createCustomers(2); }); 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; // 顾客A await test.step('顾客A', async () => { await homeNavigation.gotoModule('收银'); await page.getByRole('button', { name: /开\s单/ }).click(); await customerPage.searchCustomer(phoneA); await customerPage.selectSearchCustomer(usernameA); // 购买项目1-普通,2次 await page.getByText(ProjectA1.num).click(); await page.locator('.edit_txt div:nth-child(2)').first().click(); await numberInput.setValue(ProjectA1Quantity); await numberInput.confirmValue(); // 点击面部 await page.getByText('面部').click(); // 购买项目2-普通,1次 await page.getByText(ProjectA2.num).click(); await page.locator('.type_btn').first().click(); await page.locator('.type_item', { hasText: '普通' }).click(); // 点击护理 await page.getByText('护理', { exact: true }).click(); // 购买项目3-赠送,3次 await page.getByText(ProjectA3.num).click(); await page.locator('.edit_txt div:nth-child(2)').first().click(); await numberInput.setValue(ProjectA3Quantity); 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.locator('.add_btn', { hasText: '设置' }).last().click(); await page.getByRole('textbox').fill(ProjectA2.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.locator('.menu-item-dot', { hasText: '2' }).first().waitFor({ timeout: 2000 }); }).toPass(); await page.getByRole('button', { name: '确定选择' }).click(); await page.locator('.type_btn').first().click(); await page.locator('.type_item', { hasText: '普通' }).click(); // 消耗混合项目1次 await page.locator('.commodity_item').last().click(); await page .locator('div') .filter({ hasText: /^结 算$/ }) .click(); // 使用银联支付 await page.getByText('银联').click(); await page.getByLabel('推送消费提醒').uncheck(); await page.getByLabel('结算签字').uncheck(); 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; await test.step('顾客B', async () => { //顾客B await page.reload(); await page.getByRole('button', { name: /开\s单/ }).click(); await customerPage.searchCustomer(phoneB); await customerPage.selectSearchCustomer(usernameB); // 购买项目3-普通,20次 await page.getByText(ProjectB3.num).click(); await page.locator('.edit_txt div:nth-child(2)').first().click(); await numberInput.setValue(ProjectB3Quantity); await numberInput.confirmValue(); // 点击身体 await page.locator('.type_tab_item', { hasText: '身体' }).click(); // 购买项目4-普通,30次 await page.getByText(ProjectB4.num).click(); await page.locator('.edit_txt div:nth-child(2)').first().click(); await numberInput.setValue(ProjectB4Quantity); await numberInput.confirmValue(); // 购买项目5,9次 await page.getByText(ProjectB5.num).click(); await page.locator('.edit_txt div:nth-child(2)').first().click(); await numberInput.setValue(ProjectB5Quantity); await numberInput.confirmValue(); // 购买项目B1-B2混合,2次 await page.locator('.type_tab_item', { hasText: '护理' }).click(); await page.getByText(ProjectB1.num).first().click(); await page.locator('.add_btn', { hasText: '设置' }).last().click(); await page.getByRole('textbox').fill(ProjectB2.num); await page.getByRole('button', { name: /搜\s索/ }).click(); await expect(async () => { await page.locator('.list_box .ant-checkbox-input').click(); await page.locator('.menu-item-dot', { hasText: '2' }).first().waitFor({ timeout: 1000 }); }).toPass(); await page.getByRole('button', { name: '确定选择' }).click(); // 点击选择数量 await page.locator('.edit_txt div:nth-child(2)').first().click(); await numberInput.setValue(ProjectB12Quantity); await numberInput.confirmValue(); // 购买项目B4-B4混合,3次 await page.getByText(ProjectB3.num).first().click(); await page.locator('.add_btn', { hasText: '设置' }).last().click(); await page.getByRole('textbox').fill(ProjectB4.num); await page.getByRole('button', { name: '搜 索' }).click(); await expect(async () => { await page.locator('.list_box .ant-checkbox-input').click(); await page.locator('.menu-item-dot', { hasText: '2' }).first().waitFor({ timeout: 1000 }); }).toPass(); await page.getByRole('button', { name: '确定选择' }).click(); // 点击选择数量 await page.locator('.edit_txt div:nth-child(2)').first().click(); await numberInput.setValue(ProjectB34Quantity); await numberInput.confirmValue(); await page.locator('.commodity_item').last().click(); await page .locator('div') .filter({ hasText: /^结 算$/ }) .click(); await page.getByText('银联').click(); await page.getByLabel('推送消费提醒').uncheck(); await page.getByLabel('结算签字').uncheck(); await page.getByRole('button', { name: /^结\s算$/ }).click(); }); await test.step('查看顾客项目分析', async () => { 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 }); // 1 查找到顾客A 顾客B await expect(Customer1A).toBeVisible(); await expect(Customer1B).toBeVisible(); // 表格行 const allTr = page.locator('.m-table__body-wrapper tbody tr'); // 获取顾客B处于第几行 const nowRow = await page .locator('.m-table__body-wrapper tbody tr') .allInnerTexts() .then(async text => { return text.findIndex(item => item.includes(phoneB)); }); // 查看各单元格内容 // 护理内容 await expect.soft(allTr.nth(nowRow).locator('td').nth(2)).toContainText(`${ProjectB3Quantity - 1}`); // 身体内容 await expect .soft(allTr.nth(nowRow).locator('td').nth(5)) .toContainText(`${ProjectB12Quantity + ProjectB34Quantity}`); // 组合内容 await expect(allTr.nth(nowRow).locator('td').nth(5)).toContainText( `${ProjectB12Quantity + ProjectB34Quantity}`, ); const $productName = page.locator('.treat_box .treat_card:nth-child(1) .name_row .auto_desc'); const $productResidue = page.locator('.treat_box .treat_card:nth-child(1) .name_row .residue'); const $productName2 = page.locator('.treat_box .treat_card:nth-child(2) .name_row .auto_desc'); const $productResidue2 = page.locator('.treat_box .treat_card:nth-child(2) .name_row .residue'); // 点击查看弹窗内容 // 点击护理 await allTr.nth(nowRow).locator('td').nth(2).click(); // 项目名称 await expect.soft($productName).toContainText(ProjectB3.name); // 剩余次数 await expect($productResidue).toContainText(`${ProjectB3Quantity - 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($productResidue).toContainText(`${ProjectB4Quantity}`); // 项目名称 await expect.soft($productName2).toContainText(ProjectB5.name); // 剩余次数 await expect.soft($productResidue2).toContainText(`${ProjectB5Quantity}`); // 关闭弹窗 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($productResidue).toContainText(`${ProjectB12Quantity}`); // 项目名称 await expect.soft($productName2).toContainText(ProjectB3.name + ',' + ProjectB4.name); // 剩余次数 await expect($productResidue2).toContainText(`${ProjectB34Quantity}`); // 关闭弹窗 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)); }); // 点击护理 await allTrA.nth(nowRowA).locator('td').nth(2).click(); // 项目名称 await expect.soft($productName).toContainText(ProjectA1.name); // 剩余次数 await expect($productResidue).toContainText(`${ProjectA1Quantity - 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($productResidue).toContainText(`${ProjectA2Quantity}`); // 关闭弹窗 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($productResidue).toContainText(`${ProjectA12Quantity}`); // 关闭弹窗 await page.locator('.close_icon').last().click(); // 点击左上角设置 await page.locator('.setting_icon').click(); // 选择购买数 await page.getByText('购买数', { exact: true }).click(); // 选择显示体验/赠送项目 await page.getByText('显示体验/赠送项目').click(); // 保存 await page.getByRole('button', { name: /保\s存/ }).click(); await page.locator('.loading_container').waitFor({ state: 'hidden' }); // 护理内容 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)); }); // 点击护理 await allTrAA.nth(nowRowAA).locator('td').nth(2).click(); // 项目名称 await expect.soft($productName).toContainText(ProjectA1.name); // 剩余次数 await expect.soft($productResidue).toContainText(`${ProjectA1Quantity - 1}`); // 项目名称 await expect.soft($productName2).toContainText(ProjectA3.name); // 剩余次数 await expect($productResidue2).toContainText(`${ProjectA3Quantity}`); // 关闭弹窗 await page.locator('.close_icon').last().click(); // 点击排序后顾客在第一页显示 await page .locator('div') .filter({ hasText: /^排序$/ }) .nth(1) .click(); await page.getByRole('menuitem', { name: '上次到店时间从近到远' }).click(); await page.locator('.loading_container').waitFor({ state: 'hidden' }); // 1 查找到顾客A 顾客B await expect.soft(Customer1A).toBeVisible(); await expect(Customer1B).toBeVisible(); }); }); test('查看项目余量分析', async ({ page, homeNavigation, customerPage, createCustomer, customerAnalysisPage, numberInput, }) => { const customer = createCustomer; let billNo = ''; // 分类-项目选择器 const $$switch = page.locator('.coustom_switch'); const $categoryAndProject = $$switch .filter({ hasText: '分类' }) .filter({ hasText: '项目' }) .getByRole('switch'); // 客数-余次选择器 const $passengersAndRemainder = $$switch .filter({ hasText: '客数' }) .filter({ hasText: '余次' }) .getByRole('switch'); await test.step('进入顾客分析-》项目余量分析', async () => { await homeNavigation.gotoModule('顾客'); await customerPage.gotoSubPage('顾客分析'); await customerAnalysisPage.gotoSubPage('项目余量分析'); }); let project = { name: '', className: '' }; await test.step('获取项目中客数最高的项目', async () => { await page.getByRole('cell', { name: '普通' }).locator('svg').nth(1).click(); await page.getByRole('cell', { name: '类别' }).waitFor(); const $firstProjectTr = page.locator('.main-table-body_tr').first(); await $firstProjectTr.waitFor(); const $firstProjectTd = $firstProjectTr.locator('td'); // 获取项目名称和项目类型名称 project.name = (await $firstProjectTd.first().innerText()).trim(); project.className = (await $firstProjectTd.nth(1).innerText()).trim(); }); expect(project.name).not.toBe(''); expect(project.className).not.toBe(''); await test.step('进入顾客详情', async () => { await customerPage.gotoSubPage('顾客概要'); await customerPage.searchCustomer(customer.phone); await customerPage.selectSearchCustomer(customer.username); await customerPage.openCustomerDetail(customer.username, customer.phone); }); await test.step('开单购买普通、赠送、体验各三次,并且各消耗一次', async () => { // 项目列表 const $$project = page.locator('.project_list'); await page.locator('span').filter({ hasText: '去开单' }).first().click(); await page.getByRole('main').getByText(project.className, { exact: true }).click(); // 普通三次 await $$project.getByText(project.name, { exact: true }).click(); await page.locator('#buyList').getByText('1', { exact: true }).click(); await numberInput.setValue(3); await numberInput.confirmValue(); // 体验三次 await $$project.getByText(project.name, { exact: true }).click(); await page.locator('#buyList').getByText('1', { exact: true }).click(); await numberInput.setValue(3); await numberInput.confirmValue(); await page.getByRole('button', { name: '普' }).click(); await page.getByText('体验', { exact: true }).click(); // 赠送三次 await $$project.getByText(project.name, { exact: true }).click(); await page.locator('#buyList').getByText('1', { exact: true }).click(); await numberInput.setValue(3); await numberInput.confirmValue(); await page.getByRole('button', { name: '普' }).click(); await page.getByText('赠送', { exact: true }).click(); // 普通、体验、赠送各消耗三次 await page.locator('#shoppingCart').getByText('雪肌晶纯护理').first().click(); await page.locator('#shoppingCart').getByText('雪肌晶纯护理').nth(1).click(); await page.locator('#shoppingCart').getByText('雪肌晶纯护理').nth(2).click(); // 结算 await page .locator('div') .filter({ hasText: /^结\s算$/ }) .click(); await page.locator('.paymentInfoItem', { 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(); console.log('Bill No:' + billNo); await expect(page.getByRole('button', { name: /开\s单/ })).toBeInViewport(); }); await test.step('进入顾客分析-》项目余量分析', async () => { await homeNavigation.gotoModule('顾客'); await customerPage.gotoSubPage('顾客分析'); await customerAnalysisPage.gotoSubPage('项目余量分析'); }); await test.step('查看类别', async () => { await page.getByText('选择项目类别').click(); await page.getByRole('option', { name: project.className }).click(); await Promise.all([ waitSpecifyApiLoad(page, ['/property_analysis']), page.getByRole('cell', { name: '普通' }).locator('svg').nth(1).click(), ]); // 判断项目存在 await expect(page.getByRole('cell', { name: project.name, exact: true })).toBeVisible(); }); // 项目所在行 const $projectTr = page .locator('.main-table-body_tr') .filter({ has: page.getByText(project.name) }) .filter({ has: page.getByText(project.className) }); // 弹窗内容 const $popup = page.locator('.popup_content'); // 弹窗内顾客的信息 const $customerTr = $popup .locator('.main-table-body_tr') .filter({ has: page.getByText(customer.username) }) .filter({ has: page.getByText(customer.phone) }); //普通 const $normalProjectTd = $projectTr.getByRole('cell').nth(2); //体验 const $experienceProjectTd = $projectTr.getByRole('cell').nth(3); //赠送 const $giveAwayProjectTd = $projectTr.getByRole('cell').nth(4); await test.step('查看数据', async () => { // 普通 await $normalProjectTd.click(); await expect($customerTr).toBeVisible(); await page.locator('.title > .close_icon > svg').click(); // 体验 await $experienceProjectTd.click(); await expect($customerTr).toBeVisible(); await page.locator('.title > .close_icon > svg').click(); // 赠送 await $giveAwayProjectTd.click(); await expect($customerTr).toBeVisible(); await page.locator('.title > .close_icon > svg').click(); }); // 顾客项目分析数据 const analysisData = { normal: -1, experience: -1, giveAway: -1, }; // 项目剩余次数 const $currentItemRemaining = page .locator('.proerty_summery .item') .filter({ has: page.getByText('项目余次') }) .locator('.item_num'); await test.step('显示已用完的项目、余次,查看数据', async () => { // 配置为显示已用完的项目和项目余次 await $passengersAndRemainder.click(); await page.locator('.setting_icon').click(); await page.getByLabel('显示已用完的项目').check(); await Promise.all([ waitSpecifyApiLoad(page, ['/property_analysis']), page.getByRole('button', { name: /保\s存/ }).click(), ]); // 获取项目余次数据 analysisData.normal = Number((await $normalProjectTd.innerText()).trim()); analysisData.experience = Number((await $experienceProjectTd.innerText()).trim()); analysisData.giveAway = Number((await $giveAwayProjectTd.innerText()).trim()); // 普通 await $normalProjectTd.click(); await expect($customerTr).toBeVisible(); const currentNormalData = Number((await $currentItemRemaining.innerText()).trim()); expect(currentNormalData).toBeGreaterThanOrEqual(analysisData.normal); await page.locator('.title > .close_icon > svg').click(); // 体验 await $experienceProjectTd.click(); await expect($customerTr).toBeVisible(); const currentExperienceData = Number((await $currentItemRemaining.innerText()).trim()); expect(currentExperienceData).toBeGreaterThanOrEqual(analysisData.experience); await page.locator('.title > .close_icon > svg').click(); // 赠送 await $giveAwayProjectTd.click(); await expect($customerTr).toBeVisible(); const currentGiveAwayData = Number((await $currentItemRemaining.innerText()).trim()); expect(currentGiveAwayData).toBeGreaterThanOrEqual(analysisData.giveAway); await page.locator('.title > .close_icon > svg').click(); }); // 项目剩余次数行 const $categoryTr = page.locator('.main-table-body_tr').filter({ has: page.getByText(project.className) }); //普通 const $normalProjectTdForCategory = $categoryTr.getByRole('cell').nth(1); //体验 const $experienceProjectTdForCategory = $categoryTr.getByRole('cell').nth(2); //赠送 const $giveAwayProjectTdForCategory = $categoryTr.getByRole('cell').nth(3); await test.step('分类、客数,查看数据', async () => { // 切换为分类和客数 await $categoryAndProject.click(); await $passengersAndRemainder.click(); // 普通 await $normalProjectTdForCategory.click(); await expect($customerTr).toBeVisible(); await page.locator('.title > .close_icon > svg').click(); // 体验 await $experienceProjectTdForCategory.click(); await expect($customerTr).toBeVisible(); await page.locator('.title > .close_icon > svg').click(); // 赠送 await $giveAwayProjectTdForCategory.click(); await expect($customerTr).toBeVisible(); await page.locator('.title > .close_icon > svg').click(); }); }); test('查看套餐消耗升单分析', async ({ page, homeNavigation, createCustomer, customerPage, numberInput }) => { const c = createCustomer; // 点击顾客 拿取初始数据 await homeNavigation.gotoModule('顾客'); await page.locator('.tab_item', { hasText: '顾客分析' }).click(); await page.getByText('顾客项目分析').click(); await page.getByRole('menuitem', { name: '套餐消耗升单分析' }).click(); // 选择套餐 await page.locator('.selectpage').click(); await page.getByLabel('A套餐(GK035)').check(); await page.getByRole('button', { name: '确定选择' }).click(); await page.locator('span').filter({ hasText: '选择员工' }).click(); await page.getByLabel('陈刚').check(); await page.getByRole('button', { name: '确定选择' }).click(); await page.getByRole('button', { name: '查询' }).click(); // 点击查看购买消耗升单 await page.locator('.table_top_center').click(); // 初始购买 const Initialbuy = await page.locator('.propomTop .propomSize').nth(0).innerText(); //购买 // 初始消耗 const Initialexpend = await page.locator('.propomTop .propomSize').nth(1).innerText(); //消耗 // 初始升单 const Initialupbills = await page.locator('.propomTop .propomSize').nth(2).innerText(); //升单 // 关闭窗口 await page .locator('div') .filter({ hasText: /^A套餐(GK035)合计$/ }) .locator('i') .click(); await page.reload(); await homeNavigation.gotoModule('收银'); await page.getByRole('button', { name: /^开\s单$/ }).click(); await customerPage.searchCustomer(c.phone); await customerPage.selectSearchCustomer(c.username); // 选择套餐 await page.locator('.float_tab').getByText('套餐').click(); // 选择A套餐 await page.locator('.project_one > .item').filter({ hasText: ProjectName.SetMeal.SetMeal_6.name }).click(); // 点击添加员工 await page.locator('#buyList').getByRole('button').nth(1).click(); // 选择员工1 const employee1 = Employees.FirstShop.Employee_6.name; await page.locator('.hand_txt .name_txt').getByText(employee1).click(); // 保存并复制到其他项目 await page.locator('button.save_and_copy').filter({ hasText: '保存并复制到其他项目/卖品' }).click(); // 结算 await page .locator('div') .filter({ hasText: /^结\s算$/ }) .click(); // 点击现金 await page.getByText('现金').click(); await page.getByLabel('推送消费提醒').uncheck(); await page.getByLabel('结算签字').uncheck(); await page.getByRole('button', { name: /^结\s算$/ }).click(); await page.getByRole('button', { name: /跳\s过/ }).click(); await expect.soft(page.locator('.ant-message', { hasText: '结算成功' })).toBeVisible(); await page.getByRole('button', { name: /^开\s单$/ }).click(); await customerPage.searchCustomer(c.phone); await customerPage.selectSearchCustomer(c.username); // 消耗该项目5次 await page.locator('.treat_card_content').first().click(); // 点击选择数量 await page.locator('.buy_number').click(); // 点击删除所有数量 await page.locator('div').filter({ hasText: /^123$/ }).getByRole('button').nth(3).click(); // 选择数量5 await numberInput.setValue(5); await numberInput.confirmValue(); // 点击添加员工 await page.locator('.staff_btn').click(); // 选择员工1 await page.locator('.hand_txt .name_txt').getByText(employee1).click(); // 保存并复制到其他项目 await page.locator('button.save_and_copy').filter({ hasText: '保存并复制到其他项目' }).click(); // 购买项目C await page.getByText(ProjectName.Projects.Projects_21.num).click(); // 点击选择数量 await page.locator('.edit_txt div:nth-child(2)').first().click(); // 点击删除所有数量 await page.locator('div').filter({ hasText: /^123$/ }).getByRole('button').nth(3).click(); // 选择数量2 await numberInput.setValue(2); await numberInput.confirmValue(); await page .locator('div') .filter({ hasText: /^结\s算$/ }) .click(); // 点击现金 await page.getByText('现金').click(); // 取消推送消息提醒 await page.getByLabel('推送消费提醒').uncheck(); // 取消结算签字 await page.getByLabel('结算签字').uncheck(); // 点击结算 await page.getByRole('button', { name: /^结\s算$/ }).click(); await expect.soft(page.locator('.ant-message', { hasText: '结算成功' })).toBeVisible(); await homeNavigation.gotoModule('顾客'); await page.locator('.tab_item', { hasText: '顾客分析' }).click(); await page.getByText('顾客项目分析').click(); await page.getByRole('menuitem', { name: '套餐消耗升单分析' }).click(); // 选择套餐 await page.locator('.selectpage').click(); await page.getByLabel('A套餐(GK035)').check(); await page.getByRole('button', { name: '确定选择' }).click(); await page.locator('.search_middle .select_multiple').click(); await page.getByLabel('陈刚').check(); await page.getByRole('button', { name: '确定选择' }).click(); await page.getByRole('button', { name: '查询' }).click(); // 点击查看购买消耗升单 await page.locator('.table_top_center').click(); await expect.soft(page.locator('.propomTop .propomSize').nth(0)).toContainText(`${Number(Initialbuy) + 1}`); await expect.soft(page.locator('.propomTop .propomSize').nth(1)).toContainText(`${Number(Initialexpend) + 1}`); await expect(page.locator('.propomTop .propomSize').nth(2)).toContainText(`${Number(Initialupbills) + 1}`); // 关闭窗口 await page .locator('div') .filter({ hasText: /^A套餐(GK035)合计$/ }) .locator('i') .click(); // 顾客行数 const allTr = page.locator('.m-table__body-wrapper tbody tr'); await allTr.first().waitFor(); let nowRow = await allTr.allInnerTexts().then(async text => { return text.findIndex(item => item.includes(c.phone)); }); const ProjectA = ProjectName.Projects.Projects_19.name; const ProjectB = ProjectName.Projects.Projects_20.name; const ProjectC = ProjectName.Projects.Projects_21.name; // 员工(陈刚) await expect( page.locator('.m-table__body-wrapper tbody tr').nth(nowRow).locator('td:nth-child(4)'), ).toContainText(employee1); // 套餐消耗(水娃娃x5) await expect( page.locator('.m-table__body-wrapper tbody tr').nth(nowRow).locator('td:nth-child(5) .projectName'), ).toContainText(ProjectA + 'x5'); // 升单(德国原装冰吻之恋x2) await expect( page.locator('.m-table__body-wrapper tbody tr').nth(nowRow).locator('td:nth-child(6) .projectName'), ).toContainText(ProjectC + 'x2'); // 套餐结余(水娃娃x5 德国原装水元素x5) await expect( page.locator('.m-table__body-wrapper tbody tr').nth(nowRow).locator('td:nth-child(7)'), ).toContainText(ProjectA + 'x5'); await expect( page.locator('.m-table__body-wrapper tbody tr').nth(nowRow).locator('td:nth-child(7)'), ).toContainText(ProjectB + 'x5'); }); }); test.describe('批量操作', () => { let usePhones = Array(8).fill(null); // 创建一个长度为8的数组,初始值为null(表示未设置) test.beforeEach(async ({ page }) => { // 监听响应事件 await page.addLocatorHandler( page.locator('.popup_content .ant-btn-primary', { hasText: '我知道了' }), async () => { await page.locator('.popup_content .ant-btn-primary').click(); await expect(page.locator('.popup_content .ant-btn-primary')).not.toBeVisible(); }, ); }); test('顾客分配', async ({ page, homeNavigation }) => { await page.reload(); // 进入顾客界面 await homeNavigation.gotoModule('顾客'); // 点击潜客 await page.locator('.sub_icon').nth(3).click(); // 打开顾客列表 // await page.getByRole("menuitem", { name: "打开顾客列表" }).click(); // 选中第一个顾客 await page.locator('.m-table__fixed-left .is-center').nth(1).click(); // 点击第二页 await page.locator('.ant-pagination-item-2').click(); // 选中第一个顾客 await page.locator('.m-table__fixed-left .is-center').nth(1).click(); // 批量操作 await page.locator('.item-btns', { hasText: /^批量操作$/ }).click(); // 顾客分配 await page.getByRole('menuitem', { name: '顾客分配' }).click(); await expect(async () => { try { await page.locator('.label_text', { hasText: '移除已分配咨询师' }).waitFor({ timeout: 2000 }); await page.locator('.label_text', { hasText: '移除已分配咨询师' }).click(); } catch { // 关闭窗口 await page.locator('.ant-modal-close-x').click(); // 批量操作 await page.locator('.item-btns', { hasText: /^批量操作$/ }).click(); // 顾客分配 await page.getByRole('menuitem', { name: '顾客分配' }).click(); await page.locator('.label_text', { hasText: '移除已分配咨询师' }).waitFor({ timeout: 2000 }); await page.locator('.label_text', { hasText: '移除已分配咨询师' }).click(); } }).toPass(); // // 点击已经已分配 // await page.locator(".label_text", { hasText: "移除已分配咨询师" }).click(); // 确认分配 await page.getByRole('button', { name: '确认分配' }).click(); await expect(page.locator('.ant-message', { hasText: '操作成功' })).toBeVisible(); // 确保清完已分配重新进入进行分配 await page.reload(); // 进入顾客界面 await homeNavigation.gotoModule('顾客'); // 点击潜客 await page.locator('.sub_icon').nth(3).click(); // 打开顾客列表 // await page.getByRole("menuitem", { name: "打开顾客列表" }).click(); // 选中第一个顾客 await page.locator('.m-table__fixed-left .is-center').nth(1).click(); // 点击第二页 await page.locator('.ant-pagination-item-2').click(); // 选中第一个顾客 await page.locator('.m-table__fixed-left .is-center').nth(1).click(); // 批量操作 await page.locator('.item-btns', { hasText: /^批量操作$/ }).click(); // 顾客分配 await page.getByRole('menuitem', { name: '顾客分配' }).click(); // 选择员工A let nowRowA = 0; const employee1 = Employees.FirstShop.Employee_3.name; const allTrA = page.locator('.ant-tree-child-tree-open').first().locator('.ant-tree-treenode-switcher-open'); const countA = await allTrA.count(); // 获取第几个 for (let i = 0; i < countA; i++) { const trA = allTrA.nth(i); const employee = await trA.locator('.ant-tree-title').innerText(); console.log(employee); if (employee.includes(employee1)) { nowRowA = i; break; } } await page .locator('.ant-tree-child-tree-open') .first() .locator('.ant-tree-treenode-switcher-open') .nth(nowRowA) .click(); // 选择员工B let nowRowB = 0; const employee2 = Employees.FirstShop.Employee_4.name; const allTrB = page.locator('.ant-tree-child-tree-open').first().locator('.ant-tree-treenode-switcher-open'); const countB = await allTrB.count(); // 获取第几个 for (let i = 0; i < countB; i++) { const trB = allTrB.nth(i); const employeeB = await trB.locator('.ant-tree-title').innerText(); console.log(employeeB); if (employeeB.includes(employee2)) { nowRowB = i; break; } } await page .locator('.ant-tree-child-tree-open') .first() .locator('.ant-tree-treenode-switcher-open') .nth(nowRowB) .click(); // 确认分配 await page.getByRole('button', { name: '确认分配' }).click(); // 操作成功 await expect(page.locator('.ant-message-notice', { hasText: '操作成功' })).toBeVisible(); await page.reload(); // 进入顾客界面 await homeNavigation.gotoModule('顾客'); // 点击潜客 await page.locator('.sub_icon').nth(3).click(); // 打开顾客列表 // await page.getByRole("menuitem", { name: "打开顾客列表" }).click(); // 点击第一个会员 await page.locator('.m-table__fixed-left .user_info').first().click(); // 等待基本资料加载完成 await page.locator('.basic_box .base_info').first().waitFor(); // 判断这两员工是否分配到了 const employeeResult = await page.locator('.description .employees_txt').innerText(); expect(employeeResult).toBe(employee1 + '、' + employee2); // 关闭详情回到顾客列表 await page.locator('.close_icons').click(); // 点击第二页 await page.locator('.ant-pagination-item-2').click(); // 点击第一个会员 await page.locator('.m-table__fixed-left .user_info').first().click(); // 等待基本资料加载完成 await page.locator('.basic_box .base_info').first().waitFor(); // 判断这两员工是否分配到了 expect(employeeResult).toBe(employee1 + '、' + employee2); await page.reload(); // 进入顾客界面 await homeNavigation.gotoModule('顾客'); // 点击潜客 await page.locator('.sub_icon').nth(3).click(); // 选中第一个顾客 await page.locator('.m-table__fixed-left .is-center').nth(1).click(); // 点击第二页 await page.locator('.ant-pagination-item-2').click(); // 选中第一个顾客 await page.locator('.m-table__fixed-left .is-center').nth(1).click(); // 批量操作 await page.locator('.item-btns', { hasText: /^批量操作$/ }).click(); // 顾客分配 await page.getByRole('menuitem', { name: '顾客分配' }).click(); // 点击已经已分配 await page.locator('.label_text', { hasText: '移除已分配咨询师' }).click(); // 确认分配 await page.getByRole('button', { name: '确认分配' }).click(); // 操作成功 await expect(page.locator('.ant-message-notice', { hasText: '操作成功' })).toBeVisible(); }); test('新增待办', async ({ page, homeNavigation }) => { // 随机数字备注 const remark = faker.helpers.fromRegExp(/1[3-9][0-9]{7}/); await test.step('勾选会员并记录该会员手机', async () => { // 进入顾客界面 await homeNavigation.gotoModule('顾客'); // 点击潜客 await page.locator('.sub_icon').nth(3).click(); // 获取准备选中的会员手机1 await page.locator('.m-table-pagination .dec').waitFor(); const member = page.locator('.m-table__fixed-left tbody tr'); usePhones[0] = await member.locator('td .user_info_body').first().innerText(); // 选中第一个顾客 await page.locator('.m-table__fixed-left .is-center').nth(1).click(); // 点击第下一页 await page.locator('.ant-pagination-next').click(); // 获取准备选中的会员手机2 await expect(page.locator('.m-table__icon__warp')).toBeHidden(); usePhones[1] = await member.locator('td .user_info_body').first().innerText(); console.log('手机1=' + usePhones[0] + '手机2=' + usePhones[1]); // 选中第一个顾客 await page.locator('.m-table__fixed-left .is-center').nth(1).click(); }); await test.step('批量操作新增待办', async () => { // 判断批量操作出现 const Batch = page.locator('.item-btns', { hasText: '批量操作' }); await expect(Batch).toBeVisible(); // 批量操作 await page.locator('.item-btns', { hasText: /^批量操作$/ }).click(); // 点击新增代办事项 await page.getByRole('menuitem', { name: '新增待办事项' }).click(); await page.locator('.a_title').waitFor(); const title = (await page.locator('.a_title').innerText()).trim(); expect.soft(title).toBe('批量新增事项'); await expect(async () => { await page.getByPlaceholder('请选择日期').click(); await page.locator('.date_picker_today', { hasText: '今天' }).click(); await page.locator('.normal', { hasText: '今天' }).waitFor({ timeout: 2000 }); }).toPass(); // 选择类型 await page.locator('.ant-radio-button-wrapper', { hasText: '电话回访' }).click(); // 填入随机备注 await page.getByPlaceholder('请输入1-100个字符的备注内容').fill(remark); await page.locator('.shop_btn', { hasText: '确认添加' }).click(); await page.locator('.ant-message', { hasText: '操作成功' }).waitFor(); await expect.soft(page.locator('.ant-message', { hasText: '操作成功' })).toBeVisible(); }); await test.step('校验数据', async () => { // 点击第一个会员 await page.locator('.m-table__fixed-left .m-table__body tbody tr').first().locator('td').nth(1).click(); await page.locator('.consume_data').waitFor(); // 点击动态 await page.locator('.ant-tabs-nav-animated .ant-tabs-tab', { hasText: '动态' }).click(); await page.locator('.ant-fullcalendar-tbody').first().waitFor(); // 切换列表模式 if (await page.locator('.selected_btn', { hasText: '日历模式' }).isVisible()) { await page.locator('.date_change').first().click(); } else { console.log('无需切换'); } await page.locator('.ant-tabs-tabpane-active .m-table__body-wrapper').waitFor(); const success = page.locator('.ant-tabs-tabpane-active .m-table__body-wrapper .m-table__body tbody tr'); const success_color = await success .filter({ has: page.locator('td', { hasText: remark }) }) .locator('td') .nth(2) .innerText(); expect.soft(success_color).toBe('已完成'); await page.locator('.close_icons').click(); }); }); test('设置标签', async ({ page, homeNavigation }) => { await test.step('勾选会员并记录该会员手机', async () => { // 进入顾客界面 await homeNavigation.gotoModule('顾客'); // 点击潜客 await page.locator('.sub_icon').nth(3).click(); // 获取准备选中的会员手机1 await page.locator('.m-table-pagination .dec').waitFor(); const member = page.locator('.m-table__fixed-left tbody tr'); usePhones[2] = await member.locator('td .user_info_body').first().innerText(); // 选中第一个顾客 await page.locator('.m-table__fixed-left .is-center').nth(1).click(); // 点击第下一页 await page.locator('.ant-pagination-next').click(); // 获取准备选中的会员手机2 await expect(page.locator('.m-table__icon__warp')).toBeHidden(); usePhones[3] = await member.locator('td .user_info_body').first().innerText(); console.log('手机1=' + usePhones[2] + '手机2=' + usePhones[3]); // 选中第一个顾客 await page.locator('.m-table__fixed-left .is-center').nth(1).click(); }); await test.step('批量操作设置标签', async () => { // 判断批量操作出现 const Batch = page.locator('.item-btns', { hasText: '批量操作' }); await expect(Batch).toBeVisible(); // 批量操作 await page.locator('.item-btns', { hasText: /^批量操作$/ }).click(); // 点击设置标签 await page.getByRole('menuitem', { name: '设置标签' }).click(); // 等待选择标签出现 await page.locator('.ant-modal-title', { hasText: '选择标签' }).waitFor(); // 点击两次标题全选 全取消 await page.locator('.ant-tree-title', { hasText: '顾客六期管理' }).click(); const check = page.locator('.ant-tree-checkbox-checked').first(); await expect(check).toBeVisible(); await page.locator('.ant-tree-title', { hasText: '顾客六期管理' }).click(); await expect(check).not.toBeVisible(); // 选择铺垫期、销售期 await page.locator('.ant-tree-title', { hasText: '铺垫期' }).click(); await page.locator('.ant-tree-node-selected', { hasText: '铺垫期' }).waitFor(); await page.locator('.ant-tree-title', { hasText: '销售期' }).click(); await page.locator('.ant-tree-node-selected', { hasText: '销售期' }).waitFor(); // 确认 await page.locator('.ok_btn', { hasText: /^确\s认$/ }).click(); }); await test.step('校验数据', async () => { // 根据获取的手机号码搜索该会员 await page.getByPlaceholder('姓名(拼音首字)、手机号、档案号搜索').fill(usePhones[2]); await page.locator('.ant-input-suffix', { hasText: '搜索' }).click(); // 等待会员数据弹出 await page.locator('.alertBox .close').waitFor(); // 根据指定手机点击会员 await page.locator('.member_list_li').filter({ hasText: usePhones[2] }).click(); // 点击进入详情 await page.locator('.m-table__fixed-left .user_info_body', { hasText: usePhones[2] }).click(); // 等待基础资料特定界面出现 await page.locator('.basic_box .base_info').first().waitFor(); // 判断标签显示是否正确 const pdq = await page.locator('.sign_txt', { hasText: '铺垫期' }).innerText(); expect(pdq).toBe('铺垫期'); const xxq = await page.locator('.sign_txt', { hasText: '销售期' }).innerText(); expect(xxq).toBe('销售期'); // 顺带去掉该标签 await page.locator('.sign .edit_icon').click(); await page.locator('.ant-tree-title', { hasText: '顾客六期管理' }).click(); const checks = page.locator('.ant-tree-checkbox-checked').first(); await expect(checks).toBeVisible(); await page.locator('.ant-tree-title', { hasText: '顾客六期管理' }).click(); await expect(checks).not.toBeVisible(); await page.locator('.ok_btn', { hasText: /^确\s认$/ }).click(); await page.locator('.close_icons').click(); // 根据获取手机搜索会员 await page.getByPlaceholder('姓名(拼音首字)、手机号、档案号搜索').fill(usePhones[3]); await page.locator('.ant-input-suffix', { hasText: '搜索' }).click(); // 等待会员数据弹出 await page.locator('.alertBox .close').waitFor(); // 根据指定手机点击会员 await page.locator('.member_list_li').filter({ hasText: usePhones[3] }).click(); // 点击进入详情 await page.locator('.m-table__fixed-left .user_info_body', { hasText: usePhones[3] }).click(); // 等待基础资料特定界面出现 await page.locator('.basic_box .base_info').first().waitFor(); // 判断标签显示是否正确 expect.soft(pdq).toBe('铺垫期'); expect(xxq).toBe('销售期'); // 顺带去掉该标签 await page.locator('.sign .edit_icon').click(); await page.locator('.ant-tree-title', { hasText: '顾客六期管理' }).click(); await expect(checks).toBeVisible(); await page.locator('.ant-tree-title', { hasText: '顾客六期管理' }).click(); await expect(checks).not.toBeVisible(); await page.locator('.ok_btn', { hasText: /^确\s认$/ }).click(); }); }); test('设置无效客', async ({ page, homeNavigation, customerPage }) => { let usernameA; let phoneA; const ca = new Customer(1, 1); await test.step('创建会员', async () => { // 创建顾客 await customerPage.createCustomer(ca); usernameA = ca.username; phoneA = ca.phone; }); await test.step('搜索创建的会员设置无效客', async () => { // 进入顾客界面 await homeNavigation.gotoModule('顾客'); await page.getByPlaceholder('姓名(拼音首字)、手机号、档案号搜索').fill(phoneA); await expect(async () => { await page.locator('.ant-input-suffix', { hasText: '搜索' }).click(); await page.locator('.alertBox .close').waitFor(); await page.locator('.member_list_li').filter({ hasText: usernameA }).click(); const useinfo = page.locator('.member_list_li').filter({ hasText: usernameA }); await expect(useinfo).not.toBeVisible(); const member = page.locator('.m-table__fixed-left tbody tr'); await member.locator('td .user_info_body', { hasText: phoneA }).first().waitFor(); }).toPass(); // 选中第一个顾客 await page.locator('.m-table__fixed-left .is-center').nth(1).click(); // 判断批量操作出现 const Batch = page.locator('.item-btns', { hasText: '批量操作' }); await expect(Batch).toBeVisible(); // 批量操作 await page.locator('.item-btns', { hasText: /^批量操作$/ }).click(); // 点击设为无效客 await page.getByRole('menuitem', { name: '设为无效客' }).click(); // 确认 await page.locator('.comfirm_btn', { hasText: /^确\s认$/ }).click(); await expect(page.locator('.ant-message', { hasText: '操作成功' })).toBeVisible(); }); await test.step('高级搜索无效客', async () => { // 点击高级搜索 await page.locator('.ant-btn-default', { hasText: /^高\s级$/ }).click(); await page.locator('.shopSelect_title', { hasText: '顾客高级查询' }).waitFor(); // 点击两次全选确保所有门店默认未选 await page .locator('.item_sub') .filter({ has: page.locator('.item_name', { hasText: '所属门店' }) }) .locator('.item_val') .click(); await page .locator('.comPicker_btn', { hasText: /^全\s选$/ }) .first() .click(); // 判断某个门店被选中 await expect(page.locator('.ant-checkbox-wrapper-checked', { hasText: 'AT测试一店' })).toBeVisible(); await page .locator('.comPicker_btn', { hasText: /^全\s选$/ }) .first() .click(); // 判断门店未被选中 await expect(page.locator('.ant-checkbox-wrapper-checked', { hasText: 'AT测试一店' })).not.toBeVisible(); await page.locator('.label_checkbox', { hasText: 'AT测试一店' }).click(); // 确认选中一店 await expect(page.locator('.ant-checkbox-wrapper-checked', { hasText: 'AT测试一店' })).toBeVisible(); await page.locator('.ant-btn-primary', { hasText: '确定选择' }).nth(1).click(); // 搜索关键字手机 await page.getByPlaceholder('姓名(拼音首字)、手机号、档案号搜索').fill(phoneA); await page .locator('.ant-checkbox-wrapper') .filter({ has: page.locator('.needsclick', { hasText: '无效客' }) }) .locator('.ant-checkbox') .click(); const Invalid = page.locator('.ant-checkbox-wrapper-checked', { hasText: '无效客' }); // 判断无效客选中 await expect(Invalid).toBeVisible(); // 点击搜索 await page.locator('.ant-btn-block').click(); await expect(page.locator('.m-table__icon__warp')).toBeHidden(); const $use = page.locator('.m-table__fixed-left tbody tr').first(); await expect(async () => { if (await $use.isVisible()) { await expect(page.locator('.m-table__fixed-left tbody tr', { hasText: phoneA })).toBeVisible(); } else { // 点击高级搜索 await page.locator('.ant-btn-default', { hasText: /^高\s级$/ }).click(); await page.locator('.shopSelect_title', { hasText: '顾客高级查询' }).waitFor(); // 点击搜索 await page.locator('.ant-btn-block').click(); } }).toPass(); }); }); test('设置会员分类', async ({ page, homeNavigation }) => { await test.step('勾选会员并记录该会员手机', async () => { // 进入顾客界面 await homeNavigation.gotoModule('顾客'); // 点击潜客 await page.locator('.sub_icon').nth(3).click(); // 获取准备选中的会员手机1 await page.locator('.m-table-pagination .dec').waitFor(); const member = page.locator('.m-table__fixed-left tbody tr'); usePhones[4] = await member.locator('td .user_info_body').first().innerText(); // 选中第一个顾客 await page.locator('.m-table__fixed-left .is-center').nth(1).click(); // 点击第下一页 await page.locator('.ant-pagination-next').click(); // 获取准备选中的会员手机2 await expect(page.locator('.m-table__icon__warp')).toBeHidden(); usePhones[5] = await member.locator('td .user_info_body').first().innerText(); console.log('手机1=' + usePhones[4] + '手机2=' + usePhones[5]); // 选中第一个顾客 await page.locator('.m-table__fixed-left .is-center').nth(1).click(); }); await test.step('批量操作设置会员分类', async () => { // 判断批量操作出现 const Batch = page.locator('.item-btns', { hasText: '批量操作' }); await expect(Batch).toBeVisible(); // 批量操作 await page.locator('.item-btns', { hasText: /^批量操作$/ }).click(); // 点击设置会员分类 await page.getByRole('menuitem', { name: '设置会员分类' }).click(); // 等待设置会员分类出现 await page.locator('.ant-model-title', { hasText: '设置会员分类' }).waitFor(); await expect(async () => { // 选择铺(铺垫期) await page.locator('.class_tag .tag', { hasText: '铺' }).click(); const check = page.locator('.select_style'); await expect(check).toBeVisible({ timeout: 2000 }); // 确认 await page.locator('.comfirm_btn', { hasText: /^确\s认$/ }).click(); await page.locator('.ant-message', { hasText: '操作成功' }).waitFor({ timeout: 5000 }); }).toPass(); }); await test.step('校验数据', async () => { // 根据获取的手机号码搜索该会员 await page.getByPlaceholder('姓名(拼音首字)、手机号、档案号搜索').fill(usePhones[4]); await page.locator('.ant-input-suffix', { hasText: '搜索' }).click(); // 等待会员数据弹出 await page.locator('.alertBox .close').waitFor(); // 根据指定手机点击会员 await page.locator('.member_list_li').filter({ hasText: usePhones[4] }).click(); // 点击进入详情 await page.locator('.m-table__fixed-left .user_info_body', { hasText: usePhones[4] }).click(); // 等待基础资料特定界面出现 await page.locator('.basic_box .base_info').first().waitFor(); // 判断分类显示是否正确 const sort = page.locator('.tag_list .class_icon .icon_style', { hasText: '铺' }); await expect(sort).toBeVisible(); // 去掉该分类判断一下是否消失 // 点击三点 await page.locator('.more_icon svg').click(); // 选择会员分类设置 await page.locator('.ant-dropdown-menu-item', { hasText: '设置会员分类' }).click(); // 等待设置会员分类出现 await page.locator('.ant-model-title', { hasText: '设置会员分类' }).waitFor(); // 点击被选中的分类 await page.locator('.select_style').click(); // 判断选中分类已取消 await expect(page.locator('.select_style')).not.toBeVisible(); // 确认 await page.locator('.comfirm_btn', { hasText: /^确\s认$/ }).click(); // 关闭详情 await page.locator('.close_icons').click(); // 根据获取的手机号码搜索该会员 await page.getByPlaceholder('姓名(拼音首字)、手机号、档案号搜索').fill(usePhones[5]); await page.locator('.ant-input-suffix', { hasText: '搜索' }).click(); // 等待会员数据弹出 await page.locator('.alertBox .close').waitFor(); // 根据指定手机点击会员 await page.locator('.member_list_li').filter({ hasText: usePhones[5] }).click(); // 点击进入详情 await page.locator('.m-table__fixed-left .user_info_body', { hasText: usePhones[5] }).click(); // 等待基础资料特定界面出现 await page.locator('.basic_box .base_info').first().waitFor(); // 判断分类显示是否正确 await expect.soft(sort).toBeVisible(); // 去掉该分类判断一下是否消失 // 点击三点 await page.locator('.more_icon svg').click(); // 选择会员分类设置 await page.locator('.ant-dropdown-menu-item', { hasText: '设置会员分类' }).click(); // 等待设置会员分类出现 await page.locator('.ant-model-title', { hasText: '设置会员分类' }).waitFor(); // 点击被选中的分类 await page.locator('.select_style').click(); // 判断选中分类已取消 await expect(page.locator('.select_style')).not.toBeVisible(); // 确认 await page.locator('.comfirm_btn', { hasText: /^确\s认$/ }).click(); // 关闭详情 await page.locator('.close_icons').click(); }); }); test('赠送积分', async ({ page, homeNavigation, numberInput }) => { //输入积分 const points = 8; await test.step('勾选会员并记录该会员手机', async () => { // 进入顾客界面 await homeNavigation.gotoModule('顾客'); // 点击潜客 await page.locator('.sub_icon').nth(3).click(); // 获取准备选中的会员手机1 await page.locator('.m-table-pagination .dec').waitFor(); const member = page.locator('.m-table__fixed-left tbody tr'); usePhones[6] = await member.locator('td .user_info_body').first().innerText(); // 选中第一个顾客 await page.locator('.m-table__fixed-left .is-center').nth(1).click(); // 点击第下一页 await page.locator('.ant-pagination-next').click(); // 获取准备选中的会员手机2 await expect(page.locator('.m-table__icon__warp')).toBeHidden(); usePhones[7] = await member.locator('td .user_info_body').first().innerText(); console.log('手机1=' + usePhones[6] + '手机2=' + usePhones[7]); // 选中第一个顾客 await page.locator('.m-table__fixed-left .is-center').nth(1).click(); }); await test.step('批量操作赠送积分', async () => { // 判断批量操作出现 const Batch = page.locator('.item-btns', { hasText: '批量操作' }); await expect(Batch).toBeVisible(); // 批量操作 await page.locator('.item-btns', { hasText: /^批量操作$/ }).click(); // 点击赠送积分 await page.getByRole('menuitem', { name: '赠送积分' }).click(); // 等待赠送积分出现 await page.locator('.popup_content .title', { hasText: '赠送积分' }).waitFor(); // 输入积分 await numberInput.setValue(points); await numberInput.confirmValue(); await page.locator('.ant-message-custom-content', { hasText: '赠送成功,预计10分钟内到账' }).waitFor(); await expect( page.locator('.ant-message-custom-content', { hasText: '赠送成功,预计10分钟内到账', }), ).toBeVisible(); }); await test.step('校验核对', async () => { await page.getByPlaceholder('姓名(拼音首字)、手机号、档案号搜索').fill(usePhones[6]); await page.locator('.ant-input-suffix', { hasText: '搜索' }).click(); // 等待会员数据弹出 await page.locator('.alertBox .close').waitFor(); // 根据指定手机点击会员 await page.locator('.member_list_li').filter({ hasText: usePhones[6] }).click(); // 点击进入详情 await page.locator('.m-table__fixed-left .user_info_body', { hasText: usePhones[6] }).click(); // 等待基础资料特定界面出现 await page.locator('.basic_box .base_info').first().waitFor(); // 详情页点击流水 await page.locator('.ant-tabs-tab', { hasText: '流水' }).click(); // 等待页面加载 await page.locator('.tab_btn .ant-radio-button-wrapper').first().waitFor(); // 点击积分记录 await page.locator('.tab_btn .ant-radio-button-wrapper', { hasText: '积分记录' }).click(); // 获取积分变动 await expect(page.locator('.positive').first()).toContainText(`${points}`); }); }); test('群发优惠券', async ({ page, homeNavigation }) => { // 用于存储会员名称 let useNames: string[]; await test.step('勾选会员并记录该会员手机', async () => { // 进入顾客界面 await homeNavigation.gotoModule('顾客'); // 点击潜客 await page.locator('.sub_icon').nth(3).click(); // 打开顾客列表 // 获取准备选中的会员手机1 await page.locator('.m-table-pagination .dec').waitFor(); const member = page.locator('.m-table__fixed-left tbody tr'); useNames[0] = await member.locator('td .user_name').first().innerText(); // 选中第一个顾客 await page.locator('.m-table__fixed-left .is-center').nth(1).click(); // 点击第下一页 await page.locator('.ant-pagination-next').click(); // 获取准备选中的会员手机2 await expect.soft(page.locator('.m-table__icon__warp')).toBeHidden(); useNames[1] = await member.locator('td .user_name').first().innerText(); console.log('姓名1=' + useNames[0] + '姓名2=' + useNames[1]); // 选中第一个顾客 await page.locator('.m-table__fixed-left .is-center').nth(1).click(); }); await test.step('批量操作赠送积分', async () => { // 判断批量操作出现 const Batch = page.locator('.item-btns', { hasText: '批量操作' }); await expect(Batch).toBeVisible(); // 批量操作 await page.locator('.item-btns', { hasText: /^批量操作$/ }).click(); // 点击群发优惠券 await page.getByRole('menuitem', { name: '群发优惠券' }).click(); // 等待群发优惠券出现 await page.locator('.m_sliding_menu .header', { hasText: '群发优惠券' }).waitFor(); // 点击添加优惠券 await page.locator('.add_txt', { hasText: '添加优惠券' }).click(); await page.locator('.popup_content .title', { hasText: '选择优惠券' }).waitFor(); // 选择优惠券 await page.locator('.check_item').click(); // 判断是否选中 const coupon = page.locator('.ant-checkbox-checked').first(); await expect(coupon).toBeVisible(); // 保存 await page.locator('.confirm_btn', { hasText: /^保\s存$/ }).click(); const coupons = page.locator('.coupon_list').first(); await expect(coupons).toBeVisible(); // 确认发送 await page.locator('.sure_btn span', { hasText: '确认发送' }).click(); await page.locator('.handle_task_content').waitFor(); // 点击顾客列表 await page.locator('.m-table__fixed-right tbody .gustom_list_btn').first().click(); // 等待发送顾客列表 await page.locator('.custom_list_content .header').first().waitFor(); await expect.soft(page.locator('.custom_name').first()).toContainText(useNames[0]); await expect(page.locator('.custom_name').last()).toContainText(useNames[1]); }); }); });