Playwright Library and Advanced Browser Control

By Syncfusion®, Inc. · Last updated

Playwright Test versus the Playwright Library, writing automation scripts with chromium.launch(), launch options, persistent contexts and connecting to running browsers, PDFs and full-page screenshots, controlling time with page.clock, running code in the page with evaluate, addInitScript and exposeFunction, waiting for page conditions with waitForFunction, and CDP sessions.

Playwright Library and Advanced Browser Control

  • So far, you used Playwright Test: the test runner with test, expect, fixtures and reports.
  • Under it is the Playwright Library: the part that drives browsers. You can use it alone, to write scripts that are not tests.
  • This lesson also covers tools for unusual jobs: controlling time, running your own code in the page, and talking to the browser at a lower level.

Simple lesson: Playwright Test is for testing. The Library is for any browser automation. Both share the same page API.

A Real-World Example

  • The sale banner shows a countdown to midnight. Its text changes every moment, so how can a test check it?
  • page.clock.setFixedTime() stops the page's clock at a chosen moment. Now the text is always the same.
  • The page's Date now returns 20:00 every time. Timers still run, but the time they read never moves.

What You Will Learn

  1. Playwright Test versus the Playwright Library.
  2. Writing automation scripts: launch, context, page, close.
  3. Launch options, persistent profiles and connecting to a running browser.
  4. Controlling time with page.clock.
  5. Running code in the page: evaluate, addInitScript, exposeFunction and waitForFunction.
  6. CDP sessions and other low-level tools.

Playwright Test or the Library

Two Packages

Playwright TestPlaywright Library
Package@playwright/testplaywright
You gettest, expect, fixtures, config, reporters, retries, parallel workerschromium, firefox, webkit, and the browser API
You manageNothing, the runner opens and closes browsersLaunching, contexts, closing, errors
Use it forTesting web appsScraping, PDFs, screenshots, bots, custom tools
  • Both use the same Page, Locator and BrowserContext APIs. Everything you learned works in both.
  • Playwright Test includes the Library, so test projects need only @playwright/test.

A Library Script

  • A script launches a browser, makes a context and a page, does its job, and closes the browser.
  • Run it with Node.js: node save-prices.mjs. There is no test() and no expect().
// save-prices.ts
import { chromium } from 'playwright';

const browser = await chromium.launch();
const context = await browser.newContext({ locale: 'en-IN' });
const page = await context.newPage();

await page.goto('https://practice.devtutorials.ai/products');
const names = await page.getByTestId('product-card').getByRole('heading').allTextContents();
const prices = await page.locator('.price').allTextContents();
console.log(names.map((name, i) => `${name}: ${prices[i]}`).join('\n'));

await page.pdf({ path: 'products.pdf', format: 'A4' }); // Chromium only
await page.screenshot({ path: 'products.png', fullPage: true });

await browser.close();
  • Always close the browser, even after an error. Wrap the work in try { ... } finally { await browser.close(); }.
  • page.pdf() works only in Chromium, in headless mode.

The lab runs Playwright Test only, so Library scripts on this page are plain code. Copy them into a project with npm install playwright and run them with Node.js.

Simple lesson: Library scripts do the setup and cleanup the test runner does for you.

Launching Browsers

Launch Options

  • chromium.launch({ headless: false }) shows the window. slowMo: 250 waits after each action.
  • channel: 'chrome' or channel: 'msedge' uses the installed Google Chrome or Microsoft Edge.
  • In Playwright Test, the same options go in use: { launchOptions: { ... } } or use: { channel: 'chrome' }.

Persistent Contexts

  • Normal contexts are like incognito windows: empty every time.
  • chromium.launchPersistentContext('./profile') keeps cookies, storage and extensions in a folder, like a real user profile.
  • Use it for browser extensions, or for tools that must stay logged in between runs.
const context = await chromium.launchPersistentContext('./my-profile', {
  headless: false,
  args: ['--load-extension=./my-extension'],
});
const page = context.pages()[0] ?? await context.newPage();

Connecting to a Browser That Is Already Running

  • chromium.connectOverCDP('http://localhost:9222') attaches to a Chrome started with --remote-debugging-port=9222.
  • browserType.connect(wsEndpoint) connects to a Playwright browser server, for example a cloud browser service.
  • Remote browsers let a small CI machine drive many browsers somewhere else.

Controlling Time

Why Fake Time

  • Pages show clocks, countdowns, "posted 5 minutes ago" text and session timeouts.
  • Waiting for real time is slow, and the text changes on every run.
  • page.clock replaces the page's Date, setTimeout and setInterval with a clock you control.

The Clock Methods

  • setFixedTime(time): Date always returns this time. Timers still run.
  • install({ time }): start a fake clock at this time. Time flows, but you can move it.
  • pauseAt(time): jump to a time and stop there.
  • fastForward(ticks): jump ahead. Each due timer fires once. Ticks are milliseconds, or text like '30:00'.
  • runFor(ticks): move ahead step by step, firing every timer on the way.
  • resume(): let time flow again. Call clock methods before goto() when the page reads the time as it loads.

Animation: a timeline from 20:00 to 21:30. pauseAt jumps to 21:00 and stops. fastForward jumps 30 minutes to 21:30. The countdown text changes from 04:00:00 to 03:00:00 to 02:30:00

20:00 21:00 21:30

Countdown: 04:00:00 pauseAt(21:00) → 03:00:00 fastForward('30:00') → 02:30:00

The page's time moves only when the test says so.

With a fake clock, a test can jump hours ahead in milliseconds.

page.clock changes time only inside the page. Your test code and expect timeouts still use real time. Check the page's state with web-first assertions, as above.

Simple lesson: setFixedTime freezes the date. install plus pauseAt, fastForward and runFor move it.

Running Code in the Page

page.evaluate()

  • page.evaluate(fn, arg) runs a function inside the page and returns the result to the test.
  • The function cannot see your test's variables. Pass values as the second argument.
  • Results must be plain data: strings, numbers, arrays and objects. DOM elements cannot come back.
  • Prefer locators and assertions for what users see. Use evaluate for data users cannot see, like storage or app state.

addInitScript()

  • page.addInitScript(fn) runs code before the page's own scripts, on every page load.
  • Use it to set up state, for example a cart in local storage, a feature flag, or a fake API.

exposeFunction() and waitForFunction()

  • page.exposeFunction(name, fn) adds a function to the page's window that runs in your test. The page can call back into Node.js, for example to hash data or read a file.
  • page.waitForFunction(fn) waits until a function in the page returns a truthy value. Use it for conditions no locator can describe.

Simple lesson: evaluate reads the page, addInitScript prepares it, exposeFunction lets it call back.

Lower-Level Tools

CDP Sessions

  • Chromium speaks the Chrome DevTools Protocol (CDP). It can do things Playwright has no API for, such as CPU throttling.
  • context.newCDPSession(page) opens a session. It works only in Chromium.
test('slow CPU', async ({ page }) => {
  const client = await page.context().newCDPSession(page);
  await client.send('Emulation.setCPUThrottlingRate', { rate: 4 });
  await page.goto('/products');
  // ... measure how the page behaves on a slow phone
});

More Places Playwright Runs

  • Electron desktop apps: _electron.launch() from playwright.
  • Android: _android drives Chrome on Android devices (experimental).
  • Other languages: Playwright also has Python, Java and .NET versions with the same API names.

Reach for low-level tools last. Locators, web-first assertions, routes and the clock cover almost every test. Lower-level code is harder to read and often works in one browser only.

Simple lesson: CDP and friends exist for rare needs. Most tests never need them.

Try It in Your Project

  • These steps take the lesson from the lab to your own app.
  • Find one page in your app that shows dates or countdowns and test it with page.clock.
  • Use addInitScript() to set feature flags or test data before load.
  • Write one small Library script that takes screenshots of your key pages.

Simple lesson: use one idea from this lesson on your own app this week.

TL;DR

  • @playwright/test is for testing. playwright (the Library) is for scripts. Both share the page API.
  • Scripts launch a browser, make a context and page, and must close the browser.
  • launchPersistentContext keeps a profile. connectOverCDP attaches to a running Chrome.
  • page.clock fakes time: setFixedTime, install, pauseAt, fastForward, runFor.
  • evaluate runs code in the page. addInitScript runs before page scripts. exposeFunction calls back to the test.
  • CDP sessions, Electron and Android cover rare needs.

Common mistakes

MistakeWhat happensFix
A Library script that never closes the browserThe script hangs or leaks processestry { ... } finally { await browser.close() }
Using a test variable inside evaluateReferenceError in the pagePass it as the second argument
Returning a DOM element from evaluateThe result is empty or an errorReturn plain data, or use a locator
Setting the clock after the page read the timeThe page shows the real timeCall clock methods before goto()
Using CDP for normal checksChromium-only, hard-to-read testsUse locators and assertions

Check Yourself

Exercises

What to Remember

  • Playwright Test for tests, the Library for scripts. Same page API.
  • Scripts must launch and close browsers themselves.
  • page.clock makes time-based pages testable.
  • evaluate, addInitScript and exposeFunction reach inside the page.
  • Low-level tools are for rare needs.

Next: AI-Assisted Testing with Agents, MCP, and CLI