从 Puppeteer 迁移
迁移原则
本指南介绍了从 Puppeteer 迁移到 Playwright 库 和 Playwright 测试 的方法。这些 API 具有相似之处,但 Playwright 为 Web 测试和跨浏览器自动化提供了更多可能性。
- 大多数 Puppeteer API 可以照常使用
- 不建议使用 ElementHandle,而应使用 Locator 对象和 Web优先断言。
- Playwright 是跨浏览器的
- 你可能不需要显式等待
备忘单
Puppeteer | Playwright 库 |
---|---|
await puppeteer.launch() | await playwright.chromium.launch() |
puppeteer.launch({product: 'firefox'}) | await playwright.firefox.launch() |
WebKit 不受 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(...) | 断言 通常可以用来验证文本、属性、类... |
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,而应使用 Locator 对象和 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.net.cn/', {
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.net.cn/', {
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 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.net.cn/');
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 测试
import { test, expect } from '@playwright/test'; // 1
test.describe('Playwright homepage', () => {
test('contains hero title', async ({ page }) => { // 2, 3
await page.goto('https://playwright.net.cn/');
const titleLocator = page.locator('.hero__title'); // 4
await expect(titleLocator).toContainText( // 5
'Playwright enables reliable end-to-end testing'
);
});
});
- 每个 Playwright 测试文件都显式导入
test
和expect
函数 - 测试函数用
async
标记 - Playwright 测试提供了一个
page
作为其参数之一。这是 Playwright 测试中众多 有用夹具 之一。Playwright 测试为每个测试创建了一个隔离的 Page 对象。但是,如果要在多个测试之间重用一个 Page 对象,可以在 test.beforeAll() 中创建它,并在 test.afterAll() 中关闭它。 - 使用 page.locator() 创建定位器是同步方法中为数不多的几种方法之一。
- 使用 断言 来验证状态,而不是
page.$eval()
。
测试
为了改进测试,建议使用 定位器 和 Web优先 断言。请参见 编写测试
使用 Puppeteer 时,通常会使用 page.evaluate()
或 page.$eval()
来检查 ElementHandle 并提取文本内容、属性、类的值... Web优先 断言 为此目的提供了多个匹配器,它更可靠且更易读。
Playwright 测试 是我们推荐与 Playwright 一起使用的第一方测试运行器。它提供了许多功能,例如页面对象模型、并行、夹具或报告器。
Playwright 测试的超级力量
使用 Playwright 测试后,你会获得很多好处!
- 完整的零配置 TypeScript 支持
- 在所有 Web 引擎(Chrome、Firefox、Safari)上,在任何流行的操作系统(Windows、macOS、Ubuntu)上运行测试
- 完全支持多个来源、(i)框架、标签和上下文
- 在多个浏览器中以并行方式隔离运行测试
- 内置测试 工件收集
你还会获得与 Playwright 测试捆绑在一起的所有这些 ✨ 很棒的工具 ✨
进一步阅读
详细了解 Playwright 测试运行器