Playwright 고정 대기 대신 상태 대기를 써야 하는 이유

2026. 9. 15. 13:00·IT
728x90
반응형

브라우저 자동화 코드에서 wait_for_timeout(800) 같은 고정 대기는 "이 정도면 되겠지"라는 추측이다. 추측은 빠른 날엔 낭비고 느린 날엔 버그다. 이 글은 티스토리 에디터를 HTML 모드로 전환한 직후 본문을 넣었더니 내용이 통째로 사라졌던 일을 통해, 고정 대기가 어떻게 레이스 컨디션을 만들고 상태 대기가 왜 그것을 없애는지 다룬다.

전환이 끝나기 전에 넣은 본문은 초기화와 함께 사라진다

티스토리 에디터는 기본모드(TinyMCE)에서 HTML 모드(CodeMirror)로 바꿀 수 있다. 첫 구현은 이랬다.

page.click("#editor-mode-layer-btn-open")
page.wait_for_timeout(300)
page.click("#editor-mode-html")
page.wait_for_timeout(800)      # 전환 대기
set_body(page, html)            # 본문 주입
page.click("a.action:has-text('임시저장')")

저장은 됐다. 그런데 글을 열어보니 본문이 없었다. 원인은 둘이 겹쳐 있었다. 하나는 주입 방식 자체의 문제로 다른 글에서 다뤘다. 다른 하나가 이 글의 주제다. 전환 확인 대화상자를 수락한 뒤 에디터가 실제로 준비되기까지의 시간이 800ms보다 길 때가 있었고, 그 사이에 넣은 내용은 에디터가 재초기화되면서 지워졌다.

고정 대기의 문제는 실패가 확률적이라는 점이다. 열 번 중 여덟 번은 되고 두 번은 안 된다. 재현이 안 되니 원인을 좁히기 어렵고, "가끔 본문이 비는 버그"로 오래 남는다.

기다릴 대상은 시간이 아니라 상태다

고칠 방법은 "무엇이 준비됐다는 신호인가"를 찾는 것이다. HTML 모드가 켜지면 페이지에 있던 두 개의 .CodeMirror 요소 가운데 첫 번째가 보이게 된다. 전환 전에는 둘 다 높이가 0이다. 그러니 그 요소가 보일 때까지 기다리면 된다.

page.click("#editor-mode-layer-btn-open")
page.click("#editor-mode-html")
cm = page.locator(".CodeMirror").first
cm.wait_for(state="visible", timeout=15000)   # 상태 대기
page.wait_for_timeout(800)                     # 안정화 여유
set_body(page, html)

Playwright의 wait_for(state="visible")는 요소가 "비어 있지 않은 바운딩 박스를 갖고 visibility:hidden이 아닐 때"까지 폴링한다. 전환이 200ms 만에 끝나면 200ms 뒤에 진행하고, 3초가 걸리면 3초 뒤에 진행한다. 15초가 넘으면 TimeoutError로 명확히 실패한다.

뒤에 남긴 800ms는 성격이 다르다. 이것은 "준비됐다는 신호가 온 뒤, 내부 초기화가 마저 끝나도록 주는 여유"다. 없애도 되는지 확인하려면 몇 번 더 돌려봐야 하는데, 이 값은 실패했을 때의 비용(빈 글 저장)이 커서 그냥 두었다. 고정 대기를 전부 없애는 것이 목표가 아니다. 고정 대기가 유일한 동기화 수단이 되는 것을 막는 것이 목표다.

같은 원칙이 파이프라인 곳곳에 필요했다

이 프로젝트에서 상태 대기로 바꾼 곳은 세 군데 더 있다.

이미지 업로드는 파일을 넘긴 뒤 편집 영역에 <figure>가 하나 늘어날 때까지 기다린다. 걸린 시간은 4초에서 9초까지 편차가 컸다. wait_for_timeout(9000)이었다면 빠른 날에는 5초를 버리고, 느린 날에는 실패했을 것이다.

로그인은 사람이 브라우저에서 카카오 인증을 마칠 때까지 기다린다. 얼마나 걸릴지 아예 알 수 없다. 3초마다 별도 탭에서 관리 페이지를 열어보고, 로그인 화면으로 튕기지 않으면 완료로 본다. 최대 10분.

confirm 대화상자는 시간과 무관하다. Playwright 문서는 핸들러를 등록하지 않으면 "모든 대화상자가 자동으로 닫힌다"고 하고, 등록했다면 "반드시 처리해야 하며 아니면 동작이 멈춘다"고 한다. 티스토리는 "이어서 작성하시겠습니까?"는 취소해야 하고 "작성 모드를 변경하시겠습니까?"는 수락해야 한다. 그래서 정책을 상황마다 바꾸는 핸들러 객체를 두었다. 대기가 아니라 이벤트 처리다.

상태 대기에도 함정은 있다

반론이 있다. 상태 대기는 "무엇이 준비 신호인지"를 정확히 알아야 하는데, 그걸 틀리면 고정 대기보다 나쁘다. 맞는 말이다. 처음에 나는 HTML 모드 전환 신호로 모드 버튼의 라벨 텍스트를 보려 했다. 그런데 전환 뒤에도 라벨은 한동안 "기본모드"였다. 라벨 갱신이 에디터 준비보다 늦었던 것이다. 그 신호를 썼다면 이미 준비된 에디터 앞에서 15초를 기다리다 실패했을 것이다.

그래서 신호는 "내가 다음에 조작할 바로 그 요소"에서 찾는 것이 맞다. 본문을 넣을 대상이 .CodeMirror이니 .CodeMirror가 보이는지를 본다. 라벨이나 URL 같은 간접 신호는 대상보다 먼저 바뀔 수도, 늦게 바뀔 수도 있다.

고정 대기는 코드를 쓰는 사람의 추측을 숫자로 적어둔 것이다. 상태 대기는 브라우저가 실제로 어떤 상태인지 묻는 것이다. 자동화가 "가끔" 깨진다면, 코드 어딘가에 추측이 숫자로 박혀 있을 가능성이 크다.

참고 자료

  • Playwright Python — Auto-waiting / Actionability — visible, stable 등 대기 조건의 정의
  • Playwright Python — Dialogs — 핸들러 유무에 따른 대화상자 처리 규칙
  • CodeMirror 5 User Manual — 에디터 인스턴스와 이벤트
728x90
반응형

'IT' 카테고리의 다른 글

오픈소스 라이선스 변경, 기업이 자꾸 바꾸는 이유와 개발자의 대응  (0) 2026.09.15
Playwright intercepts pointer events 해결  (0) 2026.09.14
AI 반도체 거품 논쟁, 매출 1조 달러와 캡엑스 6천억 달러 사이  (0) 2026.09.14
Playwright 파일 업로드, input 없는 사이트 처리법  (0) 2026.09.13
프론트엔드 프레임워크 2026, 시그널이 표준이 되고 논쟁은 끝났다  (0) 2026.09.13
'IT' 카테고리의 다른 글
  • 오픈소스 라이선스 변경, 기업이 자꾸 바꾸는 이유와 개발자의 대응
  • Playwright intercepts pointer events 해결
  • AI 반도체 거품 논쟁, 매출 1조 달러와 캡엑스 6천억 달러 사이
  • Playwright 파일 업로드, input 없는 사이트 처리법
밍글링글링
밍글링글링
mingling - 밍글링, 밍글밍글링. 코드와 어우러지다. IT/ 프로그래밍/소스
    반응형
    250x250
  • 밍글링글링
    mingling
    밍글링글링
  • 전체
    오늘
    어제
    • 밍글링글링 (413) N
      • Flutter (2)
      • 일상생활 (8)
        • 리뷰 (1)
        • 생활정보 (4)
        • 맛집 (0)
        • 여행 (0)
        • 모든정보 (3)
      • JAVA (126)
        • 개념 (6)
        • 예제 (115)
        • Exception (2)
      • C (1)
        • C (1)
        • C++ (0)
        • C# (0)
      • JS (29)
        • JavaScript (18)
        • JQuery (5)
        • AJax (0)
        • NODE.JS (6)
        • Angular.JS 2.0 (0)
      • WEB (87)
        • HTML (6)
        • CSS (61)
        • JSP (20)
        • JSTL (0)
      • FrameWork (8)
        • Spring (8)
        • BootStrap (0)
        • MyBATIS (0)
        • JUnit (0)
      • 외부 라이브러리 (5)
      • 공유 소스 관리 (5)
        • Git (5)
        • SVN (0)
      • 빅데이터 프로그래밍 (37)
        • Python (37)
        • R Programming (0)
      • DB (7)
        • ORACLE (0)
        • MySql (6)
      • Development Tools (7)
        • StarUML (0)
        • eXERD (0)
        • Eclipse (4)
      • SKILL (6)
        • Migration (0)
        • Security (6)
      • MicroSoft (0)
        • Excel (0)
        • Word (0)
      • Android (0)
      • Server (21)
        • Ubuntu (5)
        • Linux (15)
      • IOS (0)
      • XML (0)
      • 미디어 (0)
      • 공지사항 (3)
      • NETWORK (1)
      • 게임 (4)
        • 피파 (1)
        • 리니지M (0)
        • 배틀그라운드 (1)
        • 듀랑고 (2)
      • 세상 이슈 (6)
      • 일렉트론 (0)
      • 대회 소식 (4)
      • 업무 (2)
      • Express, Vue (6)
      • docker (11)
      • svelte (3)
      • 블록체인 (1)
      • IT (16) N
      • Rust (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 미디어로그
    • 위치로그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    브라우저 자동화
    자바 exception
    AI 코딩 에이전트
    rust linux
    proxy pass
    자바 객체 지향
    nginx ssl 설정
    css tb
    nginx
    러스트
    자바 배열
    lang rust
    ubuntu
    css float
    css perspective
    프런트엔드
    Rust lang
    React Compiler
    에디터 팁
    nginx ssl 적용
    vue cli
    vue 설치
    svelte
    gitlab 설치
    servlet class
    오류
    mysql db
    css block
    jsp parameter
    Extension Bisect
    ssl 인증서 발급
    리눅스 설치
    spring java
    티스토리 자동화
    자바 for문
    docker
    클론코딩
    Node
    SSL 인증서
    vscode
    java casting
    자바 클래스
    css list
    css table
    API 설계
    자바 생성자
    jsp include
    VS Code 팁
    Java Array
    css transition
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
밍글링글링
Playwright 고정 대기 대신 상태 대기를 써야 하는 이유
상단으로

티스토리툴바