공개 release 발행 시 파일 본문 누출 검사(check-public-release-leakage)에 걸리던 내부 단서를 정리해 발행을 차단하지 않도록 함. - 코드/테스트 주석·문서 본문의 "" 규정 인용을 "코어 규정/규칙" 등 중립 표현으로 치환 (코어·이커머스·board·kginicis·gdpr·pay·템플릿 전 영역) - 내부 역할 호칭 ""/""를 문맥에 맞는 중립 표현으로 일반화 - config/app.php 의 보호경로 목록(G7_UPDATE_PROTECTED_PATHS) 내 파일명은 기능 코드이므로 삭제 대신 검사기 화이트리스트에 등록 주석/설명 문자열/문서 본문만 변경 — 로직·데이터·동작 무변경. 검증: 누출 재검사 error 0 / warn 0, 영향 테스트 TS 140/140·PHP 113/113 통과.
7.9 KiB
Playwright E2E (코어 영역)
G7 코어의 Playwright (TypeScript) 기반 결정론적 E2E 인프라.
빠른 시작
# PowerShell (개발 환경)
$env:PLAYWRIGHT_BASE_URL='https://g7.dev'
npm run test:e2e # 전체 spec
npm run test:e2e:smoke # @smoke 태그 (homepage / login / admin-dashboard 3건)
npm run test:e2e:wysiwyg # 위지윅 매트릭스 90건 (Phase M)
npm run test:e2e:ui # Playwright UI 모드 (디버깅)
# Bash (CI/Linux)
PLAYWRIGHT_BASE_URL=https://g7.dev npx playwright test
Base URL 해석 우선순위 (하드코딩 회피)
playwright.config.ts 의 resolveBaseUrl() 가 다음 순서로 결정:
PLAYWRIGHT_BASE_URL환경변수 — CI / 명시적 오버라이드 (최우선).env의APP_URL— 단http://localhost류는 fallback 부적합 (Apache vhost 미경유)- 그 외 — 명시 에러 (의도적으로 base URL 을 지정하지 않으면 spec 미실행)
도메인이 가변(개발자/CI/운영 환경별 다름)이므로 fallback 하드코딩 금지.
디렉토리 구조
tests/Playwright/
├── fixtures/
│ └── auth.ts (Sanctum 토큰 발급 + addInitScript 주입)
├── specs/
│ ├── smoke/ (Phase 1 — 3건)
│ │ ├── homepage.spec.ts
│ │ ├── login.spec.ts
│ │ └── admin-dashboard.spec.ts
│ └── wysiwyg/ (Phase 2 — 90건, 위지윅 편집기 Phase M)
│ ├── auth-guard.spec.ts (12: access_outcome × user_permission)
│ ├── handler-suppression.spec.ts (6: suppressed_handler 축)
│ ├── anchor-intercept.spec.ts (45: anchor_kind × modifier_key)
│ └── url-template-param.spec.ts (27: url_template_param × anchor_kind)
├── .auth/ (gitignore — storageState 캐시)
└── README.md (본 문서)
코어/확장 분리 원칙
기존 PHPUnit / Vitest 와 동일 원칙. 모듈/플러그인/템플릿 E2E spec 을 코어 디렉토리에 작성 금지.
| 영역 | spec 위치 | config 위치 |
|---|---|---|
| 코어 | tests/Playwright/specs/ |
playwright.config.ts (루트) |
| 모듈 | modules/_bundled/{id}/tests/Playwright/specs/ |
모듈 자체 playwright.config.ts |
| 플러그인 | plugins/_bundled/{id}/tests/Playwright/specs/ |
플러그인 자체 |
| 템플릿 | templates/_bundled/{id}/tests/Playwright/specs/ |
템플릿 자체 |
확장이 자체 E2E spec 을 추가하는 sample skeleton 은
modules/_bundled/sirsoft-ecommerce/tests/Playwright/ 참조.
인증 가드 (PlaywrightIssueToken 3중 보안)
app/Console/Commands/PlaywrightIssueToken.php 는 다음 3중 가드를 강제한다:
- CLI 한정 —
php_sapi_name() === 'cli'(production 웹 요청에서 절대 도달 불가) G7_PLAYWRIGHT_BYPASS=1환경변수 옵트인 —.env영구 수정 불요, 인라인 부착만으로 활성화APP_DEBUG=trueinline override —production + debug=false환경에서도 토큰 발급 가능
호출은 fixtures/auth.ts 의 issueToken() 헬퍼가 자동으로 G7_PLAYWRIGHT_BYPASS=1 을 부착하므로
spec 작성자는 가드를 인지할 필요 없음.
import { issueToken, authenticatePage } from '../../fixtures/auth';
test('...', async ({ page }) => {
const token = issueToken('core.templates.layouts.edit');
await authenticatePage(page, token);
await page.goto('/admin/dashboard');
});
권한 식별자는 임의 string — 코어/모듈/플러그인 공통 API. Permission::firstOrCreate 가 자동 생성.
데이터 생성 위치 — 책임 분리 매트릭스
E2E spec 이 "특정 유저 + 특정 역할 + 특정 도메인 상황" 에서 동작하려면 백엔드 데이터 생성 코드가 필요하다. 그 코드는 데이터를 소유한 영역에 위치해야 한다 — 기존 Seeder/Factory 분리 원칙과 동일.
| 데이터 종류 | 책임 영역 | 위치 |
|---|---|---|
코어 권한 (core.*), 역할, 유저, Sanctum 토큰 |
코어 | app/Console/Commands/PlaywrightIssueToken.php |
모듈 권한 (sirsoft-ecommerce.*) |
모듈 (코어 커맨드의 --permissions= 임의 식별자) |
— |
| 모듈 도메인 데이터 (상품/카테고리/주문) | 모듈 | modules/_bundled/{id}/src/Console/Commands/PlaywrightSeed{id}.php |
| 플러그인 도메인 데이터 (결제 키 등) | 플러그인 | plugins/_bundled/{id}/src/Console/Commands/PlaywrightSeed{id}.php |
| 외부 의존 (토스 결제창 응답 등) | spec 안 mock | page.route('https://api.tosspayments.com/**', ...) |
핵심 원칙: 코어는 모듈 도메인을 모른다. 모듈 도메인 시드 커맨드를 코어에 두면 코어↔모듈 의존이 뒤집힘 (audit 룰 위반).
시나리오 매니페스트 ↔ spec 매핑
| YAML axis | spec 파일 | 케이스 |
|---|---|---|
tests/scenarios/wysiwyg-editor-access-guard.yaml cross_product[0] (access_outcome × user_permission) |
specs/wysiwyg/auth-guard.spec.ts |
12 |
동일 yaml cross_product[1] (anchor_kind × modifier_key) |
specs/wysiwyg/anchor-intercept.spec.ts |
45 |
동일 yaml cross_product[2] (suppressed_handler) |
specs/wysiwyg/handler-suppression.spec.ts |
6 |
동일 yaml cross_product[3] (url_template_param × anchor_kind) |
specs/wysiwyg/url-template-param.spec.ts |
27 |
각 spec 은 test.describe.parallel(axisName) 으로 묶고 matrix 배열로 매개변수화.
케이스 docblock 에 // @scenario k1=v1, k2=v2 / // @effects e1, e2 마킹.
외부 의존 시나리오 — mock-first 패턴 (결제 등)
토스페이먼츠 등 외부 도메인 결제 흐름은 결정론적 자동화에 mock-first 전략 필수.
// 토스 SDK 호출 가로채기 — 결제창 띄우지 않고 즉시 success callback URL 로 redirect
await page.route('https://js.tosspayments.com/**', route => route.fulfill({
contentType: 'application/javascript',
body: `
window.TossPayments = () => ({
requestPayment: async (method, params) => {
window.location.href = params.successUrl
+ '?paymentKey=test_pk_xxx&orderId=' + params.orderId + '&amount=' + params.amount;
}
});
`,
}));
// 토스 confirm API mock — 가맹점 측 callback 흐름 검증
await page.route('https://api.tosspayments.com/v1/payments/confirm', route => route.fulfill({
status: 200, contentType: 'application/json',
body: JSON.stringify({
paymentKey: 'test_pk_xxx', orderId: 'order_001', status: 'DONE',
method: '카드', totalAmount: 10000, approvedAt: new Date().toISOString(),
}),
}));
분기별(성공/실패/취소/금액 불일치/중복) 가맹점 측 처리(주문 상태 전환, 재고 차감, 알림 발송) 정확성 검증. 실 카드 결제 자동화는 권장하지 않음 — 수동 검증.
회귀 / Flaky 처리
retries: process.env.CI ? 2 : 0— CI 에서만 자동 retrytrace: 'retain-on-failure'— 실패 시 trace.zip 보존 (npx playwright show-trace ...)- 2주 내 2회 이상 fail =
@flaky태그 격리 + RCA
디버깅 워크플로우
# UI 모드 — 단계별 step 시각화
$env:PLAYWRIGHT_BASE_URL='https://g7.dev'; npm run test:e2e:ui
# 특정 spec 만 실행
PLAYWRIGHT_BASE_URL=https://g7.dev npx playwright test tests/Playwright/specs/wysiwyg/auth-guard.spec.ts
# trace 열기
npx playwright show-trace test-results/<...>/trace.zip
Playwright 가 회귀를 발견하면 → Claude chrome-devtools-mcp 로 라이브 재현/진단 → spec 으로 승격.
참고
- 가이드:
docs/testing/e2e-testing.md - 시나리오 매니페스트:
tests/scenarios/wysiwyg-editor-access-guard.yaml - 단위 시뮬레이션 (Vitest):
resources/js/core/template-engine/wysiwyg/__tests__/previewNavigation.test.ts등 - 모듈 sample skeleton:
modules/_bundled/sirsoft-ecommerce/tests/Playwright/README.md