IKivan-kozenko -aqa
Try yourself as a QA tester
All topics·Advanced·11 / 24

Library

There are two Playwright packages: 'playwright' (the library) and '@playwright/test' (the test runner). Unless you're writing a script or a tool that isn't a test suite, always use @playwright/test. It gives you web-first assertions, fixtures, retries, reporters, and automatic cleanup. The library requires you to manage all that yourself.

Library vs @playwright/test — when to use each

Use the library (playwright package) when you're writing a Node.js script that automates a browser — web scraping, generating PDFs, automating repetitive tasks. You manage the browser lifecycle manually: launch, create context, create page, do stuff, close everything.

Use @playwright/test for everything else — e2e tests, component testing, integration tests. It provides isolated page/context per test, automatic cleanup, web-first assertions that auto-retry, fixtures, parallel execution, HTML reports.

Library — everything is manual

With the library, I explicitly launch a browser, create a context (with any device emulation settings), create a page, do my work, then close context and browser. If I forget to close, the browser process leaks. No fixtures, no auto-retry assertions — just raw async code.

ts
// my-script.ts — використання бібліотеки напряму
import { chromium, devices } from 'playwright'

;(async () => {
  // Явне налаштування
  const browser = await chromium.launch()
  const context = await browser.newContext(devices['iPhone 11'])
  const page = await context.newPage()

  // Робота
  await context.route('**.jpg', route => route.abort())
  await page.goto('https://example.com/')

  const title = await page.title()
  console.assert(title === 'Example Domain')  // ← не Web-First assertion

  // Явне прибирання (забудеш — браузер залишиться відкритим)
  await context.close()
  await browser.close()
})()
bash
# Встановлення бібліотеки
npm install playwright

# Запустити скрипт
node my-script.js

@playwright/test — the right way for tests

With the test runner, page and context are injected as fixtures — created fresh for each test, automatically closed after. toHaveTitle() is a web-first assertion: it auto-retries until the condition is met or timeout expires. No manual cleanup needed.

ts
// orders.spec.ts — використання @playwright/test
import { test, expect, devices } from '@playwright/test'

test.use(devices['iPhone 11'])

test('orders page loads', async ({ page, context }) => {
  await context.route('**.jpg', route => route.abort())
  await page.goto('/orders')

  await expect(page).toHaveTitle('Orders')  // ← web-first assertion, авто-повтор
  // page і context автоматично закриваються після тесту
})
bash
# Встановлення тестового раннера
npm init playwright@latest

# Запустити тести
npx playwright test

Key differences side by side

The biggest practical differences: assertions and cleanup. With the library, page.title() returns a Promise — you check it with assert() which doesn't retry. With the test runner, expect(page).toHaveTitle() retries automatically. With the library, you must await context.close() and await browser.close() every time. With the test runner, the framework handles it.

Other things the test runner adds that the library doesn't have: projects (multi-browser config), retries, reporters (HTML, blob, JUnit), parallel workers, trace recording, fixtures for auth state sharing.