当前位置: 首页 > news >正文

基于Midscene.js的智能UI自动化测试系统搭建实战

1. 项目概述:为什么选择 Midscene.js 来搭建 UI 自动化测试系统?

最近几年,前端技术栈的复杂度和迭代速度肉眼可见地增长,一个稍微像样点的应用,动辄就是 React/Vue + 各种状态管理 + 组件库,页面交互逻辑也越来越重。随之而来的,就是 UI 自动化测试的难度和成本直线上升。传统的基于 Selenium 或 Puppeteer 的测试脚本,写起来费劲,维护起来更费劲,页面结构一变,选择器就失效,测试用例就得跟着改,团队里负责测试的同学经常为此头疼。

正是在这种背景下,我注意到了 Midscene.js。它不是一个全新的轮子,而是在 Puppeteer 和 Playwright 这类现代浏览器自动化工具之上,构建的一套声明式、场景驱动的测试框架。它的核心思想很有意思:把测试用例看作是一系列用户操作场景(Scene)的集合,然后用一种接近自然语言的 JSON 或 YAML 来描述这些场景。比如,“点击登录按钮”、“在搜索框输入关键词并回车”、“验证搜索结果列表的第一项包含某个文本”。你不需要关心底层是用的哪个 CSS 选择器,也不需要写一堆await page.click(‘#submit-btn’)这样的命令式代码。

我第一次接触 Midscene.js 时,最打动我的就是它的“智能”定位能力。它内置了多种定位策略,会智能地尝试通过文本内容、组件角色(ARIA)、甚至是视觉特征来定位元素,这大大降低了因前端 DOM 结构微调而导致的测试用例“脆断”。对于需要快速响应业务变化、追求测试稳定性的团队来说,这无疑是个福音。

所以,这次实战的目标很明确:从零开始,搭建一套基于 Midscene.js 的智能 UI 自动化测试系统。这套系统不仅要能跑通基础的测试用例,还要融入持续集成(CI)流程,实现测试报告的自动生成与通知,最终形成一个稳定、可维护的自动化测试闭环。无论你是前端开发者想为自己的项目加一道质量保障,还是测试工程师在寻找更高效的自动化方案,这篇文章都能给你提供一条清晰的路径。

2. 核心设计思路:构建一个健壮且易维护的测试架构

在动手写第一行配置之前,我们先得把架构想清楚。一个随意的、脚本堆砌式的自动化项目,最终必然会陷入维护地狱。我们的目标是构建一个系统,而不仅仅是几个脚本。

2.1 分层设计:让关注点分离

我借鉴了经典的测试金字塔和页面对象模型(Page Object Model, POM)思想,并结合 Midscene.js 的特点,设计了四层结构:

  1. 场景层(Scene Layer):这是 Midscene.js 的核心。每个.scene.json.scene.yml文件定义了一个完整的用户操作流程,比如“用户登录并创建一条待办事项”。这一层只关心“做什么”,不关心“怎么做”和“在哪里做”。它的可读性极高,产品经理或非技术同学也能看懂大概逻辑。

  2. 页面对象层(Page Object Layer):这一层封装了具体页面的元素定位和基础操作。虽然 Midscene.js 的智能定位减少了对精确选择器的依赖,但对于复杂页面或高频使用的元素,集中管理定位信息依然是最佳实践。我们可以创建一个pages目录,里面存放各个页面的类,例如LoginPageHomePage。这些类里提供诸如getUsernameInputSelector()的方法,返回一个 Midscene.js 兼容的定位描述符(比如{ text: ‘用户名’ })。

  3. 测试用例层(TestCase Layer):这一层使用 Jest、Mocha 或 Vitest 等测试运行器,组织和管理场景。一个测试用例文件(如login.spec.js)会引入相关的页面对象和场景文件,并可能包含一些前置条件(如准备测试数据)、后置清理以及断言。Midscene.js 提供了与这些测试运行器无缝集成的运行器。

  4. 系统与CI层(System & CI Layer):这是最顶层,负责运行整个测试套件、生成报告、处理环境变量、与 CI/CD 平台(如 GitHub Actions, Jenkins)集成。我们会配置不同的运行配置文件,来区分本地开发测试和 CI 环境下的无头浏览器测试。

注意:不要试图把所有逻辑都塞进场景文件。场景文件应保持简洁,描述用户意图。复杂的业务逻辑、数据准备和清理,应该放在测试用例层或专门的工具函数中。

2.2 目录结构规划

清晰的目录结构是项目可维护的基石。以下是我推荐的结构:

smart-ui-test-system/ ├── package.json ├── midscene.config.js # Midscene.js 主配置文件 ├── jest.config.js (或其他测试框架配置) ├── .github/workflows/ # GitHub Actions CI 配置 │ └── ui-test.yml ├── src/ │ ├── scenes/ # 场景层 │ │ ├── login.scene.json │ │ ├── search.scene.yml │ │ └── checkout.scene.json │ ├── pages/ # 页面对象层 │ │ ├── LoginPage.js │ │ ├── HomePage.js │ │ └── CheckoutPage.js │ ├── tests/ # 测试用例层 │ │ ├── login.spec.js │ │ ├── search.spec.js │ │ └── checkout.spec.js │ ├── fixtures/ # 测试夹具,如静态数据、Mock 响应 │ │ └── test-data.json │ ├── utils/ # 工具函数 │ │ ├── test-helper.js │ │ └── report-generator.js │ └── runners/ # 自定义运行器(如果需要) │ └── custom-runner.js ├── reports/ # 测试报告输出目录 │ ├── html/ │ └── junit/ └── screenshots/ # 失败用例截图(可选)

这个结构将不同职责的代码清晰地分开,无论是新增场景、修改页面元素,还是调整 CI 流程,都能快速定位到相关文件。

2.3 技术选型考量

  • 测试运行器选择 Jest:我选择 Jest,因为它开箱即用,内置断言库、Mock 功能和代码覆盖率报告,生态丰富。Midscene.js 对其有很好的支持。当然,你也可以用 Mocha + Chai 的组合,看团队习惯。
  • 场景描述语言用 JSON 还是 YAML?:JSON 更通用,无需额外解析器;YAML 在书写多步骤场景时,凭借其缩进格式,可读性可能更好。我个人偏好 JSON,因为它在 JS 项目中更自然,且不易因缩进错误导致解析失败。但团队如果更熟悉 YAML,也完全没问题,Midscene.js 都支持。
  • 报告系统:除了 Jest 自带的终端输出,我们还需要更直观的 HTML 报告用于归档和分享。jest-html-reporterjest-stare是不错的选择。同时,为了 CI 平台(如 Jenkins)能解析测试结果,生成 JUnit 格式的 XML 报告也很有必要,可以使用jest-junitreporter。

3. 从零开始的环境配置与核心依赖安装

理论说完,我们开始动手。第一步就是初始化项目并安装核心依赖。

3.1 初始化项目与安装依赖

打开终端,创建一个新目录并初始化 npm 项目:

mkdir smart-ui-test-system && cd smart-ui-test-system npm init -y

接下来,安装 Midscene.js 及其 CLI 工具、测试运行器 Jest,以及浏览器自动化引擎。Midscene.js 底层默认使用 Playwright,因为它对现代浏览器支持更好,且自带浏览器内核,无需单独安装 Chrome/Chromium。

npm install --save-dev midscene @midscene/cli jest

Playwright 浏览器安装比较特殊,需要通过其自带的命令来安装:

npx playwright install chromium --with-deps

这个命令会下载 Chromium 浏览器及其所有依赖项,确保在不同环境下都能运行。如果你还需要测试 Firefox 或 WebKit,可以把chromium替换为firefoxwebkit或直接使用all

3.2 配置 Midscene.js

在项目根目录创建midscene.config.js文件。这是 Midscene.js 的核心配置文件。

// midscene.config.js module.exports = { // 指定浏览器类型,这里我们使用已安装的 chromium browserType: 'chromium', // 浏览器启动选项 launchOptions: { headless: true, // CI 环境下通常为无头模式,本地调试可设为 false slowMo: 50, // 操作间隔慢速,方便观察,生产环境可设为 0 或移除 args: ['--no-sandbox', '--disable-setuid-sandbox'], // 适用于 Docker/CI 环境 }, // 视口大小 viewport: { width: 1920, height: 1080 }, // 全局超时设置(毫秒) timeout: 30000, // 默认 30 秒 // 场景文件默认存放路径 scenesDir: './src/scenes', // 自定义步骤或断言(后面会详细讲) // extensions: './src/extensions', // 基础 URL,你的被测应用地址 baseURL: process.env.APP_BASE_URL || 'http://localhost:3000', // 报告输出配置 reporters: [ ['html', { outputDir: './reports/html' }], ['junit', { outputDir: './reports/junit' }] ] };

这里有几个关键点:

  • headless: true表示在无图形界面的模式下运行浏览器,节省资源,适合 CI。本地调试时可以设为false,看着浏览器自动操作,非常直观。
  • slowMo在调试时非常有用,它让每个操作都有个微小延迟,你能看清发生了什么。
  • args中的--no-sandbox参数在 Linux 服务器(如 Docker 容器)中通常是必须的,否则可能无法启动浏览器。
  • baseURL通过环境变量APP_BASE_URL动态获取,这让我们能轻松切换测试环境(开发、测试、预生产)。

3.3 配置 Jest

创建jest.config.js文件:

// jest.config.js module.exports = { // 测试文件匹配模式 testMatch: ['**/src/tests/**/*.spec.js'], // 测试环境,我们使用 Midscene.js 提供的环境 testEnvironment: '@midscene/jest-environment', // 在每个测试文件执行前运行,用于全局设置 setupFilesAfterEnv: ['<rootDir>/src/tests/setup.js'], // 收集测试覆盖率 collectCoverage: false, // UI 测试通常不收集代码覆盖率,可按需开启 coverageDirectory: './coverage', // 报告生成器 reporters: [ 'default', ['jest-html-reporter', { pageTitle: 'UI自动化测试报告', outputPath: './reports/test-report.html', includeFailureMsg: true, includeConsoleLog: true, }], ['jest-junit', { outputDirectory: './reports/junit', outputName: 'junit.xml', }] ], // 全局超时 testTimeout: 120000, // 单个测试用例超时时间(2分钟) };

这里我们指定了测试文件的位置,使用了@midscene/jest-environment这个专门的环境,它负责在测试前后启动和关闭浏览器。setupFilesAfterEnv指向一个设置文件,我们接下来创建它。

3.4 编写全局测试设置文件

创建src/tests/setup.js文件。这个文件会在每个测试套件运行前执行,是初始化的好地方。

// src/tests/setup.js const { setupGlobalContext } = require('@midscene/jest-environment'); // 你可以在这里进行一些全局的初始化操作 // 例如,读取环境变量,初始化全局状态,或者注册自定义的 Midscene 扩展 beforeAll(async () => { // 如果 Midscene 环境没有自动设置全局 context,你可以在这里手动初始化 // 但通常 @midscene/jest-environment 已经处理好了 console.log(`测试基础URL: ${process.env.APP_BASE_URL || 'http://localhost:3000'}`); }); afterAll(async () => { // 所有测试结束后执行,可以用于清理全局资源 });

至此,最基础的环境和框架配置就完成了。接下来,我们将进入核心部分:编写页面对象和场景。

4. 编写页面对象与智能场景描述

这一部分是整个系统的血肉,直接决定了测试用例的稳定性和可读性。

4.1 创建页面对象(Page Object)

我们先以一个简单的登录页面为例。创建src/pages/LoginPage.js

// src/pages/LoginPage.js class LoginPage { // 元素定位描述符,使用 Midscene 支持的格式 // 它不一定是严格的 CSS 选择器,可以是文本、角色等 selectors = { usernameInput: { placeholder: '请输入用户名/邮箱' }, // 通过 placeholder 定位 passwordInput: { placeholder: '请输入密码' }, loginButton: { text: '登录' }, // 通过按钮文本定位 errorMessage: { css: '.ant-alert-error' }, // 必要时仍可使用 CSS 选择器 }; // 页面 URL 片段 get path() { return '/login'; } // 封装页面操作 async goto(page) { // page 对象由 Midscene 注入 const baseURL = process.env.APP_BASE_URL || 'http://localhost:3000'; await page.goto(`${baseURL}${this.path}`); } async fillUsername(page, username) { // 使用 Midscene 提供的智能定位和操作 // 这里演示的是直接使用 Playwright 的 page 对象,实际 Midscene 场景中会更简洁 const locator = page.locator(this.selectors.usernameInput); await locator.fill(username); } // ... 其他方法如 fillPassword, clickLogin 等 } module.exports = new LoginPage();

页面对象的核心价值在于将元素定位信息从测试用例中剥离并集中管理。如果前端的登录按钮文本从“登录”改成了“Sign In”,你只需要在这个文件里修改loginButton的定位符,所有用到这个按钮的测试用例都无需改动。

实操心得:不要过度封装。对于简单的输入、点击操作,在场景文件中直接描述可能更清晰。页面对象更适合封装复杂的、重复的操作序列,或者那些定位策略需要特别处理的元素。

4.2 编写第一个智能场景(Scene)

现在,我们来创建一个登录场景。创建src/scenes/user-login.scene.json

{ "name": "用户登录成功场景", "steps": [ { "action": "goto", "url": "/login", "description": "导航到登录页面" }, { "action": "fill", "target": { "placeholder": "请输入用户名/邮箱" }, "value": "testuser@example.com", "description": "输入用户名" }, { "action": "fill", "target": { "placeholder": "请输入密码" }, "value": "Password123", "description": "输入密码", "options": { "secret": true } // 标记为敏感信息,报告中会隐藏 }, { "action": "click", "target": { "text": "登录" }, "description": "点击登录按钮" }, { "action": "waitForNavigation", "description": "等待页面跳转", "options": { "waitUntil": "networkidle" } }, { "action": "assert", "assertion": "urlContains", "expected": "/dashboard", "description": "验证跳转到了仪表盘页面" }, { "action": "assert", "assertion": "textContent", "target": { "css": ".welcome-message" }, "expected": "欢迎回来,testuser!", "description": "验证欢迎语显示正确" } ] }

这个 JSON 文件描述了一个完整的用户登录流程。它的可读性非常高,即使不懂代码的人也能理解。Midscene.js 的执行引擎会解析这个文件,并按照步骤顺序执行。

Midscene.js 的“智能”体现在哪里?

  1. 灵活的定位器target字段可以使用{ text: ‘登录’ }{ placeholder: ‘…’ }{ role: ‘button’ }等多种方式,而不局限于脆弱的 CSS 路径。引擎会尝试最合理的方式去找到元素。
  2. 内置等待与重试:像clickfill这样的操作,Midscene.js 内部会等待元素变得可交互(可见、可点击),并包含自动重试机制,这极大地增强了测试的稳定性,避免了因页面加载或渲染稍慢而导致的失败。
  3. 丰富的断言:除了例子中的urlContainstextContent,还支持toBeVisibletoHaveCounttoHaveValue等,语法直观。

4.3 创建对应的测试用例文件

场景写好了,我们需要一个 Jest 测试用例来驱动它。创建src/tests/login.spec.js

// src/tests/login.spec.js const { runScene } = require('midscene'); const LoginPage = require('../pages/LoginPage'); describe('用户登录功能', () => { // 每个测试用例开始前,可以跳转到登录页 beforeEach(async () => { // 这里演示了如何使用页面对象,实际 Midscene 场景中 goto 步骤已包含 // await LoginPage.goto(page); // 如果 page 对象可全局访问 }); it('应该使用正确凭据登录成功', async () => { // 运行我们定义好的场景 const result = await runScene('user-login.scene.json'); // runScene 会返回一个结果对象,包含步骤执行详情和最终状态 expect(result.status).toBe('passed'); // 你也可以在这里添加额外的 Jest 断言 // 例如,检查页面上的某个特定元素 // const welcomeText = await page.textContent('.welcome-message'); // expect(welcomeText).toContain('testuser'); }); it('应该在使用错误密码时登录失败', async () => { // 我们可以通过覆盖场景步骤中某个字段的值,来复用场景 const result = await runScene('user-login.scene.json', { overrides: { steps: [ {}, // 第一步 goto 保持不变 {}, // 第二步 用户名保持不变 { value: 'WrongPassword' }, // 只覆盖第三步的密码 {}, // 后续步骤... { expected: '/login' }, // 覆盖断言,期望仍在登录页 { expected: '用户名或密码错误' } // 覆盖断言,期望看到错误信息 ] } }); expect(result.status).toBe('passed'); }); });

在这个测试用例中,我们使用runScene函数来执行场景。第二个测试用例展示了如何通过overrides参数动态修改场景中的某些步骤(比如输入错误的密码),从而实现场景的复用,避免为每个边界情况都写一个完整的场景文件。

5. 运行测试与结果解析

配置和代码都写好了,是时候让测试跑起来了。

5.1 本地运行与调试

首先,确保你的被测应用(比如一个本地开发服务器)已经在运行,假设在http://localhost:3000

package.json中添加 scripts 命令:

{ "scripts": { "test": "jest", "test:ui": "jest --watchAll", // 监听模式,文件变化自动运行测试 "test:debug": "jest --runInBand --no-coverage", // 串行运行,方便调试 "scene:run": "midscene run ./src/scenes/user-login.scene.json" // 单独运行某个场景 } }

现在,运行npm testnpm run test:ui,Jest 会启动浏览器,执行我们写的测试用例。

本地调试技巧

  1. 无头模式:在midscene.config.js中设置headless: false,你可以亲眼看到浏览器的每一步操作,非常直观。
  2. 慢动作:设置slowMo: 1000(1秒),让操作慢下来,方便观察细节。
  3. 开发者工具:即使在无头模式下,你也可以通过配置launchOptions中的devtools: true来打开开发者工具。
  4. 失败截图:Midscene.js 通常会在步骤失败时自动截图。你可以在配置中指定截图保存路径,方便事后分析。

5.2 解读测试报告

测试运行完毕后,报告会输出在终端和我们在配置中指定的目录。

  • 终端输出:Jest 会给出清晰的通过/失败总结,以及失败用例的错误堆栈。
  • HTML 报告:打开./reports/test-report.html,你会看到一个更详细的网页报告。它通常包含测试套件概览、每个测试用例的通过状态、执行时间,以及详细的步骤日志。对于失败的步骤,通常会附上截图和错误信息,这是排查问题的利器。
  • JUnit 报告./reports/junit/junit.xml是一个标准格式的 XML 文件,可以被 Jenkins、GitLab CI 等 CI/CD 平台读取,用于展示测试趋势和结果。

一个高效的排查流程是:先在终端看哪个用例失败了,然后立刻打开 HTML 报告,查看失败步骤的截图和前后操作日志,能快速定位到是前端元素变了,还是网络请求超时,或是断言逻辑有问题。

6. 集成到持续集成(CI)流水线

自动化测试只有集成到 CI/CD 流程中,才能真正发挥价值,实现“质量门禁”。这里以 GitHub Actions 为例。

6.1 配置 GitHub Actions Workflow

创建.github/workflows/ui-test.yml文件:

name: UI Automation Tests on: push: branches: [ main, develop ] pull_request: branches: [ main ] jobs: test: runs-on: ubuntu-latest container: image: mcr.microsoft.com/playwright:v1.40.0-focal # 使用包含 Playwright 的官方镜像 steps: - name: Checkout repository uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: '18' cache: 'npm' - name: Install dependencies run: npm ci # 使用 ci 命令确保依赖锁一致 - name: Install Playwright Browsers run: npx playwright install chromium --with-deps - name: Run UI Tests run: npm test env: APP_BASE_URL: ${{ secrets.APP_BASE_URL }} # 从 GitHub Secrets 读取测试环境地址 # 可以设置其他环境变量,如测试用户账号密码(务必使用 Secrets!) TEST_USERNAME: ${{ secrets.TEST_USERNAME }} TEST_PASSWORD: ${{ secrets.TEST_PASSWORD }} - name: Upload test reports if: always() # 无论测试成功与否,都上传报告 uses: actions/upload-artifact@v3 with: name: ui-test-reports path: | reports/ screenshots/ # 如果有截图也上传 retention-days: 7

这个工作流做了以下几件事:

  1. 在代码推送到主分支或发起 Pull Request 时触发。
  2. 在一个包含 Playwright 的 Docker 容器中运行,确保环境一致性。
  3. 安装项目依赖和浏览器。
  4. 运行npm test,并通过环境变量APP_BASE_URL指定被测应用的地址(例如测试环境的 URL)。
  5. 无论测试结果如何,都将生成的报告(HTML、JUnit)和截图打包上传为工件(Artifact),供后续下载查看。

6.2 关键 CI 配置要点

  • 环境变量管理绝对不要将测试环境的真实 URL、用户名、密码等硬编码在代码或配置文件中。务必使用 GitHub Secrets、GitLab CI Variables 或类似机制进行管理。上面的secrets.APP_BASE_URL就是在仓库的 Settings -> Secrets and variables -> Actions 中设置的。
  • 使用特定 Docker 镜像:直接使用mcr.microsoft.com/playwright官方镜像,它已经预装了所有必要的系统依赖和浏览器,避免了在 CI 机器上安装浏览器时的各种兼容性问题。
  • 报告归档:通过actions/upload-artifact保存测试报告至关重要。当测试失败时,你可以下载这些工件,查看 HTML 报告和失败截图,这是远程调试的主要依据。
  • 失败通知:可以进一步扩展工作流,在测试失败时,通过 Slack、钉钉、企业微信或邮件发送通知,并附上报告链接。

7. 高级技巧与常见问题排查

系统搭建起来并能稳定运行后,我们可以关注一些高级特性和常见坑点,让系统更强大、更可靠。

7.1 使用自定义步骤与扩展

Midscene.js 允许你注册自定义的步骤(Actions)和断言(Assertions),以满足特定业务需求。

例如,你的应用有一个复杂的富文本编辑器,需要上传图片。你可以创建一个自定义的uploadImage步骤。

首先,创建一个扩展文件src/extensions/custom-actions.js

// src/extensions/custom-actions.js const { registerAction } = require('midscene'); registerAction('uploadImage', async (page, context, { target, filePath }) => { // page 是 Playwright 的 Page 对象 // context 包含当前场景运行上下文 // target 是定位器 // filePath 是从场景步骤中传递过来的参数 const locator = page.locator(target); // 假设这是一个通过 input[type="file"] 上传的组件 // 可能需要先点击某个按钮触发文件选择对话框,但 Playwright 可以直接设置文件 await locator.setInputFiles(filePath); // 等待上传完成,可能是等待某个提示元素出现或消失 await page.waitForSelector('.upload-success-toast', { state: 'visible', timeout: 10000 }); });

然后在midscene.config.js中引入这个扩展:

// midscene.config.js module.exports = { // ... 其他配置 extensions: './src/extensions', // 指向扩展文件所在目录 };

现在,你就可以在场景文件中使用这个自定义步骤了:

{ "action": "uploadImage", "target": { "css": ".editor-upload-input" }, "filePath": "./fixtures/test-image.png", "description": "上传文章封面图" }

7.2 处理动态数据与等待策略

UI 自动化测试最大的挑战之一就是处理异步加载和动态内容。

  • 智能等待:Midscene.js 的内置步骤(如click,fill)已经包含了等待元素可用的逻辑。但对于自定义步骤或复杂场景,你可能需要手动等待。
    • waitForSelector: 等待某个元素出现或消失。
    • waitForLoadState: 等待页面达到某个加载状态(load,domcontentloaded,networkidle)。
    • waitForFunction: 等待页面中某个 JavaScript 条件成立。
  • 处理网络请求:有时需要等待某个特定 API 调用完成。可以使用 Playwright 的page.waitForResponse(urlOrPredicate)方法。
  • 动态数据断言:如果页面上显示的数据是动态生成的(如订单号、时间戳),断言不能写死。可以使用正则表达式或函数断言。
    { "action": "assert", "assertion": "textContent", "target": { "css": ".order-id" }, "expected": "/^订单号:\\d{10}$/", // 使用正则匹配 "description": "验证订单号格式正确" }

7.3 常见问题排查实录

以下是我在实战中遇到的一些典型问题及解决方案:

问题1:测试在 CI 上失败,但在本地成功。

  • 可能原因1:环境差异。CI 环境的应用版本、数据状态可能与本地不同。解决方案:确保 CI 测试环境是独立、稳定且数据可预测的。使用数据库快照或每次测试前重置数据。
  • 可能原因2:资源不足或超时。CI 机器的性能可能较弱。解决方案:增加全局timeouttestTimeout。在launchOptions中尝试禁用 GPU 加速args: ['--disable-gpu']
  • 可能原因3:浏览器启动失败。常见于 Docker 环境。解决方案:确保在launchOptions中加入了args: ['--no-sandbox', '--disable-setuid-sandbox'],并且使用的是包含必要依赖的 Docker 镜像(如官方 Playwright 镜像)。

问题2:元素定位失败,控制台报错 “TimeoutError: Locator not found”。

  • 可能原因1:页面尚未加载完成或元素被动态渲染解决方案:在操作前增加一个明确的等待步骤,等待某个标志性元素出现。检查 Midscene 步骤的target定位器是否过于严格,尝试使用更宽松的定位方式,如{ text: ‘提交’ }而不是复杂的 CSS 路径。
  • 可能原因2:iframe 或 Shadow DOM解决方案:如果目标元素在 iframe 或 Shadow DOM 内部,需要先定位到 iframe 或 Shadow Root。Midscene.js 可能需要对这类场景进行特殊处理,查阅其文档或考虑使用 Playwright 的原生 API 在自定义步骤中处理。

问题3:测试执行速度慢。

  • 可能原因:每个测试用例都重新启动浏览器、登录,步骤间等待时间过长。解决方案
    1. 复用浏览器上下文:配置 Midscene/Jest 环境,尝试复用同一个浏览器上下文(Context)而不是为每个测试打开新窗口。注意测试之间的状态隔离。
    2. 并行执行:Jest 默认是并行执行测试的。确保你的测试用例是独立的,没有全局状态依赖,以充分利用并行优势。
    3. 优化等待:检查slowMo配置,在 CI 上设为 0。将不必要的waitForTimeout替换为更精确的waitForSelector

问题4:测试报告中没有截图或截图不清晰。

  • 解决方案:在 Midscene 配置或自定义步骤中,确保在失败时调用了截图 API,如await page.screenshot({ path: ‘screenshot.png’, fullPage: true })。对于 CI 环境,截图路径应是绝对路径或相对于工作目录的确定路径,并确保在upload-artifact步骤中包含了该路径。

搭建这样一套系统并非一蹴而就,从第一个简单的登录场景开始,逐步覆盖核心业务流程,再接入 CI,每一步都会遇到不同的问题。但一旦这套系统稳定运行起来,它所带来的质量信心和效率提升是巨大的。它不仅能捕捉到视觉和交互层面的回归问题,更能作为一个活的、可执行的产品需求文档,驱动开发者和测试者从用户视角去思考。

http://www.jsqmd.com/news/1097635/

相关文章:

  • 接口自动化测试断言设计:从基础校验到数据一致性的分层策略与实践
  • Appium与Monkey融合:实现Android应用智能随机测试
  • 外国护照翻译费用是多少?外国护照翻译如何办理?
  • 机器人避障、游戏物理引擎都离不开它:手把手教你用FCL库搞定碰撞检测
  • 技术人跨界创业实战指南:从工程思维到消费市场的转型方法论
  • Zynq7000 PL时钟调试实战:用Clock Throttle精准控制FPGA逻辑运行
  • 如何快速上手Platinum-MD:跨平台MiniDisc无损音乐管理终极指南
  • 中小企业AI测试自动化实战:低门槛工具链与三层渐进策略
  • C++中对象与类的详解及其作用介绍
  • Apache日志入侵分析实战:从日志定位到攻击链还原
  • 金融项目接口自动化测试实战:从概念到CI/CD集成的完整框架构建
  • Java+Selenium+Jmeter自动化测试实战:从框架搭建到性能压测全解析
  • 性能压测实战:如何精准筛选接口与深度解读报告
  • Web应用XSS防护实战:从原理到Agent-Skills平台纵深防御
  • AI驱动UI自动化测试:Maestro框架与LLM结合实现10倍效率提升
  • RPA项目工程化实践:基于pytest与GitHub Actions的自动化测试流水线
  • 华硕笔记本性能管家:G-Helper轻量控制工具三分钟上手指南
  • UI自动化测试实战:从原理到落地,构建可持续的自动化工程体系
  • 期货量化交易策略加密实战:外部程序隔离保护核心算法
  • Midscene.js视觉驱动架构:革新UI自动化测试,告别元素定位失效
  • 线上面试实时编程如何与面试官沟通?留学生在线写代码通关指南「蒸汽求职分享」
  • C++中声明、定义、初始化、赋值区别介绍
  • 深入剖析C++中的struct结构体字节对齐
  • Python实战WebService接口测试:从WSDL解析到自动化测试框架
  • 【Springboot毕设全套源码+文档】基于Java+springboot台球厅管理系统的设计与实现(丰富项目+远程调试+讲解+定制)
  • 基于agency-agents构建多智能体协作系统:从核心概念到实战应用
  • Nginx日志分析实战:基于命令行工具识别DDoS攻击特征
  • Java服务越权攻击的三大隐蔽漏洞与防御实践
  • 基于Pytest与Requests构建企业级接口自动化测试框架实战
  • Midscene.js与Playwright融合:提升75%自动化测试效率的工程实践