与网络应用的大多数互动都发生在浏览器上。用户搜索项目,填写表格,创建购物车,登录他们的个人资料,以及执行许多其他任务。单元测试是很好的,但没有什么比通过与面向用户的前端交互来测试一个应用程序更好的了。在本教程中,你将学习并演示如何使用Puppeteer为浏览器编写测试。然后,你将更进一步,在持续集成流程中实现测试过程的自动化。
前提条件
要学习本教程,需要具备一些条件。
安装好这些东西后,我们就可以开始学习本教程了。
克隆和运行示例应用程序
第一步是建立一个网络应用程序来测试。你需要通过运行这个命令克隆一个演示应用程序。
git clone --single-branch --branch base-project https://github.com/CIRCLECI-GWP/browser-testing
然后,进入项目的根目录(cd browser-testing),通过运行以下命令安装依赖项。
npm install
在完全安装了依赖项之后,用这个命令运行应用程序。
node server
应用服务器将在http://localhost:5000 启动。在你的浏览器上进入该URL,查看演示应用程序的主页。

该演示页面包括一个标题:Welcome to the demo Web Page ,一个包含文本的段落:This is a sample text in a paragraph on the page ,以及一个带有电子邮件字段和提交按钮的表单。当填写并提交后,该表单会将提交的电子邮件打印到屏幕上。

安装Jest和Puppeteer
你将对演示页面进行测试,以确认它是否包含页面上显示的元素,并验证表单的行为。你将需要两个软件包。
使用此命令将这些包作为开发依赖项安装。
npm install --save-dev puppeteer jest
安装好这些后,您现在可以开始向项目添加浏览器测试。
使用 Puppeteer 添加测试
您要测试的第一个元素是页眉和段落。这些测试将确认这些元素是否在页面上,并在其中包含预期的文本。
在项目的根部添加一个新的测试文件,名为homepage.test.js 。添加这段代码。
const puppeteer = require("puppeteer");
test("Confirm text on page", async () => {
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.goto("http://localhost:5000");
let pageHeader = await page.$("#pageTitle");
let pageHeaderValue = await pageHeader.evaluate((el) => el.textContent);
expect(pageHeaderValue).toContain("Welcome to the demo Web Page");
let pageParagraph = await page.$("#pageParagraph");
let pageParagraphValue = await pageParagraph.evaluate(
(el) => el.textContent
);
expect(pageParagraphValue).toContain(
"This is a sample text in a paragraph on the page"
);
} finally {
await browser.close();
}
}, 120000);
这个测试案例启动一个新的浏览器实例,并在http://localhost:5000 加载网络应用。然后,它使用CSS选择器以标题和段落为目标,读取其内容。然后将标题和段落的内容与预期结果进行比较。
要运行这些测试,请使用此代码修改package.json 中的test 脚本。
...
"scripts" : {
"test" : "jest"
}
确保网络应用程序正在运行(使用node server )。然后运行这个命令。
npm run test
运行后,CLI输出显示你有测试通过。
PASS ./homepage.test.js (32.732 s)
✓ Confirm text on page (25962 ms)
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 41.205 s
Ran all test suites.
接下来,添加另一个测试用例来测试表单的行为。在第一个测试用例下面添加这段代码。
...
test("Confirm form submission output", async () => {
const browser = await puppeteer.launch();
try {
const page = await browser.newPage();
await page.goto("http://localhost:5000");
await page.type("#userEmail", "test@company.com");
await page.click("#submitButton");
let emailContainer = await page.$("#infoDisplay");
let value = await emailContainer.evaluate((el) => el.textContent);
expect(value).toContain("test@company.com");
} finally {
await browser.close();
}
}, 120000);
第二个测试用例引用电子邮件字段,使用其id 属性和输入该字段的电子邮件(test@company.com)。测试引用提交按钮并使用按钮的id 属性 "点击 "它。最后,电子邮件的显示容器被锁定,文本内容被获取并与预期值进行比较,也就是输入的电子邮件。
保存这个文件,然后使用npm run test 命令再次运行你的测试。CLI输出显示,测试已经通过。
PASS ./homepage.test.js (64.297 s)
✓ Confirm text on page (42118 ms)
✓ Confirm form submission output (9664 ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 84.997 s
Ran all test suites.
设置CI管道以实现自动化测试
为了完成本教程的目标,我们将通过把测试过程插入持续集成(CI)管道来实现自动化。每次在你的远程仓库上更新代码时,该管道都会运行测试。第一步是将代码推送到GitHub。确保这是与您的CircleCI账户相连的GitHub账户。
接下来,去CircleCI仪表板上的项目页面添加项目。

点击Set Up Project按钮,打开设置页面。然后在弹出的模版上点击跳过这一步,因为我们将在本教程的后面手动添加我们的CircleCI配置。

在设置页面,点击使用现有的配置,表明你将手动添加一个配置文件,而不是使用样本。接下来,你会被提示为管道下载一个配置文件或开始构建。

点击开始构建。这次构建将失败,因为我们还没有设置我们的配置文件。设置它是我们的下一个步骤。
最后一步,在项目的根部创建一个名为.circleci 的文件夹。在你刚刚创建的文件夹内添加一个名为config.yml 的配置文件。在这个文件中,输入以下代码。
version: 2.1
jobs:
build:
working_directory: ~/repo
docker:
- image: circleci/node:12-browsers
steps:
- checkout
- run:
name: Update NPM
command: "sudo npm install -g npm"
- restore_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
- run:
name: Install Dependencies
command: npm install
- save_cache:
key: dependency-cache-{{ checksum "package-lock.json" }}
paths:
- ./node_modules
- run:
name: Run the application
command: node server.js
background: true
- run:
name: Run tests
command: npm run test
在这个配置中,所需的Node.js图像被拉入。这个图像包含浏览器,这对运行浏览器测试很重要。配置的下一部分是更新npm 。然后,项目的依赖性被安装和缓存。
为了运行针对应用程序的浏览器测试,使用node server 在后台进程中启动应用程序。然后使用npm run test 命令来运行测试。
提交项目的所有修改,并推送到你的远程GitHub仓库。这将自动触发流水线。

成功了!点击构建,查看测试的细节。

伟大的工作!
结论
从应用程序用户的角度进行测试,可以得到很多启示。你可以了解应用程序的不同单元是如何一起工作的,以帮助用户在你的应用程序中实现他们的任务。尽管如此,大多数界面/浏览器测试仍然是手动完成的。在本教程中,你已经演示了如何将这些类型的测试自动化,以加快开发流程并提高生产力。功能性浏览器测试通过给你的团队提供快速捕捉和响应错误的能力来提高你的应用程序的质量。一定要与你的团队分享你成功测试的细节,以便他们也能从这些信息中受益。
编码愉快!