跳到主要内容
版本:23.11.1

Puppeteer Angular 原理图

向您的 Angular 项目添加基于 Puppeteer 的 e2e 测试。

入门

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

请注意,这会将原理图作为依赖项添加到您的项目中。

ng add @puppeteer/ng-schematics

或者,您可以使用相同的命令,后跟下面的 选项

目前,此原理图支持以下测试运行器

安装原理图后,您可以运行 E2E 测试

ng e2e

选项

向您的项目添加原理图时,您可以提供以下选项

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

创建单个测试文件

Puppeteer Angular 原理图公开了一种创建单个测试文件的方法。

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 = 'https://127.0.0.1:8080';

贡献

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

沙盒冒烟测试

为了简化集成,可以使用单个命令运行冒烟测试,该命令将创建全新的 Angular 安装(单个应用程序和多个应用程序项目)。然后它将在其中安装原理图并运行初始的 e2e 测试

node tools/smoke.mjs

单元测试

原理图使用 @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、文本、XPath 和 pierce 选择器。下表显示了 Puppeteer 对 Protractor By 的等效项。

为了提高可靠性并减少不稳定性,请尝试我们的实验性 定位器 API

ByProtractor 代码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('http://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('http://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');
});
});