Pw
TypeScript Β· @playwright/test
Element handling with Playwright
23 copy-ready Playwright recipes in TypeScript, JavaScript, Python, Java and C# (.NET), each linked to a live challenge page to run them against.
Language
Conventions Β· TypeScript
// Every snippet runs inside: test('...', async ({ page }) => { await page.goto('/<challenge>'); ... })1Type into inputs & read output
Practice on /elements/text-box βTypeScript
await page.getByTestId('full-name-input').fill('Ada Lovelace');
await page.getByTestId('submit-text-box').click();
await expect(page.getByTestId('output-name')).toHaveText('Name: Ada Lovelace');2Checkboxes & select-all
Practice on /elements/check-box βTypeScript
await page.getByTestId('checkbox-select-all').check();
await expect(page.getByTestId('checkbox-documents')).toBeChecked();3Native <select> dropdown
Practice on /widgets/selects-autocomplete βTypeScript
await page.getByTestId('native-select').selectOption('Mumbai');
await expect(page.getByTestId('native-select-result')).toHaveText('Selected: Mumbai');4Autocomplete suggestions
Practice on /widgets/selects-autocomplete βTypeScript
await page.getByTestId('autocomplete-input').fill('Ben');
await page.getByTestId('autocomplete-option-bengaluru').click();
await expect(page.getByTestId('autocomplete-result')).toHaveText('Picked: Bengaluru');5Find a table row by its text
Practice on /elements/web-tables βTypeScript
const row = page.getByTestId('table-row').filter({ hasText: 'Priya' });
await row.locator('[data-testid^="delete-row-"]').click();
await expect(page.getByTestId('table-row')).toHaveCount(2);6Double-click & right-click
Practice on /elements/buttons βTypeScript
await page.getByTestId('double-click-me').dblclick();
await page.getByTestId('right-click-me').click({ button: 'right' });
await expect(page.getByTestId('right-click-result')).toBeVisible();7JS alert, confirm & prompt
Practice on /alerts βTypeScript
page.once('dialog', (d) => d.accept('Ada')); // register BEFORE the click
await page.getByTestId('prompt-button').click();
await expect(page.getByTestId('prompt-result')).toHaveText('You entered Ada');
page.once('dialog', (d) => d.dismiss());
await page.getByTestId('confirm-button').click();
await expect(page.getByTestId('confirm-result')).toHaveText('You selected Cancel');8Iframes & nested iframes
Practice on /frames βTypeScript
const frame = page.frameLocator('[data-testid="single-frame"]');
await frame.getByTestId('single-frame-button').click();
await expect(frame.getByTestId('single-frame-result')).toHaveText('Clicked inside iframe');
const inner = page.frameLocator('[data-testid="outer-frame"]')
.frameLocator('[data-testid="innermost-frame"]');
await expect(inner.getByTestId('innermost-text')).toBeVisible();9New tabs & windows
Practice on /windows βTypeScript
const [tab] = await Promise.all([
page.context().waitForEvent('page'),
page.getByTestId('new-tab-button').click(),
]);
await expect(tab.getByTestId('new-tab-heading')).toBeVisible();10HTML5 drag & drop
Practice on /interactions/droppable βTypeScript
await page.getByTestId('draggable-box').dragTo(page.getByTestId('accept-zone'));
await expect(page.getByTestId('accept-zone')).toContainText('Accept (1)');11File upload
Practice on /elements/upload-download βTypeScript
await page.getByTestId('file-input').setInputFiles('fixtures/sample.txt');
await expect(page.getByTestId('uploaded-file-info')).toContainText('sample.txt');12Hover tooltips
Practice on /widgets/tooltips-menus βTypeScript
await page.getByTestId('tooltip-trigger').hover();
await expect(page.getByTestId('tooltip')).toBeVisible();13Wait for dynamically loaded content
Practice on /dynamic/dynamic-loading βTypeScript
await page.getByTestId('loading-1-start').click();
// Auto-waits up to the expect timeout (5s by default).
await expect(page.getByTestId('loading-1-result')).toContainText('Hello World!');14Shadow DOM
Practice on /shadow-dom βTypeScript
// CSS locators pierce open shadow roots automatically.
await page.locator('shadow-counter #inc').click();
await expect(page.locator('shadow-counter #count')).toHaveText('Count: 1');15Nested & closed shadow roots
Practice on /shadow-dom βTypeScript
// Nested open roots: getByTestId pierces every level.
await page.getByTestId('nested-input').fill('Ada');
await page.getByTestId('nested-submit').click();
await expect(page.getByTestId('nested-result')).toHaveText('Hello, Ada!');
// Closed root: nothing can query inside β drive it with the keyboard.
await page.getByTestId('closed-host').click(); // delegatesFocus β the input
await page.keyboard.type('Ada');
await page.keyboard.press('Tab'); // β Submit button
await page.keyboard.press('Enter');
await expect(page.getByTestId('closed-host')).toHaveAttribute('data-result', 'Hello, Ada!');16Shadow DOM inside an iframe
Practice on /shadow-dom βTypeScript
const frame = page.frameLocator('[data-testid=shadow-in-iframe]');
await frame.getByTestId('frame-nested-input').fill('Ada');
await frame.getByTestId('frame-nested-submit').click();
await expect(frame.getByTestId('frame-nested-result')).toHaveText('Hello, Ada!');17Cross-origin iframe
Practice on /frames βTypeScript
// Playwright handles cross-origin frames like any other.
const frame = page.frameLocator('[data-testid=cross-origin-frame]');
await frame.getByTestId('xorigin-input').fill('Ada');
await frame.getByTestId('xorigin-submit').click();
await expect(frame.getByTestId('xorigin-result')).toHaveText('Hello, Ada!');18Element covered by an overlay
Practice on /elements/hidden-elements βTypeScript
// A plain click waits, then fails: "<div β¦> intercepts pointer events".
await page.getByTestId('remove-overlay').click();
await page.getByTestId('covered-button').click();
await expect(page.getByTestId('covered-result')).toBeVisible();
// Last resort only: click({ force: true }) skips actionability checks.19Tick a table row by another cell's text
Practice on /elements/web-tables βTypeScript
await page.getByRole('row', { name: /Farah Siddiqui/ }).getByRole('checkbox').check();
await expect(page.getByTestId('selected-users')).toContainText('EMP-1043');20Verify a column sorts correctly (numbers, not text)
Practice on /elements/web-tables βTypeScript
await page.getByTestId('sort-amount').click();
await expect(page.getByTestId('sort-th-amount')).toHaveAttribute('aria-sort', 'ascending');
// "βΉ1,299.00" β 1299 β compare as numbers, never as strings
const nums = (await page.locator('[data-testid="sort-row"] [data-col="amount"]').allTextContents())
.filter((t) => t !== 'β').map((t) => Number(t.replace(/[^\d.]/g, '')));
expect(nums).toEqual([...nums].sort((a, b) => a - b));21normalize-space(), pseudo-elements & DOM comments
Practice on /elements/xpath-functions βTypeScript
// Accessible names are whitespace-normalised, so getByLabel just works.
await page.getByLabel('Delivery Address').fill('12 MG Road');
// β¦or the XPath way:
await page.locator("xpath=//label[normalize-space()='Delivery Address']/following::input[1]").fill('12 MG Road');
// ::before text isn't in the DOM β read the computed style.
const before = await page.getByTestId('pseudo-price').evaluate((el) => getComputedStyle(el, '::before').content);
expect(before).toContain('βΉ');
// HTML comments: evaluate an XPath that returns the comment's text.
const code = await page.evaluate(() => document.evaluate(
"//span[@data-testid='comment-target']/following-sibling::comment()",
document, null, XPathResult.STRING_TYPE, null).stringValue.trim());
expect(code).toBe('secret-code: QA-2026');22Find a record across pages
Practice on /elements/breadcrumbs-pagination βTypeScript
const row = page.locator('[data-order-id="ORD-1042"]');
while (!(await row.isVisible())) {
await page.getByTestId('orders-next').click(); // throws if we run out of pages
}
await expect(row).toContainText('ORD-1042');23Keyboard keys
Practice on /interactions/key-presses βTypeScript
await page.getByTestId('key-input').press('Enter');
await expect(page.getByTestId('key-result')).toHaveText('You entered: Enter');