본문으로 건너뛰기

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일 필요가 없습니다.

Navigation과 popup 수명주기 재현 화면

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가 보일 수 있습니다. 사용자가 기대하는 두 계약을 함께 검사합니다.

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;

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();

실습

  1. Lab help link에서 popup을 얻고 heading을 검사합니다.
  2. Popup을 닫고 원래 page가 계속 usable한지 확인합니다.
  3. Login 뒤 dashboard URL과 heading을 함께 검증합니다.
  4. networkidle을 readiness marker로 바꿉니다.
  5. Admin/user context를 두 개 만들어 서로 다른 local storage 값을 확인합니다.

실패 분석 질문

  • Event promise가 action 전에 만들어졌는가?
  • 기다리는 대상이 page lifecycle인가, 제품 readiness인가?
  • 새 window가 popup인지 독립 page인지 구분했는가?
  • Same-context와 multi-context가 사용자 model과 일치하는가?

참고: Pages and popups, Navigations, Isolation