Skip to content

근태 현황 E2E iframe 트랙 (PR-E2) Implementation Plan ​

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: 근태 현황의 iframe 탭 2개(근무 현황·연장근무 현황) 내부를 E2E로 커버한다 — dual-origin 인증, iframe 내 결재 여정, postMessage 실배선(모달 dim).

Architecture: 스펙 §5.2 PR-E2. PR-E1 브랜치(test/attendance-e2e-native) 위에 스택 — openAttendanceTab·att-embed-* testid·tsconfig.e2e.json을 전제. dual-origin 인증은 스펙이 유보한 (a)/(b) 대신 더 단순한 방식으로 확정: global-setup이 한 브라우저 컨텍스트로 admin(:4001)과 tm(:4004)을 모두 방문해 두 origin의 토큰을 하나의 storageState(adminTmState.json)에 저장하고, 전용 project가 그것을 쓴다 (addInitScript 불필요 — storageState는 원래 multi-origin을 지원).

Tech Stack: Playwright frameLocator, 전제는 E1과 동일 (make dev + 시드 DB + 마이그레이션 최신, CI 범위 외).

Global Constraints ​

  • E1 계획의 Global Constraints를 그대로 상속 (러너/타입 게이트/딥링크 금지/init 레이스/날짜 헬퍼/README 등록/KI 무수정).
  • spec 파일명은 attendance-embed-*.spec.ts — admin- 접두를 쓰면 기존 admin project의 testMatch(/apps\/admin-.*\.spec\.ts/)에도 걸려 tm 토큰 없는 컨텍스트로 이중 실행된다. 신규 project의 testMatch는 /apps\/attendance-embed-.*\.spec\.ts/.
  • iframe 내부 조작은 page.frameLocator('[data-testid="att-embed-work|overtime"]') 경유. 어서션은 배선까지만 — 날짜 값·페이지 산수·라벨 문구는 PR-U 소관 (스펙 §5.2 E2-1 비고).
  • 검증 러너: pnpm --filter @hereby/test exec playwright test --project=attendance-embed.

File Structure ​

packages/test/
  playwright.config.ts                    Task 1  TM_BASE_URL + tm webServer + attendance-embed project
  e2e/global-setup.ts                     Task 1  dual-origin adminTmState.json 생성
  e2e/helpers/cross-app.ts                Task 3  getOvertimeStatus 래퍼
  e2e/tests/apps/attendance-embed-work.spec.ts      Task 4  E2-1
  e2e/tests/apps/attendance-embed-overtime.spec.ts  Task 5  E2-2
  e2e/tests/apps/attendance-embed-messaging.spec.ts Task 6  E2-3
  e2e/README.md                           Task 2  testid 레지스트리 갱신
apps/admin/src/views/dashboard.html       Task 2  att-embed-dim (tmModalOpen dim :44)
apps/team-manager/src/views/
  tabs/overview.html                      Task 2  att-work-row(+data-id)·preset·range·page
  tabs/work.html                          Task 2  att-work-kind-nav (부재 어서션용)
  tabs/overtime.html                      Task 2  att-ot-row(+data-id)·view·approve·reject·row-check·check-all
  modals/reject-reason.html               Task 2  tm-reject-reason / tm-reject-submit

스펙 대비 결정 (§5.2가 유보한 것): project 배정은 (a)(admin project 상속+토큰 보충)도 (b)(전용 project 자체 컨텍스트)도 아닌 (c) 전용 project + dual-origin storageState — global-setup 선례(managerState 등)와 같은 패턴이라 스펙 코드가 가장 적다. tm 뷰의 testid는 admin과 동일하게 근태 도메인 att- 접두(스펙 §5.3의 tm 대상 파일 목록 준수), 앱 공용 모달만 tm- 접두.


Task 0: 브랜치 (E1 위 스택) ​

  • [ ] git checkout test/attendance-e2e-native && git checkout -b test/attendance-e2e-embed
  • [ ] 이 계획 문서 커밋
  • [ ] 주의(메모리): 스택 PR은 E1 머지 후 base를 develop로 전환하고, 최종 머지 후 git merge-base --is-ancestor 로 develop 도달을 검증한다

Task 1: dual-origin 인프라 ​

Files: playwright.config.ts, e2e/global-setup.ts

  • [ ] config: TEAM_MANAGER_PORT/TM_BASE_URL const 추가, webServer에 tm(:4004) 항목(admin과 동일 형식), projects에 추가:
ts
    {
      // 근태 현황 iframe(tm :4004) 스펙 — admin 페이지를 열지만 iframe이 tm 토큰을 요구해
      // dual-origin storageState(adminTmState.json, global-setup 생성)를 쓴다.
      name: "attendance-embed",
      testMatch: /apps\/attendance-embed-.*\.spec\.ts/,
      use: {
        ...devices["Desktop Chrome"],
        baseURL: ADMIN_BASE_URL,
        storageState: "e2e/playwright/adminTmState.json",
      },
    },
  • [ ] global-setup: loginAndStash와 나란히 dual-origin 버전 추가 — 한 컨텍스트로 admin 방문+토큰 주입 → tm 방문+토큰 주입 → context.storageState({ path: ADMIN_TM_STATE_PATH }) (multi-origin 저장). admin 스테이트 생성 직후 호출.
  • [ ] 검증: tsc 게이트 + --list로 기존 project 수집 불변 확인 → Commit

Task 2: testid 부여 (tm 뷰 + admin dim) & README 등록 ​

  • [ ] admin dashboard.html:44 dim div → data-testid="att-embed-dim"
  • [ ] tm overview.html: 행 <tr>(:72, x-for="row in dashAttRows") → data-testid="att-work-row" :data-id="row.id"; 프리셋 this-month 버튼(:46) → att-work-preset-this-month; "N-M" span(pageItemRange) → att-work-range; 페이지 번호 버튼(:101 template) → :data-testid="'att-work-page-' + p"
  • [ ] tm work.html:11 세그먼트 nav → data-testid="att-work-kind-nav" (noOffsite에서 부재 어서션용)
  • [ ] tm overtime.html: 행 <tr>(:119) → att-ot-row + :data-id="item.id"; 보기(:144) → att-ot-view; 상세 모달 반려(:317) → att-ot-reject, 승인(:319) → att-ot-approve; 행 체크박스 → att-ot-row-check, 헤더 체크박스 → att-ot-check-all
  • [ ] tm modals/reject-reason.html: textarea(:22) → tm-reject-reason, 확인(:30 submitReject()) → tm-reject-submit
  • [ ] README data-testid additions에 att-work-*/att-ot-*/tm-reject-*/att-embed-dim 등록 → 빌드(components 불필요, admin+tm) → Commit

Task 3: 시드 래퍼 ​

  • [ ] cross-app.ts에 getOvertimeStatus(token, id) — overtime.get(입력 형태는 bare uuid 우선, 400이면 { id }로 교정) → tsc → Commit (기존 submitOvertimeRequest 재사용)

Task 4: E2-1 — 근무 현황 iframe 배선 (attendance-embed-work.spec.ts) ​

  • [ ] openAttendanceTab(page, "work") → frameLocator('[data-testid="att-embed-work"]')
  • [ ] 어서션: 출퇴근 테이블 헤더 렌더 → 프리셋(this-month) 클릭 → attendance.list 응답 대기(재조회 배선) → att-work-range 표기 존재. totalPages>1일 때만 페이지 2 클릭 → 행 목록 교체 확인 (조건부 — 시드 DB 데이터량 의존이라 무조건 어서션 금지)
  • [ ] 실행 green → Commit

Task 5: E2-2 — 연장근무 결재 모드 + 승인/반려 (attendance-embed-overtime.spec.ts) ​

  • [ ] 시드: submitOvertimeRequest 2건 (승인용/반려용 — workDate 어제, 어제 날짜는 기존 관례)
  • [ ] openAttendanceTab(page, "overtime") → frameLocator(att-embed-overtime)
  • [ ] 결재 모드 확정 어서션 (스펙 §3.1 — mode 파라미터가 "수정"되면 깨져 의도 재확인 강제): 시드 행의 att-ot-row-check 존재(체크박스=결재 UI) + att-work-kind-nav 부재(noOffsite로 외근 세그먼트 숨김)
  • [ ] 승인: 행(data-id) → att-ot-view → att-ot-approve → getOvertimeStatus poll "approved"
  • [ ] 반려: 행 → att-ot-view → att-ot-reject → tm-reject-submit 비활성(사유 필수) → tm-reject-reason 입력 → submit → poll "rejected"
  • [ ] 실행 green → Commit

Task 6: E2-3 — postMessage 실배선 (attendance-embed-messaging.spec.ts) ​

  • [ ] openAttendanceTab(page, "overtime") → iframe에서 시드 행 보기 모달 열기 → 부모(admin) 문서의 att-embed-dim visible (hereby™️modal cross-frame 실검증 — 단위에서 커버 불가했던 tm 송신부)
  • [ ] 모달 닫기(iframe 내 닫기 버튼) → dim hidden
  • [ ] 실행 green → Commit

Task 7 (선택): E2-4 — SECOM 지문 여정 ​

  • [ ] secomEvent.ingestEvents 시드(정상 페어+자정 넘김) → processPending → admin 직원별 근태 모달에서 지문 툴팁/! 경고 렌더. 대상 직원 attendanceMethod="secom" 시드 보강 필요 — 시드 보강이 과대해지면 사유와 함께 보류하고 PR 본문에 기록

Task 8: 게이트 + PR ​

  • [ ] --project=attendance-embed + --project=admin + --project=employee-team-flow 전체 green (2회 연속 — 병렬 결정성)
  • [ ] tsc 게이트 + pnpm build green
  • [ ] Push + PR (base: test/attendance-e2e-native — E1 머지 후 develop로 전환). 본문은 무엇을/왜/어떻게/리뷰 포인트 구조(한글 풀어쓰기)

Self-Review ​

  • 스펙 §5.2 커버: 선행 인프라(tm webServer+dual-origin)→Task 1, project 배정 명시 결정→(c) 채택 기록, E2-1→4, E2-2→5, E2-3→6, E2-4→7(선택). §5.3 tm 대상 파일 testid→Task 2.
  • 관찰-확정 항목: overtime.get 입력 형태(Task 3에 분기 명시), E2-1 페이지네이션(데이터량 조건부).