Puppeteer 中文文档v25.8.0

Puppeteer Angular Schematic

为你的 Angular 项目添加基于 Puppeteer 的 e2e 测试。

开始使用

在 Angular CLI 应用目录中运行以下命令,并按照提示操作。

注意,这会将 schematic 作为依赖添加到你的项目中。

ng add @puppeteer/ng-schematics

或者你也可以使用相同的命令,并在其后跟上下面的选项

目前,此 schematic 支持以下测试运行器:

安装 schematics 后,你就可以运行 E2E 测试:

ng e2e

选项

向项目中添加 schematics 时,你可以提供以下选项:

选项 描述 是否必需
--test-runner 与 Puppeteer 一起安装的测试框架。 "jasmine", "jest", "mocha", "node" true

创建单个测试文件

Puppeteer Angular Schematic 提供了一种创建单个测试文件的方法。

ng generate @puppeteer/ng-schematics:e2e "<TestName>"

同时运行测试服务器和开发服务器

默认情况下,E2E 测试会在与 ng start 相同的端口上运行应用。 为了避免这种情况,你可以在 angular.json 中指定端口。 将 e2epuppeteer(取决于初始配置)更新为:

{
  "e2e": {
    "builder": "@puppeteer/ng-schematics:puppeteer",
    "options": {
      "commands": [...],
      "devServerTarget": "sandbox:serve",
      "testRunner": "<TestRunner>",
      "port": 8080
    },
    ...
}

现在,将 E2E 测试文件 utils.ts 中的 baseUrl 更新为:

const baseUrl = 'http://localhost:8080';

参与贡献

查看我们的贡献指南,了解在 Puppeteer 仓库中进行开发所需的内容。

沙盒冒烟测试

为了便于集成,冒烟测试可以通过一条命令运行,该命令会创建一个全新的 Angular 安装(单应用项目和多应用项目)。然后它会在其中安装 schematics,并运行初始的 e2e 测试:

node tools/smoke.mjs

单元测试

schematics 使用 @angular-devkit/schematics/testing 来验证文件创建是否正确以及 package.json 的更新是否正确。要执行测试套件:

npm run test

从 Protractor 迁移

入口点

Puppeteer 有自己的 browser,它暴露了浏览器进程。 与 Protractor 的 browser 更接近的对应物是 Puppeteer 的 page

// Testing framework specific imports

import {setupBrowserHooks, getBrowserState} from './utils';

describe('<Test Name>', function () {
  setupBrowserHooks();
  it('is running', async function () {
    const {page} = getBrowserState();
    // Query elements
    await page
      .locator('my-component')
      // Click on the element once found
      .click();
  });
});

获取元素属性

你可以轻松获取元素的任意属性。

// Testing framework specific imports

import {setupBrowserHooks, getBrowserState} from './utils';

describe('<Test Name>', function () {
  setupBrowserHooks();
  it('is running', async function () {
    const {page} = getBrowserState();
    // Query elements
    const elementText = await page
      .locator('.my-component')
      .map(button => button.innerText)
      // Wait for element to show up
      .wait();

    // Assert via assertion library
  });
});

查询选择器

Puppeteer 支持多种类型的选择器,即 CSS、ARIA、text、XPath 和 pierce 选择器。 下表展示了 Puppeteer 与 Protractor By 对应的等价写法。

为了获得更高的可靠性和更少的不稳定性,请尝试我们的 实验性 Locators API

By Protractor 代码 Puppeteer querySelector
CSS(单个) $(by.css('<CSS>')) page.$('<CSS>')
CSS(多个) $$(by.css('<CSS>')) page.$$('<CSS>')
Id $(by.id('<ID>')) page.$('#<ID>')
CssContainingText $(by.cssContainingText('<CSS>', '<TEXT>')) page.$('<CSS> ::-p-text(<TEXT>)') `
DeepCss $(by.deepCss('<CSS>')) page.$(':scope >>> <CSS>')
XPath $(by.xpath('<XPATH>')) page.$('::-p-xpath(<XPATH>)')
JS $(by.js('document.querySelector("<CSS>")')) page.evaluateHandle(() => document.querySelector('<CSS>'))

对于更高级的用例,例如 Protractor 的 by.addLocator,你可以查看 Puppeteer 的自定义选择器

操作选择器

Puppeteer 允许你执行测试应用所需的所有必要操作。

// Click on the element.
element(locator).click();
// Puppeteer equivalent
await page.locator(locator).click();

// Send keys to the element (usually an input).
element(locator).sendKeys('my text');
// Puppeteer equivalent
await page.locator(locator).fill('my text');

// Clear the text in an element (usually an input).
element(locator).clear();
// Puppeteer equivalent
await page.locator(locator).fill('');

// Get the value of an attribute, for example, get the value of an input.
element(locator).getAttribute('value');
// Puppeteer equivalent
const element = await page.locator(locator).waitHandle();
const value = await element.getProperty('value');

示例

Protractor 测试示例:

describe('Protractor Demo', function () {
  it('should add one and two', function () {
    browser.get('https://juliemr.github.io/protractor-demo/');
    element(by.model('first')).sendKeys(1);
    element(by.model('second')).sendKeys(2);

    element(by.id('gobutton')).click();

    expect(element(by.binding('latest')).getText()).toEqual('3');
  });
});

Puppeteer 迁移示例:

import {setupBrowserHooks, getBrowserState} from './utils';

describe('Puppeteer Demo', function () {
  setupBrowserHooks();
  it('should add one and two', function () {
    const {page} = getBrowserState();
    await page.goto('https://juliemr.github.io/protractor-demo/');

    await page.locator('.form-inline > input:nth-child(1)').fill('1');
    await page.locator('.form-inline > input:nth-child(2)').fill('2');
    await page.locator('#gobutton').fill('2');

    const result = await page
      .locator('.table tbody td:last-of-type')
      .map(header => header.innerText)
      .wait();

    expect(result).toEqual('3');
  });
});