IKivan-kozenko -aqa
Try yourself as a QA tester
All topics·Beginner·16 / 16

Pages

One page = one browser tab. You get one automatically in every test. The tricky part is when an action opens a NEW tab or popup — you need to capture that page object before interacting with it.

The page fixture

In every Playwright test you get a page fixture automatically — it's a fresh browser tab isolated from other tests. You use it to navigate, interact, and assert. One page per test is the default and works for most scenarios.

ts
test('orders page loads', async ({ page }) => {
  // page — ізольована вкладка, свіжа для кожного тесту
  await page.goto('/orders')
  await expect(page.getByRole('heading', { name: 'Orders' })).toBeVisible()
  await expect(page).toHaveURL('/orders')
  await expect(page).toHaveTitle('Orders | My App')
})

New tabs and popups

New tabs and popups are separate Page objects — await context.waitForEvent('page') or page.waitForEvent('popup') BEFORE clicking

When a link has target="_blank" or JavaScript calls window.open(), a new browser tab opens. The new tab is a separate Page object. The pattern: set up the promise BEFORE clicking (just like waitForResponse or download events), then click, then await.

ts
test('order receipt opens in new tab', async ({ page, context }) => {
  await page.goto('/orders/42')

  // Встановлюємо очікування ДО кліку
  const newPagePromise = context.waitForEvent('page')

  // Клік відкриває нову вкладку
  await page.getByRole('link', { name: 'View receipt' }).click()

  // Отримуємо нову сторінку
  const receiptPage = await newPagePromise
  await receiptPage.waitForLoadState()

  // Взаємодіємо з новою вкладкою нормально
  await expect(receiptPage).toHaveURL(//receipts/d+/)
  await expect(receiptPage.getByRole('heading', { name: 'Receipt' })).toBeVisible()
})
ts
test('payment gateway opens in popup', async ({ page }) => {
  await page.goto('/checkout')

  // waitForEvent('popup') — для popup вікон (не нових вкладок)
  const popupPromise = page.waitForEvent('popup')

  await page.getByRole('button', { name: 'Pay now' }).click()

  const popup = await popupPromise
  await popup.waitForLoadState()

  // Взаємодіємо з popup
  await popup.getByLabel('Card number').fill('4242424242424242')
  await popup.getByRole('button', { name: 'Pay' }).click()
})

Multiple pages in one test

Sometimes you need multiple tabs in one test — for example, testing that changes made in one tab appear in another (real-time sync). Create pages from context directly.

ts
test('order update syncs between tabs', async ({ context }) => {
  // Відкриваємо дві вкладки в одному контексті (одна сесія)
  const adminTab = await context.newPage()
  const viewerTab = await context.newPage()

  await adminTab.goto('/orders/42')
  await viewerTab.goto('/orders/42')

  // Адмін оновлює статус
  await adminTab.getByRole('combobox', { name: 'Status' }).selectOption('shipped')
  await adminTab.getByRole('button', { name: 'Save' }).click()

  // Viewer бачить зміну (якщо є WebSocket або polling)
  await viewerTab.reload()
  await expect(viewerTab.getByTestId('status-badge')).toContainText('Shipped')
})