init
Some checks are pending
Playwright Tests / test (push) Waiting to run

This commit is contained in:
LingandRX 2024-11-07 21:44:08 +08:00
parent a19e9a4b5c
commit 8bda3fc244
7 changed files with 85 additions and 291 deletions

27
.github/workflows/playwright.yml vendored Normal file
View 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

View File

@ -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"

View File

@ -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();
});
});

View File

@ -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: '请输入您的手机号码' });

View File

@ -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;

View File

@ -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);
});
});

View File

@ -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 });
// });