로케이터는 페이지에서 요소를 찾는 방법을 제공한다. Playwright에서는 다양한 로케이터를 제공한다.
- page.getByRole : 접근성 속성을 통한 로케이터
- page.getByText : 텍스트 내용을 통한 로케이터
- page.getByLabel : 라벨의 텍스트 기반으로 연결된 폼의 대상을 찾는 로케이터
- page.getByPlaceholder : input의 플레이스홀더를 통한 로케이터
- page.getByAltText : 보통 이미지에서 대체 테스트를 통한 로케이터
- page.getByTitle : 타이틀 속성을 통한 로케이터
- page.getByTestId : data-testid 속성에 기반한 로케이터
await page.getByLabel('이름').fill('나의 이름은');
await page.getByRole('button', { name: '전송' });
로케이터는 체이닝이 가능하다. 아래와 같이 체이닝을 통해서 로케이터의 범위를 좁혀나갈 수 있다.
page.getByRole('form').getByRole('listitem');
🎈 getByRole
각 요소에 반영된 role에 따라 로케이터를 찾을 수 있다.
<h1>타이틀</h1>
<label>
<input type="checkbox" /> Check
</label>
<button>전송</button>
위의 요소를 role로 찾는 방법은 아래와 같다. name을 활용하면 대상을 찾기가 좀더 쉬워진다. name은 태그에 존재하는 텍스트를 검색한다.
page.getByRole('heading');
page.getByRole('checkbox');
page.getByRole('button', { name: /전송/ });
✨ getByRole을 사용한다고 해서 접근성에 대한 테스트가 되는 것은 아니다.
✨ getByRole을 사용하는 것이 가장 좋다. 즉, getByRole을 사용할 수 있도록 적절하게 role을 가진 html 태그를 사용하자.
🛒 getByLabel
보통 폼 내부에 라벨과 연결 된 폼 요소를 찾아준다. 라벨을 찾는 것이 아님에 주의!
<label>
<input type="checkbox" /> Check
</label>
await(page.getByLabel('Check')).toBeChecked();
📯 getByText
요소가 가지고 있는 텍스트를 기반으로 요소를 찾는다. 일부만 일치하거나, 정확히 일치하거나, 정규식을 사용 하는 방법 모두 제공한다.
<p>안녕하세요. 좋은 아침입니다.</p>
await expect(page.getByText('안녕하세요')).toBeVisible();
await expect(page.getByText('안녕하세요. 좋은 아침입니다.', { exact: true })).toBeVisible();
await expect(page.getByText(/안녕하세요./)).toBeVisible();
- exact 옵션을 통해서 정확히 일치하는 경우만 찾을 수 있다.
- div, span, p 와 같은 인터렉션 요소가 아닌 경우에만 해당 로케이터를 사용하는 것이 좋다.
- 보통 정적 텍스트보다는 동적으로 받아온 데이터를 텍스트로 출력할 때 사용할 것 같다.
👓 getByAltText
이미지는 대체 텍스트를 사용하는 것을 권장하고 있다. 그래서 대체 텍스트를 통해서 요소 찾는다.
<img alt="로고입니다" src="/images/logo.png" />
page.getByAltText('로고입니다')
👔 getByTitle
요소에 존재하는 title 속성으로 로케이터를 찾는다.
<span title="나는 span"></span>
page.getByTitle('나는 span')
🩳 locator
CSS 선택자를 활용해서 대상을 찾을 수 도 있다. 이미 알고 있는 선택자를 통해서 좀 더 쉽게 대상을 찾게 해준다.
page.locator('div > button')
✨ 너무 복잡하고 긴 선택자는 별로 좋지 못한 방법이다. 대상을 찾는 핵심적인 선택자로만 사용하자.
체이닝을 사용하는 경우 자식선택자 또는 형제 선택자부터 시작할 수 있다.
page.locator('div').locator('> button').locator('+ span');
🧣 필터링
위의 방법으로 대상을 찾을 때 대상이 두 개 이상인 경우에 필터를 통해서 대상을 추릴 수 있다.
<ul>
<li>
<h3>Product 1</h3>
<button>Add to cart</button>
</li>
<li>
<h3>Product 2</h3>
<button>Add to cart</button>
</li>
</ul>
page.getByRole('listitem')
.filter({ hasText: 'Product 2' });
필터 조건은 다음과 같다.
- hasText : 대상이 텍스트를 가지고 있는 경우
- hasNotText : 대상이 텍스트를 가지지 않은 경우
- has : 대상이 주어진 Locator를 가지고 있는 경우
- hasNot : 대상이 주어진 Locator를 가지지 않은 경우
여기에서 주의해야할 점은 has와 hasNot이다. Locator를 전달할 때는 현재 내가 찾고 있는 대상 보다 상위에서부터 체이닝되는 대상을 filter에 전달하면 안된다. 이게 무슨 의미인지는 아래의 예제를 보면 이해가 더 잘 될 것이다.
아래와 같이 button이지만 ul 로부터 시작하고 있다. ul은 listitem보다 상위의 존재이기 때문에 찾지 못한다.
page.getByRole('listitem')
.filter({ has: page.locator('ul button', { hasText: 'Product 2' }) }); - ❎
page.getByRole('listitem')
.filter({ has: page.locator('ul').locator('button', { hasText: 'Product 2' }) }); - ❎
정상적으로 수정하면 아래와 같다.
page.getByRole('listitem')
.filter({ has: page.locator('button', { hasText: 'Product 2' }) });
✨ 체이닝(has에 전달되는 Locator에서 체이닝 했을 경우를 의미) 되는 것까지 고려해서 찾으려는 대상보다 상위의 존재가 포함되면 안된다.
이걸 모르고 가장 마지막에 체이닝 되는 대상만 하위 요소이면 되는 줄 알고 삽질을 많이 했다 🙁
👜 and
and는 여러 locator를 활용해서 대상을 좁힐 때 사용한다. 아래처럼 and로 체이닝하면 된다.
const button = page.getByRole('button').and(page.getByTitle('Subscribe'));
🎨 or
or는 두개 모두 일치 또는 하나를 일치하도록 해준다. 아래는 두개 모두 또는 한개의 로케이터를 선택하게 되었을 때 첫번째 대상을 검증한다.
const newEmail = page.getByRole('button', { name: 'New' });
const dialog = page.getByText('Confirm security settings');
await expect(newEmail.or(dialog).first()).toBeVisible();
Locator 사용시 우선순위
- 가능하다면 getByRole 사용하기
- 인터렉션 요소가 아닌 경우getByText 사용하기
- Form의 요소(input, select, textarea) 이면서 라벨과 연결 된 경우 getByLabel 사용하기
- 나머지는 상황에 따라 위으 3가지 중 한가지에 해당하지 않는 경우 사용하기
해당 포스트에 설명하지 않은 다양한 locator 메서드들을 제공하기 때문에 공식 문서를 참고하자!
'학습 정리(공식문서,강의) > Playwright' 카테고리의 다른 글
7. Playwright 다운로드 테스트 (0) | 2025.02.23 |
---|---|
6. Playwright Fixture (0) | 2025.01.18 |
4. Playwright Assertion (0) | 2025.01.10 |
3. Playwright Action (0) | 2025.01.07 |
2. Playwright 명령어 (0) | 2025.01.02 |