BROWSER INTERACTIONS · LESSON 16 OF 24
Dialogs and frames
Handle modal browser dialogs and enter an iframe explicitly.
- dialog
- accept
- dismiss
- frameLocator
Your runnable checkpoint
Extract into a new practice folder. Each download contains tests, configuration, the complete local practice app and an offline lesson. Use Node.js 22 or 24. Each checkpoint is independent.
Install dependencies and browser binaries using the commands below. The test runner starts the practice server on port 4174. Tests target localhost, never the production EduPoly site.
1. Understand the concepts
JavaScript alert, confirm and prompt dialogs are different from HTML modal elements. A dialog listener must accept or dismiss the dialog; leaving it open can block the action that triggered it.
Attach one-time listeners before the triggering click when only one dialog is expected. Check the dialog’s type or message when that is part of the requirement.
An iframe has its own document. frameLocator enters that document before finding its controls. A page-level locator does not automatically search every frame.
Use the frame’s title or a stable selector to identify it. Avoid selecting a frame by its incidental position when several frames may be present.
2. Build and run
These are complete test files and configuration. The download also includes app/ and server.mjs; preserve their paths. Stop any manually started practice server before running the suite.
npm install
npx playwright install chromium
npm run check
npm testtests/lesson.spec.ts
import { test, expect } from '@playwright/test';
test('confirm a reset and interact inside a frame', async ({ page }) => {
await page.goto('/');
page.once('dialog', async dialog => {
expect(dialog.type()).toBe('confirm');
await dialog.accept();
});
await page.getByRole('button', { name: 'Reset practice tasks' }).click();
await expect(page.locator('#task-status')).toHaveText('Practice tasks reset');
const frame = page.frameLocator('iframe[title="Practice frame"]');
await frame.getByLabel('Frame name').fill('Asha');
await frame.getByRole('button', { name: 'Greet' }).click();
await expect(frame.getByRole('status')).toHaveText('Hello, Asha');
});
playwright.config.ts
import { defineConfig, devices } from '@playwright/test';
export default defineConfig({
testDir: './tests',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 1 : 0,
workers: process.env.CI ? 2 : undefined,
timeout: 30000,
expect: { timeout: 5000 },
reporter: [['list'], ['html', { open: 'never' }]],
use: { baseURL: 'http://127.0.0.1:4174', trace: 'retain-on-failure', screenshot: 'only-on-failure' },
projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }],
webServer: { command: 'node server.mjs', url: 'http://127.0.0.1:4174', reuseExistingServer: false, timeout: 15000 }
});
package.json
{
"name": "edupoly-playwright-dialogs-and-frames",
"version": "1.0.0",
"private": true,
"scripts": {
"test": "playwright test",
"test:headed": "playwright test --headed",
"test:ui": "playwright test --ui",
"check": "tsc --noEmit",
"report": "playwright show-report",
"serve": "node server.mjs"
},
"devDependencies": {
"@playwright/test": "1.56.1",
"typescript": "5.9.3",
"@types/node": "22.20.5"
}
}
tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "CommonJS",
"moduleResolution": "Node",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"types": [
"node"
],
"noEmit": true
},
"include": [
"tests/**/*.ts",
"pages/**/*.ts",
"playwright.config.ts"
]
}
.gitignore
node_modules/
playwright-report/
test-results/
playwright/.auth/
.env
3. Trace the code and check the result
- The listener handles the browser dialog rather than a DOM button.
- frameLocator scopes subsequent locators to the child document.
- The assertion reads the frame’s status element.
Verify your result
- The reset confirmation is handled.
- The iframe greeting reads Hello, Asha.
4. Practice independently
Change the entered frame name and verify the greeting changes.
Show the explanation
Fill Frame name with another synthetic name, click Greet and assert the exact greeting inside the frame.
When something goes wrong
If a browser executable is missing, run npx playwright install chromium in the project folder. If port 4174 is occupied, stop your manual practice server. Read assertion call logs for mismatched locators or expectations. Use npm run report to inspect failures; do not add fixed sleeps or broad resets to hide them.
