3.3 Dialog와 Browser Event
Browser event를 다루는 핵심은 event listener를 trigger보다 먼저 준비하는 것입니다. Dialog는 page 실행을 막으므로 listener를 등록했다면 반드시 accept 또는 dismiss해야 합니다.
기본 동작
Listener가 없으면 Playwright는 alert, confirm, prompt를 자동 dismiss합니다. 내용을 검증하거나 accept해야 할 때 handler를 등록합니다.
page.once('dialog', async dialog => {
expect(dialog.type()).toBe('confirm');
expect(dialog.message()).toContain('삭제');
await dialog.accept();
});
await page.getByRole('button', { name: '삭제' }).click();
await expect(page.getByText('삭제했습니다')).toBeVisible();
page.once()는 다음 dialog 하나만 처리하므로 test 범위가 분명합니다. 여러 dialog를 처리해야 할 때만 page.on()을 사용하고 teardown을 고려합니다.
Prompt 입력
page.once('dialog', dialog => dialog.accept('playwright-student'));
await page.getByRole('button', { name: '이름 입력' }).click();
await expect(page.getByTestId('dialog-result')).toHaveText('playwright-student');
흔한 교착 상태
page.on('dialog', dialog => {
console.log(dialog.message());
// accept/dismiss하지 않았다.
});
await page.getByRole('button', { name: '삭제' }).click(); // 멈춤
Listener가 존재하면 Playwright는 자동 dismiss하지 않습니다. Handler가 log만 남기고 종료하면 dialog가 page를 계속 block합니다.
Event promise pattern
Popup, download, request, response도 같은 순서를 적용합니다.
const responsePromise = page.waitForResponse(response =>
response.url().endsWith('/api/summary') && response.status() === 200,
);
await page.getByRole('button', { name: '새로고침' }).click();
const response = await responsePromise;
expect(await response.json()).toMatchObject({ source: 'real-server' });
Promise.all()도 사용할 수 있지만 action과 기다리는 대상이 읽기 어려워질 수 있습니다. Promise 변수 이름이 event의 의미를 설명하게 합니다.
Console과 page error를 증거로 모으기
const errors: string[] = [];
page.on('console', message => {
if (message.type() === 'error') errors.push(message.text());
});
page.on('pageerror', error => errors.push(error.message));
await page.goto('/');
expect(errors).toEqual([]);
모든 console error를 무조건 실패로 만들면 third-party script noise에 suite가 불안정해질 수 있습니다. 제품 코드 범위, 허용 목록, source URL을 명확히 하십시오.
beforeunload 주의
page.close({ runBeforeUnload: true })는 unload handler를 실행하지만 page가 실제로 닫힐 때까지 기다리지 않을 수 있습니다. Unsaved-change 흐름은 dialog handler와 최종 page 상태를 함께 검증합니다.
실습
- Lab의 confirm dialog를 accept하고 result text를 확인합니다.
- 같은 dialog를 dismiss하고 취소 상태를 확인합니다.
- Handler에서
accept()를 제거해 timeout이 발생하는 위치를 trace로 찾습니다. /api/summaryresponse promise를 click 전에 등록합니다.- Console error collector를 fixture로 추출하고 test 종료 시 attachment로 남깁니다.