Files
Gnuboard7/modules/_bundled/sirsoft-ecommerce/tests/Playwright
HeuJung b505ac7ba7 fix(core,board,ecommerce,page,gdpr): 목록 컨텍스트 왕복·엔진 렌더 파이프 결함 일괄 수정 + 공개문서 정리
세 갈래의 결함을 한 브랜치에서 정리한다.

## 목록 컨텍스트 왕복 시 URL 상태 소실 ( @jiwonpapa 님께서 제보해주셨습니다.)

목록에서 상세·형제 상세(이전/다음)·작성/수정 폼에 다녀오면 보고 있던
page/search/category/filters 가 사라지던 문제를 전 도메인에서 수정했다.

- 엔진(engine-v1.54.2): `mergeQuery: true` 만 적고 `query` 를 생략하면 병합이
 통째로 건너뛰어지던 함정을 교정 — `ActionDispatcher.handleNavigate`/`handleReplaceUrl`.
- 게시판·이커머스·페이지·회원·마이페이지·gdpr 등 9개 확장 레이아웃의 왕복 leg 전수
 적용(mergeQuery: true). 의도적 리셋(검색/필터 초기화·탭 전환·프리셋)은 면제 주석으로 구분.
- 무한스크롤 목록(브랜드·상품 공통정보·고시정보)의 새로고침이 URL 검색·정렬을 떨구던
 결함 수정.
- 재발 차단: audit 룰 `layout-list-context-navigate-merge-query`(목록 클러스터 자동 도출,
 page/필터 URL 신호 4종) + `layout-navigate-path-absolute`(navigate path 동작 키워드 금지).

## cellChildren 등 반복 렌더에서 단일 바인딩 파이프 미적용 ( @glitter-gim 님께서 제보해주셨습니다.)

목록 표의 각 칸에 넣은 날짜·숫자 서식(`{{row.x | datetime(...)}}`)이 빈 값이 되거나
서식 없는 원본으로 나오던 문제를, 표현식 판정 로직이 엔진 전역에 복제되며 갈라진
구조적 결함으로 진단하고 판정 경로를 단일화했다(engine-v1.54.3).

- `RenderHelpers`(renderItemChildren·evaluateIfCondition)·`ConditionEvaluator`·
 `DataBindingEngine.resolveObject`·`DynamicRenderer` props 5곳에 단일 바인딩 파이프 분기 추가.
- 계획: `g7-scalable-lobster.md`(렌더 경로 비대칭 결함 일괄 수정).

## 공개 문서 내부 도구 귀속 제거

release 에 포함되는 공개 문서(`docs/**`)에서 내부 audit 룰 ID 귀속 서술을
도구 비귀속 표현("정적 검사")으로 정리. 재발 차단 룰 `public-no-internal-audit-reference` 신설.

전 계층 테스트(PHPUnit·Vitest·Playwright)·회귀 테스트 동반, 버전/CHANGELOG/활성 디렉토리 동기 완료.
2026-07-26 15:17:56 +09:00
..

이커머스 모듈 Playwright E2E (sample skeleton)

본 디렉토리는 이커머스 모듈이 자체 E2E spec 을 추가하기 위한 sample skeleton 이다. 현재 모든 spec 은 test.skip 으로 비활성화 되어 있으며, 모듈 작업 세션에서 활성화한다.

디렉토리 구조

modules/_bundled/sirsoft-ecommerce/
├── src/Console/Commands/
│   └── PlaywrightSeedEcommerce.php       (도메인 시드 커맨드 — stub, LogicException)
└── tests/Playwright/
    ├── playwright.config.ts              (모듈 자체 config — testDir=./specs)
    ├── fixtures/
    │   ├── ecommerce-auth.ts             (모듈 권한 토큰 fixture)
    │   └── ecommerce-seed.ts             (도메인 시드 fixture)
    ├── specs/
    │   └── admin/
    │       └── ecommerce-settings-menu.spec.ts  (placeholder — test.skip)
    └── README.md                         (본 문서)

데이터 생성 위치 분리 (CRITICAL)

E2E spec 이 "특정 유저 + 특정 역할 + 특정 도메인 상황" 에서 동작하려면 백엔드 데이터 생성 코드가 필요하다. 그 코드는 데이터를 소유한 영역에 위치해야 한다 — 기존 G7 의 Seeder/Factory 분리 원칙과 동일.

데이터 종류 위치
코어 권한 (core.*), 역할, 유저, Sanctum 토큰 코어 app/Console/Commands/PlaywrightIssueToken.php
모듈 권한 (sirsoft-ecommerce.*) 코어 커맨드의 --permissions= 임의 식별자 (Permission::firstOrCreate 자동 생성)
모듈 도메인 데이터 (상품/카테고리/주문/배송지) 본 모듈 src/Console/Commands/PlaywrightSeedEcommerce.php
외부 의존 데이터 (토스 결제창 응답 등) spec 안에서 page.route() mock

핵심 원칙: 코어는 모듈 도메인을 모른다. 모듈 도메인 시드 커맨드를 코어에 두면 코어 ↔ 모듈 의존이 뒤집힘.

활성화 절차

1. PlaywrightSeedEcommerce 본문 구현

src/Console/Commands/PlaywrightSeedEcommerce.php 의 throw new \LogicException(...) 부분을 실제 시드 로직으로 교체:

$categoryIds = Category::factory()->count((int) $this->option('categories'))->create()->pluck('id')->toArray();
$productIds = Product::factory()
    ->count((int) $this->option('products'))
    ->state(fn () => ['category_id' => $categoryIds[array_rand($categoryIds)]])
    ->create()
    ->pluck('id')
    ->toArray();
$orderIds = Order::factory()->count((int) $this->option('orders'))->create()->pluck('id')->toArray();

$payload = ['productIds' => $productIds, 'categoryIds' => $categoryIds, 'orderIds' => $orderIds];

if ($this->option('json')) {
    $this->line(json_encode($payload));
} else {
    $this->info(sprintf('시드 완료 — products:%d, categories:%d, orders:%d', count($productIds), count($categoryIds), count($orderIds)));
}

return self::SUCCESS;

2. 사전 testid 보강

templates/sirsoft-admin_basic 사이드바 메뉴 컴포넌트:

<a data-testid="admin-menu-ecommerce-settings" href="/admin/ecommerce/settings">...</a>

이커머스 환경설정 폼 컴포넌트:

<form data-testid="ecommerce-settings-form">...</form>

3. spec 의 test.skip 제거

specs/admin/ecommerce-settings-menu.spec.ts 의 test.describe.skip(...) → test.describe(...).

4. 모듈 자체 실행

cd modules/_bundled/sirsoft-ecommerce
$env:PLAYWRIGHT_BASE_URL='https://g7.dev'
npx playwright test

또는 모듈 package.json 에 script 추가:

"test:e2e": "playwright test --config=tests/Playwright/playwright.config.ts"

토스페이먼츠 결제 spec (외부 의존 시나리오)

토스페이먼츠 플러그인 결제 흐름은 외부 도메인(js.tosspayments.com) 의존 — 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(),
  }),
}));

분기별 가맹점 측 처리(주문 상태 전환, 재고 차감, 알림 발송 등) 가 정확한지 검증. 실 카드 결제 자동화는 권장하지 않음 — 수동 검증.

참고

  • 코어 가이드: tests/Playwright/README.md
  • 시나리오 매니페스트 매핑: tests/scenarios/*.yaml ↔ spec describe.parallel + matrix 배열
  • 코어 fixture: tests/Playwright/fixtures/auth.ts (issueToken, authenticatePage)