从Puppeteer迁移
迁移原则
本指南描述了如何从Puppeteer迁移到Playwright Library和Playwright Test。虽然两者的API有相似之处,但Playwright为网页测试和跨浏览器自动化提供了更多可能性。
- 大多数Puppeteer API可以直接使用
- 不建议使用ElementHandle,请改用Locator对象和面向Web的断言。
- Playwright 是跨浏览器的
- 你可能不需要显式等待
速查表
| Puppeteer | Playwright Library |
|---|---|
await puppeteer.launch() | await playwright.chromium.launch() |
puppeteer.launch({product: 'firefox'}) | await playwright.firefox.launch() |
| WebKit is not supported by Puppeteer | await 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 input | await 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.waitForNavigation 和 page.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代码片段中的内联注释):
- 每个Playwright库文件都明确导入了
chromium。也可以使用其他浏览器webkit或firefox。 - 为了实现浏览器状态隔离,可以考虑使用browser contexts
setViewport更名为setViewportSizenetworkidle2变为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'
);
});
});
- 每个Playwright Test文件都明确导入了
test和expect函数 - 测试函数被标记为
async - Playwright Test 提供了一个
page作为其参数之一。这是 Playwright Test 中众多实用夹具中的一个。Playwright Test 会为每个测试创建一个隔离的Page对象。不过,如果您想在多个测试之间重复使用同一个Page对象,可以在test.beforeAll()中创建它,并在test.afterAll()中关闭它。 - 使用page.locator()创建定位器是少数同步方法之一。
- 使用断言来验证状态,而不是
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测试运行器的信息: