跳至主要内容

从Puppeteer迁移

迁移原则

本指南描述了如何从Puppeteer迁移到Playwright LibraryPlaywright Test。虽然两者的API有相似之处,但Playwright为网页测试和跨浏览器自动化提供了更多可能性。

  • 大多数Puppeteer API可以直接使用
  • 不建议使用ElementHandle,请改用Locator对象和面向Web的断言。
  • Playwright 是跨浏览器的
  • 你可能不需要显式等待

速查表

PuppeteerPlaywright Library
await puppeteer.launch()await playwright.chromium.launch()
puppeteer.launch({product: 'firefox'})await playwright.firefox.launch()
WebKit is not supported by Puppeteerawait playwright.webkit.launch()
await browser.createIncognitoBrowserContext(...)await browser.newContext(...)
await page.setViewport(...)await page.setViewportSize(...)
await page.waitForXPath(XPathSelector)await page.waitForSelector(XPathSelector)
await page.waitForNetworkIdle(...)await page.waitForLoadState('networkidle')
await page.$eval(...)Assertions can often be used instead to verify text, attribute, class...
await page.$(...)Discouraged, use Locators instead
await page.$x(xpath_selector)Discouraged, use Locators instead
No methods dedicated to checkbox or radio inputawait page.locator(selector).check()
await page.locator(selector).uncheck()
await page.click(selector)await page.locator(selector).click()
await page.focus(selector)await page.locator(selector).focus()
await page.hover(selector)await page.locator(selector).hover()
await page.select(selector, values)await page.locator(selector).selectOption(values)
await page.tap(selector)await page.locator(selector).tap()
await page.type(selector, ...)await page.locator(selector).fill(...)
await page.waitForFileChooser(...)
await elementHandle.uploadFile(...)
await page.locator(selector).setInputFiles(...)
await page.cookies([...urls])await browserContext.cookies([urls])
await page.deleteCookie(...cookies)await browserContext.clearCookies()
await page.setCookie(...cookies)await browserContext.addCookies(cookies)
page.on(...)page.on(...)
In order to intercept and mutate requests, see page.route()

page.waitForNavigationpage.waitForSelector 仍然存在,但在许多情况下由于自动等待功能可能不再需要。

不建议使用ElementHandle,请改用Locator对象和面向网页的断言。

定位器(Locators)是Playwright自动等待和重试能力的核心部分。定位器是严格的,这意味着如果多个元素匹配给定的选择器,所有暗示目标DOM元素的定位器操作都将抛出异常。

示例

自动化示例

Puppeteer:

const puppeteer = require('puppeteer');

(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({ width: 1280, height: 800 });
await page.goto('https://playwright.dev/', {
waitUntil: 'networkidle2',
});
await page.screenshot({ path: 'example.png' });
await browser.close();
})();

逐行迁移到Playwright:

const { chromium } = require('playwright'); // 1

(async () => {
const browser = await chromium.launch();
const page = await browser.newPage(); // 2
await page.setViewportSize({ width: 1280, height: 800 }); // 3
await page.goto('https://playwright.dev/', {
waitUntil: 'networkidle', // 4
});
await page.screenshot({ path: 'example.png' });
await browser.close();
})();

迁移亮点(请参阅Playwright代码片段中的内联注释):

  1. 每个Playwright库文件都明确导入了chromium。也可以使用其他浏览器webkitfirefox
  2. 为了实现浏览器状态隔离,可以考虑使用browser contexts
  3. setViewport 更名为 setViewportSize
  4. networkidle2 变为 networkidle。请注意在大多数情况下,由于自动等待功能,它并不实用。

测试示例

Puppeteer 与 Jest:

import puppeteer from 'puppeteer';

describe('Playwright homepage', () => {
let browser;
let page;

beforeAll(async () => {
browser = await puppeteer.launch();
page = await browser.newPage();
});

it('contains hero title', async () => {
await page.goto('https://playwright.dev/');
await page.waitForSelector('.hero__title');
const text = await page.$eval('.hero__title', e => e.textContent);
expect(text).toContain('Playwright enables reliable end-to-end testing'); // 5
});

afterAll(() => browser.close());
});

逐行迁移到Playwright Test:

import { test, expect } from '@playwright/test'; // 1

test.describe('Playwright homepage', () => {
test('contains hero title', async ({ page }) => { // 2, 3
await page.goto('https://playwright.dev/');
const titleLocator = page.locator('.hero__title'); // 4
await expect(titleLocator).toContainText( // 5
'Playwright enables reliable end-to-end testing'
);
});
});
  1. 每个Playwright Test文件都明确导入了testexpect函数
  2. 测试函数被标记为async
  3. Playwright Test 提供了一个 page 作为其参数之一。这是 Playwright Test 中众多实用夹具中的一个。Playwright Test 会为每个测试创建一个隔离的Page对象。不过,如果您想在多个测试之间重复使用同一个Page对象,可以在test.beforeAll()中创建它,并在test.afterAll()中关闭它。
  4. 使用page.locator()创建定位器是少数同步方法之一。
  5. 使用断言来验证状态,而不是page.$eval()

测试

为了改进测试,建议使用Locators和面向网页的Assertions。详见Writing Tests

在使用Puppeteer时,通常会使用page.evaluate()page.$eval()来检查ElementHandle并提取文本内容、属性、类等的值。而Web-first的Assertions为此提供了多个匹配器,这种方式更加可靠且可读性更好。

Playwright Test 是我们官方推荐与Playwright配合使用的测试运行器。它提供了多种功能,如页面对象模型、并行测试、固件和报告器等。

Playwright Test 超级能力

一旦你开始使用Playwright Test,你将获得很多功能!

  • 完全零配置的TypeScript支持
  • 所有主流操作系统(Windows、macOS、Ubuntu)上运行所有网页引擎(Chrome、Firefox、Safari)的测试
  • 全面支持多源站、(i)frames标签页和上下文
  • 在多个浏览器中以隔离方式并行运行测试
  • 内置测试artifact collection

你还将获得这些✨超棒工具✨,它们都随Playwright Test捆绑提供:

延伸阅读

了解更多关于Playwright测试运行器的信息: