VALIDATION LAB•NEW TAB / WINDOW
Navigation
New Tab / Window
Click a link that opens a new tab and assert against the content of the popup page.
Scenario
Magic links, third-party OAuth, pricing pages — every product opens new tabs. Tests that ignore them lose coverage on the entire post-link experience. `context.waitForEvent('page')` is the canonical pattern.
Open the destination in a new tab; assert against popup.
Live widget · interact freely
Manual test checklist
- 1Click — a new tab opens with the destination
- 2Confirm `target='_blank'` AND `rel='noreferrer noopener'` (security)
- 3Close the popup, return to the original tab — original session intact
- 4Open via Cmd-click — same destination
- 5Confirm the destination page itself is linkable (has its own URL)
Expected result
The popup loads /practice/new-tab/destination and exposes a recognizable heading.
Automation challenge
Set up `const popupPromise = context.waitForEvent('page')` BEFORE the click. Await it after, then call `popup.waitForLoadState('domcontentloaded')` and assert against `popup.getByRole(...)`.
Stable selectors
- External link
[data-testid="tab-link"]
Locator strategy
Three levels from simple IDs to scoped Playwright locators. IDs and names are easy to learn but are not always the best long-term choice when labels change or components repeat.
Use simple IDs and names to understand how locating elements works.
123
await page.goto('https://lab.hakdogan.com/practice/new-tab');
await page.locator('#tab-link').click();Avoid as primary strategies
XPath (unless there is no alternative), long CSS chains, Tailwind-style utility class selectors, generated or unstable IDs, and volatile framework internals break when layout, styling, or DOM structure shifts.
12
await page.locator('.w-full.rounded-xl.border.bg-blue-500').fill('demo@example.com');
await page.locator('//div[2]/form/div[1]/input').fill('demo@example.com');Reference Playwright spec
123456789101112
import { test, expect } from '@playwright/test';
test('open external link in new tab', async ({ page, context }) => {
await page.goto('https://lab.hakdogan.com/practice/new-tab');
const popupPromise = context.waitForEvent('page');
await page.getByTestId('tab-link').click();
const popup = await popupPromise;
await popup.waitForLoadState('domcontentloaded');
await expect(popup.getByRole('heading', { name: /destination/i })).toBeVisible();
});Headed Test Playback
Simulated headed-browser flow — no real browser is launched.
Automation-style playback (Playwright-shaped logs). No real browser; no commands run on your machine.
new-tab.spec.ts- Clicking external link
- Awaiting popup
- Asserting destination heading