Compare commits
6 Commits
db0603dcfd
...
73cce24b80
| Author | SHA1 | Date | |
|---|---|---|---|
| 73cce24b80 | |||
| 5247b50c0c | |||
| be91605c3c | |||
| 44a701cbed | |||
|
|
af98ccd0b8 | ||
| d870c80378 |
2
.github/workflows/playwright.yml
vendored
2
.github/workflows/playwright.yml
vendored
@ -5,7 +5,7 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
branches: [main, master]
|
branches: [main, master]
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '30 9 * * *' # 每天凌晨 12 点执行一次
|
- cron: '30 1 * * *' # 每天 上午 9.30 执行一次
|
||||||
workflow_dispatch: # 手动触发
|
workflow_dispatch: # 手动触发
|
||||||
jobs:
|
jobs:
|
||||||
test:
|
test:
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
"mgj_codegen": "npx playwright codegen https://vip1.meiguanjia.net/shair/?v=mgj",
|
"mgj_codegen": "npx playwright codegen https://vip1.meiguanjia.net/shair/?v=mgj",
|
||||||
"zhb_codegen": "npx playwright codegen https://shengyibao.meiguanjia.net/young/",
|
"zhb_codegen": "npx playwright codegen https://shengyibao.meiguanjia.net/young/",
|
||||||
"test:repeat": "npx playwright test ./tests/zhb ./tests/mgj ./tests/hlk --repeat-each=3",
|
"test:repeat": "npx playwright test ./tests/zhb ./tests/mgj ./tests/hlk --repeat-each=3",
|
||||||
|
"test:simple": "npx playwright test ./tests/zhb ./tests/mgj ./tests/hlk",
|
||||||
"ui": "npx playwright test --ui",
|
"ui": "npx playwright test --ui",
|
||||||
"pwi": "npm ci && npx playwright install",
|
"pwi": "npm ci && npx playwright install",
|
||||||
"pwu": "npx playwright install --with-deps"
|
"pwu": "npx playwright install --with-deps"
|
||||||
|
|||||||
@ -24,12 +24,18 @@ module.exports = defineConfig({
|
|||||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
||||||
forbidOnly: !!process.env.CI,
|
forbidOnly: !!process.env.CI,
|
||||||
/* Retry on CI only */
|
/* Retry on CI only */
|
||||||
retries: process.env.CI ? 2 : 0,
|
retries: process.env.CI ? 1 : 0,
|
||||||
/* Opt out of parallel tests on CI. */
|
/* Opt out of parallel tests on CI. */
|
||||||
workers: process.env.CI ? 1 : 1,
|
workers: process.env.CI ? 1 : 1,
|
||||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||||
reporter: 'html',
|
reporter: 'html',
|
||||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
||||||
|
timeout: 3 * 60000,
|
||||||
|
expect: {
|
||||||
|
toPass: {
|
||||||
|
timeout: 30000,
|
||||||
|
},
|
||||||
|
},
|
||||||
use: {
|
use: {
|
||||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
/* Base URL to use in actions like `await page.goto('/')`. */
|
||||||
baseURL: process.env.BASE_URL,
|
baseURL: process.env.BASE_URL,
|
||||||
@ -41,7 +47,7 @@ module.exports = defineConfig({
|
|||||||
'Accept-Language': 'zh-CN,zh;q=0.9',
|
'Accept-Language': 'zh-CN,zh;q=0.9',
|
||||||
},
|
},
|
||||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||||
trace: 'on-first-retry',
|
trace: 'retain-on-failure',
|
||||||
},
|
},
|
||||||
|
|
||||||
/* Configure projects for major browsers */
|
/* Configure projects for major browsers */
|
||||||
|
|||||||
@ -2,59 +2,50 @@ const { test, expect } = require('./fixtures/common');
|
|||||||
const { Customer } = require('./pom/customer');
|
const { Customer } = require('./pom/customer');
|
||||||
const { faker } = require('@faker-js/faker/locale/zh_CN');
|
const { faker } = require('@faker-js/faker/locale/zh_CN');
|
||||||
|
|
||||||
test('登录touch和h5,创建顾客购买会员卡,使用顾客账号到h5商城购买货品', async ({
|
test.describe
|
||||||
touchPage,
|
.serial('登录touch和h5,创建顾客购买会员卡,使用顾客账号到h5商城购买货品', async () => {
|
||||||
h5Page,
|
|
||||||
touchCustomerPage,
|
|
||||||
h5LoginPage,
|
|
||||||
}) => {
|
|
||||||
const phone = faker.helpers.fromRegExp(/1[3-9][0-1]{9}/);
|
const phone = faker.helpers.fromRegExp(/1[3-9][0-1]{9}/);
|
||||||
const customer = new Customer(1, 1, { phone: phone });
|
const customer = new Customer(1, 1, { phone: phone });
|
||||||
|
console.log(`${customer.phone}-${customer.username}`);
|
||||||
|
|
||||||
await touchCustomerPage.createCustomer(customer);
|
test('登录touch和h5,创建顾客购买会员卡', async ({ touchPage, touchCustomerPage }) => {
|
||||||
/** @type string*/
|
|
||||||
let cardName;
|
|
||||||
await test.step('在touch页面购买会员卡', async () => {
|
await test.step('在touch页面购买会员卡', async () => {
|
||||||
|
await touchCustomerPage.createCustomer(customer);
|
||||||
await touchPage.getByText('去开单').click();
|
await touchPage.getByText('去开单').click();
|
||||||
await touchPage.locator('.more > .icon > svg').click();
|
await touchPage.locator('.more > .icon > svg').click();
|
||||||
await touchPage.getByText('去开卡').click();
|
await touchPage.getByText('去开卡').click();
|
||||||
const $firstCard = touchPage.locator('.memberCard_box').first();
|
const $firstCard = touchPage.locator('.memberCard_box').first();
|
||||||
await $firstCard.click();
|
await $firstCard.click();
|
||||||
cardName = await $firstCard.locator('.card_name').innerText();
|
|
||||||
await touchPage.getByRole('button', { name: '去结算' }).click();
|
await touchPage.getByRole('button', { name: '去结算' }).click();
|
||||||
await touchPage.locator('.row').filter({ hasText: '总额' }).locator('.touchIcon').click();
|
await touchPage.locator('.row').filter({ hasText: '总额' }).locator('.touchIcon').click();
|
||||||
await touchPage.getByPlaceholder('请输入内容').fill('1000');
|
await touchPage.getByPlaceholder('请输入内容').fill('1000');
|
||||||
await touchPage.locator('div').filter({ hasText: /^789$/ }).getByRole('button').nth(3).click();
|
await touchPage
|
||||||
|
.locator('div')
|
||||||
|
.filter({ hasText: /^789$/ })
|
||||||
|
.getByRole('button')
|
||||||
|
.nth(3)
|
||||||
|
.click();
|
||||||
await touchPage.locator('.paymentInfoItem', { hasText: '现金' }).click();
|
await touchPage.locator('.paymentInfoItem', { hasText: '现金' }).click();
|
||||||
await touchPage.getByText('推送消费提醒').click();
|
await touchPage.getByLabel('推送消费提醒').uncheck();
|
||||||
await touchPage.getByLabel('结算签字').uncheck();
|
await touchPage.getByLabel('结算签字').uncheck();
|
||||||
await touchPage.getByRole('button', { name: /结\s算/ }).click();
|
await touchPage.getByRole('button', { name: /结\s算/ }).click();
|
||||||
await touchPage.getByRole('button', { name: /跳\s过/ }).click();
|
await touchPage.getByRole('button', { name: /跳\s过/ }).click();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
await test.step('登录h5,并且商城页面使用会员卡进行购买', async () => {
|
test('登录h5,并且商城页面使用会员卡进行购买', async ({ h5Page, h5LoginPage }) => {
|
||||||
await h5LoginPage.login(customer.phone);
|
await h5LoginPage.login(customer.phone);
|
||||||
await h5Page.locator('.singIn_content > .iconfont').click();
|
await h5Page.locator('.singIn_content > .iconfont').click();
|
||||||
const element = h5Page.locator('.coupon_content');
|
await h5Page.locator('.get_btn').click();
|
||||||
const boundingBox = await element.boundingBox();
|
await h5Page.locator('.back').click();
|
||||||
|
|
||||||
if (boundingBox) {
|
|
||||||
const x = boundingBox.x + boundingBox.width / 2; // 元素水平中心
|
|
||||||
const y = boundingBox.y - 10; // 元素上侧空白区域
|
|
||||||
|
|
||||||
await h5Page.mouse.click(x, y);
|
|
||||||
}
|
|
||||||
await h5Page.locator('.bar_item', { hasText: '商城' }).click();
|
await h5Page.locator('.bar_item', { hasText: '商城' }).click();
|
||||||
await expect(h5Page.locator('.title', { hasText: '商城' })).toBeVisible();
|
await expect(h5Page.locator('.title', { hasText: '商城' })).toBeVisible();
|
||||||
await h5Page.locator('.li span', { hasText: '全部' }).click();
|
await h5Page.locator('.li span', { hasText: '全部' }).click();
|
||||||
await h5Page.locator('.p-item').nth(2).click();
|
await h5Page.locator('.p-item').filter({ hasText: '美肤' }).first().click();
|
||||||
await h5Page.getByText('立即购买').click();
|
await h5Page.getByText('立即购买').click();
|
||||||
await h5Page.locator('uni-text').filter({ hasText: '佘山二店' }).click();
|
|
||||||
await h5Page.getByText('确认').click();
|
await h5Page.getByText('确认').click();
|
||||||
await h5Page.getByText('哎哟代理卡').click();
|
await h5Page.getByText('哎哟代理卡').click();
|
||||||
await expect(h5Page.getByText('确认支付')).toBeEnabled();
|
|
||||||
await h5Page.getByText('确认支付').click();
|
await h5Page.getByText('确认支付').click();
|
||||||
await expect(h5Page.getByText('支付成功').first()).toBeVisible();
|
await expect(h5Page.getByText('支付成功').first()).toBeVisible();
|
||||||
await expect(h5Page.getByText('查看订单')).toBeVisible();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -39,18 +39,17 @@ test('demo', async ({ mgjPage, customerPage }) => {
|
|||||||
await expect($signature).not.toHaveClass(/checked/, { timeout: 2000 });
|
await expect($signature).not.toHaveClass(/checked/, { timeout: 2000 });
|
||||||
}).toPass();
|
}).toPass();
|
||||||
|
|
||||||
await expect(async () => {
|
|
||||||
const $cashBtn = mgjPage.locator('#page_pay .pay_cash');
|
const $cashBtn = mgjPage.locator('#page_pay .pay_cash');
|
||||||
|
await expect(async () => {
|
||||||
|
if ($cashBtn.isVisible()) {
|
||||||
await $cashBtn.click();
|
await $cashBtn.click();
|
||||||
await expect(mgjPage.locator('#page_pay .pay_cash.selected')).toBeVisible();
|
}
|
||||||
|
await expect(mgjPage.locator('#page_pay .pay_cash.selected')).toBeVisible({ timeout: 2000 });
|
||||||
|
}).toPass();
|
||||||
await mgjPage
|
await mgjPage
|
||||||
.locator('#page_pay span')
|
.locator('#page_pay span')
|
||||||
.filter({ hasText: /结\s算/ })
|
.filter({ hasText: /结\s算/ })
|
||||||
.click();
|
.click();
|
||||||
await expect(mgjPage.getByText('顾客满意度点评')).toBeVisible({ timeout: 2000 });
|
await expect(mgjPage.getByText('顾客满意度点评')).toBeVisible();
|
||||||
}).toPass();
|
|
||||||
|
|
||||||
await mgjPage.getByText('不想评价').click();
|
|
||||||
await expect(mgjPage.locator('#page_footBathPay').getByText('立即返回')).not.toBeVisible();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -5,17 +5,18 @@ const { faker } = require('@faker-js/faker');
|
|||||||
const { test, expect } = require('./fixture/common');
|
const { test, expect } = require('./fixture/common');
|
||||||
const { Customer } = require('./pom/customerPage');
|
const { Customer } = require('./pom/customerPage');
|
||||||
|
|
||||||
|
/**@type {{name: string, phone: string}[]} */
|
||||||
const records = parse(fs.readFileSync(path.join(__dirname, 'zhb.csv')), {
|
const records = parse(fs.readFileSync(path.join(__dirname, 'zhb.csv')), {
|
||||||
columns: true,
|
columns: true,
|
||||||
skip_empty_lines: true,
|
skip_empty_lines: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
test('csv', async ({ zhbPage }, workerInfo) => {
|
test('csv', async ({ zhbPage }) => {
|
||||||
console.log(records.length);
|
console.log(records.length);
|
||||||
const $area = zhbPage
|
const $$emptyRoom = zhbPage
|
||||||
.locator('.area')
|
.locator('.area')
|
||||||
.filter({ has: zhbPage.locator('.area-name', { hasText: '二楼' }) });
|
.locator('.room-list .room')
|
||||||
const $$room = $area.locator('.room-list .room');
|
.filter({ has: zhbPage.getByText('空房') });
|
||||||
|
|
||||||
// 随机csv文件中的任意一个顾客
|
// 随机csv文件中的任意一个顾客
|
||||||
const record = records[faker.number.int({ min: 0, max: records.length - 1 })];
|
const record = records[faker.number.int({ min: 0, max: records.length - 1 })];
|
||||||
@ -23,16 +24,13 @@ test('csv', async ({ zhbPage }, workerInfo) => {
|
|||||||
console.log({ name, phone });
|
console.log({ name, phone });
|
||||||
const customer = new Customer({ name: name, phone: name });
|
const customer = new Customer({ name: name, phone: name });
|
||||||
|
|
||||||
// 使用房间名称
|
/**@type {string} 房间名称 */
|
||||||
let useRoomName;
|
let useRoomName;
|
||||||
await test.step('购买商品', async () => {
|
await test.step('购买商品', async () => {
|
||||||
await zhbPage.locator('#tab_main li').filter({ hasText: '营业' }).click();
|
await zhbPage.locator('#tab_main li').filter({ hasText: '营业' }).click();
|
||||||
const $emptyRoom = $$room
|
await $$emptyRoom.first().waitFor();
|
||||||
.filter({ has: zhbPage.getByText('空房') })
|
useRoomName = await $$emptyRoom.first().locator('.roomName').innerText();
|
||||||
.nth(workerInfo.workerIndex % 3);
|
await $$emptyRoom.first().click();
|
||||||
useRoomName = await $emptyRoom.locator('.roomName').innerText();
|
|
||||||
expect(useRoomName).not.toBeNull();
|
|
||||||
await $emptyRoom.click();
|
|
||||||
await expect(async () => {
|
await expect(async () => {
|
||||||
if (await zhbPage.locator('.close > .iconfont').first().isVisible()) {
|
if (await zhbPage.locator('.close > .iconfont').first().isVisible()) {
|
||||||
await zhbPage.locator('.close > .iconfont').first().click();
|
await zhbPage.locator('.close > .iconfont').first().click();
|
||||||
@ -56,7 +54,7 @@ test('csv', async ({ zhbPage }, workerInfo) => {
|
|||||||
await expect(zhbPage.locator('#serviceSelector').getByText('项目选择')).toBeVisible();
|
await expect(zhbPage.locator('#serviceSelector').getByText('项目选择')).toBeVisible();
|
||||||
await zhbPage
|
await zhbPage
|
||||||
.locator('.goods-content-item')
|
.locator('.goods-content-item')
|
||||||
.nth(faker.number.int({ min: 0, max: 14 }))
|
.nth(faker.number.int({ min: 0, max: 10 }))
|
||||||
.click();
|
.click();
|
||||||
await zhbPage.locator('#serviceSelector').getByText('确认').click();
|
await zhbPage.locator('#serviceSelector').getByText('确认').click();
|
||||||
await zhbPage
|
await zhbPage
|
||||||
@ -65,8 +63,10 @@ test('csv', async ({ zhbPage }, workerInfo) => {
|
|||||||
.locator('span')
|
.locator('span')
|
||||||
.first()
|
.first()
|
||||||
.click();
|
.click();
|
||||||
|
await expect(async () => {
|
||||||
await zhbPage.getByRole('button', { name: '完成开单' }).click();
|
await zhbPage.getByRole('button', { name: '完成开单' }).click();
|
||||||
await expect(zhbPage.getByRole('button', { name: '结账' })).toBeVisible({ timeout: 30_000 });
|
await zhbPage.getByRole('button', { name: '结账' }).waitFor();
|
||||||
|
}).toPass();
|
||||||
await zhbPage.getByRole('button', { name: '结账' }).click();
|
await zhbPage.getByRole('button', { name: '结账' }).click();
|
||||||
await zhbPage.locator('#page_footBathPay').getByText('结算签字').click();
|
await zhbPage.locator('#page_footBathPay').getByText('结算签字').click();
|
||||||
|
|
||||||
@ -75,26 +75,29 @@ test('csv', async ({ zhbPage }, workerInfo) => {
|
|||||||
await expect(zhbPage.locator('#page_footBathPay li').filter({ hasText: '现金' })).toHaveClass(
|
await expect(zhbPage.locator('#page_footBathPay li').filter({ hasText: '现金' })).toHaveClass(
|
||||||
/selected/
|
/selected/
|
||||||
);
|
);
|
||||||
|
}).toPass();
|
||||||
await zhbPage
|
await zhbPage
|
||||||
.locator('#page_footBathPay span')
|
.locator('#page_footBathPay span')
|
||||||
.filter({ hasText: /结\s算/ })
|
.filter({ hasText: /结\s算/ })
|
||||||
.click();
|
.click();
|
||||||
await expect(zhbPage.getByText('顾客满意度点评')).toBeVisible({ timeout: 2000 });
|
await expect(zhbPage.getByText('顾客满意度点评')).toBeVisible();
|
||||||
}).toPass();
|
|
||||||
|
|
||||||
await zhbPage.getByText('不想评价').click();
|
await zhbPage.getByText('不想评价').click();
|
||||||
await zhbPage.locator('#page_footBathPay').getByText('立即返回').click();
|
await zhbPage.locator('#page_footBathPay').getByText('立即返回').click();
|
||||||
});
|
});
|
||||||
|
|
||||||
await test.step('起钟下钟,清理房间', async () => {
|
await test.step('起钟下钟,清理房间', async () => {
|
||||||
|
const $$room = zhbPage.locator('.area').locator('.room-list .room');
|
||||||
const $cleanRoom = $$room.filter({
|
const $cleanRoom = $$room.filter({
|
||||||
has: zhbPage.locator('.roomName', { hasText: new RegExp(`^${useRoomName}$`) }),
|
has: zhbPage.locator('.roomName', { hasText: new RegExp(`^${useRoomName}$`) }),
|
||||||
});
|
});
|
||||||
await expect($cleanRoom).toContainText('已结清');
|
await expect($cleanRoom).toContainText('已结清');
|
||||||
await $cleanRoom.click();
|
await $cleanRoom.click();
|
||||||
await zhbPage.getByText('技师操作').click();
|
await zhbPage.getByText('技师操作').click();
|
||||||
|
await expect(async () => {
|
||||||
await zhbPage.getByText('起钟', { exact: true }).click();
|
await zhbPage.getByText('起钟', { exact: true }).click();
|
||||||
await zhbPage.getByText('起钟成功!').click();
|
await zhbPage.getByText('起钟成功!').waitFor();
|
||||||
|
}).toPass();
|
||||||
await zhbPage.getByText('技师操作').click();
|
await zhbPage.getByText('技师操作').click();
|
||||||
await zhbPage.getByText('下钟', { exact: true }).click();
|
await zhbPage.getByText('下钟', { exact: true }).click();
|
||||||
await zhbPage
|
await zhbPage
|
||||||
|
|||||||
Reference in New Issue
Block a user