Playwright 'strict mode violation' 에러 및 해결방안

이재영·2025년 5월 10일

Playwright를 이용한 항공권 자동 예약 시스템 구축 프로젝트를 진행하면서 꽤 애를 먹었던 문제와 해결 과정에 대해 작성해보겠습니다...
사용자 요청을 받아 항공권 예매 사이트에서 자동으로 항공권을 검색하고 예약하는 시스템을 구현하는 과정에서 도착지를 입력하는 부분에서 예상치 못한 문제가 발생했습니다.. 🤔


🐞 문제 상황: 도착지 입력을 출발지 필드에 fill() 처리함

Playwright 스크립트를 실행하여 페이지에 접속한 후, 출발지 입력 필드와 도착지 입력 필드에 각각 사용자가 요청한 도시 이름을 입력하는 작업을 자동화하고 있었습니다.

출발지 입력은 성공적으로 작동했습니다. 하지만 도착지 입력 차례가 되었을 때, 분명 도착지 입력 필드를 클릭했는데도 도착지 텍스트가 엉뚱하게 출발지 입력 필드에 다시 입력되는 현상이 나타났습니다.


Playwright 로그

Error: strict mode violation: locator("div[data-testid=\"search_city_from0_wrapper\"]").locator("input[data-testid=\"search_city_from0\"]:visible") resolved to 2 elements:
    1) <input value="" type="text" placeholder="출발지" autocomplete="off" data-testid="search_city_from0" class="module-input f-16 f-bold color-main placeholder-gray"/> aka locator("#searchBox-content").get_by_test_id("search_city_from0")
    2) <input value="" type="text" placeholder="출발지" autocomplete="off" data-testid="search_city_from0" class="module-input f-16 f-bold color-main placeholder-gray"/> aka get_by_test_id("search_city_from0_poi_wrapper").get_by_test_id("search_city_from0")

Call log:
  - waiting for locator("div[data-testid=\"search_city_from0_wrapper\"]").locator("input[data-testid=\"search_city_from0\"]:visible") to be visible

에러 내용이 Playwright의 'strict mode violation' 인 것을 발견


🦠 문제 진단: 'strict mode violation'이란?

Playwright는 기본적으로 엄격 모드(strict mode)로 동작합니다. 이는 page.locator("어떤 선택자")로 요소를 찾은 후 click(), fill(), textContent() 등의 액션을 수행할 때, 해당 선택자가 웹 페이지에서 단 하나의 요소만을 가리켜야 한다는 규칙입니다. 만약 동일한 선택자에 해당하는 요소가 여러 개 발견되면, Playwright는 어떤 요소와 상호작용해야 할지 알 수 없어 strict mode violation 에러를 발생시키고 실행을 멈춥니다.

제 경우, 에러 메시지를 보니 제가 사용한 선택자인 departure_wrapper.locator('input[data-testid="search_city_from0"]:visible')두 개의 요소를 찾아냈다는 것을 명확히 알 수 있었습니다. 심지어 해당 오류를 해결하려고 :visible 필터를 사용하여 화면에 보이는 요소만 찾도록 했는데도 두 개가 발견되었다고 합니다....

에러 메시지에 나온 두 요소의 HTML 구조와 "aka" 부분을 보면, 동일한 data-testid="search_city_from0"를 가진 input 요소가 DOM 트리 상에서 서로 다른 경로에 위치하고 있음을 시사했습니다. 아마도 UI 구조상 두 개의 비슷한 입력 필드가 존재하고, Playwright가 둘 다 'visible'하다고 판단하여 어떤 필드에 텍스트를 입력해야 할지 결정하지 못한 것이었습니다.


❌ 해결 시도: Wrapper에 바로 입력

이 문제를 해결하기 위한 시도 중 하나로, "그렇다면 출발지 입력 필드를 감싸는 div(departure_city_wrapper_selector)에 바로 fill()을 하거나, 도착지 입력 필드를 감싸는 div(arrival_city_wrapper_selector)에 바로 fill()을 하면 어떨까?" 하고 생각했습니다. 각 wrapper는 data-testid로 명확하게 구분되기 때문에 이런 방안을 생각했던것 같습니다...

하지만 이 방법은 작동하지 않았습니다.

이유는 간단합니다: Playwright의 fill() 메서드는 사용자가 키보드로 텍스트를 직접 입력할 수 있는 HTML 요소(input[type="text"], textarea 등)에만 사용할 수 있습니다. departure_city_wrapper_selectorarrival_city_wrapper_selector가 가리키는 요소들은 <div ...> 태그이며, 이 div는 단순히 다른 요소들을 감싸거나 클릭 이벤트를 처리하는 컨테이너(Container) 역할만 할 뿐, 텍스트 입력을 직접 받는 요소가 아니기 때문입니다.

Wrapper div를 클릭하는 것은 웹사이트의 UI 로직을 발동시키는 역할을 하지만, 텍스트를 입력하는 것은 그 클릭으로 인해 새롭게 나타나거나 활성화되는 실제 <input> 태그가 담당합니다.


✨ 문제 해결: .first() 사용

stackoverflow 포스트와 github issue 중 저와 비슷한 문제상황을 겪은 것을 발견했고, 해당 글의 답변들을 참고하여 제 문제 상황을 해결하기 위해 Playwright의 .first() 메서드를 사용하기로 했습니다!

에러 해결 코드 블럭:

# 해결 코드 (출발지 입력 예시)
departure_city_input_field = departure_wrapper.locator(
    'input[data-testid="search_city_from0"]'
).first # <-- 여기에 .first() 추가!

await departure_city_input_field.wait_for(state="visible") # .first를 썼어도 대기는 필요
await departure_city_input_field.fill(origin_city_name) # 이제 에러 없이 성공!

도착지 입력 부분도 동일하게 수정했습니다 (도착지 data-testidsearch_city_to0이라고 가정):

# 해결 코드 (도착지 입력 예시)
arrival_city_input_field = arrival_wrapper.locator(
    'input[data-testid="search_city_to0"]' # 도착지 data-testid 확인 필요
).first # <-- 여기에 .first() 추가!

await arrival_city_input_field.wait_for(state="visible")
await arrival_city_input_field.fill(destination_city_name) # 이제 도착지 필드에 정확히 입력!

작동원리 : 왜 .first()가 작동했을까? ✅

.first()는 Playwright에게 "네가 locator()로 요소를 찾았을 때, 만약 여러 개의 요소가 발견된다면, 그중에서 DOM 트리 상에서 가장 먼저 나오는 요소 하나만 선택해서 다음 액션을 수행해!" 라고 명확하게 지시하는 역할을 합니다.

kr.trip.com의 UI 구조상, 사용자가 실제로 텍스트를 입력해야 하는 입력 필드가 Playwright가 선택자로 찾은 여러 요소들 중 가장 먼저 발견되는 요소였던 것입니다. .first()를 붙여주자 Playwright는 이제 두 개 중 첫 번째 요소를 명시적으로 선택할 수 있게 되었고, 더 이상 어떤 요소와 상호작용해야 할지 혼란스러워하지 않게 되어 strict mode violation 에러가 해결되었습니다!!


마무리

Playwright의 'strict mode violation' 에러의 해결 방안을 아래와 같이 정리해보았습니다.

  1. 에러 메시지를 꼼꼼히 읽고, 어떤 선택자가 몇 개의 요소를 찾았는지, 그리고 어떤 요소들인지 (aka 부분) 파악하는 것이 중요합니다.
  2. 브라우저 개발자 도구를 사용하여 문제의 요소들이 실제 HTML 구조상 어디에 위치하며, 어떤 속성(ID, 클래스, data-* 속성 등)을 가지고 있는지 정확하게 확인해야 합니다.
  3. 찾아낸 정보를 바탕으로 가장 고유하고 안정적인 선택자를 구성하거나, .first(), :visible 등의 필터를 적절히 사용하여 원하는 요소를 명시적으로 선택하도록 코드를 수정해야 합니다.

이번을 통해 다시 한번 디버깅의 중요성을 깨달았습니다 🥹


https://stackoverflow.com/questions/78138968/getting-this-error-strict-mode-violation-on-multiple-locators-in-playwright

profile
how to define. how to solve.

0개의 댓글