Show HN: Biloba: Go와 Vitest로 구현한 빠르고 안정적인 Chrome 기반 브라우저 테스트
요약
Biloba는 chromedp 기반의 Go 및 Vitest 지원 자동화된 브라우저 테스트 도구입니다. 병렬화, 실용주의적 안정성, Ginkgo/Gomega를 통한 간결함을 목표로 합니다. 이 도구는 빠르고 안정적인 웹 애플리케이션 테스트 환경을 제공합니다.
핵심 포인트
- Go와 Vitest를 지원하는 브라우저 테스트 프레임워크입니다.
- chromedp 기반으로 병렬화 및 안정성을 확보했습니다.
- Ginkgo/Gomega 또는 TypeScript(Vitest)로 작성할 수 있습니다.
Biloba
"자동화된 브라우저 테스트는 느리고 불안정하다" - 모든 개발자, 언제나
Biloba는 chromedp를 기반으로 하여 Ginkgo에 안정적이고 성능 좋은 자동화된 브라우저 테스트 기능을 제공합니다. 이 도구는 세 가지 원칙을 따릅니다:
- 병렬화를 통한 성능(Performance via parallelization)
- 실용주의를 통한 안정성(Stability via pragmatism)
- Ginkgo와 Gomega를 통한 간결함(Conciseness via Ginkgo and Gomega)
매우 빠르며(#performance) Claude Code 같은 AI 툴체인과 진짜 잘 작동하도록 설계되었습니다.
더 자세히 알아보고 시작하려면 문서(documentation)를 확인하고 사용을 시작하세요! Biloba 테스트는 Ginkgo를 사용하여 Go로 작성할 수 있고, vitest를 사용하여 typescript로도 작성할 수 있습니다. (vitest용 빠른 시작 가이드).
또는 Claude Code가 설정하도록 할 수도 있습니다.
Biloba는 놀라울 정도로 기능이 완벽하며 활발하게 개발 중입니다. 아직 1.0 릴리스 마일스톤에 도달하지 않았기 때문에, 프로젝트가 발전함에 따라 공개 API 계약은 변경될 수 있습니다. 피드백을 보내주세요!
다음은 Ginkgo에서 Biloba 스펙이 어떻게 생겼는지 간략하게 보여주는 예시입니다:
func login(tab *Biloba, user string, password string) {
GinkgoHelper()
tab.Navigate("/login")
...
이 코드를 ginkgo와 순차적으로 실행하거나, 빠르고 안정적이며 격리된 브라우저 테스트를 위해 ginkgo -p로 병렬 실행할 수 있습니다.
기본값으로 Poll
브라우저는 비동기적이기 때문에 Biloba의 상호작용(interactions)과 값 가져오기(value-getters)는 기본적으로 폴링(poll) 방식으로 작동합니다. tab.Click("#go")나 tab.SetValue("#input", "hi")와 같이 완전히 적용되는 호출은 성공하거나 시간 초과될 때까지 재시도하며, 브라우저 내에서 찾고 행동하는 과정을 원자적으로 처리합니다.
대기(wait)를 명시적으로 하고 싶을 때 (예: Consistently와 조합하거나 더 풍부한 조건에 대해 단언할 때), 모든 상호작용에는 Gomega 매처(matcher) 형태가 있습니다:
Eventually("#go").Should(tab.Click())
Eventually(tab.ByLabel("Email")).Should(tab.SetValue("[email protected]"))
그리고 정말로 한 번만 행동하고 즉시 실패하는 의미론(act-once / fail-fast semantics)을 원한다면, tab.Immediate()를 사용하여 폴링 기능을 비활성화할 수 있습니다:
tab.Immediate().Click("#go") // 지금 바로 행동합니다; 아직 클릭 가능하지 않으면 즉시 실패합니다
폴링 시간 초과(timeout), 간격(interval), 그리고 컨텍스트는 tab.WithTimeout(...), tab.WithPolling(...), 그리고 tab.WithContext(...)를 사용하여 Gomega 스타일로 설정할 수 있습니다.
빠르고 현실적인 상호작용 트랙 (Fast and realistic interaction tracks)
기본적으로 Biloba의 상호작용은 빠릅니다: 단일 인-브라우저 스니펫(snippet)으로 실행되는 원자적 JavaScript 시뮬레이션(el.click(), 값 설정, 합성 이벤트)이며, 스크롤이나 가려짐 확인(occlusion check), 실제 커서 움직임이 없습니다. 이것이 Biloba를 빠르고 안정적으로 유지하는 요소이며, 대부분의 테스트 케이스에 적합한 기본값입니다.
진정한 입력 충실도(input fidelity)가 필요한 소수의 테스트 케이스 — 즉, 실제 CSS :hover, 가려짐을 인지하는 클릭, 스크롤-인투뷰(scroll-into-view), 실제 키 입력/드래그/휠/터치 — 의 경우, b.Realistic()은 동일한 탭의 뷰를 반환하며, 이 상호작용들은 실제 Chrome DevTools Protocol 입력을 통해 처리됩니다. API는 동일하지만, 더 충실하고 (약간 느린) 상호작용 엔진을 사용합니다. 문서와 (biloba-go:realistic-mode Claude Code skill)를 참조하세요.
성능 (Performance)
Biloba는 빠릅니다. onsi/biloba-comparison은 Playwright와 비교하는 재현 가능한 3가지 속도 비교를 제공합니다. 이 비교는 biloba-fast, biloba-realistic, 그리고 Playwright 하에서 동일한 32개 시나리오 스위트를 실행한 결과입니다. Apple M1 Max(전체 스위트 벽시계 시간, 15회 실행의 중앙값) 기준:
| config | parallel (8 workers) | serial |
|---|---|---|
| biloba-fast | 2.57s | 9.55s |
| ... | ||
| biloba-fast는 Playwright보다 병렬 실행 시 약 3.2배 / 직렬 실행 시 약 4.0배 빠르며, 심지어 Playwright와 동일한 실제 CDP(Chrome DevTools Protocol) 입력 작업을 수행하는 biloba-realistic조차도 각각 약 2.5배 / 약 2.1배 앞서 나갑니다. 방법론, 개별 버킷 분석 및 차트는 비교 저장소를 참조하십시오. |
물론 합성 벤치마크가 반드시 실제 성능을 포착하는 것은 아닙니다. 여기 두 가지 실제 데이터 포인트가 있습니다:
- M1 Max Macbook Pro에서 1,689개의 스펙을 가진 Ginkgo Biloba 스위트가 60초 이내에 완료됩니다(https://claude.ai/code/artifact/d2e1b070-780c-478b-80f9-5fc617dd81d5?org=b6fadba7-f133-4a3c-b118-3b76f250d94f). 이는 go 서버에 의해 지원되는 상호작용이 풍부한 javascript 앱을 위한 실제 브라우저 테스트입니다.
- 성숙한 165개 시나리오의 playwright 스위트가 Biloba vitest 스위트로 변환되었습니다. 런타임은 약 3분 10초에서 약 1분 13초로 줄어들었으며, 이는 2.6배의 관찰된 속도 향상입니다.
빠른 브라우저 테스트 스위트는 더 나은 규율을 촉진하고 더 안정적인 스위트로 가는 문을 열어줍니다. 권장되는 워크플로우는 장시간 코딩 세션 후에 주기적으로 로컬 flake-hunt를 실행하는 것입니다. 위에서 설명한 1,689개 스펙 스위트는 이러한 의식 덕분에 1% 미만의 스위트 플레이크율을 가집니다(플레이크가 나타나려면 60회 이상의 스위트 실행이 필요합니다). 문서와 flake-hunt 기능은 플레이크 헌트를 설정하는 방법을 설명합니다.
Lightpanda는 어떻습니까?
Lightpanda는 Chrome DevTools Protocol을 사용하는 자동화용 헤드리스 브라우저입니다. 저희는 Biloba를 Lightpanda에 연결하고, Biloba 자체 스위트와 위에서 설명한 실제 애플리케이션 스위트를 실행했습니다. 성능 향상은 미미했습니다. 두 브라우저 모두에서 통과된 테스트 케이스는 Biloba 스위트에서 약 1.5배 빠르고, 실제 애플리케이션에서는 약 1.2배 빨랐습니다. Biloba는 이미 Chrome을 느리게 만드는 대부분의 요소를 피합니다. 하나의 공유 chrome-headless-shell에서 탭을 재사용하고, Chrome으로의 왕복 시간은 밀리초(millisecond)보다 훨씬 짧기 때문입니다. 테스트 케이스 실행 시간의 대부분은 두 브라우저 모두에서 V8에서 실행되는 애플리케이션 자체 JavaScript와 서버에 소요됩니다.
하지만 비용은 컸습니다. Biloba 스위트의 17%와 실제 애플리케이션 스위트의 28%가 실패했습니다. Lightpanda는 레이아웃 엔진이 없기 때문에 요소 기하학(element geometry), 뷰포트 및 스크롤 확인이 작동하지 않으며, 레이아웃에 의존하는 가시성 확인도 마찬가지입니다. 스크린샷은 실제 렌더링 결과물이 아니므로 시각적 회귀 테스트(visual regression)는 불가능합니다. 각 연결마다 하나의 페이지를 받기 때문에 새롭거나 생성된 탭이 없습니다. 다운로드, 네트워크 가로채기(network interception)의 대부분, 접근성 트리(accessibility tree), 그리고 현실적인 입력 또한 누락되어 있습니다. 만약 Lightpanda 기반으로 더 빠른 DOM 전용 경로가 필요하시다면, issue를 열어주세요. 저희가 검토해 보겠습니다.
Claude Code와 Biloba 사용하기
Biloba는 Go/Gomega 및 TypeScript/Vitest 클라이언트를 위한 별도의 Claude Code 플러그인을 제공하며, 이 저장소는 마켓플레이스 역할도 합니다. 사용하는 클라이언트를 설치하세요:
/plugin marketplace add onsi/biloba
/plugin install biloba-go@biloba
/plugin install biloba-vitest@biloba
(또는 claude plugin marketplace add onsi/biloba를 사용한 후 claude plugin install biloba-go@biloba 또는 claude plugin install biloba-vitest@biloba를 사용하세요.)
아니면 Claude Code가 전체 설정을 처리하도록 하세요. 이 중 하나를 프로젝트 루트의 Claude Code에 붙여넣으면 플러그인이 설치되고, Biloba가 추가되며, 첫 번째 스위트가 실행됩니다:
Go (Ginkgo 및 Gomega):
Biloba (https://github.com/onsi/biloba) 브라우저 테스트를 이 Go 프로젝트에 설정하세요.
- 이 프로젝트용 Claude Code 플러그인을 설치하세요:
...
TypeScript (Vitest):
Set up Biloba (https://github.com/onsi/biloba) browser tests with Vitest for this TypeScript project.
1. Install the Claude Code plugin for this project:
...
실패 출력(Failure Output)
Biloba는 테스트가 실패할 때 스크린샷과 모든 JavaScript 콘솔 출력을 자동으로 캡처하고 방출합니다. 심지어 Ginkgo의 진행률 에미터 인프라에 연결되어 있어 Mac에서는 ^T/SIGNIFO (Linux에서는 SIGUSR2)를 누르면 스크린샷이 출력됩니다.
스크린샷은 사람에게는 훌륭하지만 대부분의 CI 시스템에서는 표시되지 않으며 AI 에이전트에게도 도움이 되지 않습니다. Biloba는 자신이 CI 환경이나 에이전트에 의해 실행되는지 자동으로 감지하여 DOM 윤곽선을 방출하고 스크린샷 파일을 디스크에 자동으로 저장합니다.
동일한 직관은 Biloba의 시각적 회귀 매처(visual-regression matcher)인 b.HaveScreenshot에도 적용됩니다. 커밋된 기준선과 비교했을 때 실패가 발생하면, Biloba는 일반적인 .actual.png/.diff.png 쌍을 작성할 뿐만 아니라 에이전트에게 변경된 내용을 말로 알려줍니다—몇 개의 픽셀인지, 변경된 박스가 어디에 있는지, 그리고 변화의 모양이 하나의 영역으로 읽히는지, 균일한 이동(uniform shift)인지, 아니면 모든 텍스트 실행에 걸쳐 흩어진 것인지를 알려줍니다. 이 세 가지는 서로 다른 버그이며, 이미지를 열어보지 않고도 구별할 수 있습니다.
Vitest 지원
Biloba의 TypeScript 클라이언트를 사용하면 vitest 스위트가 Biloba를 통해 Chrome을 구동하도록 할 수 있습니다. 자세한 내용은 Biloba for Vitest를 읽어보세요. 각 vitest 워커 프로세스는 작은 Go 데몬 (bilobad)을 생성하고 stdin/stdout의 프레임화된 JSON을 통해 이와 통신합니다. 모든 데몬은 하나의 공유 Chrome에 연결됩니다—이는 Go 스위트를 빠르게 만드는
npm install -D vitest biloba
npx biloba install-chrome # chrome-headless-shell을 가져옵니다; Chrome 버전당 한 번 실행
install 명령은 라이브러리와 미리 컴파일된 bilobad를 불러오며, macOS/Linux의 x64/armn64 환경에서 Go 툴체인이 필요하지 않습니다. Windows는 아직 지원되지 않으니, 원하시면 이슈를 열어주세요.
이것이 이 README 상단에 있는 채팅 앱을 TypeScript로 구현한 코드입니다. 액션과 어설션은 기본적으로 폴링(poll) 방식으로 작동하며, Go에서와 정확히 동일합니다:
import {beforeEach, describe, it} from "vitest";
import {contains, Keys, not, type Session} from "biloba";
...
Vitest 테스트 실행하기
vitest의 전역 설정(global setup)에서 전체 실행을 위한 Chrome 하나를 시작하고 그 연결을 워커들에게 전달합니다. 이 설정을 등록해야 합니다 — 그리고 프로세스 풀도 함께요. 이렇게 하면 각 테스트 파일이 자체 데몬을 가진 독립적인 워커가 됩니다. 이는 vitest 설정 파일에 작성합니다:
// vitest.config.ts
import {defineConfig} from "vitest/config";
...
그런 다음 다른 모든 vitest 스위트와 동일한 방식으로 실행합니다:
npx vitest run # 전체 스위트를 워커 프로세스에 걸쳐 병렬로 실행
npx vitest # 감시 모드(watch mode)
npx vitest run chat # 경로가 "chat"과 일치하는 파일만 실행
모든 워커는 전역 설정이 시작한 단일 Chrome을 공유하므로, 워커를 추가하는 것은 브라우저 하나와 탭 하나를 사용하는 것이 아니라 데몬 하나와 탭 하나를 사용하는 비용입니다. global-setup.ts 및 파일별 connect/openSession 기본 코드는 Vitest 문서의 설정(setup) 섹션을 참고하세요.
Ginkgo Tree Graphics Designed By 可行 From <a href="https://lovepik.com/image-401791345/ginkgo-branches-in-autumn.html">LovePik.com</a>
AI 자동 생성 콘텐츠
본 콘텐츠는 HN Claude Code Search의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기