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()