1、jest.config.js
- /*
- * For a detailed explanation regarding each configuration property, visit:
- * https://jestjs.io/docs/configuration
- */
- module.exports = {
- "reporters": [
- "default",
- ["jest-html-reporters", {
- "publicPath": "./html-report",
- "filename": `${new Date().getTime()}.html`,
- "openReport": false
- }]
- ]
-
- };
2、src/case/page
login_page.js
- /**
- * @description steps表示每个用例的执行步骤,selector字段使用的是playwright的selector选择器
- * @description assertElement表示需要断言的元素,selector可以直接使用浏览器copy的selector
- */
- module.exports = {
- pageName: 'login-page',
- url: 'https://192.168.3.80:8080/user/login',
- steps: [
- {
- type: 'input',
- selector: 'text=账号',
- value: 'user'
- },
- {
- type: 'input',
- selector: 'text=密码',
- value: 'Wlh@1234567'
- },
- {
- type: 'click',
- selector: 'button',
- }
- ],
- assertElement: [
- {
- selector: '#root > div > div > div:nth-child(1) > div > h1 > span',
- value: 'test信息平台'
- },
- {
- selector: '#root > div > div > div:nth-child(1) > div > form > div:nth-child(3) > button > span',
- value: '登录'
- }
- ]
- }
home_page.js
- module.exports = {
- pageName: 'home-page',
- url: 'https://192.168.3.80:8080/home',
- steps: [],
- assertElement: [
- {
- selector: '#logo > a > h1',
- value: 'test信息平台'
- },
- {
- selector: '#content > div > div > div > div > div.react-grid-layout.layout > div:nth-child(4) > div > div > div > div._2Wj8-Ajffvav9sQz3y4esS > span',
- value: '近30天趋势'
- },
- {
- selector: '#content > div > div > div > div > div.react-grid-layout.layout > div:nth-child(5) > div > div > div > div._2Wj8-Ajffvav9sQz3y4esS > span',
- value: '年度趋势'
- },
- {
- selector: '#content > div > div > div > div > div.react-grid-layout.layout > div:nth-child(6) > div > div > div > div._2Wj8-Ajffvav9sQz3y4esS > span',
- value: '结果占比'
- },
- {
- selector: '#content > div > div > div > div > div.react-grid-layout.layout > div:nth-child(7) > div > div > div > div._2Wj8-Ajffvav9sQz3y4esS > span',
- value: '任务占比'
- },
- {
- selector: '#root > div > div > div._1wGopWCKE7xbN00hj3CcxY.ant-layout > div._1Z92MrfcbggFRHWL0Eku7O.ant-layout-header > div > span._1r_Ku5UxCqCBFcxYwa7YcI.ant-dropdown-trigger > span.TPdRrLa458rcF0shFyj7D > span._1DLXYUJQFelazd_39MSHRs > span',
- value: '已登录'
- }
- ]
- }
keyword_page.js
- module.exports = {
- pageName: 'keyword-page',
- url: 'https://192.168.3.80:8080/keyword/list',
- steps: [],
- assertElement: [
- {
- selector: '#content > div > div > div > h3',
- value: 'xxx管理'
- },
- {
- selector: '#content > div > div > div > div > div > div._2z6IDqY1I9YYJ78A_TdGrW > div > div > div._3ICFjh4oC0gh_vBuZ4fsMO > button.ant-btn.my-button.ant-btn-primary.ant-btn-background-ghost > span',
- value: '重置'
- },
- {
- selector: '#content > div > div > div > div > div > div:nth-child(2) > div > div.ant-spin-nested-loading > div > div > div:nth-child(1) > div > div > div > div.qZHpEC_JchvC5swxxm4uE > button > span',
- value: '新建xxx策略'
- }
- ]
- }
3、src/config/setting.js
- /**
- * @description projectName表示用例集的名称
- * @description tempLogPath表示请求失败日志存放的地方
- * @type {{tempLogPath: string, projectName: string}}
- */
- module.exports = {
- projectName: 'test信息平台',
- tempLogPath:'/log/request.log'
- }
- /**
- * @description orderList表示任务运行时的执行顺序
- */
- module.exports.orderList =[
- 'login_page',
- 'home_page',
- 'keyword_page'
- ]
4、src/log/request.log
5、src/test/test.js
- const setting = require('../config/setting')
- const {chromium} = require('playwright');
- const file_load = require('../utils/file_load')
- const assertElement = require('../utils/assert_element')
- const path = require('path')
- const temp_log = require('../utils/file_temp_log')
- jest.setTimeout(10000)
- describe(`${setting.projectName}`, function () {
- let browser
- let page
- let case_path = 'src/case/page'
- let files = file_load(case_path)
- beforeAll(async function () {
- browser = await chromium.launch({
- headless: false, slowMo: 300, args: ['--start-maximized']
- });
- page = await browser.newPage({viewport: null, ignoreHTTPSErrors: true});
- page.on('requestfailed', function (request) {
- let obj = {
- time: new Date().toLocaleString(),
- url: request.url(),
- method: request.method(),
- // headers: request.allHeaders(),//这个方法用来取代下面的request.headers(),但是实际上没有生效
- headers: request.headers(),
- data: request.postData(),
- }
- temp_log(setting.tempLogPath, JSON.stringify(obj))
- })
-
- })
- beforeEach(async () => {
- })
- for (let i = 0; i < files.length; i++) {
- let module_name = files[i].replace('.js', '')
- let module_path = path.join('../case/page', module_name)
- let module_list = {}
- module_list[module_name] = require(module_path)
- it(`${module_list[module_name].pageName}`, async () => {
- if (module_list[module_name].url !== '') {
- await page.goto(module_list[module_name].url);
- }
- await assertElement(page, module_list[module_name].assertElement)
- if (module_list[module_name].steps.length !== 0) {
- for (let j of module_list[module_name].steps) {
- if (j.hasOwnProperty('type')) {
- if (j.type === 'input') {
- await page.fill(j.selector, j.value)
- } else {
- await page.click(j.selector)
- await page.waitForLoadState()
- }
- }
- }
- }
- })
- }
-
-
- afterEach(async function () {
- })
- afterAll(async () => {
- page.close()
- browser.close()
- })
- })
6、src/util/
add_style.js
- /**
- * @description 给断言的元素添加样式
- * @param page
- * @param ele
- * @param num 传0代表通过标记为绿色,1代表value没匹配,标记为红色
- * @return {Promise
} - */
- async function addStyle(page, ele, num) {
- const elementHandle = await page.$(ele)
- if (num === 0) {
- await elementHandle.evaluateHandle((ele) => ele.style = "border-style:solid;border-width:2px;border-color:green")
- } else if (num === 1) {
- await elementHandle.evaluateHandle((ele) => ele.style = "border-style:solid;border-width:2px;border-color:red")
- }
- await elementHandle.dispose();
- }
-
- module.exports = addStyle
-
-
assert_element.js
- /**
- *@description 断言页面上的元素的value,并且根据结果添加样式进行标记
- */
- const assert = require('assert')
- const addStyle = require('../utils/add_style')
- async function assertElements(page, elements) {
- for (let i of elements) {
- if (i.hasOwnProperty('value') && i.hasOwnProperty('selector')) {
- let context = await page.$eval(i.selector, e => e.innerText)
- if ((context.replace(' ', '')) === i.value) {
- await addStyle(page, i.selector, 0)
- assert.ok(`${i.value} matched`)
- } else {
- await addStyle(page, i.selector, 1)
- assert.fail(`${i.value} not matched`)
- }
- }
- }
- }
- module.exports = assertElements
file_load.js
- /**
- * @description 动态加载case中的文件,并且依据config/setting中的orderList进行排序
- */
- const fs = require('fs')
- const setting = require('../config/setting')
- module.exports = (path) => {
- let file = fs.readdirSync(path)
- for (let i in setting.orderList) {
- for (let j in file) {
- if (new RegExp(setting.orderList[i]).test(file[j])) {
- let temp = file[j]
- file[j] = file[i]
- file[i] = temp
- }
- }
- }
- return file
- }
-
-
file_temp_log.js
- /**
- * @description 生成日志
- */
- const fs = require('fs')
- const path = require('path')
- const os = require('os')
- function tempLog(log_path, data) {
- let config = path.join(__dirname.replace('utils', ''), log_path)
- if (!fs.existsSync(config)) {
- fs.writeFileSync(config, data, 'utf8')
- } else {
- fs.appendFileSync(config, `${os.EOL}${data}`, 'utf8')
- }
- }
- module.exports = tempLog
最终效果