This commit is contained in:
parent
a19e9a4b5c
commit
8bda3fc244
27
.github/workflows/playwright.yml
vendored
Normal file
27
.github/workflows/playwright.yml
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
name: Playwright Tests
|
||||
on:
|
||||
push:
|
||||
branches: [main, master]
|
||||
pull_request:
|
||||
branches: [main, master]
|
||||
jobs:
|
||||
test:
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Install Playwright Browsers
|
||||
run: npx playwright install --with-deps
|
||||
- name: Run tests repeat 3
|
||||
run: npx playwright test:repeat
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: ${{ !cancelled() }}
|
||||
with:
|
||||
name: playwright-report
|
||||
path: playwright-report/
|
||||
retention-days: 30
|
||||
@ -6,7 +6,7 @@
|
||||
"hlk_codegen": "npx playwright codegen https://hlk.meiguanjia.net/#/",
|
||||
"mgj_codegen": "npx playwright codegen https://vip1.meiguanjia.net/shair/?v=mgj",
|
||||
"zhb_codegen": "npx playwright codegen https://shengyibao.meiguanjia.net/young/",
|
||||
"zhb_csv-5": "npx playwright test ./tests/zhb/csv-demo.spec.js:13 --repeat-each=5",
|
||||
"test:repeat": "npx playwright test ./tests/zhb ./tests/mgj ./tests/hlk --repeat-each=3",
|
||||
"ui": "npx playwright test --ui",
|
||||
"pwi": "npm ci && npx playwright install",
|
||||
"pwu": "npx playwright install --with-deps"
|
||||
|
||||
@ -2,70 +2,59 @@ const { test, expect } = require('./fixtures/common');
|
||||
const { Customer } = require('./pom/customer');
|
||||
const { faker } = require('@faker-js/faker/locale/zh_CN');
|
||||
|
||||
for (let i = 0; i < 3; i++) {
|
||||
test(`登录touch和h5,创建顾客购买会员卡,使用顾客账号到h5商城购买货品${i}`, async ({
|
||||
touchPage,
|
||||
h5Page,
|
||||
touchCustomerPage,
|
||||
h5LoginPage,
|
||||
}) => {
|
||||
const phone = faker.helpers.fromRegExp(/1[3-9][0-1]{9}/);
|
||||
const customer = new Customer(1, 1, { phone: phone });
|
||||
test('登录touch和h5,创建顾客购买会员卡,使用顾客账号到h5商城购买货品', async ({
|
||||
touchPage,
|
||||
h5Page,
|
||||
touchCustomerPage,
|
||||
h5LoginPage,
|
||||
}) => {
|
||||
const phone = faker.helpers.fromRegExp(/1[3-9][0-1]{9}/);
|
||||
const customer = new Customer(1, 1, { phone: phone });
|
||||
|
||||
await touchCustomerPage.createCustomer(customer);
|
||||
let cardName;
|
||||
await test.step('在touch页面购买会员卡', async () => {
|
||||
await touchPage.getByText('去开单').click();
|
||||
await touchPage.locator('.more > .icon > svg').click();
|
||||
await touchPage.getByText('去开卡').click();
|
||||
const $firstCard = touchPage.locator('.memberCard_box').first();
|
||||
await $firstCard.click();
|
||||
cardName = await $firstCard.locator('.card_name').innerText();
|
||||
await touchPage.getByRole('button', { name: '去结算' }).click();
|
||||
await touchPage.locator('.row').filter({ hasText: '总额' }).locator('.touchIcon').click();
|
||||
await touchPage.getByPlaceholder('请输入内容').fill('1000');
|
||||
await touchPage
|
||||
.locator('div')
|
||||
.filter({ hasText: /^789$/ })
|
||||
.getByRole('button')
|
||||
.nth(3)
|
||||
.click();
|
||||
await touchPage.locator('.paymentInfoItem', { hasText: '现金' }).click();
|
||||
await touchPage.getByText('推送消费提醒').click();
|
||||
await touchPage.getByLabel('结算签字').uncheck();
|
||||
await touchPage.getByRole('button', { name: /结\s算/ }).click();
|
||||
await touchPage.getByRole('button', { name: /跳\s过/ }).click();
|
||||
});
|
||||
|
||||
await test.step('登录h5,并且商城页面使用会员卡进行购买', async () => {
|
||||
await h5LoginPage.login(customer.phone);
|
||||
await h5Page.locator('.singIn_content > .iconfont').click();
|
||||
await h5Page.locator('.get_btn').click();
|
||||
await h5Page.locator('.back').click();
|
||||
await h5Page.locator('.bar_item', { hasText: '商城' }).click();
|
||||
await expect(h5Page.locator('.title', { hasText: '商城' })).toBeVisible();
|
||||
await h5Page.waitForTimeout(2000);
|
||||
await h5Page.reload();
|
||||
await h5Page.locator('.bar_item', { hasText: '商城' }).click();
|
||||
await expect(h5Page.locator('.title', { hasText: '商城' })).toBeVisible();
|
||||
await h5Page.locator('.li span', { hasText: '全部' }).click();
|
||||
await h5Page.locator('.p-item').nth(2).click();
|
||||
await h5Page.waitForLoadState();
|
||||
await h5Page.getByText('立即购买').click();
|
||||
await h5Page
|
||||
.locator('.goodsClassBoxMain .footerBug_true_all')
|
||||
.filter({ hasText: '确定' })
|
||||
.click();
|
||||
await h5Page.locator('.mgj-picker-head .mgj-picker-btn').filter({ hasText: '确认' }).click();
|
||||
await expect(
|
||||
h5Page
|
||||
.locator('.pay-way .form_row', { hasText: cardName })
|
||||
.locator('.radio_btn .uni-radio-input')
|
||||
).toHaveClass(/uni-radio-input-checked/);
|
||||
await expect(h5Page.getByText('确认支付')).toBeEnabled();
|
||||
await h5Page.getByText('确认支付').click();
|
||||
await expect(h5Page.getByText('支付成功').first()).toBeVisible();
|
||||
await expect(h5Page.getByText('查看订单')).toBeVisible();
|
||||
});
|
||||
await touchCustomerPage.createCustomer(customer);
|
||||
/** @type string*/
|
||||
let cardName;
|
||||
await test.step('在touch页面购买会员卡', async () => {
|
||||
await touchPage.getByText('去开单').click();
|
||||
await touchPage.locator('.more > .icon > svg').click();
|
||||
await touchPage.getByText('去开卡').click();
|
||||
const $firstCard = touchPage.locator('.memberCard_box').first();
|
||||
await $firstCard.click();
|
||||
cardName = await $firstCard.locator('.card_name').innerText();
|
||||
await touchPage.getByRole('button', { name: '去结算' }).click();
|
||||
await touchPage.locator('.row').filter({ hasText: '总额' }).locator('.touchIcon').click();
|
||||
await touchPage.getByPlaceholder('请输入内容').fill('1000');
|
||||
await touchPage.locator('div').filter({ hasText: /^789$/ }).getByRole('button').nth(3).click();
|
||||
await touchPage.locator('.paymentInfoItem', { hasText: '现金' }).click();
|
||||
await touchPage.getByText('推送消费提醒').click();
|
||||
await touchPage.getByLabel('结算签字').uncheck();
|
||||
await touchPage.getByRole('button', { name: /结\s算/ }).click();
|
||||
await touchPage.getByRole('button', { name: /跳\s过/ }).click();
|
||||
});
|
||||
}
|
||||
|
||||
await test.step('登录h5,并且商城页面使用会员卡进行购买', async () => {
|
||||
await h5LoginPage.login(customer.phone);
|
||||
await h5Page.locator('.singIn_content > .iconfont').click();
|
||||
const element = h5Page.locator('.coupon_content');
|
||||
const boundingBox = await element.boundingBox();
|
||||
|
||||
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 expect(h5Page.locator('.title', { hasText: '商城' })).toBeVisible();
|
||||
await h5Page.locator('.li span', { hasText: '全部' }).click();
|
||||
await h5Page.locator('.p-item').nth(2).click();
|
||||
await h5Page.getByText('立即购买').click();
|
||||
await h5Page.locator('uni-text').filter({ hasText: '佘山二店' }).click();
|
||||
await h5Page.getByText('确认').click();
|
||||
await h5Page.getByText('哎哟代理卡').click();
|
||||
await expect(h5Page.getByText('确认支付')).toBeEnabled();
|
||||
await h5Page.getByText('确认支付').click();
|
||||
await expect(h5Page.getByText('支付成功').first()).toBeVisible();
|
||||
await expect(h5Page.getByText('查看订单')).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
const { test: setup, expect } = require('@playwright/test');
|
||||
const path = require('path');
|
||||
const hlkAuthFile = path.join(__dirname, '../../.auth/hlk_admin.json');
|
||||
const hlkAuthFile = path.join(process.cwd(), '.auth', 'hlk_admin.json');
|
||||
|
||||
setup('hlk总部管理员登录', async ({ page, baseURL }) => {
|
||||
const $account = page.getByRole('textbox', { name: '请输入您的手机号码' });
|
||||
@ -1,6 +1,6 @@
|
||||
const { test: setup, expect } = require('@playwright/test');
|
||||
const path = require('path');
|
||||
const mgjAuthFile = path.join(__dirname, '../../.auth/mgj_admin.json');
|
||||
const mgjAuthFile = path.join(process.cwd(), '.auth', 'mgj_admin.json');
|
||||
|
||||
setup('mgj管理员登录', async ({ page, baseURL }) => {
|
||||
const account = process.env.MGJ_ACCOUNT;
|
||||
@ -1,202 +0,0 @@
|
||||
const { faker } = require('@faker-js/faker');
|
||||
const { test, expect } = require('./fixture/common');
|
||||
const { Customer } = require('./pom/customerPage');
|
||||
|
||||
test(`demo`, async ({ zhbPage, customerPage }, workerInfo) => {
|
||||
const $area = zhbPage
|
||||
.locator('.area')
|
||||
.filter({ has: zhbPage.locator('.area-name', { hasText: '二楼' }) });
|
||||
const $$room = $area.locator('.room-list .room');
|
||||
|
||||
const customer = new Customer();
|
||||
await test.step('创建顾客', async () => {
|
||||
await zhbPage.locator('#tab_main li').filter({ hasText: '顾客' }).click();
|
||||
await customerPage.createCustomer(customer);
|
||||
});
|
||||
|
||||
let useRoomName;
|
||||
await test.step('购买商品', async () => {
|
||||
await zhbPage.locator('#tab_main li').filter({ hasText: '营业' }).click();
|
||||
const $emptyRoom = $$room
|
||||
.filter({ has: zhbPage.getByText('空房') })
|
||||
.nth(workerInfo.workerIndex % 3);
|
||||
useRoomName = await $emptyRoom.locator('.roomName').innerText();
|
||||
expect(useRoomName).not.toBeNull();
|
||||
await $emptyRoom.click();
|
||||
await expect(async () => {
|
||||
if (await zhbPage.locator('.close > .iconfont').first().isVisible()) {
|
||||
await zhbPage.locator('.close > .iconfont').first().click();
|
||||
}
|
||||
await zhbPage.getByRole('button', { name: '选择顾客' }).click({ timeout: 3000 });
|
||||
await expect(zhbPage.locator('#page_searchMember').getByText('创建会员')).toBeVisible();
|
||||
}).toPass();
|
||||
await zhbPage
|
||||
.getByRole('textbox', { name: '输入会员手机号或姓名或卡号搜索' })
|
||||
.fill(customer.phone, { delay: 100 });
|
||||
await zhbPage.locator('#page_searchMember svg').click();
|
||||
|
||||
const $customerTr = zhbPage
|
||||
.locator('.list-warp')
|
||||
.filter({ has: zhbPage.locator('.name', { hasText: customer.name }) });
|
||||
await $customerTr.locator('.list-body').first().click();
|
||||
|
||||
await zhbPage.getByText('项目开单').click();
|
||||
await expect(zhbPage.locator('#page_roomDetail').getByText('服务项目')).toBeVisible();
|
||||
await zhbPage.getByText('选择', { exact: true }).nth(1).click();
|
||||
await expect(zhbPage.locator('#serviceSelector').getByText('项目选择')).toBeVisible();
|
||||
await zhbPage
|
||||
.locator('.goods-content-item')
|
||||
.nth(faker.number.int({ min: 0, max: 14 }))
|
||||
.click();
|
||||
await zhbPage.locator('#serviceSelector').getByText('确认').click();
|
||||
await zhbPage
|
||||
.locator('div')
|
||||
.filter({ hasText: /^明星足浴$/ })
|
||||
.locator('span')
|
||||
.first()
|
||||
.click();
|
||||
await zhbPage.getByRole('button', { name: '完成开单' }).click();
|
||||
await expect(zhbPage.getByRole('button', { name: '结账' })).toBeVisible({ timeout: 30_000 });
|
||||
await zhbPage.getByRole('button', { name: '结账' }).click();
|
||||
await zhbPage.locator('#page_footBathPay').getByText('结算签字').click();
|
||||
|
||||
await expect(async () => {
|
||||
await zhbPage.locator('#page_footBathPay li').filter({ hasText: '现金' }).click();
|
||||
await expect(zhbPage.locator('#page_footBathPay li').filter({ hasText: '现金' })).toHaveClass(
|
||||
/selected/
|
||||
);
|
||||
await zhbPage
|
||||
.locator('#page_footBathPay span')
|
||||
.filter({ hasText: /结\s算/ })
|
||||
.click();
|
||||
await expect(zhbPage.getByText('顾客满意度点评')).toBeVisible({ timeout: 2000 });
|
||||
}).toPass();
|
||||
|
||||
await zhbPage.getByText('不想评价').click();
|
||||
await zhbPage.locator('#page_footBathPay').getByText('立即返回').click();
|
||||
});
|
||||
|
||||
await test.step('起钟下钟,清理房间', async () => {
|
||||
const $cleanRoom = $$room.filter({
|
||||
has: zhbPage.locator('.roomName', { hasText: new RegExp(`^${useRoomName}$`) }),
|
||||
});
|
||||
await expect($cleanRoom).toContainText('已结清');
|
||||
await $cleanRoom.click();
|
||||
await zhbPage.getByText('技师操作').click();
|
||||
await zhbPage.getByText('起钟', { exact: true }).click();
|
||||
await zhbPage.getByText('起钟成功!').click();
|
||||
await zhbPage.getByText('技师操作').click();
|
||||
await zhbPage.getByText('下钟', { exact: true }).click();
|
||||
await zhbPage
|
||||
.locator('div')
|
||||
.filter({ hasText: /^确认返回$/ })
|
||||
.locator('div')
|
||||
.first()
|
||||
.click();
|
||||
await zhbPage.getByRole('button', { name: '不需要' }).click();
|
||||
|
||||
await expect($cleanRoom).toContainText('打扫');
|
||||
await $cleanRoom.click();
|
||||
await zhbPage
|
||||
.locator('div')
|
||||
.filter({ hasText: /^确定取消$/ })
|
||||
.locator('div')
|
||||
.first()
|
||||
.click();
|
||||
await expect($cleanRoom).toContainText('空房');
|
||||
});
|
||||
});
|
||||
|
||||
test.skip('h5 demo', async ({
|
||||
zhbAdminPage,
|
||||
// zhbPage,
|
||||
h5Page,
|
||||
h5LoginPage,
|
||||
// customerPage
|
||||
}) => {
|
||||
// const customer = new Customer();
|
||||
// await test.step('创建顾客', async () => {
|
||||
// await zhbPage.locator('#tab_main li').filter({ hasText: '顾客' }).click();
|
||||
// await customerPage.createCustomer(customer);
|
||||
// });
|
||||
|
||||
// await test.step('搜索顾客进行开卡', async () => {
|
||||
// await zhbPage.getByRole('textbox', { name: '输入会员手机号或姓名搜索' }).fill(customer.phone);
|
||||
// await zhbPage.locator('#page_member svg').click();
|
||||
// await zhbPage
|
||||
// .locator('.searchresultBox tbody tr')
|
||||
// .first()
|
||||
// .locator('#page_member')
|
||||
// .getByText('详情')
|
||||
// .click();
|
||||
// await expect(zhbPage.getByText('会员卡 点击卡片即可用卡进行结算哦~')).toBeVisible();
|
||||
// await zhbPage
|
||||
// .locator('p')
|
||||
// .filter({ hasText: '会员卡 点击卡片即可用卡进行结算哦~' })
|
||||
// .locator('span')
|
||||
// .nth(2)
|
||||
// .click();
|
||||
// await zhbPage.locator('#page_memberCard').getByText('5000元储值卡', { exact: true }).click();
|
||||
|
||||
// await expect(zhbPage.locator('#page_memberCard .cashierBox tbody tr').first()).toBeVisible();
|
||||
// await zhbPage
|
||||
// .locator('#page_memberCard')
|
||||
// .getByText(/结\s算/)
|
||||
// .click();
|
||||
|
||||
// await expect(async () => {
|
||||
// const $signature = zhbPage.locator('#page_pay').getByText('结算签字');
|
||||
// await $signature.click();
|
||||
// await expect($signature).not.toHaveClass(/checked/, { timeout: 2000 });
|
||||
// }).toPass();
|
||||
|
||||
// await expect(async () => {
|
||||
// const $cashBtn = zhbPage.locator('#page_pay .pay_cash');
|
||||
// await $cashBtn.click();
|
||||
// await expect(zhbPage.locator('#page_pay .pay_cash.selected')).toBeVisible();
|
||||
// await zhbPage
|
||||
// .locator('#page_pay span')
|
||||
// .filter({ hasText: /结\s算/ })
|
||||
// .click();
|
||||
// await expect(zhbPage.locator('#payConfirm').getByText('立即返回')).not.toBeVisible({
|
||||
// timeout: 2000,
|
||||
// });
|
||||
// }).toPass();
|
||||
// });
|
||||
|
||||
const $smsCodeInput = h5Page.getByRole('textbox', { name: '验证码', exact: true });
|
||||
await test.step('获取手机验证码', async () => {
|
||||
const graphCode = await h5LoginPage.sendSmsCode('17770898274');
|
||||
await h5Page.getByRole('textbox', { name: '请输入图形验证码' }).fill(graphCode);
|
||||
await h5Page.locator('#setup_loginForm').getByText('获取验证码').nth(1).first().tap();
|
||||
await expect(h5Page.getByText('重新发送')).toBeVisible();
|
||||
});
|
||||
|
||||
let smsCode;
|
||||
await test.step('获取短信验证码', async () => {
|
||||
await zhbAdminPage
|
||||
.locator('a')
|
||||
.filter({ hasText: /^管理$/ })
|
||||
.click();
|
||||
await zhbAdminPage.locator('.menu-item').getByText('短信发送记录', { exact: true }).click();
|
||||
const $smsCodeTr = zhbAdminPage
|
||||
.locator('#routerView iframe')
|
||||
.contentFrame()
|
||||
.locator('.table-responsive tbody tr')
|
||||
.filter({ hasText: '17770898274' })
|
||||
.first()
|
||||
.locator('td')
|
||||
.nth(2);
|
||||
await expect($smsCodeTr).toBeVisible();
|
||||
const text = await $smsCodeTr.innerText();
|
||||
smsCode = text.match(/验证码是(\d{4})/)[1];
|
||||
});
|
||||
expect(smsCode).not.toBeUndefined();
|
||||
|
||||
await test.step('使用短信验证码登录h5', async () => {
|
||||
await h5Page.getByRole('textbox', { name: '验证码', exact: true }).fill(smsCode);
|
||||
await h5Page.locator('#setup_loginForm span').first().tap();
|
||||
await h5Page.getByText('绑定', { exact: true }).tap();
|
||||
await h5Page.waitForTimeout(5000);
|
||||
});
|
||||
});
|
||||
@ -1,7 +1,6 @@
|
||||
const { test: setup, expect } = require('@playwright/test');
|
||||
const path = require('path');
|
||||
const zhbAuthFile = '.auth/zhb.json';
|
||||
const zhbAdminAuthFile = '.auth/zhb_admin.json';
|
||||
const zhbAuthFile = path.join(process.cwd(), '.auth', 'zhb.json');
|
||||
|
||||
setup('zhb总部管理员登录', async ({ page, baseURL }) => {
|
||||
const account = process.env.ZHB_ACCOUNT;
|
||||
@ -19,22 +18,3 @@ setup('zhb总部管理员登录', async ({ page, baseURL }) => {
|
||||
await expect(page.locator('#tab_main li').filter({ hasText: '营业' })).toBeVisible();
|
||||
await page.context().storageState({ path: zhbAuthFile });
|
||||
});
|
||||
|
||||
// setup('zhb管理页面登录', async ({ page }) => {
|
||||
// const account = process.env.ZHB_ACCOUNT;
|
||||
// const password = process.env.ZHB_PASSWORD;
|
||||
// const baseURL = process.env.ZHB_ADMIN_URL;
|
||||
|
||||
// await page.goto(baseURL);
|
||||
|
||||
// await page.getByPlaceholder('账户').fill(account);
|
||||
// await page.getByPlaceholder('密码').fill(password);
|
||||
// await page.getByRole('button', { name: '登 录' }).click();
|
||||
// await expect(page.locator('a').filter({ hasText: /^收银$/ })).toBeVisible();
|
||||
// await page
|
||||
// .locator('a')
|
||||
// .filter({ hasText: /^顾客$/ })
|
||||
// .click();
|
||||
// await expect(page.getByText('顾客概要分析')).toBeVisible();
|
||||
// await page.context().storageState({ path: zhbAdminAuthFile });
|
||||
// });
|
||||
Reference in New Issue
Block a user