Recent Posts
Recent Comments
반응형
«   2026/03   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Archives
Today
Total
관리 메뉴

오늘도 공부

Playwright Interactive mode 설명 본문

AI

Playwright Interactive mode 설명

행복한 수지아빠 2026. 3. 10. 11:14
반응형

js_repl로 Playwright를 오래 붙잡고 테스트하는 방법

브라우저 자동화는 익숙해질수록 역설적인 불편이 생긴다.
테스트 한 번 돌리고 끝나는 용도라면 괜찮지만, 화면을 조금 고치고 다시 보고, 상태를 바꾸고 또 보고, 모바일까지 확인하는 반복 작업에서는 매번 처음부터 브라우저를 다시 띄우는 방식이 금방 비효율적으로 느껴진다.

여기서 유용한 접근이 js_repl 기반의 Playwright 세션 유지 방식이다. 핵심은 단순하다. Playwright를 한 번 띄우고 끝내는 게 아니라, 같은 브라우저와 같은 페이지 핸들을 계속 붙잡은 채로 테스트를 이어가는 것이다.

왜 이 방식이 좋은가

보통 브라우저 자동화는 이런 흐름으로 끝난다.

  1. 스크립트 실행
  2. 브라우저 실행
  3. 페이지 이동
  4. 테스트 수행
  5. 종료

문제는 실제 UI 작업이 저렇게 한 번에 끝나지 않는다는 점이다.
현실의 작업은 다음에 가깝다.

  1. 화면을 본다
  2. 코드를 조금 바꾼다
  3. 같은 화면을 다시 본다
  4. 다른 상태로 전환해 본다
  5. 모바일도 확인한다
  6. 다시 데스크톱으로 돌아온다
  7. 미묘한 레이아웃 문제를 잡는다

이때 세션 유지형 Playwright는 훨씬 자연스럽다.

  • 브라우저를 매번 다시 띄우지 않아도 된다
  • 로그인 상태를 유지한 채 반복 검증할 수 있다
  • 데스크톱과 모바일 컨텍스트를 동시에 관리할 수 있다
  • “기능 테스트”와 “시각 확인”을 분리해서 수행하기 쉽다
  • 디버깅 중간 상태를 버리지 않고 이어서 볼 수 있다

즉, 테스트 러너라기보다 “브라우저가 붙은 디버깅 작업대”에 가깝다.

핵심 아이디어

이 방식의 본질은 두 가지다.

첫째, Playwright 객체를 한 번 만든 뒤 계속 재사용한다.

  • browser
  • context
  • page
  • 필요하면 mobileContext, mobilePage

둘째, 변경 종류에 따라 대응이 달라진다.

  • UI만 바뀌면 reload
  • 앱 시작 코드나 프로세스가 바뀌면 relaunch

이 차이를 분리하면 반복 작업이 훨씬 빨라진다.

기본 세팅

가장 먼저 필요한 것은 js_repl과 Playwright다.

[features]
js_repl = true

그리고 작업 디렉터리에서:

npm install playwright
npx playwright install chromium

이후 js_repl 안에서 Playwright를 로드한다.

var chromium;
var browser;
var context;
var page;

({ chromium } = await import("playwright"));

여기서 중요한 점은 const보다 var를 쓰는 경우가 많다는 것이다.
이 세션은 일회성 스크립트가 아니라, 이후 셀에서 같은 바인딩을 계속 재사용하는 방식이기 때문이다.

처음 한 번만 하는 부트스트랩

브라우저를 매번 새로 만드는 대신, 연결 상태를 보고 재사용할 수 있게 헬퍼를 두는 편이 좋다.

var ensureWebBrowser = async function () {
  if (browser && !browser.isConnected()) {
    browser = undefined;
    context = undefined;
    page = undefined;
  }

  browser ??= await chromium.launch({ headless: false });
  return browser;
};

이 패턴의 장점은 명확하다.
“이미 브라우저가 살아 있으면 그대로 쓰고, 죽어 있으면 다시 띄운다.”

이것만으로도 디버깅 흐름이 부드러워진다.

페이지를 붙잡고 일하는 방식

보통은 고정된 viewport로 시작하는 편이 낫다.

await ensureWebBrowser();
context ??= await browser.newContext({
  viewport: { width: 1600, height: 900 },
});
page ??= await context.newPage();
await page.goto("http://localhost:3000", { waitUntil: "domcontentloaded" });

이렇게 해두면 이후에는 다음처럼 계속 이어갈 수 있다.

  • 특정 버튼 클릭
  • 폼 입력
  • 상태 전환
  • 스크린샷 저장
  • 코드 수정
  • 페이지 새로고침
  • 같은 위치에서 다시 확인

이 흐름이 익숙해지면, 테스트가 “스크립트 실행”이 아니라 “브라우저를 붙잡고 탐사하는 작업”으로 바뀐다.

reload와 relaunch를 구분하는 감각

이 방식에서 가장 중요한 습관 중 하나가 이것이다.

reload가 맞는 경우

  • 스타일 수정
  • 컴포넌트 텍스트 변경
  • 레이아웃 조정
  • 클라이언트 렌더링 로직 변경

이때는 대체로:

await page.reload({ waitUntil: "domcontentloaded" });

혹은 여러 페이지를 동시에 쓰면:

for (const p of context.pages()) {
  await p.reload({ waitUntil: "domcontentloaded" });
}

relaunch가 맞는 경우

  • 앱 시작 로직 변경
  • 서버 쪽 인증 초기화 변경
  • 프로세스 재시작이 필요한 설정 변경
  • Electron 메인 프로세스 변경

이때는 브라우저나 앱 자체를 다시 띄워야 한다.

이 판단을 잘하면 “왜 변경이 안 보이지?” 같은 시간을 크게 줄일 수 있다.

기능 QA와 시각 QA를 분리해야 하는 이유

실무에서는 자주 이런 착각을 한다.

“버튼이 눌렸으니 됐다.”

하지만 실제로는 그렇지 않다.

  • 눌리긴 눌리는데 레이아웃이 깨질 수 있다
  • 저장은 됐는데 상태 배지가 안 보일 수 있다
  • 내용은 맞는데 모바일에서 잘릴 수 있다

그래서 기능 QA와 시각 QA를 일부러 분리하는 편이 좋다.

기능 QA에서 확인할 것

  • 클릭, 입력, 저장, 삭제가 되는가
  • 상태 전환이 의도대로 일어나는가
  • 잘못된 입력에 오류가 보이는가
  • 로그인/로그아웃/권한 흐름이 맞는가

시각 QA에서 확인할 것

  • 텍스트가 읽기 쉬운가
  • 배지가 구분되는가
  • 카드, 표, 모달이 겹치지 않는가
  • 모바일에서 잘리지 않는가
  • 첫 화면이 설득력 있게 보이는가

이 둘을 분리하면 테스트 품질이 눈에 띄게 올라간다.

모바일 검증까지 같이 가는 이유

데스크톱만 보고 끝내면 대개 나중에 다시 돌아오게 된다.
특히 다음 문제는 모바일에서 자주 터진다.

  • 헤더 높이 문제
  • 검색창 폭 문제
  • 모달 overflow
  • 버튼 줄바꿈
  • 카드 내부 텍스트 겹침

그래서 같은 세션 안에서 모바일 컨텍스트를 함께 두는 방식이 효율적이다.

mobileContext ??= await browser.newContext({
  viewport: { width: 390, height: 844 },
  isMobile: true,
  hasTouch: true,
});
mobilePage ??= await mobileContext.newPage();
await mobilePage.goto("http://localhost:3000", { waitUntil: "domcontentloaded" });

이렇게 해두면 데스크톱과 모바일을 오가며 비교 검증하기가 쉬워진다.

스크린샷은 증거로 남겨야 한다

테스트를 했다는 말만으로는 부족하다.
실제로 무엇을 봤는지 남겨야 나중에 설명이 가능하다.

그래서 스크린샷은 단순 캡처가 아니라 “검증 증거”로 관리하는 편이 낫다.

추천하는 방식:

  • 로그인 화면
  • 빈 상태 화면
  • 생성 직후 상태
  • 수정 후 상세 화면
  • 모바일 첫 화면

처럼 “주장하려는 내용”에 맞춰 남긴다.

즉, 스크린샷은 많다고 좋은 게 아니라, 검증 포인트와 대응되어야 좋다.

긴 테스트를 한 셀에 몰아넣지 말 것

js_repl 기반 워크플로의 실전 팁 중 하나는 이것이다.

긴 시나리오를 한 번에 다 넣지 말고 끊어서 실행할 것.

예를 들어:

  • 인증
  • 카테고리
  • 상품 생성
  • 상품 수정
  • 공지사항
  • 모바일

처럼 나누는 편이 좋다.

이유는 단순하다.

  • 타임아웃이 덜 난다
  • 어디서 실패했는지 바로 보인다
  • 브라우저 상태를 유지하면서 부분 재실행이 가능하다

필요하면 pragma로 타임아웃을 늘릴 수도 있다.

// codex-js-repl: timeout_ms=60000

자주 막히는 지점

이 방식이 강력하긴 하지만, 자주 부딪히는 지점도 있다.

1. js_repl이 안 보임

가장 흔하다.
대부분은 설정만 바꾸고 세션 자체를 다시 시작하지 않은 경우다.

2. Playwright는 설치됐는데 브라우저 실행 파일이 없음

npx playwright install chromium로 해결된다.

3. localhost 접속은 되는데 origin 문제 발생

인증 시스템이 trusted origin을 강하게 보는 경우가 있다.
브라우저 자동화에서 localhost와 127.0.0.1을 섞어 쓰면 의외로 자주 꼬인다.

4. 오버레이나 모달이 클릭을 가로막음

브라우저 자동화에서 가장 흔한 UI 문제다.
실패 로그를 자세히 보면 어떤 요소가 pointer event를 가로막는지 바로 나온다.

5. 같은 이름을 다시 선언해서 REPL이 꼬임

이건 세션 유지형 방식의 대표적인 실수다.
한 번 만든 바인딩을 재사용해야 한다.

이 방식이 특히 잘 맞는 사람

  • UI 디버깅을 자주 하는 프론트엔드 개발자
  • 관리자 화면을 반복적으로 검증하는 사람
  • 기능 테스트와 시각 테스트를 같이 다루는 사람
  • 브라우저 상태를 유지한 채 탐색적으로 QA하고 싶은 사람

반대로, 아주 짧은 단발성 테스트만 돌린다면 일반 Playwright 테스트 파일이 더 간단할 수 있다.

Codex에서 쓰는 방법

Codex에서 이 방식을 쓰려면, 단순히 Playwright만 설치하는 것으로는 부족하다.
핵심은 js_repl이 켜진 세션으로 Codex를 다시 시작하는 것이다.

1. js_repl 활성화

~/.codex/config.toml에 아래 설정을 넣는다.

[features]
js_repl = true

중요:

  • 설정 저장만으로 바로 되는 것은 아니다
  • 기존 Codex 세션을 종료하고 새로 열어야 한다

2. Codex를 새 세션으로 실행

가능하면 sandbox 제한 없이 여는 편이 낫다.

codex --sandbox danger-full-access

또는 실행 시점에 기능을 명시할 수도 있다.

codex -c features.js_repl=true --sandbox danger-full-access

3. 작업 디렉터리에서 Playwright 준비

npm install playwright
npx playwright install chromium

그리고 현재 워크스페이스에서 import가 되는지 확인한다.

node -e "import('playwright').then(() => console.log('playwright import ok')).catch((error) => { console.error(error); process.exit(1); })"

4. Codex에게 세션 부트스트랩을 시킨다

이후에는 Codex에게 다음 흐름으로 요청하면 된다.

  • js_repl로 Playwright bootstrap
  • 브라우저 launch
  • 데스크톱 context 생성
  • 모바일 context 생성
  • 특정 URL 접속
  • 기능 QA
  • 시각 QA
  • 스크린샷 저장

예를 들어 이런 식이다.

playwright-interactive 방식으로 테스트해줘.
js_repl 세션을 띄우고 localhost:3000에 접속한 뒤
로그인, 상품 생성, 모바일 화면까지 순서대로 검증해줘.

5. Codex 세션 안에서의 기본 흐름

보통은 아래 순서로 간다.

  1. 체크리스트 정리
  2. js_repl bootstrap
  3. 브라우저 실행
  4. 페이지 접속
  5. 테스트 수행
  6. 코드 수정 후 reload
  7. 추가 검증
  8. 스크린샷 저장
  9. cleanup

6. 잘 안 될 때 확인할 것

  • Codex 세션에 정말 js_repl 도구가 보이는지
  • 현재 디렉터리에 playwright가 설치돼 있는지
  • 브라우저 실행 파일이 설치돼 있는지
  • dev server가 살아 있는지
  • 너무 긴 셀을 한 번에 실행해서 타임아웃 난 것은 아닌지

결국 Codex에서의 사용법도 본질은 같다.
브라우저 자동화를 “한 번 돌리는 스크립트”로 쓰는 것이 아니라, “지속적으로 붙잡고 탐사하는 세션”으로 다루는 것이다.

결론

js_repl + Playwright 방식의 장점은 “자동화”보다 “지속성”에 있다.

한 번 띄운 브라우저를 계속 유지하면서:

  • 상태를 바꾸고
  • 화면을 보고
  • 다시 고치고
  • 같은 문맥에서 검증을 이어갈 수 있다.

이 차이는 생각보다 크다.
특히 UI를 만들고 고치는 작업에서는 테스트 러너보다 더 실용적인 “상호작용형 브라우저 디버깅 환경”이 된다.

자동화 스크립트를 쓰는 감각보다, 브라우저를 도구처럼 붙잡고 일하는 감각에 가깝다.
그게 이 방식의 가장 큰 매력이다.

반응형