3.4 Navigation, Tab, Popup
한눈에 보기
page.goto()는 response와 document load lifecycle을 다루지만 application readiness 전체를 보장하지 않습니다.- UI navigation은 URL과 화면의 제품 상태를 web-first assertion으로 검증합니다.
- 새 tab과 popup은 action 전에
waitForEvent('page' | 'popup')를 시작합니다. networkidle을 보편적인 readiness 신호로 사용하지 않습니다. 제품이 노출하는 의미 있는 state를 기다립니다.- Context 안의 page는 서로 독립적으로 foreground일 필요가 없습니다.
URL과 화면 상태를 함께 검증하기
await page.getByRole('link', { name: 'Dashboard' }).click();
await expect(page).toHaveURL(/\/dashboard$/);
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
URL만 확인하면 empty shell이나 error boundary도 통과할 수 있습니다. Heading만 확인하면 route가 잘못되어도 같은 component가 보일 수 있습니다. 사용자가 기대하는 두 계약을 함께 검사합니다.
Popup event
const popupPromise = page.waitForEvent('popup');
await page.getByRole('link', { name: '도움말 새 창' }).click();
const popup = await popupPromise;
await expect(popup).toHaveTitle(/Help/);
await expect(popup.getByRole('heading', { name: 'Playwright Lab Help' }))
.toBeVisible();
await popup.close();
Popup이 어느 page에서 열렸는지 중요하지 않다면 context의 page event를 기다립니다.
const newPagePromise = context.waitForEvent('page');
await page.getByRole('button', { name: '외부 결제' }).click();
const paymentPage = await newPagePromise;
Navigation wait를 과하게 추가하지 않기
Locator click은 관련 actionability와 navigation을 자동으로 조정합니다. 모든 click에 waitForLoadState()를 붙이면 불필요한 coupling이 생깁니다.
// 제품이 streaming/polling을 사용하면 networkidle에 도달하지 않을 수 있다.
await page.waitForLoadState('networkidle');
대신 제품의 readiness marker를 assertion합니다.
await expect(page.getByTestId('dashboard-ready')).toHaveAttribute('data-state', 'ready');
Multi-page 상태 공유
같은 BrowserContext의 page는 cookie와 storage를 공유합니다. 한 page에서 login하고 다른 page를 열면 동일 session을 사용합니다. 서로 다른 사용자를 표현하려면 page가 아니라 context를 두 개 만들어야 합니다.
const adminContext = await browser.newContext();
const userContext = await browser.newContext();
const adminPage = await adminContext.newPage();
const userPage = await userContext.newPage();
실습
- Lab help link에서 popup을 얻고 heading을 검사합니다.
- Popup을 닫고 원래 page가 계속 usable한지 확인합니다.
- Login 뒤 dashboard URL과 heading을 함께 검증합니다.
networkidle을 readiness marker로 바꿉니다.- Admin/user context를 두 개 만들어 서로 다른 local storage 값을 확인합니다.
실패 분석 질문
- Event promise가 action 전에 만들어졌는가?
- 기다리는 대상이 page lifecycle인가, 제품 readiness인가?
- 새 window가 popup인지 독립 page인지 구분했는가?
- Same-context와 multi-context가 사용자 model과 일치하는가?