Playwright Node

This implementation is experimental and does not provide the same features as using Playwright Test. It is not configured for use with Replay Test Teams.

Recording with Playwright as a Node script

You can write tests as a function that uses playwright.[browser].launch(). This can give you more control over which tests are recorded.
In this configuration, you’ll use the getExecutablePath() function from @replayio/playwright to ensure the Replay-enabled browser is used.
👉
Passing the RECORD_ALL_CONTENT: 1 is only required for Replay Firefox.

Metadata

You can add metadata to your playwright recordings using either the RECORD_REPLAY_METADATA or RECORD_REPLAY_METADATA_FILE environment variable. If both are set, RECORD_REPLAY_METADATA_FILE takes precedence.
👉
Currently, this metadata is only available locally except for title
  • RECORD_REPLAY_METADATA_FILE - The path to a file containing JSON-formatted metadata
  • RECORD_REPLAY_METADATA - JSON-formatted metadata string

Examples

New Browser per Test

javascript
// firefox.spec.js const playwright = require("playwright"); const { getExecutablePath } = require("@replayio/playwright"); (async () => { const browser = await playwright.firefox.launch({ headless: true, executablePath: getExecutablePath("firefox"), env: { ...process.env, RECORD_ALL_CONTENT: 1, RECORD_REPLAY_METADATA: JSON.stringify({ title: "Take screenshot of replay.io" }) }, }); const page = await browser.newPage(); await page.goto("<https://replay.io>"); await page.screenshot({ path: "replay.png" }); await page.close(); await browser.close(); })();
Run node firefox.spec.js to run and record your tests. This will generate a new replay for each test.

Shared Browser between Tests

javascript
const path = require("path"); const { writeFileSync } = require("fs"); const playwright = require("playwright"); const { getExecutablePath } = require("@replayio/playwright"); (async () => { const metadataFilePath = path.join( process.env.HOME, "replay-metadata-file.json" ); const browser = await playwright.firefox.launch({ headless: true, executablePath: getExecutablePath("firefox"), env: { ...process.env, RECORD_ALL_CONTENT: 1, RECORD_REPLAY_METADATA_FILE: metadataFilePath, }, }); writeFileSync( metadataFilePath, JSON.stringify({ title: "Screenshot of replay.io" }) ); let page = await browser.newPage(); await page.goto("<https://replay.io>"); await page.screenshot({ path: "replay.png" }); await page.close(); writeFileSync( metadataFilePath, JSON.stringify({ title: "Screenshot of google.com" }) ); page = await browser.newPage(); await page.goto("<https://google.com>"); await page.screenshot({ path: "google.png" }); await page.close(); await browser.close(); })();
Run node firefox.spec.js to run and record your tests. This will generate a single replay of all the test code in the file.

Uploading recordings

Use @replayio/replay to manage and upload replays.
View the available recordings with npx @replayio/replay ls. Upload all with npx @replayio/replay upload-all or individual replays with npx @replayio/replay upload <id>.
You can also use functions provided by @replayio/replay in your Node script to upload recordings, like in the example below.
javascript
const cli = require("@replayio/replay"); async function uploadAll() { const recordings = cli.listAllRecordings(); console.log( "Processing", recordings.length, "recordings" ); let failed = []; let success = []; for await (let r of recordings) { try { success.push(await cli.uploadRecording(r.id, { verbose: true })); } catch (e) { failed.push(e); } } failed.forEach((reason) => { console.error("Failed to upload replay:", reason); }); return success; } async function main() { try { const recordingIds = await uploadAll(); console.log("Uploaded", recordingIds.length, "replays"); } catch (e) { console.error("Failed to upload recordings"); console.error(e); return []; } } main().then(() => { console.log("Done!"); });

Using expect with Node script configuration

You can still use expect from @playwright/test in your test code. Import the command directly like in the example below.
javascript
// firefox-expect.spec.js const playwright = require("playwright"); const { expect } = require('@playwright/test'); const { getExecutablePath } = require("@replayio/playwright"); (async () => { const browser = await playwright.firefox.launch({ headless: true, executablePath: getExecutablePath("firefox"), env: { ...process.env, RECORD_ALL_CONTENT: 1, }, }); const page = await browser.newPage(); await page.goto('https://demo.playwright.dev/todomvc'); const TODO_ITEMS = [ 'buy some cheese', 'feed the cat' ]; // Create 1st todo. await page.locator('.new-todo').click(); await page.locator('.new-todo').fill(TODO_ITEMS[0]); await page.locator('.new-todo').press('Enter'); // Create 2nd todo. await page.locator('.new-todo').fill(TODO_ITEMS[1]); await page.locator('.new-todo').press('Enter'); // Assert todo content await expect(page.locator('.view label')).toHaveText([ TODO_ITEMS[0], TODO_ITEMS[1] ]); await page.close(); await browser.close(); })()

Uploading automatically as a Node script

Writing your tests as a Node script allows you to upload failed recordings automatically using @replayio/replay as a Node module.
For the example below, use REPLAY_API_KEY=123 node upload-failure.spec.js to execute and record the test.
javascript
//upload-failure.spec.js const playwright = require("playwright"); const { expect } = require('@playwright/test'); const { getExecutablePath } = require("@replayio/playwright"); const replayCli = require("@replayio/replay"); async function test() { const browser = await playwright.firefox.launch({ headless: true, executablePath: getExecutablePath("firefox"), env: { ...process.env, RECORD_ALL_CONTENT: 1, }, }); const page = await browser.newPage(); await page.goto('https://demo.playwright.dev/todomvc'); const TODO_ITEMS = [ 'buy some cheese', 'feed the cat', 'book a doctors appointment' ]; // Create 1st todo. await page.locator('.new-todo').click(); await page.locator('.new-todo').fill(TODO_ITEMS[0]); await page.locator('.new-todo').press('Enter'); // Create 2nd todo. await page.locator('.new-todo').fill(TODO_ITEMS[1]); await page.locator('.new-todo').press('Enter'); // This purposefully fails to trigger an upload await expect(page.locator('.view label')).toHaveText([ TODO_ITEMS[1], TODO_ITEMS[2] ]); await page.close(); await browser.close(); }; async function testRun() { try { await test() } catch (e) { const recordingId = await replayCli.viewLatestRecording({apiKey: `${process.env.REPLAY_API_KEY}`}) console.log({e, recordingId}) process.exit(1) } } testRun()