diff --git a/playwright.config.js b/playwright.config.js index 366ac72..9e67eef 100644 --- a/playwright.config.js +++ b/playwright.config.js @@ -2,6 +2,7 @@ const { defineConfig, devices } = require('@playwright/test'); // import dotenv from "dotenv"; import path from 'path'; + /** * Read environment variables from file. * https://github.com/motdotla/dotenv @@ -41,7 +42,8 @@ module.exports = defineConfig({ /* Opt out of parallel tests on CI. */ workers: process.env.CI ? 1 : 2, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: [['html'], ['list'], ['./my-awesome-reporter.ts']], + // reporter: [['html'], ['list'], ['./my-awesome-reporter.ts']], + reporter: [['html'], ['list']], // reporter: './my-awesome-reporter.ts', /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ @@ -71,12 +73,12 @@ module.exports = defineConfig({ projects: [ { name: '总部管理员鉴权', - testMatch: /.*boss_auth\.setup\.js/, + testMatch: /.*boss_auth\.setup\.ts/, use: { baseURL: process.env.BASE_URL }, }, { name: '门店员工鉴权', - testMatch: /.*staff_auth\.setup\.js/, + testMatch: /.*staff_auth\.setup\.ts/, use: { baseURL: process.env.BASE_URL }, }, { @@ -88,7 +90,7 @@ module.exports = defineConfig({ viewport: { width: 1280, height: 720 }, isMobile: true, }, - testMatch: /.*boss_.*\.spec\.js/, + testMatch: /.*boss_.*\.spec\.ts/, dependencies: ['总部管理员鉴权'], }, { @@ -100,7 +102,7 @@ module.exports = defineConfig({ viewport: { width: 1280, height: 720 }, isMobile: true, }, - testMatch: /.*boss_.*\.spec\.js/, + testMatch: /.*boss_.*\.spec\.ts/, dependencies: ['总部管理员鉴权'], }, { @@ -111,7 +113,7 @@ module.exports = defineConfig({ viewport: { width: 1280, height: 720 }, isMobile: false, }, - testMatch: /.*staff_.*\.spec\.js/, + testMatch: /.*staff_.*\.spec\.ts/, dependencies: ['门店员工鉴权'], }, { @@ -122,7 +124,7 @@ module.exports = defineConfig({ viewport: { width: 1280, height: 720 }, isMobile: false, }, - testMatch: /.*staff_.*\.spec\.js/, + testMatch: /.*staff_.*\.spec\.ts/, dependencies: ['门店员工鉴权'], }, ], diff --git a/tests/fixtures/customerFixture.ts b/tests/fixtures/customerFixture.ts index 24742ae..40a21d1 100644 --- a/tests/fixtures/customerFixture.ts +++ b/tests/fixtures/customerFixture.ts @@ -1,16 +1,8 @@ -import { test as base } from '@playwright/test'; +import { test as base, Page } from '@playwright/test'; import { CustomerPage, CustomerDetailsPage, CustomerAnalysisPage } from '@/pages/customer'; import { Customer } from '@/utils/customer'; type MyFixture = { - singleCustomerPage: { - createCustomer: (customer: Customer) => Promise; - setInvalidCustomer: (customer: Customer) => Promise; - }; - moreCustomerPage: { - createMoreCustomer: (customer: Customer[]) => Promise; - setMoreInvalidCustomer: (customer: Customer[]) => Promise; - }; customerPage: CustomerPage; customerDetailsPage: CustomerDetailsPage; customerAnalysisPage: CustomerAnalysisPage; @@ -20,34 +12,50 @@ type MyFixture = { createCustomCustomers: (customers: Customer[]) => Promise; }; +/** + * 跳转到顾客管理页面 + */ +const navigateToCustomerSchema = async (page: Page, baseURL: string) => { + await page.goto(baseURL); + await page.getByRole('button', { name: /开\s单/ }).waitFor(); + await page.goto('/#/member/member-schame'); +}; + +/** + * 设置为无效顾客 + * @param customerPage { CustomerPage } 顾客页面 + * @param customers { Customer | Customer[] } 顾客列表 + */ +const setInvalidCustomers = async (customerPage: CustomerPage, customers: Customer[] | Customer) => { + try { + if (Array.isArray(customers)) { + await customerPage.setMoreInvalidCustomer(customers); + } else { + await customerPage.setInvalidCustomer(customers); + } + } catch (error) { + console.error('Failed to set invalid customers:', error); + throw error; + } +}; + export const test = base.extend({ /** * 创建一个顾客 */ createCustomer: async ({ page, baseURL }, use) => { - if (!baseURL) { - throw new Error('baseUrl is required'); - } - const customerPage = new CustomerPage(page); const customer = new Customer(1, 1); await customerPage.createCustomer(customer); - await page.goto(baseURL); await use(customer); - await page.goto(baseURL); - await page.getByRole('button', { name: /开\s单/ }).waitFor(); - await page.goto('/#/member/member-schame'); - await customerPage.setInvalidCustomer(customer); + await navigateToCustomerSchema(page, baseURL!); + await setInvalidCustomers(customerPage, customer); }, /** * 创建多个顾客 */ createCustomers: async ({ page, baseURL }, use): Promise => { - if (!baseURL) { - throw new Error('baseUrl is required'); - } - const customerPage = new CustomerPage(page); let createdCustomers: Customer[] = []; @@ -70,56 +78,44 @@ export const test = base.extend({ if (createdCustomers.length === 0) return; - // 测试结束后将客户设置为无效 - await page.goto(baseURL); - await page.getByRole('button', { name: /开\s单/ }).waitFor(); - await page.goto('/#/member/member-schame'); - await customerPage.setMoreInvalidCustomer(createdCustomers); + await navigateToCustomerSchema(page, baseURL!); + await setInvalidCustomers(customerPage, createdCustomers); }, /** * 创建一个自定义顾客 */ createCustomCustomer: async ({ page, baseURL }, use) => { - if (!baseURL) { - throw new Error('baseUrl is required'); - } - const customerPage = new CustomerPage(page); - let tmp: Customer | undefined; - const setCustomer = async (customer: Customer) => { - await customerPage.createCustomer(customer); - tmp = customer; - }; - await use(setCustomer); + let customizeCustomer: Customer | undefined; - if (!tmp) return; - await page.goto(baseURL); - await page.getByRole('button', { name: /开\s单/ }).waitFor(); - await page.goto('/#/member/member-schame'); - await customerPage.setInvalidCustomer(tmp); + const createCustomizeCustomer = async (customer: Customer) => { + await customerPage.createCustomer(customer); + customizeCustomer = customer; + }; + + await use(createCustomizeCustomer); + + if (!customizeCustomer) return; + await navigateToCustomerSchema(page, baseURL!); + await setInvalidCustomers(customerPage, customizeCustomer); }, /** * 创建多个自定义顾客 */ createCustomCustomers: async ({ page, baseURL }, use) => { - if (!baseURL) { - throw new Error('baseUrl is required'); - } const customerPage = new CustomerPage(page); - let tmp: Customer[] | undefined; + let createCustomizeCustomerArray: Customer[] | undefined; const setCustomers = async (customers: Customer[]) => { await customerPage.createMoreCustomer(customers); - tmp = customers; + createCustomizeCustomerArray = customers; }; await use(setCustomers); - if (!tmp) return; - await page.goto(baseURL); - await page.getByRole('button', { name: /开\s单/ }).waitFor(); - await page.goto('/#/member/member-schame'); - await customerPage.setMoreInvalidCustomer(tmp); + if (!createCustomizeCustomerArray) return; + await navigateToCustomerSchema(page, baseURL!); + await setInvalidCustomers(customerPage, createCustomizeCustomerArray); }, /** diff --git a/tests/pages/components/numberInput.ts b/tests/pages/components/numberInput.ts index 8c02505..8e5ef2f 100644 --- a/tests/pages/components/numberInput.ts +++ b/tests/pages/components/numberInput.ts @@ -34,7 +34,6 @@ export class NumberInput { /** * 设置值 - * @param value */ async setValue(value: number): Promise { await this.inputLocator.fill(value.toString()); diff --git a/tests/pages/customer/customerAnalysisPage.ts b/tests/pages/customer/customerAnalysisPage.ts index 4447035..d7c405d 100644 --- a/tests/pages/customer/customerAnalysisPage.ts +++ b/tests/pages/customer/customerAnalysisPage.ts @@ -6,7 +6,6 @@ export class CustomerAnalysisPage { /** * 顾客分析页面 - * @param {import("@playwright/test").Page} page */ constructor(page: Page) { this.page = page; diff --git a/tests/pages/customer/customerPage.ts b/tests/pages/customer/customerPage.ts index f0a4ac2..edd6c14 100644 --- a/tests/pages/customer/customerPage.ts +++ b/tests/pages/customer/customerPage.ts @@ -1,7 +1,6 @@ import { expect, type Locator, type Page } from '@playwright/test'; -import { HomeNavigation } from '../homeNavigationPage.js'; -import { Customer, employee } from '../../utils/customer'; -import { waitSpecifyApiLoad } from '../../utils/utils.js'; +import { Customer, employee } from '@/utils/customer'; +import { waitSpecifyApiLoad } from '@/utils/utils'; type SubPage = { name: string; @@ -14,7 +13,6 @@ type SubPage = { */ export class CustomerPage { page: Page; - private readonly homeNavigation: HomeNavigation; private readonly subPages: SubPage[] = [ { name: '顾客概要', url: ['summary', 'todo'] }, { name: '顾客分配', url: ['search_new', 'distribution'] }, @@ -42,15 +40,14 @@ export class CustomerPage { $register: Locator; $tabItem: Locator; $searchInput: Locator; - $searchConfirm: Locator; + $searchBtn: Locator; constructor(page: Page) { this.page = page; this.$tabItem = this.page.locator('.top_tab .tab_item'); this.$register = this.page.locator('.regmeber_warp', { hasText: '创建会员' }); this.$searchInput = this.page.getByPlaceholder('姓名(拼音首字)、手机号、档案号搜索'); - this.$searchConfirm = this.page.getByText('搜索', { exact: true }); - this.homeNavigation = new HomeNavigation(this.page); + this.$searchBtn = this.page.getByText('搜索', { exact: true }); } /** @@ -68,19 +65,19 @@ export class CustomerPage { throw new Error(`子页面 ${subPageName} 不存在`); } - const $subPage = this.$tabItem.filter({ hasText: subPageName }); + const $subPageTab = this.$tabItem.filter({ hasText: subPageName }); - await $subPage.waitFor(); + await $subPageTab.waitFor(); - const classAttribute = await $subPage.getAttribute('class', { timeout: 5000 }); + const classAttribute = await $subPageTab.getAttribute('class', { timeout: 5000 }); if (classAttribute && classAttribute.includes('active')) { return; } await Promise.all([ expect(async () => { - await $subPage.click(); - await expect($subPage).toHaveClass(/active/); + await $subPageTab.click(); + await expect($subPageTab).toHaveClass(/active/); }).toPass(), waitSpecifyApiLoad(this.page, subPage.url), ]); @@ -95,7 +92,7 @@ export class CustomerPage { const $customerInfoCard = $$customerContent.filter({ hasText: text }).first(); await this.$searchInput.fill(text); - await this.$searchConfirm.click(); + await this.$searchBtn.click(); await $customerInfoCard.waitFor(); }; @@ -136,14 +133,13 @@ export class CustomerPage { * 关闭顾客详情页面 */ closeCustomerDetail = async () => { - const closeButton = this.page.locator('.member_info_box .close_icons > svg'); - await closeButton.click(); - await closeButton.waitFor({ state: 'detached' }); + const $closeBtn = this.page.locator('.member_info_box .close_icons > svg'); + await $closeBtn.click(); + await $closeBtn.waitFor({ state: 'detached' }); }; /** * 创建顾客 - * @param {Customer} customer 顾客 */ createCustomer = async (customer: Customer) => { const customerPage = '/#/member/member-schame'; @@ -249,11 +245,22 @@ export class CustomerPage { * @param gender 性别 */ private readonly selectGender = async (gender: number) => { + // 定义性别选项的映射 + const GENDER_OPTIONS = { + FEMALE: 0, + MALE: 1, + }; + + // 定义对应的文本 + const GENDER_TEXTS = { + [GENDER_OPTIONS.FEMALE]: '女性', + [GENDER_OPTIONS.MALE]: '男性', + }; + if (gender === 0) { - await this.$register.locator('label').filter({ hasText: '女性' }).click(); - } else if (gender === 1) { - await this.$register.locator('label').filter({ hasText: '男性' }).click(); + return; } + await this.$register.locator('label').filter({ hasText: GENDER_TEXTS[gender] }).click(); }; /** @@ -264,22 +271,36 @@ export class CustomerPage { * @param {number} birthday.day 日期 */ private readonly selectBirthday = async (birthday: { year: number; month: number; day: number }) => { - if (birthday) { - const { year, month, day } = birthday; - const birthdayLocator = this.$register.locator('.ant-form-item', { hasText: '生日' }); - if (year) { - await birthdayLocator.getByText('年份').click(); - await this.page.getByRole('option', { name: `${year}` }).click(); - await expect(this.page.getByRole('option', { name: `${year}` })).not.toBeVisible(); - } - if (month && day) { - await birthdayLocator.getByText('日期').click(); - await this.page.getByRole('option', { name: new RegExp(`^${month}\\s月$`) }).click(); - await this.page.getByRole('option', { name: new RegExp(`^${day}\\s日$`) }).click(); - await this.page.getByRole('button', { name: /确\s认/ }).click(); - } else { - throw new Error(`month:${month}, day:${day}其中一个为空`); - } + if (!birthday) { + throw new Error('birthday参数为空'); + } + const { year, month, day } = birthday; + + if (!Number.isInteger(year) || year < 1900 || year > new Date().getFullYear()) { + throw new Error(`年份 ${year} 不合法`); + } + + if (!Number.isInteger(month) || month < 1 || month > 12) { + throw new Error(`月份 ${month} 不合法`); + } + + if (!Number.isInteger(day) || day < 1 || day > 31) { + throw new Error(`日期 ${day} 不合法`); + } + + const $birthday = this.$register.locator('.ant-form-item', { hasText: '生日' }); + if (year) { + await $birthday.getByText('年份').click(); + await this.page.getByRole('option', { name: `${year}` }).click(); + await expect(this.page.getByRole('option', { name: `${year}` })).not.toBeVisible(); + } + if (month && day) { + await $birthday.getByText('日期').click(); + await this.page.getByRole('option', { name: new RegExp(`^${month}\\s月$`) }).click(); + await this.page.getByRole('option', { name: new RegExp(`^${day}\\s日$`) }).click(); + await this.page.getByRole('button', { name: /确\s认/ }).click(); + } else { + throw new Error(`month:${month}, day:${day}其中一个为空`); } }; @@ -296,9 +317,8 @@ export class CustomerPage { * @param {string} remark 备注 */ private readonly fillRemark = async (remark: string) => { - if (remark) { - await this.$register.getByPlaceholder('请输入1-100个字符备注内容').fill(remark); - } + if (!remark) return; + await this.$register.getByPlaceholder('请输入1-100个字符备注内容').fill(remark); }; /** @@ -315,7 +335,7 @@ export class CustomerPage { const responseBody = await response.json(); const phoneStatus = responseBody?.content?.status; - if (!phoneStatus) { + if (phoneStatus === undefined || phoneStatus === null) { return; } await this.page.getByText('系统查询到当前手机号被建档后转为无效客,是否要恢复无效客?').waitFor(); @@ -341,7 +361,6 @@ export class CustomerPage { await this.page.locator('.m-table__fixed-left').getByText(customer.username).first().click(); // 设置无效客 - await this.page.locator('.person_content').waitFor(); await this.page.locator('.person_content .tag_box .more_icon svg').click(); await this.page.getByRole('menuitem', { name: '设为无效客' }).click(); const [response] = await Promise.all([ @@ -372,7 +391,7 @@ export class CustomerPage { */ setMoreInvalidCustomer = async (customerArray: Customer[]) => { for (const customer of customerArray) { - this.page.reload(); + await this.page.reload(); await this.setInvalidCustomer(customer); } }; diff --git a/tests/pages/inventory/InventoryManagementPage.ts b/tests/pages/inventory/InventoryManagementPage.ts index 9ff25a6..1656a47 100644 --- a/tests/pages/inventory/InventoryManagementPage.ts +++ b/tests/pages/inventory/InventoryManagementPage.ts @@ -4,6 +4,7 @@ import { waitSpecifyApiLoad } from '@/utils/utils'; export class InventoryManagementPage { page: Page; subPages: { name: string; url?: string[] }[]; + /** * 库存管理页 * @param page diff --git a/tests/pages/inventory/inventoryTransferManagementPage.ts b/tests/pages/inventory/inventoryTransferManagementPage.ts index 47ba39c..14adcb6 100644 --- a/tests/pages/inventory/inventoryTransferManagementPage.ts +++ b/tests/pages/inventory/inventoryTransferManagementPage.ts @@ -4,9 +4,10 @@ import { waitSpecifyApiLoad } from '@/utils/utils'; export class TransferManagementPage { page: Page; subPages: { name: string; url?: string[] }[]; + /** * 库存-调货管理页面 - * @param {import("@playwright/test").Page} page + * @param {import('@playwright/test').Page} page */ constructor(page: Page) { this.page = page; diff --git a/tests/setup/boss_auth.setup.ts b/tests/setup/boss_auth.setup.ts index 1af27a2..319729e 100644 --- a/tests/setup/boss_auth.setup.ts +++ b/tests/setup/boss_auth.setup.ts @@ -11,20 +11,20 @@ const regex = /^https?:\/\/(www\.)?hlk\.meiguanjia\.net\/?(#\s)?$/; const personalizedPages = '/#/marketing/brand/personalized'; class testAccount { - constructor(account, password, path) { + constructor(account: string, password: string, path: string) { this.account = account; this.password = password; this.path = path; } - account; - password; - path; + account: string; + password: string; + path: string; } const allAccounts = [ - new testAccount(process.env.boss_account, process.env.boss_password, firstAuthFile), - new testAccount(process.env.boss_account_2, process.env.boss_password_2, secondAuthFile), + new testAccount(process.env.boss_account!, process.env.boss_password!, firstAuthFile), + new testAccount(process.env.boss_account_2!, process.env.boss_password_2!, secondAuthFile), ]; for (let a of allAccounts) { @@ -37,7 +37,7 @@ for (let a of allAccounts) { .locator('div', { has: page.getByRole('textbox', { name: '请输入您的手机号码' }) }) .locator('.pass_svg'); - await page.goto(baseURL); + await page.goto(baseURL!); await page.getByRole('textbox', { name: '请输入您的手机号码' }).fill(account); await page.getByRole('textbox', { name: '请输入登录密码' }).fill(password); await page.getByLabel('请同意慧来客隐私政策和用户协议').check(); @@ -45,7 +45,7 @@ for (let a of allAccounts) { await page.getByRole('button', { name: /登\s录/ }).click(); await page.getByRole('button', { name: /开\s单/ }).waitFor(); - if (regex.test(baseURL)) { + if (regex.test(baseURL!)) { await page.goto(personalizedPages); await page.getByRole('button', { name: '新增模块' }).waitFor(); const $sideIframe = page.locator('.side iframe').contentFrame(); diff --git a/tests/touch/boss_appointment.spec.ts b/tests/touch/boss_appointment.spec.ts index 1efc703..7a00a3c 100644 --- a/tests/touch/boss_appointment.spec.ts +++ b/tests/touch/boss_appointment.spec.ts @@ -1,20 +1,20 @@ // @ts-check import { faker } from '@faker-js/faker/locale/zh_CN'; import { test, expect } from '@/fixtures/boss_common.js'; -import path from 'path'; -import fs from 'fs'; import { staffData } from '@/fixtures/staff.js'; import { HomeNavigation } from '@/pages/homeNavigationPage.js'; import { AppointmentPage } from '@/pages/appointmentPage.js'; import { AppointmentOperation } from '@/pages/appointmentPage.js'; test('使用预约单元格', async ({ page, homeNavigation, createCustomer, appointmentPage, customerPage }) => { - const setAppointmentTime = appointmentPage.getAppointmentTimesAvailable(); - const customer = createCustomer; const employee = staffData.firstStore.firstSector.employee_1; - // 当前可预约时间定位器 + const setAppointmentTime = appointmentPage.getAppointmentTimesAvailable(); + + const customer = createCustomer; + + /** 当前可预约时间定位器 */ const $time = page.locator('.times_table td').filter({ hasText: setAppointmentTime }); - // 顾客预约定位器 + /** 顾客预约定位器 */ const $customerAppointment = page .locator('.a_userInfo') .filter({ hasText: customer.phone }) @@ -309,36 +309,6 @@ test.describe('预约状态', () => { expect(customerStatus).toEqual(appointmentStatusSetting.SETTLED.name); }); }); - - test.skip('预约-过期', async ({ page, createCustomer, appointmentPage, customerPage }) => { - // 获取预约时间 - let setAppointmentTime = appointmentPage.getAppointmentTimesAvailable(); - - // 创建顾客 - const customer = createCustomer; - // 员工赵军 - const employee = staffData.firstStore.firstSector.employee_5; - // 预约时间定位器 - const $time = page.locator('.times_table td').filter({ hasText: setAppointmentTime }); - // 员工定位器 - const $employee = page.locator('.room_table .tr .name_th').filter({ hasText: employee.name }); - - await test.step('选择顾客进行预约', async () => { - await $employee.scrollIntoViewIfNeeded(); - await $time.scrollIntoViewIfNeeded(); - await appointmentPage.openAppointmentCell(employee.name); - await expect(async () => { - await appointmentPage.operationAppointment(AppointmentOperation.ADD_APPOINT); - await expect(page.getByText('选择会员')).toBeVisible(); - }).toPass(); - await customerPage.searchCustomer(customer.phone); - await customerPage.selectSearchCustomer(customer.phone); - await expect(page.locator('.newAppointmentContent .header_title')).toContainText('新建预约'); - await expect(page.locator('.newAppointmentContent .content .phone')).toContainText(customer.phone); - await page.getByRole('button', { name: '确认新建' }).click(); - await expect(page.locator('.ant-message', { hasText: '预约成功' })).toBeVisible(); - }); - }); }); test.afterEach(async ({ homeNavigation, wasteBookBusinessRecordPage, billSet }) => { diff --git a/tests/touch/boss_cashier.spec.ts b/tests/touch/boss_cashier.spec.ts index 12dcacb..ae1998d 100644 --- a/tests/touch/boss_cashier.spec.ts +++ b/tests/touch/boss_cashier.spec.ts @@ -5,11 +5,12 @@ import { decodeQR, KeepOnlyNumbers } from '@/utils/utils.js'; import { faker } from '@faker-js/faker/locale/zh_CN'; import path from 'path'; import { AppointmentOperation } from '@/pages/appointmentPage.js'; +import { Customer } from '@/utils/customer'; test.describe('挂单', () => { - let c; - let username; - let phone; + let c: Customer; + let username: string; + let phone: string; test.beforeEach('测试前新建会员', async ({ page, homeNavigation, createCustomer, customerPage }) => { // 创建顾客 c = createCustomer; @@ -423,8 +424,7 @@ test.describe('挂单', () => { await page.locator('.qrcode').screenshot({ path: filePath }); }).toPass(); - /**@type {string} 解析后的网址 */ - let result = await decodeQR(filePath); + let result: string = await decodeQR(filePath); console.log(result); let url_1 = new URL(result); @@ -597,13 +597,13 @@ test.describe('收银-房态', () => { }); test('占用床位', async ({ - page, - homeNavigation, - createCustomer, - cashierRoomPage, - customerPage, - appointmentPage, - }) => { + page, + homeNavigation, + createCustomer, + cashierRoomPage, + customerPage, + appointmentPage, + }) => { const customer = createCustomer; const employee = Employees.FirstShop.Employee_6; @@ -760,8 +760,7 @@ test.describe('收银-房态', () => { const setAppointment = appointmentPage.getAppointmentTimesAvailable(); // 获取当前时间 const cede = page.locator('.left_table td'); // 找到当前时间的行数 - /**@type {number} 找到当前时间的行数 */ - const nowRowTime = await cede.allInnerTexts().then(text => { + const nowRowTime: number = await cede.allInnerTexts().then(text => { return text.findIndex(item => item === setAppointment) + 2; }); // 获取第几列没被占用 @@ -822,9 +821,7 @@ test.describe('收银-房态', () => { const setAppointment = appointmentPage.getAppointmentTimesAvailable(); // 获取当前时间 const cede = page.locator('.left_table td'); // 找到当前时间的行数 - // const nowRowTime = await cede.allInnerTexts().then(text => text.indexOf(setAppointment) + 3); - /**@type{number} 找到当前时间的行数 */ - const nowRowTime = await cede.allInnerTexts().then(text => { + const nowRowTime: number = await cede.allInnerTexts().then(text => { return text.findIndex(item => item === setAppointment) + 2; }); // 获取第几列没被占用 @@ -890,13 +887,13 @@ test.describe('收银-房态', () => { test.describe('收银-开单&结算', () => { test('开单-反结算-撤单', async ({ - page, - homeNavigation, - createCustomer, - customerPage, - wasteBookBusinessRecordPage, - numberInput, - }) => { + page, + homeNavigation, + createCustomer, + customerPage, + wasteBookBusinessRecordPage, + numberInput, + }) => { // 定义一个随机单号 const randomBillNo1 = faker.helpers.fromRegExp(/1[3-9][0-9]{8}/); const randomBillNo2 = faker.helpers.fromRegExp(/1[3-9][0-9]{9}/); @@ -1197,12 +1194,12 @@ test.describe('收银-开单&结算', () => { }); test('开卡-使用卡金和赠金-充值卡金', async ({ - page, - homeNavigation, - createCustomer, - customerPage, - numberInput, - }) => { + page, + homeNavigation, + createCustomer, + customerPage, + numberInput, + }) => { const c = createCustomer; const username = c.username; const phone = c.phone; diff --git a/tests/touch/boss_customer.spec.ts b/tests/touch/boss_customer.spec.ts index 1077543..1b1878c 100644 --- a/tests/touch/boss_customer.spec.ts +++ b/tests/touch/boss_customer.spec.ts @@ -97,7 +97,7 @@ test.describe('顾客通用', () => { await page.getByPlaceholder('姓名(拼音首字)、手机号、档案号搜索').click(); await page.locator('.historyALertBox_title', { hasText: '搜索历史' }).waitFor(); // 判断搜索历史是否存在 - await expect(page.locator('.historyMemberList_item')).toContainText([@.historySet].reverse()); + await expect(page.locator('.historyMemberList_item')).toContainText([...historySet].reverse()); }); }); @@ -1026,8 +1026,7 @@ test.describe('顾客详情', () => { }); test('操作套餐', async ({ page, homeNavigation, customerPage, createCustomer }) => { - /**@type {string} */ - let billNo; + let billNo: string; const date = new Date(); const currentYear = date.getFullYear(); const currentMonth = date.getMonth() + 1; @@ -1166,8 +1165,7 @@ test.describe('顾客详情', () => { await page.getByRole('button', { name: /确\s认/ }).click(); }); - /**@type {string} 当前单号 */ - let billNo = ''; + let billNo: string; await test.step('购买项目并消耗,购买卖品并结算,结算使用优惠券、卡金、赠金、欠款、积分,拿取单号', async () => { // 左右两侧的支付方式定位器 diff --git a/tests/touch/boss_goal.spec.ts b/tests/touch/boss_goal.spec.ts index d304554..72b6814 100644 --- a/tests/touch/boss_goal.spec.ts +++ b/tests/touch/boss_goal.spec.ts @@ -361,8 +361,7 @@ test.describe('门店看板', () => { // 收银结算button const leftPaymentInfoItem = page.locator('.left .paymentmain .paymentInfoItem'); - /**@type {Customer[]} */ - let customers = []; + let customers: Customer[] = []; await test.step('创建3个顾客', async () => { customers = await createCustomers(3); }); @@ -1261,8 +1260,7 @@ test.describe('精细目标', () => { let firstStoreFirstSector = staffData.firstStore.firstSector; let firstStoreSecondSector = staffData.firstStore.secondSector; - /**@type {Customer[]} */ - let customers = []; + let customers: Customer[] = []; await test.step('创建两个顾客', async () => { customers = await createCustomers(2); }); diff --git a/tests/touch/boss_inventory.spec.ts b/tests/touch/boss_inventory.spec.ts index aa74c6f..106a470 100644 --- a/tests/touch/boss_inventory.spec.ts +++ b/tests/touch/boss_inventory.spec.ts @@ -3,7 +3,6 @@ import { faker } from '@faker-js/faker/locale/zh_CN'; import { expect, test } from '@/fixtures/boss_common.js'; import { CleanPunctuation, getListIndexForTargetElement, KeepOnlyNumbers } from '@/utils/utils.js'; import { ProjectName } from '@/fixtures/userconfig.js'; -import { Customer } from '@/utils/customer'; test.describe('出入库管理', () => { test.describe('入库单', () => { @@ -11,8 +10,8 @@ test.describe('出入库管理', () => { const remark = '入库' + faker.helpers.fromRegExp(/1[0-9]{4}/); const productA = ProjectName.Product.Product_3; - /**@type {number} 产品A余量 */ - let productASurplus; + /** 产品A余量 */ + let productASurplus: number; const quantity1 = 100; const quantity2 = 5; await test.step('获取入库前数据', async () => { @@ -63,8 +62,8 @@ test.describe('出入库管理', () => { await expect(page.getByRole('button', { name: '确认入库' })).not.toBeVisible(); }); - /**@type {number} 入库单的索引 */ - let billEntryIndex; + /** 入库单的索引 */ + let billEntryIndex: number; await test.step('校验入库单', async () => { // 根据备注找出入库单在第几行 const codes = page.locator('.table-warp .m-table__body-wrapper .m-table__body tbody tr'); @@ -898,8 +897,7 @@ test.describe('库存管理', () => { const productA = ProjectName.Product.Product_2.name; const productNum = ProjectName.Product.Product_2.num; - /**@type {string} 单号*/ - let billNo; + let billNo: string; await test.step('出库', async () => { // 点击库存 await homeNavigation.gotoModule('库存'); @@ -1247,13 +1245,13 @@ test.describe('库存管理', () => { }); test('寄存记录', async ({ - page, - homeNavigation, - createCustomer, - customerPage, - tablePage, - inventoryManagementPage, - }) => { + page, + homeNavigation, + createCustomer, + customerPage, + tablePage, + inventoryManagementPage, + }) => { const goods = { no: 'aa100022', name: '芳香护理套(身体)', @@ -1261,8 +1259,7 @@ test.describe('库存管理', () => { const customer = createCustomer; - /**@type {string} */ - let billNo; + let billNo: string; await test.step('进行开单购买卖品并寄存', async () => { await homeNavigation.gotoModule('收银'); await page.getByRole('button', { name: /开\s单/ }).click(); @@ -1338,8 +1335,7 @@ test.describe('统计', async () => { const quantity1 = 20; //数量 const UnitPrice = 10; //单价 - /**@type {string} 单号*/ - let billNo; + let billNo: string; let totality; let GrossAmount; @@ -1839,8 +1835,7 @@ test.describe('统计', async () => { const quantity1 = 20; //数量 const UnitPrice = 10; //单价 - /**@type {string} 单号*/ - let billNo; + let billNo: string; let totality = 0; await test.step('获取出库前总数', async () => { @@ -1990,7 +1985,7 @@ test.describe('统计', async () => { }).toPass({ timeout: 60000 }); // 获取出库后总数 - await expect(page.locator('.main-table-body_tr td').nth(5)).toBe(Number(totality) + Number(quantity1)); + expect(page.locator('.main-table-body_tr td').nth(5)).toBe(Number(totality) + Number(quantity1)); // 点击总数进入流水 await page.locator('.main-table-body_tr td').nth(5).click(); @@ -2683,8 +2678,7 @@ test.describe('统计', async () => { .then(Number); }); - /**@type {string} 单号*/ - let billNo; + let billNo: string; await test.step('顾客开单购买3次项目,并消耗3次项目,选择产品配方3次5ml', async () => { await homeNavigation.gotoModule('收银'); await page.getByRole('button', { name: /开\s单/ }).click(); @@ -2806,7 +2800,7 @@ test.describe('调货管理', () => { }; const remarkA = '调货管理' + faker.helpers.fromRegExp(/[a-d]{2}[0-9]{2}/); const remarkB = '调货管理' + faker.helpers.fromRegExp(/[a-d]{2}[0-9]{2}/); - let billA, billB; + let billA:string, billB:string; let quantity = 0; // 数量 let outQuantity = 0; // 调出数量 @@ -3310,8 +3304,7 @@ test.describe.serial('盘点', () => { let ProductMargin; // 获取单号的ID let billId; - /**@type {string} 单号*/ - let billNo; + let billNo: string; await test.step('记录各自批次数量', async () => { // 点击库存 @@ -3537,8 +3530,7 @@ test.describe.serial('盘点', () => { // 获取单号的ID let billId; - /**@type {string} 单号*/ - let billNo; + let billNo: string; await test.step('记录各自批次数量', async () => { // 点击库存 diff --git a/tests/touch/boss_marketing.spec.ts b/tests/touch/boss_marketing.spec.ts index e1aab3f..e00c052 100644 --- a/tests/touch/boss_marketing.spec.ts +++ b/tests/touch/boss_marketing.spec.ts @@ -7,6 +7,7 @@ import { Customer } from '@/utils/customer'; import { staffData } from '@/fixtures/staff.js'; import { HomeNavigation } from '@/pages/homeNavigationPage.js'; import fs from 'fs'; +import { Page } from '@playwright/test'; test.describe('商城', () => { test.describe('上架好物', () => { @@ -1117,8 +1118,8 @@ test.describe('品牌', () => { }); test('门店排序', async ({ page, homeNavigation }) => { - let firstTrStoreName; - let secondTrStoreName; + let firstTrStoreName: string; + let secondTrStoreName: string; await test.step('进入门店信息', async () => { await homeNavigation.gotoModule('营销'); @@ -1285,8 +1286,7 @@ test.describe('品牌', () => { }); }); - /**@type { import("@playwright/test").Page } 初始化页面*/ - let initPage; + let initPage: Page; test.beforeAll(async ({ browser, baseURL }) => { initPage = await browser.newPage(); const homeNavigation = new HomeNavigation(initPage); @@ -1336,7 +1336,7 @@ test.describe('品牌', () => { test.describe('个性化', () => { test('配色', async ({ page, homeNavigation }) => { - let colorArray; + let colorArray: string[]; await test.step('进入个性化装扮', async () => { await homeNavigation.gotoModule('营销'); @@ -1701,8 +1701,7 @@ test.describe('邀客系统', () => { }); test('邀客管理', async ({ page, homeNavigation, tablePage, customerPage, createCustomers, marketingPage }) => { - /**@type {Customer[]} */ - let customers = []; + let customers: Customer[] = []; await test.step('创建顾客', async () => { customers = await createCustomers(2); }); diff --git a/tests/touch/boss_wastebook.spec.ts b/tests/touch/boss_wastebook.spec.ts index 43acf2e..311a3f0 100644 --- a/tests/touch/boss_wastebook.spec.ts +++ b/tests/touch/boss_wastebook.spec.ts @@ -817,8 +817,7 @@ test.describe('对账流水', () => { test('根据条件搜索对账流水', async ({ page, homeNavigation, createCustomer, wasteBookBusinessRecordPage }) => { const customer = createCustomer; const project = { no: '100018', name: '苹果精萃护理', shortName: '精萃护理', price: '980' }; - /**@type {string} 单号*/ - let billNo; + let billNo: string; await test.step('选择顾客开单,结算使用银联、支付宝、微信、欠款、现金', async () => { await homeNavigation.gotoModule('收银'); await page.getByRole('button', { name: /开\s单/ }).click(); @@ -930,8 +929,7 @@ test.describe('对账流水', () => { const customer = createCustomer; - /**@type {string} 单号*/ - let billNo; + let billNo:string; await test.step('选择顾客开单,结算使用银联、支付宝、微信、欠款、现金', async () => { await homeNavigation.gotoModule('收银'); @@ -1000,7 +998,7 @@ test.describe('对账流水', () => { ]); // 拿取现金列的列数 - let index; + let index: number; const thLocator = page.locator('.m-table__header tr').last().locator('th'); const headers = await thLocator.allInnerTexts(); index = headers.findIndex(headerText => headerText.includes('支付方式')); diff --git a/tests/utils/indexedDBUtils.ts b/tests/utils/indexedDBUtils.ts index 88eef63..f6bc553 100644 --- a/tests/utils/indexedDBUtils.ts +++ b/tests/utils/indexedDBUtils.ts @@ -1,58 +1,52 @@ export async function readIndexedDB() { const databases = await indexedDB.databases(); - const allData: Array<{ databaseName: string; data: { key: IDBValidKey; value: any }[] }> = []; + const allData = []; for (const db of databases) { - const databaseName = db.name!; + const databaseName = db.name; - try { - const dbInstance = await openDatabase(databaseName); - const transaction = dbInstance.transaction(dbInstance.objectStoreNames, 'readonly'); - const objectStore = transaction.objectStore(dbInstance.objectStoreNames[0]); - const storeData = await getAllDataFromObjectStore(objectStore); + // 打开数据库 + const request = indexedDB.open(databaseName); - allData.push({ - databaseName, - data: storeData, - }); + const databaseData = await new Promise((resolve, reject) => { + request.onsuccess = (event) => { + const db = event.target.result; + const transaction = db.transaction(db.objectStoreNames, 'readonly'); + const objectStore = transaction.objectStore(db.objectStoreNames[0]); + const cursorRequest = objectStore.openCursor(); - dbInstance.close(); - } catch (error) { - console.error(`Error reading database ${databaseName}:`, error); - } + const storeData = []; + + cursorRequest.onsuccess = (event) => { + const cursor = event.target.result; + if (cursor) { + storeData.push({ key: cursor.key, value: cursor.value }); + cursor.continue(); + } else { + resolve(storeData); // 执行 resolve,返回数据 + } + }; + + cursorRequest.onerror = (event) => { + reject(event.target.error); // 发生错误时 reject + }; + }; + + request.onerror = (event) => { + reject(event.target.error); // 发生错误时 reject + }; + }); + + // 将数据库数据存入 allData + allData.push({ + databaseName, + data: databaseData, + }); } return allData; } -function openDatabase(databaseName: string): Promise { - return new Promise((resolve, reject) => { - const request = indexedDB.open(databaseName); - - request.onsuccess = event => resolve(event.target.result); - request.onerror = event => reject(event.target.error); - }); -} - -function getAllDataFromObjectStore(objectStore: IDBObjectStore): Promise> { - return new Promise((resolve, reject) => { - const storeData: Array<{ key: IDBValidKey; value: any }> = []; - const cursorRequest = objectStore.openCursor(); - - cursorRequest.onsuccess = event => { - const cursor = event.target.result; - if (cursor) { - storeData.push({ key: cursor.key, value: cursor.value }); - cursor.continue(); - } else { - resolve(storeData); - } - }; - - cursorRequest.onerror = event => reject(event.target.error); - }); -} - export async function writeIndexedDB(jsonData) { return new Promise((resolve, reject) => { const processDatabase = async (database, objectStoreNames) => {