유저 실사용 시뮬레이션 (브라우저 풀스택 E2E)
v0.17.7 표시 이름 — #1470: 번호 브라우저 행동 검사는 유저 실사용 시뮬레이션(
browser-journeys, 로컬 키browser), 화면 크기·탭 구조 검사는 화면 정합성 검사(viewport-matrix, 로컬 키viewport)로 표시한다. 명령·잡 ID·JSON 키·아티팩트 이름은 유지한다. 아래 과거 버전의 수치는 당시 기록이다. 화면 정합성 검사의 자세한 설명은 원문 해당 절을 따른다.
저장소 분리 (#1463):
README.md와USER-JOURNEY.md는dekerd/Barbelic-docs의 같은 CASE 경로에, 실행용case.json·회귀 테스트·support 코드는 앱 저장소에 둔다. 아래의 패키지는 두 저장소에 걸친 같은 CASE를 뜻한다. 각 소유 저장소에서 갱신하고 PR·커밋을 연결하며 앱 CI가 사람용 문서를 읽게 하지 않는다. 저장소 경계를 따른다.
2026-09-09 개정 (이슈 #1456·#1457·#1458, 오너 결정) — 명령·워크플로 이름이 바뀌었다. 작업 PR 통합 요청
npm run merge:request(구 landing:request), PR 전 사전 검증npm run ci:precheck-local(최신 release 합치기 → verify → 서버 변경 시 DB 단계, 브라우저 없음), 전체 검증npm run ci:full-local(릴리스 큐 runner 안에서만; 세션은--only <단계>재현만). 워크플로 표시 이름:3-Release Merge Request(release-merge-request.yml) ·GitHub Full CI(policy-contract.yml) ·1-Production Deploy/2-Staging Deploy(production-deploy.yml·staging-deploy.yml, 단계 정의는 deploy-steps.yml) ·Production smoke (manual)·Social login daily check·Daily data backup.landing:lock·db:preflight스크립트는 폐기됐다(GitHub concurrency 가 잠금, DB 검사는 사전 검증과 큐가 한다). 아래 본문의 옛 이름은 그 개정 전 기록이다.
한국어 번역본
이 문서는 원문(영어)의 한국어 번역이다. 정본은 원문이며, 계약·게이트 판단이 갈리면 원문을 따른다. 원문: docs/testing/browser-full-stack-e2e.md
Barbelic은 의도적으로 서로 다른 두 개의 통합 스위트를 유지한다:
e2e/crudRoundtrip.e2e.mjs와e2e/emptyAccountJourney.e2e.mjs는 브라우저를 렌더링하지 않고 실제 리포지토리와 데이터베이스를 구동한다.error-cases/CASE-###-slug/regression.spec.mjs는 실제 Chromium, 출시되는 React UI, Supabase Auth/RLS/RPC, 원시 PostgreSQL 재조회(read-back), 새로고침/재진입, 예기치 못한 에러 관찰, 검증된 정리(cleanup)를 사용한다. 케이스가 소유하는 이 파일들은 장애 회귀와 선제적으로 선정한 기대 사용자 행동을 모두 다룬다.
번호가 매겨진 각 디렉터리는 자기완결적인 패키지다. USER-JOURNEY.md는 한눈에 보는 사용자 상태와 단계별 UI 경로이고, README.md는 사람이 읽는 상세 기록이며, case.json은 타입이 정의된 레지스트리 매니페스트이고, regression.spec.mjs는 실행 가능한 여정이다. kind: "incident-regression"은 장애 사실과 Red/Green 증거를 요구한다. kind: "expected-behavior"는 선행 에러나 Red 실행 없이 수동으로 추가할 수 있다. 둘 다 연결된 핵심 체크포인트와 동일한 fail-closed 완료 계약을 요구한다.
번호 케이스는 장애 발생 여부가 아니라 실행 경계로 나뉜다:
standard-full-stack케이스는playwright.config.mjs가 발견하며, 로컬 Supabase와 배포된 프로덕션을 대상으로 실행된다.production-external-oauth케이스는 배포된 앱과 실제 외부 신원 공급자를 함께 통과한다.production-provider-assumed-success케이스는playwright.external-auth.config.mjs를 사용하되 공급자가 소유한 성공 결과 경계만 대체하고, 그다음 배포된 앱/Supabase/데이터베이스의 모든 계층을 구동한다.
로컬과 외부 공급자 발견 집합은 상호 배타적이다. 로컬 전용 Auth Admin 및 오류 주입 프로필은 아래에 설명한다. 일반 브라우저 스위트를 실행하는 것으로는 외부 공급자 케이스가 조용히 Green으로 표시될 수 없다.
PR 필수 게이트 (v0.17.2)
실행 코드·설정·의존성·테스트·migration 또는 미분류 경로를 바꾸는 PR은 자동화 필수 집합 전체를 실행한다. 명시적으로 등록한 문서·이미지·템플릿 경로만 면제하며 full-ci 라벨로 전체 실행을 강제할 수 있다. 영향 범위별 부분 선택은 아직 적용하지 않는다.
독립 목록 e2e/required-coverage.json은 번호 브라우저 여정 57개(CASE001–058 중 CASE003 제외)와 viewport 시나리오 14개를 요구한다. 전체 패키지는 58개다. main의 S04 CASE040을 보존하면서 개발 브랜치의 IndexedDB enqueue 실패 여정을 CASE058로 옮겼으며, 기존 39→약 57개 계획에 S04 1개가 추가됐다. 브라우저는 서로 독립적인 Supabase 4샤드에서 실행한다. 별도 결과 집계 잡이 검사 커밋, 모든 샤드, 발견/완료 ID, 첫 시도 성공, 완료 신호 7종과 정리 증거를 대조한다. 누락·skip·fixme·예상 실패·재시도 통과·artifact 부재·선행 잡 실패는 required verify를 통과할 수 없다.
로컬에서는 같은 스택 준비, 실제 Edge Functions, 앱·독립 관리자 빌드, 테스트와 증거 집계를 한 번에 실행한다.
npm run ci:local -- --full개발 중 npm run ci:local -- --only browser는 번호 여정만 실행하며 전체 PR 게이트를 대신하지 않는다. helper는 격리 스택에서 Auth Admin 자격과 테스트용 JWT secret을 읽는다. 필수 실행의 E2E_REQUIRED_PROFILE=local은 로컬 기능이 없을 때 부분 credential 실행으로 바꾸지 않고 발견 전 실패한다.
local-auth-admin-full-stack: 일회용 사용자 생성·검증·삭제를 포함하며 파괴적 계정/소유권 검사는 로컬 Supabase에서만 수행한다.fault-injection-full-stack: 정확한 HTTP 시도, 필요한 복구 UI/오류 영수증, 제한된 실제 offline 구간을 선언한다. 선언된 상황이 실제 발생하고 복구까지 끝나야 한다. 일반 오류 무시 목록이 아니며 local-only 사례는 배포 환경의 credential 실행에서 제외한다.- CASE049/051은 제공자 결과 경계만 제어한 뒤 실제 앱 callback·Auth·DB 동작을 검증한다. CASE003의 provider-assumed QA는 별도 증거이며 실제 제공자 동의나 native SDK 완주를 증명하지 않는다.
CASE048은 실제 HTTPS·출시 SW·offline 캐시 진입·IndexedDB 보존·실제 worker 교체·단일 서버 저장을 검사한다. 변경된 앱 bundle 교체 증거는 CASE039가 담당한다. 실제 네이티브, 감독하의 제공자 완주, 릴리스 성능 예산, populated upgrade/restore는 별도 출시 증거를 요구한다.
정확한 구현 범위·실행 결과·남은 출시 증거는 구현 기록을 따른다.
로컬 풀스택 실행
전체 필수 실행은 격리 스택을 준비하는 로컬 CI helper를 사용한다.
npm run ci:local -- --full서비스 관리(service-managed) 모드는 인증된 일회용 사용자를 만들고, 실제 RPC로 온보딩을 완료하고, 반환된 Supabase 세션을 앱이 부팅되기 전에 주입하며, 실행이 끝난 뒤 그 사용자를 삭제한다. 일회용 사용자 셋업은 번호 여정이 시작되기 전에, 인식된 로컬 Auth 업스트림/5xx 실패에 한해서만 재시도할 수 있다. 영구적인 셋업 실패와 재시도로만 통과한 모든 Playwright 케이스 결과는 여전히 CI를 실패시킨다. 동일한 프로덕션 번들을 테스트 전용 부팅 전 런타임 오버라이드를 통해 로컬 Supabase로 겨냥한다. 로그인 우회나 특권 브라우저 API는 추가하지 않는다.
프로덕션 실행
.github/workflows/prod-smoke.yml은 Vercel 프로덕션 배포가 성공한 뒤 가벼운 CRUD 카나리를 실행한다. 번호 브라우저 케이스는 명시적인 통합 릴리스 게이트다. 자동 CRUD 잡이 Green이 된 뒤, 해당 릴리스에 대해 main에서 full_browser=true로 Production smoke를 수동으로 한 번 실행한다. 이 워크플로는 main이 아닌 ref로 수동 실행하면 체크아웃이나 프로덕션 시크릿 접근 전에 거부한다. CRUD 잡이 실패하면 더 비싼 브라우저 스위트는 시작되지 못한다. 두 레인 모두 공개 Supabase 키와 프로덕션 E2E 전용 사용자의 이메일/비밀번호만 사용한다:
PROD_SUPABASE_URLPROD_SUPABASE_ANON_KEYPROD_SMOKE_EMAILPROD_SMOKE_PASSWORD
브라우저는 일반적인 인증 RLS를 사용한다. 고유하게 표시된 레코드를 만들고, 원시 행을 정확히 검증하고, 완료된 세션을 삭제하고, 소유자에 묶인 RPC로 커스텀 종목을 보관 처리한다. 정리 결과는 실행이 통과될 수 있기 전에 동일한 인증 클라이언트로 재조회된다. 프로덕션 service-role 키는 이 워크플로에 결코 노출되지 않는다.
요청된 모든 풀브라우저 실행은 JSON 결과와 함께 실패 트레이스, 스크린샷, 비디오, HTML 리포트, 케이스별 여정 완료 아티팩트를 발행한다. CI는 진단 증거를 위해 재시도를 한 번 허용하지만, 재시도로만 통과한 것은 플레이키로 간주해 게이트를 실패시킨다. 프로덕션 브라우저 자격 증명이 없으면 오해를 부르는 skipped Green을 내는 대신 번호 케이스 잡을 실패시킨다. standard-full-stack 케이스는 정확한 로컬 잡과 수동으로 요청된 배포 브라우저 잡이 자신의 case.json에 기록된 뒤에야 production_verified가 된다.
공급자 성공 가정 Kakao 실행
CASE-003은 데스크톱 로그인 화면, 실제 Kakao 버튼, 정확한 Supabase PKCE 인가 요청, 프로덕션 Supabase가 그 요청을 Kakao로 리다이렉트하는지에 대한 자격 증명 없는 라이브 확인, 출시된 콜백/교환 성공 경로, 새로 발급된 브라우저 세션, 기존 계정 해석, 소유자 범위 프로필 재조회, 새로고침 지속성을 구동한다.
성공했다고 가정하는 것은 Kakao가 소유한 계정 인증, 모바일 승인, 동의, 그리고 그 결과인 외부 코드 교환뿐이다. 테스트 러너는 기존 프로덕션 스모크 계정에 대해 새로 발급한 세션으로 그 경계를 채운다. 스토리지를 미리 채우거나 프로덕션 인증 우회를 추가하지 않는다. 앱은 자신의 일반적인 exchangeCodeForSession 성공 처리 경로를 통해 세션을 영속화해야 한다.
기존 프로덕션 스모크 계정으로 실행한다:
E2E_PROVIDER_BOUNDARY_REQUIRED=1 \
E2E_APP_URL="https://www.barbelic.com" \
E2E_SUPABASE_URL="https://PROJECT.supabase.co" \
E2E_SUPABASE_ANON_KEY="..." \
E2E_TEST_EMAIL="..." \
E2E_TEST_PASSWORD="..." \
npm run test:e2e-provider-assumed-auth.github/workflows/social-login-daily-check.yml은 ENABLE_KAKAO_E2E가 true일 때 같은 실행을 수동 및 야간(nightly)으로 노출한다. PROD_SUPABASE_URL, PROD_SUPABASE_ANON_KEY, PROD_SMOKE_EMAIL, PROD_SMOKE_PASSWORD를 재사용한다. 설정이 빠지면 필수 실행이 실패한다. 공급자 페이지 트레이스, 스크린샷, 비디오, 아티팩트 업로드는 계속 비활성 상태다. 증거에는 정제된 오리진, 경로, 요청 계약 불리언, 어서션 결과만 담긴다.
Green은 "Kakao가 유효한 성공 결과를 반환하면 Barbelic이 그것을 유효한 API 및 PostgreSQL 접근을 갖춘 지속적인 인증 홈까지 끝까지 처리한다"는 조건문을 증명한다. 실행 중에 Kakao가 자격 증명이나 모바일 승인을 수락했음을 증명하지는 않는다. 릴리스 QA를 위해 별도로 감독되는 라이브 공급자 실행을 여전히 수행할 수 있으나, 이 결정론적 프로파일과 혼동해서는 안 된다.
다음 케이스 추가하기
- 다음 공용
CASE-###를 할당한다. ID를 재사용하거나 번호를 다시 매기지 않는다.error-cases/CASE-###-slug/를 만들고USER-JOURNEY.md,README.md,case.json,regression.spec.mjs를 넣는다. - 관측된 실패에는
incident-regression을, 수동으로 선정한 제품 여정에는expected-behavior를 고른다. 그다음 실제 경로 경계에 따라standard-full-stack,production-external-oauth,production-provider-assumed-success중 하나를 선언한다. 공급자 가정은 명시적이어야 하며 라이브 공급자 증거를 주장할 수 없다. USER-JOURNEY.md에는 사용자의 티어/인증/데이터/기기/시작 상태와Step 01부터Step n까지 순차적인 행을 기록한다. 모든 행은 사용자 행동, 기대되는 렌더링 결과, 기대되는 시스템/데이터베이스 결과를 명시해야 한다. 정확한 최종 결과는case.json.intendedOutcome과 일치해야 한다.- 완전한 실제 사용자 경로를 기록하고, 의도한 경험에 필요한 만큼 핵심 체크포인트를 정의한다. 모든 정확한 체크포인트 문자열을
case.json, README, 그리고 직접 어서션을 갖춘 이름 붙은test.step에 넣는다. - 체크포인트를 모든 완료 시그널에 매핑하고, 그 어서션을
caseContext.prove(signal, callback)을 통해 실행한다. 시그널은 그 콜백이 성공한 뒤에야 기록된다. - 렌더링된 UI를 통해 사용자의 실제 입력 순서를 재현하고 끝까지 완료한다. 프런트엔드 상태, 인증된 API/RPC 동작, 원시 데이터베이스 행, 새로고침/재진입, 최종 렌더링 출력을 어서션한다. 패치 존재 여부 확인과 주변부 확인은 이 결과들을 결코 대신할 수 없다.
caseContext.completeJourney(page, monitor)로 끝낸다. 이 호출은 모든 시그널을 요구하고, 치명적/렌더링된 에러, 예외, 콘솔 에러, 앱 에러 리포트, 관련 4xx/5xx 및 네트워크 실패를 거부하며, 재조회로 정리를 검증하고, 개별 체크포인트가 성공했더라도 예기치 못한 문제가 나타나면 실패시킨다.- 장애의 경우에만, 패치 이전 애플리케이션을 대상으로 정확히 같은 여정을 실행하고, 원래 트리거에 도달해 선언된 제품 체크포인트에서 실패하는 잡을 보존한다. 기대 행동(expected-behavior) 케이스는 의도적으로 Red 증거를 생략한다.
npm run check:error-cases, 해당 브라우저 케이스 단독 실행,npm run check,npm run build를 실행한 뒤,case.json에서 선택한 실행 프로파일이 요구하는 모든 환경에 대해 전부 Green인 증거를 보존한다.
목(mock) 전용, 컴포넌트 전용, 리포지토리 전용, 재조회 없는 저장, 축약된 여정은 여전히 유용한 보조 테스트지만, 그중 어떤 것도 번호가 매겨진 풀스택 행동 케이스를 닫을 수는 없다.