端到端测试框架选取
- playwright 、 cypress 、 selenium 对比
cypress使用
- 下载 cypress
- npm install cypress --save-dev
- package.json
- npm run cypress:open
{ "scripts": { "cypress:open": "cypress open" } }
使用流程
- 入门官方文档
-
npm run cypress:open
-
左侧端测试,右侧组件测试,点击左侧
-
选择你需要的浏览器,点击开始
-
自动打开浏览器,点击左侧specs(测试文件菜单),点击内容区域.cy.ts文件
-
左侧是测试执行栏,会有每个指令的详细信息以及成功失败,箭头可以点开看详细信息. 右侧是内容显示栏会有页面显示
code
- 每次it测试,触发窗口大小变化,然后登录,第一次会正常执行,然后保存登录状态,cy.session再次触发,如果登录过,会直接跳过
- 指令解析
- cy.visit 访问地址
- cy.origin 如果登录地址会先跳到一个login登录链接,登录完成再次回到业务链接时,域变化,需要加origin指令
- cy.get 得到dom元素, id class都支持
- dom元素后可以 click 点击 , type 填充内容, each 循环dom列表, first 第一个儿子等.
- cypress/support/commands.ts
- // Cypress.Commands.add(‘login’, (email, password) => { … })
- 登录方法可以封装成全局方法
- // Cypress.Commands.add(‘login’, (email, password) => { … })
- cypress/e2e/home-cypress.cy.ts
describe('template spec', () => { beforeEach(() => { cy.viewport(2000, 1000); cy.session('mySession', () => { cy.visit('https://xxxx'); cy.get('#account').type('xxxx'); cy.get('#password').type('xxxx'); cy.get('.btn-login').click(); }); }); it('login done', () => { cy.origin('https://xxxx', () => { cy.visit('https://xxxx/xxx'); cy.on('uncaught:exception', (e) => { // 控制台报错会让测试停止,需要添加这段 return false; }); // cy.wait(500) 等待时间 , 直接写wait或者 get第二个参数填写timeout cy.get('.ls-workstation-sidebar-avatar-name', { timeout: 30 * 1000 }).should('contain', '刘胜'); cy.get('.ant-pro-form-collapse-button', { timeout: 30 * 1000 }).each(($el, index, $list) => { // $el is a wrapped jQuery element cy.wrap($el).click(); }); cy.get('#contractNo', { timeout: 30 * 1000 }).type('PH0038417'); const btnEles = cy .get('button.ant-btn-primary', { timeout: 30 * 1000 }) .first() .click(); }); }); });
selenium使用
- npm install selenium-webdriver
- npm install chromedriver --save
- npm下载以外还可以手动下载浏览器
使用流程
- 官方入门指南
- 写js文件, 用node执行此文件
- 会自动打开谷歌,然后自动执行代码
code
- 指令解析
- driver.get 导航到url
- driver.findElement(By.css()) dom元素, by.css里可以是id class
- sendKeys 填充内容, click点击, getText 得到文本内容
- driver.findElements dom元素列表
- tests/home-selenium.js
const {By, Builder, until} = require('selenium-webdriver'); const assert = require("assert"); const driver = new Builder().forBrowser('chrome').build(); (async function () { // 导航到某个网站 await driver.get('https://xxx/xxx'); driver.findElement(By.css('#account')).sendKeys('ddd'); driver.findElement(By.css('#password')).sendKeys('aaa'); await driver.findElement(By.css('.btn-login')).click(); const avatarName = await driver.wait( until.elementLocated(By.className('ls-sidebar-avatar-name')), 30000, );// 等待得到这个dom,超时时间30000ms const avatarText = await avatarName.getText(); assert(avatarText === '清羽', 'login done');// 断言 const contractNoEle = await driver.wait(until.elementLocated(By.css('#contractNo')), 30000); contractNoEle.sendKeys('PC00398414'); const collapseEles = await driver.findElements(By.css('.ant-pro-form-collapse-button')); for (const ele of collapseEles) { ele.click(); } const btnEles = await driver.findElements(By.css('button.ant-btn-primary')); let index = 0; for (const ele of btnEles) { if (index == 0) { ele.click(); } index++; } // 关闭浏览器 // await driver.quit(); })();
playwright
- 下载
- tnpm init playwright@latest
- 官方插件
- Playwright Test for VSCode 插件
使用流程
- 官方入门文档
- 使用官方插件测试, 选中home.spec.ts点击三角执行,会打开WebDriver(需勾选show browser),然后可以看到自动化测试页面
--
不勾选,使用无头浏览器测试,勾选后测试会打开WebDriver
-
WebDriver
- 指令执行测试
- 测试文件
- npx playwright test example.spec.ts
- 在特定浏览器上运行测试
- npx playwright test home.spec.ts --project=‘chromium’
- 测试报告
- codegen在浏览器中运行并执行操作。Playwright 将为用户交互生成代码。
- npx playwright codegen home.spec.ts
- npx playwright test home.spec.ts --project=‘chromium’
-
code
- 指令解析
- test.beforeEach 每次子test执行之前会执行一下
- page.locator(“#account”) 得到dom元素
- fill 快速填充, click点击, filter 过滤 , first 第一个儿子
- async await 异步变同步
- tests/home.spec.ts
test.describe("workstation login", () => { test.beforeEach(async ({ page }) => { await page.goto( "https://xxxx/xxx" ); }); test("login", async ({ page }) => { await page.locator("#account").fill("xxx"); await page.locator("#password").fill("xxx"); await page.locator(".btn-login").click(); const avatarName = await page.locator( ".lzd-workstation-sidebar-avatar-name" ); expect(avatarName).toContainText("万物"); await page.locator('div').filter({ hasText: /^Expand$/ }).first().click(); await page.locator('div').filter({ hasText: /^Expand$/ }).first().click(); await page.locator("#contractNo").first().fill("PC09038414"); await page.locator("button.ant-btn-primary").first().click(); }); });
- playwright.config.ts
- 配置文件
import { defineConfig, devices } from '@playwright/test'; /** * Read environment variables from file. * https://github.com/motdotla/dotenv */ // require('dotenv').config(); /** * See https://playwright.dev/docs/test-configuration. */ export default defineConfig({ testDir: './tests', // 测试目录 expect: { /** * expect()应等待满足条件的最长时间 * 例如,在'await expect(locator).toHaveText()' */ timeout: 20 * 1000, }, timeout: 30 * 1000, // 每个测试用例超时 globalTimeout: 60 * 1000, // 总超时 fullyParallel: true, /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: !!process.env.CI, /* Retry on CI only */ retries: process.env.CI ? 2 : 0, /* Opt out of parallel tests on CI. */ workers: process.env.CI ? 1 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ // reporter: 'html', reporter: [['html', { outputFolder: './playwrightTests', open: 'always' }]], // 测试报告 /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Base URL to use in actions like `await page.goto('/')`. */ // baseURL: 'http://127.0.0.1:3000', /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ // trace: 'on-first-retry', launchOptions: { headless: false, // 不是无头模式 }, contextOptions: { viewport: { // 窗口视野大小 width: 1400, height: 900, }, }, }, /* Configure projects for major browsers */ projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] }, }, { name: 'firefox', use: { ...devices['Desktop Firefox'] }, }, { name: 'webkit', use: { ...devices['Desktop Safari'] }, }, /* Test against mobile viewports. */ // { // name: 'Mobile Chrome', // use: { ...devices['Pixel 5'] }, // }, // { // name: 'Mobile Safari', // use: { ...devices['iPhone 12'] }, // }, /* Test against branded browsers. */ // { // name: 'Microsoft Edge', // use: { ...devices['Desktop Edge'], channel: 'msedge' }, // }, // { // name: 'Google Chrome', // use: { ..devices['Desktop Chrome'], channel: 'chrome' }, // }, ], /* Run your local dev server before starting the tests */ // webServer: { // command: 'npm run start', // url: 'http://127.0.0.1:3000', // reuseExistingServer: !process.env.CI, // }, });