본문으로 건너뛰기

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에서 자세히 다룹니다.

실습

  1. Iframe 안 button을 page locator로 찾았을 때 error를 확인합니다.
  2. frameLocator()로 바꾸고 role locator를 사용합니다.
  3. Open shadow DOM custom element를 semantic locator로 찾습니다.
  4. Frame reload 중 locator가 action 시점에 다시 평가되는지 관찰합니다.

참고: Frames, Pages and popups