从 Puppeteer 迁移
迁移原则
本指南描述了如何从 Puppeteer 迁移到 Playwright 库 和 Playwright 测试。两者的 API 有相似之处,但 Playwright 为网页测试和跨浏览器自动化提供了更多可能性。
- 大多数 Puppeteer API 可以直接使用
- 不建议使用 ElementHandle,推荐使用 Locator 对象和面向网页的断言
- Playwright 支持跨浏览器
- 通常不需要显式等待
速查表
Puppeteer | Playwright 库 |
---|---|
await puppeteer.launch() | await playwright.chromium.launch() |
puppeteer.launch({product: 'firefox'}) | await playwright.firefox.launch() |
Puppeteer 不支持 WebKit | 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(...) | 通常可以使用断言替代来验证文本、属性、类等 |
await page.$(...) | 不推荐使用,改用定位器 |
await page.$x(xpath_selector) | 不推荐使用,改用定位器 |
没有专门针对复选框或单选按钮的方法 | 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(...) 要拦截和修改请求,请参阅page.route() |
page.waitForNavigation
和 page.waitForSelector
仍然存在,但由于自动等待功能,许多情况下不再需要。
不推荐使用 ElementHandle,改用[定位器]对象和面向Web的断言。
定位器是 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
- 为了实现浏览器状态隔离,请考虑使用 浏览器上下文
setViewport
改为setViewportSize
networkidle2
改为networkidle
。请注意在大多数情况下由于自动等待机制,这个参数并不实用
测试示例
使用 Jest 的 Puppeteer 示例:
import puppeteer from 'puppeteer';
describe('Playwright 首页', () => {
let browser;
let page;
beforeAll(async () => {
browser = await puppeteer.launch();
page = await browser.newPage();
});
it('包含主标题', 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 首页', () => {
test('包含主标题', 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 中众多实用 fixture之一。Playwright Test 会为每个测试创建独立的 Page 对象。不过,如果你想在多个测试间复用同一个 Page 对象,可以在 test.beforeAll() 中创建并在 test.afterAll() 中关闭它。 - 使用 page.locator() 创建定位器是少数同步方法之一
- 使用断言来验证状态,而不是
page.$eval()
测试指南
为了提升测试质量,建议使用定位器(Locators)和面向Web的断言(Assertions)。详见编写测试
在Puppeteer中常见的使用方式是page.evaluate()
或page.$eval()
来检查ElementHandle并提取文本内容、属性、类等值。面向Web的断言(Assertions)为此提供了多种匹配器,这种方式更加可靠且易读。
Playwright Test是我们官方推荐与Playwright配合使用的测试运行器。它提供了多种功能,如页面对象模型、并行测试、测试夹具和报告器等。
Playwright Test 的超强能力
一旦使用Playwright Test,你将获得以下优势:
- 开箱即用的TypeScript支持
- 可在所有主流操作系统(Windows、macOS、Ubuntu)上运行所有浏览器引擎(Chrome、Firefox、Safari)的测试
- 全面支持多源站、(i)frames、标签页和上下文
- 支持多浏览器并行隔离运行测试
- 内置测试结果收集
你还将获得这些✨强大的工具✨:
延伸阅读
了解更多关于Playwright测试运行器的信息: