diff --git a/docs/src/puppeteer-js.md b/docs/src/puppeteer-js.md new file mode 100644 index 0000000000..f8511aa8ae --- /dev/null +++ b/docs/src/puppeteer-js.md @@ -0,0 +1,178 @@ +--- +id: puppeteer +title: "Migrating from Puppeteer" +--- + + + +## Migration Principles + +This guide describes migration to [Playwright Library](./library) and [Playwright Test](./intro.md) from Puppeteer. The APIs have similarities, but Playwright offers much more possibilities for web testing and cross-browser automation. + +- Most Puppeteer APIs can be used as is +- The use of [ElementHandle] is discouraged, use [Locator] objects and web-first assertions instead. +- Playwright is cross-browser +- You probably don't need explicit wait + +## Cheat Sheet + +| 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({ state: 'networkidle' }})` | +| `await page.$eval(...)` | [Assertions](./test-assertions) can often be used instead to verify text, attribute, class... | +| `await page.$(...)` | Discouraged, use [Locators](./api/class-locator) instead | +| `await page.$x(xpath_selector)` | Discouraged, use [Locators](./api/class-locator) 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).type(...)`
Please also consider [`method: Locator.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 [`method: Page.route`] | + +`page.waitForNavigation` and `page.waitForSelector` remain, but in many cases will not be necessary due to [auto-waiting](./actionability). + +The use of [ElementHandle] is discouraged , use [Locator] objects and web-first assertions instead. + +Locators are the central piece of Playwright's auto-waiting and retry-ability. Locators are strict. This means that all operations on locators that imply some target DOM element will throw an exception if more than one element matches given selector. + +## Examples + +### Automation example + +Puppeteer: + +```js +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('http://whatsmyuseragent.org/', { + waitUntil: 'networkidle2', + }); + await page.screenshot({ path: 'example.png' }); + await browser.close(); +})(); +``` + +Line-by-line migration to Playwright: + +```js +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('http://whatsmyuseragent.org/', { + waitUntil: 'networkidle', // 4 + }); + await page.screenshot({ path: 'example.png' }); + await browser.close(); +})(); +``` + +Migration highlights (see inline comments in the Playwright code snippet): + +1. Each Playwright Library file has explicit import of `chromium`. Other browsers `webkit` or `firefox` can be used. +1. For browser state isolation, consider [browser contexts](./browser-contexts.md) +1. `setViewport` becomes `setViewportSize` +1. `networkidle2` becomes `networkidle`. Please note that on most cases it is not useful, thanks to auto-waiting. + +### Test example + +Puppeteer with Jest: + +```js +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()); +}); +``` +Line-by-line migration to Playwright Test: + +```js +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. Each Playwright Test file has explicit import of the `test` and `expect` functions +1. Test function is marked with `async` +1. Playwright Test is given a `page` as one of its parameters. This is one of the many [useful fixtures](./api/class-fixtures) in Playwright Test. +Playwright Test creates an isolated [Page] object for each test. However, if you'd like to reuse a single [Page] object between multiple tests, you can create your own in [`method: Test.beforeAll`] and close it in [`method: Test.afterAll`]. +1. Locator creation with [`method: Page.locator`] is one of the few methods that is sync. +1. Use [assertions](./test-assertions) to verify the state instead of `page.$eval()`. + +## Testing + +With a few lines of code, you can hook up Playwright to your existing JavaScript [test runner](./test-runners). + +To improve testing, it is adviced to use [Locators](./api/class-locator) and web-first [Assertions](./test-assertions). See [Writing Tests](./writing-tests) + +It is common with Puppeteer to use `page.evaluate()` or `page.$eval()` to inspect an [ElementHandle] and extract the value of text content, attribute, class... Web-first [Assertions](./test-assertions) offers several matchers for this purpose, it is more reliable and readable. + +[Playwright Test](./intro.md) is our first-party recommended test runner to be used with Playwright. It provides several features like Page Object Model, parallelism, fixtures or reporters. + +## Playwright Test Super Powers + +Once you're on Playwright Test, you get a lot! + +- Full zero-configuration TypeScript support +- Run tests across **all web engines** (Chrome, Firefox, Safari) on **any popular operating system** (Windows, macOS, Ubuntu) +- Full support for multiple origins, [(i)frames](./api/class-frame), [tabs and contexts](./pages) +- Run tests in isolation in parallel across multiple browsers +- Built-in test artifact collection: [video recording](./test-configuration#record-video), [screenshots](./test-configuration#automatic-screenshots) and [playwright traces](./test-configuration#record-test-trace) + +Also you get all these ✨ awesome tools ✨ that come bundled with Playwright Test: +- [Playwright Inspector](./debug.md) +- [Playwright Test Code generation](./auth#code-generation) +- [Playwright Tracing](./trace-viewer) for post-mortem debugging + +## Further Reading + +Learn more about Playwright Test runner: + +- [Getting Started](./intro) +- [Fixtures](./test-fixtures) +- [Locators](./api/class-locator) +- [Selectors](./selectors) +- [Assertions](./test-assertions) +- [Auto-waiting](./actionability)