2.4 Frame, popup, 새 page
Iframe 안의 element는 frameLocator 또는 frame-scoped locator로 찾습니다.
const payment = page.frameLocator('[title="결제"]');
await payment.getByLabel('카드 번호').fill('4242 4242 4242 4242');
새 tab이나 popup event는 click 전에 기다림을 등록합니다.
const popupPromise = page.waitForEvent('popup');
await page.getByRole('link', { name: '영수증' }).click();
const popup = await popupPromise;
await expect(popup).toHaveURL(/receipt/);
Context 전체에서 새 page를 기다릴 수도 있습니다.
const pagePromise = context.waitForEvent('page');
await page.getByText('새 창에서 열기').click();
const newPage = await pagePromise;
await newPage.waitForLoadState();
networkidle을 일반적인 ready signal로 남용하지 않습니다. Background polling과 analytics가 있으면 끝나지 않거나 제품 상태와 무관할 수 있습니다. 필요한 heading, button, API response 같은 application-specific state를 기다립니다.
Frame과 popup도 같은 context의 cookie, permission을 공유하지만 서로 다른 page lifecycle을 가집니다. 각 page의 close와 navigation을 명확히 다룹니다.
Frame locator
const payment = page.frameLocator('[title="결제"]');
await payment.getByLabel('카드 번호').fill('4111111111111111');
await payment.getByRole('button', { name: '결제' }).click();
Frame 내부 element를 page locator로 찾을 수 없습니다. Frame 자체의 stable attribute와 내부 accessible locator를 분리합니다.
Shadow DOM
Playwright locator는 기본적으로 open shadow DOM을 통과할 수 있습니다. XPath는 shadow root를 관통하지 않으므로 semantic locator가 더 유리합니다. Closed shadow root는 내부 구현에 직접 접근할 수 없으므로 component가 노출하는 사용자 contract로 test합니다.
Cross-origin frame
Origin이 달라도 Playwright frame locator로 사용자 interaction은 가능합니다. 다만 application code의 same-origin restriction을 우회하는 결과로 해석해서는 안 됩니다. Test credential과 payment sandbox policy를 별도로 관리합니다.
Popup과의 구분
Frame은 같은 page 안의 browsing context이고 popup은 별도 Page입니다. Popup event와 navigation은 Part III. Navigation, Tab, Popup에서 자세히 다룹니다.
실습
- Iframe 안 button을 page locator로 찾았을 때 error를 확인합니다.
frameLocator()로 바꾸고 role locator를 사용합니다.- Open shadow DOM custom element를 semantic locator로 찾습니다.
- Frame reload 중 locator가 action 시점에 다시 평가되는지 관찰합니다.
참고: Frames, Pages and popups