Jest 与 puppeteer 一起使用

2021-09-04 13:41 更新

借助全局设置/拆卸异步测试环境API,Jest 可以与puppeteer顺利工作。

如果测试使用​page.$eval​,​page.$$eval​或者​page.evaluate则当前无法使用 Puppeteer 为测试文件生成代码覆盖率。因为传递的函数在 Jest 的作用域之外执行。查看GitHub 上的问题 #7962以获取解决方法。

使用 jest-puppeteer 预设

Jest Puppeteer提供了使用 Puppeteer 运行测试所需的所有配置。首先,安装 jest-puppeteer

  1. yarn add --dev jest-puppeteer

在 Jest 配置中指定预设:

  1. {
  2. "preset": "jest-puppeteer"
  3. }

写你的测试:

  1. describe('Google', () => {
  2. beforeAll(async () => {
  3. await page.goto('https://google.com');
  4. });
  5. it('should be titled "Google"', async () => {
  6. await expect(page.title()).resolves.toMatch('Google');
  7. });
  8. });

无需加载任何依赖项。Puppeteer 的​page​和​browser​类将自动公开

请参阅文档

没有 jest-puppeteer 预设的自定义示例

可以从头开始连接 puppeteer。基本思想是:

  1. 使用全局设置启动并归档 puppeteer 的 websocket 端点
  2. 从每个测试环境连接到 puppeteer
  3. 使用 Global Teardown 关闭 puppeteer

这是 GlobalSetup 脚本的示例

  1. // setup.js
  2. const path = require('path');
  3. const fs = require('fs');
  4. const os = require('os');
  5. const mkdirp = require('mkdirp');
  6. const puppeteer = require('puppeteer');
  7. const DIR = path.join(os.tmpdir(), 'jest_puppeteer_global_setup');
  8. module.exports = async function () {
  9. const browser = await puppeteer.launch();
  10. // store the browser instance so we can teardown it later
  11. // this global is only available in the teardown but not in TestEnvironments
  12. global.__BROWSER_GLOBAL__ = browser;
  13. // use the file system to expose the wsEndpoint for TestEnvironments
  14. mkdirp.sync(DIR);
  15. fs.writeFileSync(path.join(DIR, 'wsEndpoint'), browser.wsEndpoint());
  16. };

然后我们需要为 puppeteer 定制一个测试环境

  1. // puppeteer_environment.js
  2. const fs = require('fs');
  3. const path = require('path');
  4. const os = require('os');
  5. const puppeteer = require('puppeteer');
  6. const NodeEnvironment = require('jest-environment-node');
  7. const DIR = path.join(os.tmpdir(), 'jest_puppeteer_global_setup');
  8. class PuppeteerEnvironment extends NodeEnvironment {
  9. constructor(config) {
  10. super(config);
  11. }
  12. async setup() {
  13. await super.setup();
  14. // get the wsEndpoint
  15. const wsEndpoint = fs.readFileSync(path.join(DIR, 'wsEndpoint'), 'utf8');
  16. if (!wsEndpoint) {
  17. throw new Error('wsEndpoint not found');
  18. }
  19. // connect to puppeteer
  20. this.global.__BROWSER__ = await puppeteer.connect({
  21. browserWSEndpoint: wsEndpoint,
  22. });
  23. }
  24. async teardown() {
  25. await super.teardown();
  26. }
  27. runScript(script) {
  28. return super.runScript(script);
  29. }
  30. }
  31. module.exports = PuppeteerEnvironment;

最后,我们可以关闭 puppeteer 实例并清理文件

  1. // teardown.js
  2. const os = require('os');
  3. const path = require('path');
  4. const rimraf = require('rimraf');
  5. const DIR = path.join(os.tmpdir(), 'jest_puppeteer_global_setup');
  6. module.exports = async function () {
  7. // close the browser instance
  8. await global.__BROWSER_GLOBAL__.close();
  9. // clean-up the wsEndpoint file
  10. rimraf.sync(DIR);
  11. };

完成所有设置后,我们现在可以像这样编写测试:

  1. // test.js
  2. const timeout = 5000;
  3. describe(
  4. '/ (Home Page)',
  5. () => {
  6. let page;
  7. beforeAll(async () => {
  8. page = await global.__BROWSER__.newPage();
  9. await page.goto('https://google.com');
  10. }, timeout);
  11. it('should load without error', async () => {
  12. const text = await page.evaluate(() => document.body.textContent);
  13. expect(text).toContain('google');
  14. });
  15. },
  16. timeout,
  17. );

最后,设置​jest.config.js​为从这些文件中读取。(​jest-puppeteer​预设在幕后做了类似的事情。)

  1. module.exports = {
  2. globalSetup: './setup.js',
  3. globalTeardown: './teardown.js',
  4. testEnvironment: './puppeteer_environment.js',
  5. };

这是完整工作示例的代码。


以上内容是否对您有帮助:
在线笔记
App下载
App下载

扫描二维码

下载编程狮App

公众号
微信公众号

编程狮公众号