3.1 Form, Keyboard, Pointer
한눈에 보기
- 일반 text input은
fill()을 우선합니다. - key event 자체가 제품 기능이면
press()또는pressSequentially()를 사용합니다. - checkbox, radio는
check()/uncheck(), select는selectOption()으로 의도를 표현합니다. force: true는 test를 고치는 도구가 아니라 actionability 검사를 우회하는 마지막 수단입니다.- drag-and-drop은
dragTo()부터 시작하고, 제품이 세밀한 pointer event를 요구할 때만 mouse API로 내려갑니다.
fill()과 실제 typing의 차이
fill()은 input을 focus하고 값을 설정하며 input event를 발생시킵니다. 대부분의 form test에는 이것이 더 빠르고 결정적입니다.
const email = page.getByLabel('이메일');
await email.fill('student@example.com');
await expect(email).toHaveValue('student@example.com');
자동 완성, keydown 단축키, 글자마다 동작하는 formatter처럼 keyboard event sequence가 요구될 때만 한 글자씩 입력합니다.
await page.getByLabel('검색').pressSequentially('postgres', { delay: 30 });
await page.getByLabel('검색').press('Enter');
delay를 flaky test 회피용 wait로 쓰면 안 됩니다. 제품 요구사항이 실제 key interval에 의존하지 않는다면 fill()이 더 적합합니다.
상태에 맞는 전용 action
await page.getByLabel('이용 약관에 동의').check();
await expect(page.getByLabel('이용 약관에 동의')).toBeChecked();
await page.getByLabel('지역').selectOption({ label: '서울' });
await expect(page.getByLabel('지역')).toHaveValue('seoul');
전용 API는 이미 원하는 상태인지 확인하고 필요한 경우에만 action합니다. 무조건 click하는 것보다 test intent와 failure message가 분명합니다.
Pointer와 modifier
await page.getByText('메뉴').hover();
await page.getByRole('menuitem', { name: '복제' }).click();
await page.getByRole('row', { name: /order-42/ }).click({
modifiers: ['ControlOrMeta'],
});
운영체제별 modifier 차이는 ControlOrMeta로 흡수할 수 있습니다. 좌표 click은 responsive layout에 취약하므로 semantic locator로 표현할 수 없을 때만 사용합니다.
Drag-and-drop
const card = page.getByRole('listitem', { name: '검토 중' });
const done = page.getByRole('region', { name: '완료' });
await card.dragTo(done);
await expect(done.getByText('검토 중')).toBeVisible();
제품이 dragover를 특정 횟수로 요구하는 경우 low-level mouse sequence가 필요할 수 있습니다. 이때도 source와 target bounding box를 고정 좌표로 복사하지 말고 실행 시 계산합니다.
실패 사례: programmatic click으로 문제 숨기기
// 사용자에게 button이 overlay로 가려져도 통과할 수 있다.
await page.getByRole('button', { name: '저장' }).dispatchEvent('click');
dispatchEvent()는 DOM event만 발생시키므로 visible, stable, receives-events 같은 조건을 검증하지 않습니다. 제품의 실제 사용성을 확인하려면 정상 click()을 사용합니다.
실습
- Todo Lab에서 할 일을
fill()로 추가합니다. - 같은 흐름을
pressSequentially()로 바꾸고 trace의 event와 실행 시간을 비교합니다. - 완료 checkbox를
click()대신check()로 바꿉니다. - button 위에 overlay를 잠시 표시하고 정상 click이 기다리는지 관찰합니다.
force: true를 적용했을 때 어떤 제품 결함을 놓치는지 기록합니다.
점검표
- Action이 사용자 의도를 이름으로 드러내는가?
- Keyboard event를 검증할 이유가 명확한가?
- 고정 좌표나 styling class에 의존하지 않는가?
- Action 뒤에 최종 제품 상태를 assertion하는가?