2.2 Auto-waiting과 actionability
Playwright는 action 전에 element가 실제 사용자 행동을 받을 수 있는지 검사합니다. locator.click()은 단일 element인지, visible, stable, enabled 상태인지, pointer event를 받는지 확인하고 timeout 안에서 기다립니다.
await page.getByRole('button', { name: '결제' }).click();
따라서 다음처럼 고정 sleep을 넣지 않습니다.
// 피합니다.
await page.waitForTimeout(3000);
고정 시간은 빠른 환경을 불필요하게 늦추고, 느린 환경에서는 여전히 부족합니다. 기다려야 할 observable state를 assertion이나 event로 표현합니다.
await expect(page.getByText('결제 완료')).toBeVisible();
const responsePromise = page.waitForResponse('**/api/orders');
await page.getByRole('button', { name: '주문' }).click();
const response = await responsePromise;
expect(response.ok()).toBeTruthy();
Event promise는 action 전에 등록해야 빠른 event를 놓치지 않습니다.
force: true는 일부 actionability check를 건너뜁니다. Overlay가 실제로 click을 막는 제품 bug까지 숨길 수 있으므로 진단용으로만 제한합니다.
참고: Auto-waiting
Actionability를 failure message로 읽기
Click이 기다리는 동안 Playwright는 locator가 하나로 해석되는지, visible, stable, enabled인지, pointer event를 받는지 확인합니다. Timeout message의 “element is not stable”, “intercepts pointer events” 같은 문구는 기다림 부족이 아니라 제품 상태에 대한 증거입니다.
Action과 assertion의 retry 차이
- Action: click 가능한 조건까지 기다린 뒤 한 번 action
- Assertion: expected state가 될 때까지 locator를 반복 평가
- 일반
expect(value): 이미 계산된 JavaScript 값을 즉시 비교
expect(await locator.textContent()).toBe('완료'); // 한 번만 읽음
await expect(locator).toHaveText('완료'); // locator를 재평가
실습
- Button에 500ms animation을 넣고 click이 stable condition을 기다리는지 확인합니다.
- Overlay가 pointer event를 가로채는 failure를 만듭니다.
force: true로 통과시킨 뒤 놓친 제품 문제를 설명합니다.waitForTimeout()을 observable state assertion으로 교체합니다.
심화
Custom component가 disabled state를 ARIA와 native semantics로 노출하지 않으면 Playwright와 실제 사용자 모두 상태를 이해하기 어렵습니다. Testability 개선이 accessibility 개선으로 이어지는 지점입니다.