diff --git a/playwright.config.js b/playwright.config.js index 9e67eef..1984f5d 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'; +import { firstAccount, secondAccount } from './tests/common/auth'; /** * Read environment variables from file. @@ -15,9 +16,9 @@ require('dotenv').config({ path: path.resolve(__dirname, '.env') }); // ".env" + `${process.env.NODE_ENV ? "." + process.env.NODE_ENV : ""}` // ), // }); -const authPath = '.auth/user.json'; -const firstAuthFile = '.auth/admin_first.json'; -const secondAuthFile = '.auth/admin_second.json'; + +const firstAuthFile = firstAccount.authFile; +const secondAuthFile = secondAccount.authFile; /** * @see https://playwright.dev/docs/test-configuration */ diff --git a/tests/common/auth.ts b/tests/common/auth.ts new file mode 100644 index 0000000..00916f0 --- /dev/null +++ b/tests/common/auth.ts @@ -0,0 +1,52 @@ +import { getEnvVar } from '@/utils/envUtils'; +import { readFileSync } from 'fs'; + +const authConfig = { + authFilePath: '.auth/', + indexedDBFilePath: '.auth/', +}; + +class AuthAccount { + account: string; + password: string; + authFile: string; + indexedDBFile: string; + + constructor(account: string, password: string, authFile: string, indexedDBFile: string) { + this.account = account; + this.password = password; + this.authFile = authFile; + this.indexedDBFile = indexedDBFile; + } + + static loadIndexedDBFile(account: string, accountArray: AuthAccount[]) { + try { + for (const item of accountArray) { + if (item.account === account) { + return JSON.parse(readFileSync(item.indexedDBFile, 'utf-8')); + } + } + } catch (e) { + throw new Error('indexedDB文件读取失败'); + } + + throw new Error('未找到该账户'); + } +} + +const firstAccount = new AuthAccount( + getEnvVar('boss_account'), + getEnvVar('boss_password'), + `${authConfig.authFilePath}${getEnvVar('boss_account')}.json`, + `${authConfig.indexedDBFilePath}${getEnvVar('boss_account')}_indexedDB.json`, +); + +const secondAccount = new AuthAccount( + getEnvVar('boss_account_2'), + getEnvVar('boss_password_2'), + `${authConfig.authFilePath}${getEnvVar('boss_account_2')}.json`, + `${authConfig.indexedDBFilePath}${getEnvVar('boss_account_2')}_indexedDB.json`, +); + + +export { firstAccount, secondAccount, AuthAccount }; \ No newline at end of file diff --git a/tests/fixtures/staff.js b/tests/common/staff.ts similarity index 64% rename from tests/fixtures/staff.js rename to tests/common/staff.ts index f6a1238..608a297 100644 --- a/tests/fixtures/staff.js +++ b/tests/common/staff.ts @@ -1,7 +1,7 @@ //@ts-check // 默认为生产 -let nodeEnv = process.env.NODE_ENV || "production"; -nodeEnv = nodeEnv === "staging" ? "production" : nodeEnv; +let nodeEnv = process.env.NODE_ENV || 'production'; +nodeEnv = nodeEnv === 'staging' ? 'production' : nodeEnv; /** * - 员工数据 门店 部门 员工 姓名 @@ -14,163 +14,163 @@ nodeEnv = nodeEnv === "staging" ? "production" : nodeEnv; let staffData = { firstStore: { firstSector: { - name: "美容部", + name: '美容部', employee_1: { - name: "张伟", - phone: "13812345678", + name: '张伟', + phone: '13812345678', id: { production: 3, test: 1 }, }, employee_2: { - name: "李娜", - phone: "13987654321", + name: '李娜', + phone: '13987654321', id: { production: 4, test: 2 }, }, employee_3: { - name: "王芳", - phone: "13723456789", + name: '王芳', + phone: '13723456789', id: { production: 5, test: 3 }, }, employee_4: { - name: "陈刚", - phone: "13698765432", + name: '陈刚', + phone: '13698765432', id: { production: 6, test: 4 }, }, employee_5: { - name: "赵军", - phone: "13512349876", + name: '赵军', + phone: '13512349876', id: { production: 7, test: 5 }, }, employee_6: { - name: "刘强", - phone: "13498761234", + name: '刘强', + phone: '13498761234', id: { production: 8, test: 6 }, }, employee_7: { - name: "周萍", - phone: "13365432109", + name: '周萍', + phone: '13365432109', id: { production: 9, test: 7 }, }, employee_8: { - name: "吴浩", - phone: "13287654329", + name: '吴浩', + phone: '13287654329', id: { production: 10, test: 8 }, }, employee_9: { - name: "徐亮", - phone: "13123459876", + name: '徐亮', + phone: '13123459876', id: { production: 11, test: 9 }, }, employee_10: { - name: "杨雪", - phone: "13098761234", + name: '杨雪', + phone: '13098761234', id: { production: 12, test: 10 }, }, }, secondSector: { - name: "医美部", + name: '医美部', employee_1: { - name: "赵伟", - phone: "13923456789", + name: '赵伟', + phone: '13923456789', id: { production: 13, test: 11 }, }, employee_2: { - name: "钱丽", - phone: "13898765432", + name: '钱丽', + phone: '13898765432', id: { production: 14, test: 12 }, }, employee_3: { - name: "孙峰", - phone: "13712349876", + name: '孙峰', + phone: '13712349876', id: { production: 15, test: 13 }, }, employee_4: { - name: "李涛", - phone: "13687654321", + name: '李涛', + phone: '13687654321', id: { production: 16, test: 14 }, }, employee_5: { - name: "周慧", - phone: "13598761234", + name: '周慧', + phone: '13598761234', id: { production: 17, test: 15 }, }, employee_6: { - name: "吴凯", - phone: "13465432109", + name: '吴凯', + phone: '13465432109', id: { production: 18, test: 16 }, }, employee_7: { - name: "郑翔", - phone: "13387654329", + name: '郑翔', + phone: '13387654329', id: { production: 19, test: 17 }, }, employee_8: { - name: "冯敏", - phone: "13223459876", + name: '冯敏', + phone: '13223459876', id: { production: 20, test: 18 }, }, employee_9: { - name: "朱强", - phone: "13198761234", + name: '朱强', + phone: '13198761234', id: { production: 21, test: 19 }, }, employee_10: { - name: "何平", - phone: "13065432198", + name: '何平', + phone: '13065432198', id: { production: 22, test: 20 }, }, }, }, secondStore: { - name: "美容部", + name: '美容部', firstSector: { employee_1: { - name: "张凯", - phone: "13865432198", + name: '张凯', + phone: '13865432198', id: { production: 1, test: 1 }, }, employee_2: { - name: "李军", - phone: "13923459876", + name: '李军', + phone: '13923459876', id: { production: 2, test: 2 }, }, employee_3: { - name: "王涛", - phone: "13798761234", + name: '王涛', + phone: '13798761234', id: { production: 3, test: 3 }, }, employee_4: { - name: "陈敏", - phone: "13654321987", + name: '陈敏', + phone: '13654321987', id: { production: 4, test: 4 }, }, employee_5: { - name: "赵峰", - phone: "13523456789", + name: '赵峰', + phone: '13523456789', id: { production: 5, test: 5 }, }, employee_6: { - name: "刘丽", - phone: "13487654321", + name: '刘丽', + phone: '13487654321', id: { production: 6, test: 6 }, }, employee_7: { - name: "周亮", - phone: "13398765432", + name: '周亮', + phone: '13398765432', id: { production: 7, test: 7 }, }, employee_8: { - name: "吴平", - phone: "13212349876", + name: '吴平', + phone: '13212349876', id: { production: 8, test: 8 }, }, employee_9: { - name: "徐浩", - phone: "13165432109", + name: '徐浩', + phone: '13165432109', id: { production: 9, test: 9 }, }, employee_10: { - name: "孙杰", - phone: "13087654329", + name: '孙杰', + phone: '13087654329', id: { production: 10, test: 10 }, }, }, @@ -200,7 +200,7 @@ function init(staffData, nodeEnv) { const store = updatedData[storeKey]; Object.keys(store).forEach(sectorKey => { const sector = store[sectorKey]; - if (typeof sector === "object" && sector !== null && sector.name) { + if (typeof sector === 'object' && sector !== null && sector.name) { updateIds(sector); // 更新每个 sector 的员工 id } }); diff --git a/tests/fixtures/baseFixture.ts b/tests/fixtures/baseFixture.ts index 438e53a..2af3b52 100644 --- a/tests/fixtures/baseFixture.ts +++ b/tests/fixtures/baseFixture.ts @@ -1,7 +1,7 @@ import { test as base, expect } from '@playwright/test'; import { HomeNavigation } from '@/pages/homeNavigationPage'; import { writeIndexedDB } from '@/utils/indexedDBUtils'; -import { readFileSync } from 'fs'; +import { firstAccount, secondAccount, AuthAccount } from '@/common/auth'; type MyFixture = { homeNavigation: HomeNavigation; @@ -17,7 +17,6 @@ export const test = base.extend({ if (!baseURL) throw new Error('baseURL is required'); await page.goto(baseURL); - // await page.getByRole('button', { name: /开\s单/ }).waitFor(); const mobileObject = await page.evaluate(() => { return window.localStorage.getItem('hlk_touch_mobile'); @@ -26,36 +25,26 @@ export const test = base.extend({ throw new Error('localStorage does not contain boss_account or boss_account2'); } const mobileString = JSON.parse(mobileObject); - const bossAccount = process.env.boss_account || ''; - const bossAccount2 = process.env.boss_account2 || ''; - - let jsonData: []; - if (mobileString.val?.includes(bossAccount)) { - jsonData = JSON.parse(readFileSync('.auth/admin_first_indexeddb.json', 'utf-8')); - } else if (mobileString.val?.includes(bossAccount2)) { - jsonData = JSON.parse(readFileSync('.auth/admin_second_indexeddb.json', 'utf-8')); - } else { - throw new Error('localStorage does not contain boss_account or boss_account2'); - } + const data = AuthAccount.loadIndexedDBFile(mobileString.val, [firstAccount, secondAccount]); await page.evaluate( - async ({ fnString, jsonData }) => { - // 在浏览器上下文中动态创建函数 + async ({ fnString, data }) => { const writeIndexedDBFn = new Function('return ' + fnString)(); - - // 调用函数并传递参数 - return await writeIndexedDBFn(jsonData); + return await writeIndexedDBFn(data); }, - { fnString: writeIndexedDB.toString(), jsonData }, + { fnString: writeIndexedDB.toString(), data }, ); - // await page.reload(); + await page.waitForFunction( async () => { const databases = await indexedDB.databases(); // 获取所有数据库 return databases.some(db => db.name === 'hlk_touch_test_init'); // 判断是否存在目标数据库 }, - { timeout: 30000 }, // 设置超时时间,默认为 30 秒 + { timeout: 30000 }, ); + + await page.reload(); + await page.getByRole('button', { name: /开\s单/ }).waitFor(); await use(page); diff --git a/tests/pages/appointmentPage.ts b/tests/pages/appointmentPage.ts index 6c78308..f51f525 100644 --- a/tests/pages/appointmentPage.ts +++ b/tests/pages/appointmentPage.ts @@ -1,5 +1,6 @@ import { expect, type Page, type Locator } from '@playwright/test'; import { Customer } from '@/utils/customer'; +import { getNextAppointmentTime } from '@/utils/timeUtils'; /** * 预约状态颜色 @@ -88,22 +89,6 @@ export class AppointmentPage { await this.page.reload(); }; - /** - * 获取预约时间 - * - 8:00 --> 8:30 - * - 8:30 --> 9:00 - * - 8:50 --> 9:00 - */ - getAppointmentTimesAvailable = (data = new Date()) => { - if (!(data instanceof Date)) { - throw new Error(`传入的${data}不是时间类型`); - } - const currentHour = data.getHours(); - const nextTime = data.getMinutes() > 28 ? ':00' : ':30'; - const hour = String(currentHour + (nextTime === ':00' ? 1 : 0)).padStart(2, '0'); - return `${hour}${nextTime}`; - }; - /** * 获取预约状态 */ @@ -159,7 +144,7 @@ export class AppointmentPage { * 根据员工和时间的中心进行点击预约单元格 */ openAppointmentCell = async (name: string, time?: Date, retry = 10) => { - const currentAppointment = time ? this.getAppointmentTimesAvailable(time) : this.getAppointmentTimesAvailable(); + const currentAppointment = time ? getNextAppointmentTime(time) : getNextAppointmentTime(); const $currentTime = this.$$time.filter({ hasText: currentAppointment }); const currentTimeBoundingBox = await $currentTime.boundingBox(); diff --git a/tests/setup/boss_auth.setup.ts b/tests/setup/boss_auth.setup.ts index 319729e..4e227de 100644 --- a/tests/setup/boss_auth.setup.ts +++ b/tests/setup/boss_auth.setup.ts @@ -1,37 +1,21 @@ import { test as setup } from '@playwright/test'; import { readIndexedDB } from '@/utils/indexedDBUtils'; import fs from 'fs'; +import { firstAccount, secondAccount } from '@/common/auth'; -const firstAuthFile = '.auth/admin_first.json'; -const secondAuthFile = '.auth/admin_second.json'; - -const regex = /^https?:\/\/(www\.)?hlk\.meiguanjia\.net\/?(#\s)?$/; +const regex = /^https?:\/\/(?:www\.)?hlk\.meiguanjia\.net\/$/; /** @param personalizedPages 营销-个性化页面*/ const personalizedPages = '/#/marketing/brand/personalized'; -class testAccount { - constructor(account: string, password: string, path: string) { - this.account = account; - this.password = password; - this.path = path; - } +const testAccountArray = [firstAccount, secondAccount]; - 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), -]; - -for (let a of allAccounts) { - setup(`租户${a.account}总部管理员登录`, async ({ page, baseURL }) => { - const account = a.account; - const password = a.password; - const savePath = a.path; +for (let testAccount of testAccountArray) { + setup(`租户${testAccount.account}总部管理员登录`, async ({ page, baseURL }) => { + const account = testAccount.account; + const password = testAccount.password; + const authFile = testAccount.authFile; + const indexedDBFile = testAccount.indexedDBFile; const $phonePassIcon = page .locator('div', { has: page.getByRole('textbox', { name: '请输入您的手机号码' }) }) @@ -64,7 +48,7 @@ for (let a of allAccounts) { const readIndexedDBFn = new Function('return ' + readIndexedDBFnString)(); return await readIndexedDBFn(); }, readIndexedDB.toString()); - fs.writeFileSync('.auth/admin_first_indexeddb.json', JSON.stringify(result)); - await page.context().storageState({ path: savePath }); + fs.writeFileSync(indexedDBFile, JSON.stringify(result)); + await page.context().storageState({ path: authFile }); }); } diff --git a/tests/setup/staff_auth.setup.ts b/tests/setup/staff_auth.setup.ts index cf456c7..89f2eaf 100644 --- a/tests/setup/staff_auth.setup.ts +++ b/tests/setup/staff_auth.setup.ts @@ -1,5 +1,7 @@ -import { test as setup, expect } from "@playwright/test"; -const authFileArray = [".auth/user_1.json", ".auth/user_2.json"]; +import { test as setup, expect } from '@playwright/test'; +import { getEnvVar } from '@/utils/envUtils'; + +const authFileArray = ['.auth/user_1.json', '.auth/user_2.json']; const employee = [ { phone: process.env.staff1_account, @@ -10,21 +12,21 @@ const employee = [ password: process.env.staff2_password, }, ]; -setup.describe("员工登录", () => { +setup.describe('员工登录', () => { for (let i = 0; i < 2; i++) { setup(`门店员工登录_${i}`, async ({ page }) => { - const baseUrl = process.env.BASE_URL; - const $phone = page.getByRole("textbox", { name: "请输入您的手机号码" }); - const $password = page.getByRole("textbox", { name: "请输入登录密码" }); - const $login = page.getByRole("button", { name: /登\s录/ }); + const baseUrl = getEnvVar('BASE_URL'); + const $phone = page.getByRole('textbox', { name: '请输入您的手机号码' }); + const $password = page.getByRole('textbox', { name: '请输入登录密码' }); + const $login = page.getByRole('button', { name: /登\s录/ }); await page.goto(baseUrl); await $phone.fill(employee[i].phone); - const checkPhone = page.locator(".ant-row", { has: $phone }).locator(".pass_svg"); + const checkPhone = page.locator('.ant-row', { has: $phone }).locator('.pass_svg'); await expect(checkPhone).toBeVisible(); await $password.fill(employee[i].password); - await page.getByLabel("请同意慧来客隐私政策和用户协议").check(); + await page.getByLabel('请同意慧来客隐私政策和用户协议').check(); await $login.click(); - await expect(page.getByRole("button", { name: /开\s单/ })).toBeEnabled(); + await expect(page.getByRole('button', { name: /开\s单/ })).toBeEnabled(); await page.context().storageState({ path: authFileArray[i] }); }); } diff --git a/tests/touch/boss_appointment.spec.ts b/tests/touch/boss_appointment.spec.ts index 7a00a3c..a2b1ebb 100644 --- a/tests/touch/boss_appointment.spec.ts +++ b/tests/touch/boss_appointment.spec.ts @@ -1,24 +1,19 @@ // @ts-check import { faker } from '@faker-js/faker/locale/zh_CN'; import { test, expect } from '@/fixtures/boss_common.js'; -import { staffData } from '@/fixtures/staff.js'; -import { HomeNavigation } from '@/pages/homeNavigationPage.js'; -import { AppointmentPage } from '@/pages/appointmentPage.js'; -import { AppointmentOperation } from '@/pages/appointmentPage.js'; +import { staffData } from '@/common/staff'; +import { AppointmentOperation } from '@/pages/appointmentPage'; +import { getNextAppointmentTime } from '@/utils/timeUtils'; test('使用预约单元格', async ({ page, homeNavigation, createCustomer, appointmentPage, customerPage }) => { const employee = staffData.firstStore.firstSector.employee_1; - const setAppointmentTime = appointmentPage.getAppointmentTimesAvailable(); - + const appointmentTime = getNextAppointmentTime(); const customer = createCustomer; /** 当前可预约时间定位器 */ - const $time = page.locator('.times_table td').filter({ hasText: setAppointmentTime }); + const $time = page.locator('.times_table td').filter({ hasText: appointmentTime }); /** 顾客预约定位器 */ - const $customerAppointment = page - .locator('.a_userInfo') - .filter({ hasText: customer.phone }) - .filter({ hasText: customer.username }); + const $customerAppointment = page.locator('.a_userInfo').filter({ hasText: customer.phone }).filter({ hasText: customer.username }); await test.step('进行未指定预约', async () => { await homeNavigation.gotoModule('预约'); @@ -96,7 +91,7 @@ test('使用预约单元格', async ({ page, homeNavigation, createCustomer, app test('占用预约单元格', async ({ page, homeNavigation, createCustomer, appointmentPage, customerPage }) => { // 获取当前可预约时间 - let setAppointmentTime = appointmentPage.getAppointmentTimesAvailable(); + let appointmentTime = getNextAppointmentTime(); // 创建顾客 const customer = createCustomer; @@ -106,7 +101,7 @@ test('占用预约单元格', async ({ page, homeNavigation, createCustomer, app const remark = '占用预约单元格' + faker.string.alpha(2); // 当前可预约时间定位器 - const $time = page.locator('.times_table td').filter({ hasText: setAppointmentTime }); + const $time = page.locator('.times_table td').filter({ hasText: appointmentTime }); // 员工定位器 const $employee = page.locator('.room_table .tr .name_th').filter({ hasText: employee.name }); // 顾客预约定位器 @@ -202,18 +197,15 @@ test('占用预约单元格', async ({ page, homeNavigation, createCustomer, app test.describe('预约状态', () => { test('预约-挂单-结算', async ({ page, homeNavigation, createCustomer, appointmentPage, customerPage, billSet }) => { - // 员工4 const employee = staffData.firstStore.firstSector.employee_4; - // 使用的项目 const project = { no: '100018', name: '苹果精萃护理', shortName: '精萃护理', price: 980 }; - // 获取当前可预约时间 - const setAppointmentTime = appointmentPage.getAppointmentTimesAvailable(); + const appointmentTime = getNextAppointmentTime(); + const customer = createCustomer; + // 当前可预约时间定位器 - const $time = page.locator('.times_table td').filter({ hasText: setAppointmentTime }); + const $time = page.locator('.times_table td').filter({ hasText: appointmentTime }); // 员工定位器 const $employee = page.locator('.room_table .tr .name_th').filter({ hasText: employee.name }); - // 创建顾客 - const customer = createCustomer; // 获取设置的预约状态 let appointmentStatusSetting; @@ -311,74 +303,29 @@ test.describe('预约状态', () => { }); }); -test.afterEach(async ({ homeNavigation, wasteBookBusinessRecordPage, billSet }) => { - // 撤回预约开的单 - await homeNavigation.gotoModule('流水'); - await wasteBookBusinessRecordPage.revokeOrder(billSet); -}); - -// 清除当前时间之后所有的预约和占用 -test.afterAll(async ({ browser, baseURL }) => { - const page = await browser.newPage(); - await page.goto(baseURL ?? ''); - - const homeNavigation = new HomeNavigation(page); - const appointmentPage = new AppointmentPage(page); - +test('测试预约操作', async ({ page, homeNavigation }) => { await homeNavigation.gotoModule('预约'); - await expect(page.getByText('张伟')).toBeVisible(); - const $$userInfo = page.locator('.a_userInfo'); - // 获取顾客占用预约单元格信息 - const $$appointmentBox = $$userInfo.locator('.appointment_content'); + await page.getByRole('button', { name: /设\s置/ }).waitFor(); + await page.waitForTimeout(3000); + // await page.mouse.wheel(0, 500); - const names = await $$appointmentBox.locator('.name').allInnerTexts(); - const userPhones = await $$appointmentBox.locator('.user_phone').allInnerTexts(); + const $table = page.locator('.content_table'); + const tableBox = await $table.boundingBox(); + if (tableBox) { + const startX = tableBox.x + tableBox.width / 2; // 元素中心点 X 坐标 + const startY = tableBox.y + tableBox.height / 2; // 元素中心点 Y 坐标 - const userInfoData = names.map((name, index) => { - return { - name, - phone: userPhones[index], - }; - }); + // 移动鼠标到起始位置 + await page.mouse.move(startX, startY); - // 取消预约占用 - // 获取占用框的数量 - let occupyBoxCount = await $$userInfo.locator('.occupy').count(); - while (occupyBoxCount > 0) { - // 每次都使用 first() 获取第一个占用框 - const $occupyBox = $$userInfo.locator('.occupy').first(); - await $occupyBox.click(); - await page - .locator('.popup_content .class_content') - .getByText(/^取消占用$/) - .click(); + // 按下鼠标左键 + await page.mouse.down(); - try { - // 等待请求成功,确认按钮和响应并行处理 - await Promise.all([ - page.waitForResponse(res => res.url().includes('/reservation') && res.status() === 200, { - timeout: 5000, - }), // 添加超时 - page.getByRole('button', { name: /确\s认/ }).click(), - ]); - } catch (error) { - console.error('取消预约时出现错误: ', error); - } + // 向左拖动 (X 坐标减小,Y 坐标保持不变) + await page.mouse.move(startX - 400, startY, { steps: 10 }); - await page.waitForTimeout(500); - occupyBoxCount = await $$userInfo.locator('.occupy').count(); + // 松开鼠标左键 + await page.mouse.up(); } - // 取消有取消预约按钮的预约 - for (const user of userInfoData) { - const { name } = user; - const $appointmentBox = $$appointmentBox.filter({ has: page.getByText(name) }).locator('.user_name_info'); - const appointCount = await $appointmentBox.count(); - if (appointCount === 1 && (await appointmentPage.elementCenterInViewport($appointmentBox.first()))) { - await $appointmentBox.first().click(); - await appointmentPage.cancelAppoint(); - } - } - - await page.close(); -}); +}); \ No newline at end of file diff --git a/tests/touch/boss_goal.spec.ts b/tests/touch/boss_goal.spec.ts index 72b6814..f533541 100644 --- a/tests/touch/boss_goal.spec.ts +++ b/tests/touch/boss_goal.spec.ts @@ -1,6 +1,6 @@ // @ts-check import { expect, test } from '@/fixtures/boss_common.js'; -import { staffData } from '@/fixtures/staff.js'; +import { staffData } from '@/common/staff'; import { Employees } from '@/fixtures/userconfig.js'; import { Customer } from '@/utils/customer'; import { KeepOnlyNumbers } from '@/utils/utils.js'; diff --git a/tests/touch/boss_marketing.spec.ts b/tests/touch/boss_marketing.spec.ts index e00c052..f864980 100644 --- a/tests/touch/boss_marketing.spec.ts +++ b/tests/touch/boss_marketing.spec.ts @@ -4,7 +4,7 @@ import { test, expect } from '@/fixtures/boss_common.js'; import path from 'path'; import { decodeQR } from '@/utils/utils.js'; import { Customer } from '@/utils/customer'; -import { staffData } from '@/fixtures/staff.js'; +import { staffData } from '@/common/staff'; import { HomeNavigation } from '@/pages/homeNavigationPage.js'; import fs from 'fs'; import { Page } from '@playwright/test'; diff --git a/tests/touch/boss_wastebook.spec.ts b/tests/touch/boss_wastebook.spec.ts index 311a3f0..f6999ee 100644 --- a/tests/touch/boss_wastebook.spec.ts +++ b/tests/touch/boss_wastebook.spec.ts @@ -6,7 +6,7 @@ import { KeepOnlyNumbers } from '@/utils/utils.js'; import fs from 'fs'; import path from 'path'; import { Employees, ProjectName } from '@/fixtures/userconfig.js'; -import { staffData } from '@/fixtures/staff.js'; +import { staffData } from '@/common/staff'; test.describe('营业记录', () => { test.beforeEach(async ({ page }) => { diff --git a/tests/utils/envUtils.ts b/tests/utils/envUtils.ts new file mode 100644 index 0000000..03e4228 --- /dev/null +++ b/tests/utils/envUtils.ts @@ -0,0 +1,7 @@ +export function getEnvVar(key: string): string { + const value = process.env[key]; + if (!value) { + throw new Error(`Environment variable ${key} is not set`); + } + return value; +} \ No newline at end of file diff --git a/tests/utils/timeUtils.ts b/tests/utils/timeUtils.ts new file mode 100644 index 0000000..612e484 --- /dev/null +++ b/tests/utils/timeUtils.ts @@ -0,0 +1,14 @@ +/** + * 获取下一个预约时间段的时间 + * - 8:00 --> 8:30 + * - 8:30 --> 9:00 + * - 8:50 --> 9:00 + */ +function getNextAppointmentTime(date = new Date()) { + const currentHour = date.getHours(); + const nextTime = date.getMinutes() > 28 ? ':00' : ':30'; + const hour = String(currentHour + (nextTime === ':00' ? 1 : 0)).padStart(2, '0'); + return `${hour}${nextTime}`; +} + +export { getNextAppointmentTime }; \ No newline at end of file