{ "id": "approval-box", "name": "결재함 E2E 테스트", "screenshotPolicy": { "onErrorOnly": true, "captureOn": ["error", "fail", "timeout", "404", "500", "blocked"] }, "description": "결재함 페이지의 전체 기능을 검증합니다 (탭 전환, 검색, 필터, 승인/반려, 모달)", "baseUrl": "https://dev.codebridge-x.com", "menuNavigation": { "level1": "결재관리", "level2": "결재함", "expectedUrl": "/ko/approval/inbox", "searchWithinParent": true, "closeOtherMenus": true }, "auth": { "username": "TestUser5", "password": "password123!" }, "navigation": { "targetUrl": "/approval/inbox", "urlPattern": "/approval/inbox|/ko/approval/inbox", "menuHints": ["결재함", "결재 함", "결재관리"] }, "menuNavigationEnhanced": { "strategy": "scroll-and-search", "description": "사이드바를 스크롤하며 메뉴를 찾고 클릭하여 404를 방지", "level1": "결재관리", "level2": "결재함", "alternativeLevel2Names": ["결재함", "결재 함", "승인함", "Approval Box", "inbox"], "fallbackUrls": [ "/ko/approval/inbox", "/ko/approval/box", "/ko/approvals/inbox", "/ko/approval-management/inbox", "/approval/inbox" ], "scrollConfig": { "sidebarSelector": "nav, aside, [role='navigation'], .sidebar, #sidebar", "menuItemSelector": "a, button, [role='menuitem'], [role='treeitem']", "scrollStep": 200, "maxScrollAttempts": 10, "scrollDelay": 300 } }, "steps": [ { "id": 0, "name": "사이드바 메뉴 전체 펼치기", "description": "모두 펼치기 버튼을 클릭하여 전체 메뉴를 펼친 후 메뉴 탐색 준비", "actions": [ { "type": "scroll", "target": "sidebar", "direction": "top", "description": "사이드바 최상단으로 스크롤" }, { "type": "wait", "duration": 300 }, { "type": "evaluate", "script": "Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click()" }, { "type": "wait", "duration": 2000 } ], "verification": [ "사이드바가 화면에 보이는지 확인", "모든 메뉴가 펼쳐졌는지 확인" ] }, { "id": 1, "name": "1차 메뉴 찾기: 결재관리 (스크롤 포함)", "description": "사이드바를 스크롤하며 '결재관리' 메뉴를 찾아 클릭", "actions": [ { "type": "scrollAndFind", "target": "결재관리", "alternativeTexts": ["결재관리", "결재 관리", "Approval", "전자결재"], "scrollContainer": "sidebar", "maxAttempts": 10, "description": "스크롤하며 결재관리 메뉴 찾기" }, { "type": "wait", "duration": 300 }, { "type": "click", "target": "결재관리", "description": "결재관리 메뉴 클릭" }, { "type": "wait", "duration": 500, "description": "서브메뉴 펼쳐지기 대기" }, { "type": "screenshot", "name": "approval_menu_expanded" } ], "verification": [ "결재관리 메뉴가 클릭되었는지 확인", "서브메뉴가 펼쳐졌는지 확인", "하위 메뉴 항목들이 보이는지 확인" ], "fallback": { "if": "메뉴를 찾을 수 없음", "then": "사이드바 전체를 스크롤하며 재탐색" } }, { "id": 2, "name": "2차 메뉴 찾기: 결재함 (스크롤 포함)", "description": "서브메뉴에서 '결재함'을 찾아 클릭", "actions": [ { "type": "scrollAndFind", "target": "결재함", "alternativeTexts": ["결재함", "결재 함", "Inbox", "승인함"], "scrollContainer": "submenu", "maxAttempts": 5, "description": "서브메뉴에서 결재함 찾기" }, { "type": "wait", "duration": 200 }, { "type": "click", "target": "결재함", "description": "결재함 메뉴 클릭" }, { "type": "wait", "target": "페이지 로드 완료", "timeout": 10000 }, { "type": "screenshot", "name": "approval_box_page" } ], "verification": [ "결재함 메뉴 클릭 성공", "페이지 이동 또는 컨텐츠 로드" ] }, { "id": 3, "name": "404 에러 감지 및 대체 경로 시도", "description": "페이지 로드 후 404 에러 여부 확인, 404시 대체 경로 탐색", "actions": [ { "type": "wait", "duration": 1000 }, { "type": "checkFor404", "indicators": [ "페이지를 찾을 수 없습니다", "404", "Not Found", "존재하지 않거나" ]}, { "type": "screenshot", "name": "page_load_result" } ], "verification": [ "현재 페이지가 404인지 확인" ], "onError404": { "description": "404 에러 발생 시 대체 URL 시도", "actions": [ { "type": "log", "message": "404 감지 - 대체 경로 탐색 시작" }, { "type": "tryAlternativeUrls", "urls": [ "/ko/approval/inbox", "/ko/approvals/inbox", "/ko/approval-box" ], "stopOnSuccess": true }, { "type": "ifStillFailed", "action": "navigateViaMenuClick", "description": "URL 직접 접근 실패 시 메뉴 클릭으로 재시도" } ] } }, { "id": 4, "name": "페이지 정상 로드 확인", "description": "결재함 페이지가 정상적으로 로드되었는지 확인", "actions": [ { "type": "verify", "target": "pageTitle", "contains": ["결재함", "결재", "Approval"] }, { "type": "verify", "target": "pageContent", "notContains": ["404", "찾을 수 없습니다", "Not Found"] } ], "verification": [ "페이지 제목 '결재함' 또는 관련 텍스트 표시", "404 에러 메시지 미표시", "콘텐츠가 정상 렌더링됨" ], "successCriteria": { "urlPattern": "/approval", "requiredElements": ["결재", "문서", "승인"] } }, { "id": 5, "name": "통계 카드 확인", "action": "현황 카드의 데이터 수집", "verification": [ "전체결재 건수 기록", "미결재 건수 기록", "결재완료 건수 기록", "결재반려 건수 기록" ] }, { "id": 6, "name": "탭 구조 확인", "action": "4개 탭 존재 여부 확인", "verification": [ "'전체결재' 탭 존재 확인", "'미결재' 탭 존재 확인", "'결재완료' 탭 존재 확인", "'결재반려' 탭 존재 확인" ] }, { "id": 7, "name": "테이블 데이터 확인", "action": "테이블에 데이터가 표시되는지 확인", "verification": [ "테이블 헤더 컬럼 확인", "데이터 행 존재 여부 확인", "페이지네이션 표시 확인" ] }, { "id": 8, "name": "⚠️ 필수 검증: 결재 문서 상세 보기", "description": "테이블에서 결재 문서 클릭하여 상세 모달/페이지 확인", "critical": true, "actions": [ { "type": "click", "target": "미결재 탭", "description": "미결재 탭으로 이동" }, { "type": "wait", "duration": 500 }, { "type": "click", "target": "첫 번째 결재 문서 행", "description": "결재 문서 클릭" }, { "type": "wait", "target": "상세 모달 또는 페이지" } ], "expect": { "detailView": true, "fields": ["문서 제목", "기안자", "기안일", "결재 상태"], "buttons": ["승인", "반려", "PDF", "인쇄"] }, "note": "결재 문서가 없으면 데이터 생성 또는 SKIP" }, { "id": "8-pdf-1", "name": "⚠️ 필수 검증: PDF 다운로드 전 모달 스크린샷", "critical": true, "description": "PDF 생성 전 모달 상태를 스크린샷으로 캡처하여 CSS 문제 감지용 기준 이미지 확보", "prerequisite": "step-8의 문서 상세 모달이 열려있는 상태에서 실행", "actions": [ { "type": "screenshot", "name": "pdf-preview-before-download-approval-box", "fullPage": false, "selector": "[role='dialog'], .modal, [data-state='open']", "savePath": "tests/e2e/results/hotfix/screenshots/", "description": "PDF 생성 대상 모달 전체 캡처" } ], "verify": { "screenshotCaptured": true, "purpose": "PDF CSS 문제 감지를 위한 기준 이미지" } }, { "id": "8-pdf-2", "name": "⚠️ 필수 검증: PDF 다운로드 실행 및 파일 보관", "critical": true, "description": "PDF 다운로드 후 파일을 지정 폴더에 보관하여 수동 검증 가능하게 함", "actions": [ { "type": "verify", "target": "PDF 버튼 존재", "selector": "button:has-text('PDF'), [aria-label*='PDF']", "description": "PDF 다운로드 버튼 존재 확인" }, { "type": "expectResponse", "id": "pdf-download-response-approval-box", "urlPattern": "/api/v1/approvals/*/pdf", "description": "PDF 다운로드 API 응답 대기 설정" }, { "type": "click", "target": "PDF 버튼", "selector": "button:has-text('PDF')", "description": "PDF 다운로드 버튼 클릭" }, { "type": "wait", "duration": 3000, "description": "PDF 생성 및 다운로드 대기" }, { "type": "assertResponse", "id": "pdf-download-response-approval-box", "checks": { "status": 200, "contentType": "application/pdf" } }, { "type": "saveDownloadedFile", "targetPath": "tests/e2e/results/hotfix/pdf-samples/", "fileNamePattern": "approval-box-{timestamp}.pdf", "description": "다운로드된 PDF 파일을 지정 폴더에 보관" } ], "verify": { "apiSuccess": true, "fileDownloaded": true, "fileSaved": "tests/e2e/results/hotfix/pdf-samples/" } }, { "id": "8-pdf-3", "name": "⚠️ PDF 파일 유효성 검증", "critical": true, "description": "다운로드된 PDF 파일의 기본 유효성 검사", "actions": [ { "type": "verifyDownloadedFile", "checks": { "fileExists": true, "fileSize": "> 1024", "pdfSignature": "%PDF-", "description": "PDF 파일 헤더 검증" } } ], "verify": { "pdfValid": true, "minFileSize": "1KB 이상" } }, { "id": "8-pdf-4", "name": "📋 PDF 스타일 수동 확인 체크리스트", "type": "manualVerification", "critical": true, "description": "개발자가 다운로드된 PDF를 열어 시각적으로 확인해야 하는 항목", "manualChecklist": [ {"id": "css-1", "item": "테이블 경계선이 올바르게 표시되는가?", "category": "테이블 스타일"}, {"id": "css-2", "item": "한글 폰트가 깨지지 않고 정상 표시되는가?", "category": "폰트"}, {"id": "css-3", "item": "숫자/금액 정렬이 올바른가? (우측 정렬)", "category": "정렬"}, {"id": "css-4", "item": "여백(margin/padding)이 적절한가?", "category": "레이아웃"}, {"id": "css-5", "item": "헤더/푸터가 각 페이지에 올바르게 표시되는가?", "category": "페이지 구조"}, {"id": "css-6", "item": "로고/이미지가 정상 표시되는가?", "category": "이미지"}, {"id": "css-7", "item": "페이지 나눔(page break)이 적절한 위치에서 발생하는가?", "category": "페이지 나눔"}, {"id": "css-8", "item": "배경색/강조색이 올바르게 적용되었는가?", "category": "색상"}, {"id": "css-9", "item": "텍스트가 잘리거나 겹치지 않는가?", "category": "오버플로우"}, {"id": "css-10", "item": "결재선 정보가 정상적으로 표시되는가?", "category": "결재선"} ], "outputFiles": { "screenshot": "tests/e2e/results/hotfix/screenshots/pdf-preview-before-download-approval-box-*.png", "pdfFile": "tests/e2e/results/hotfix/pdf-samples/approval-box-*.pdf" }, "reportFlag": { "requiresManualReview": true, "message": "⚠️ PDF 스타일 수동 확인 필요 - 위 체크리스트 항목을 PDF 파일에서 직접 확인하세요" } }, { "id": 9, "name": "⚠️ 필수 검증 #4: 결재 승인 실제 수행", "description": "미결재 문서에 대해 실제 승인 처리 수행", "critical": true, "actions": [ { "type": "verify", "target": "승인 버튼 존재" }, { "type": "click", "target": "승인 버튼", "description": "결재 승인 클릭" }, { "type": "wait", "target": "확인 다이얼로그" }, { "type": "click", "target": "확인", "description": "승인 확인" } ], "expect": { "urlMaintained": true, "noErrorPage": true, "apiCall": "POST /api/v1/approvals/{id}/approve", "toast": "승인되었습니다", "statusChange": "미결재 → 결재완료" }, "note": "⚠️ 버튼 존재만 확인하면 불완전! 실제 승인까지 검증 필수!" }, { "id": "9-1", "name": "결재 승인 결과 확인", "description": "승인 후 결재완료 탭에서 해당 문서 확인", "actions": [ { "type": "click", "target": "결재완료 탭" }, { "type": "wait", "duration": 500 } ], "verify": { "documentMoved": "승인한 문서가 결재완료 탭에 표시", "statusUpdated": "결재 상태가 '완료'로 변경" } }, { "id": 10, "name": "⚠️ 필수 검증 #4: 결재 반려 실제 수행", "description": "미결재 문서에 대해 실제 반려 처리 수행", "critical": true, "actions": [ { "type": "click", "target": "미결재 탭", "description": "미결재 탭으로 이동" }, { "type": "wait", "duration": 500 }, { "type": "click", "target": "결재 문서 행", "description": "결재 문서 선택" }, { "type": "wait", "target": "상세 보기" }, { "type": "click", "target": "반려 버튼", "description": "결재 반려 클릭" }, { "type": "wait", "target": "반려 사유 입력 모달" }, { "type": "type", "target": "반려 사유", "value": "E2E 테스트 반려 사유" }, { "type": "click", "target": "확인", "description": "반려 확인" } ], "expect": { "urlMaintained": true, "noErrorPage": true, "apiCall": "POST /api/v1/approvals/{id}/reject", "toast": "반려되었습니다", "statusChange": "미결재 → 결재반려" }, "note": "⚠️ 반려 버튼 존재만 확인하면 불완전! 실제 반려까지 검증 필수!" }, { "id": "10-1", "name": "결재 반려 결과 확인", "description": "반려 후 결재반려 탭에서 해당 문서 확인", "actions": [ { "type": "click", "target": "결재반려 탭" }, { "type": "wait", "duration": 500 } ], "verify": { "documentMoved": "반려한 문서가 결재반려 탭에 표시", "statusUpdated": "결재 상태가 '반려'로 변경", "rejectReason": "반려 사유가 표시" } }, { "id": 11, "name": "검색 기능 테스트", "description": "검색 필터로 결재 문서 검색", "actions": [ { "type": "click", "target": "전체결재 탭" }, { "type": "type", "target": "검색 입력창", "value": "테스트" }, { "type": "click", "target": "검색 버튼" } ], "verify": { "searchApplied": true, "filteredResults": "검색어에 맞는 결과 표시" } } ], "mandatoryVerifications": { "description": "E2E_TEST_CONFIG.md 기준 필수 검증 항목", "items": [ { "id": 4, "name": "결재 승인/반려 완료", "trigger": "결재 문서 상세의 승인/반려 버튼", "verification": "실제 승인/반려 동작 + API 호출 + 결과 확인", "failCondition": "버튼 존재만 확인, 클릭하지 않음", "steps": ["9", "10"] } ] }, "expectedAPIs": [ "GET /api/v1/approvals/inbox - 결재함 목록 조회", "GET /api/v1/approvals/inbox/summary - 결재함 통계", "GET /api/v1/approvals/{id} - 결재 문서 상세 조회", "POST /api/v1/approvals/{id}/approve - 결재 승인", "POST /api/v1/approvals/{id}/reject - 결재 반려" ], "notes": [ "⚠️ 404 방지: 반드시 메뉴 클릭으로 페이지 진입 (직접 URL 접근 금지)", "⚠️ 스크롤 필수: 사이드바가 길 경우 메뉴가 화면 밖에 있을 수 있음", "⚠️ 대체 경로: 메뉴명이 변경되었을 수 있으므로 다양한 이름으로 탐색", "메뉴 계층: 결재관리 > 결재함", "탭 전환 시 URL 변경 없이 데이터만 필터링됨" ] }