{ "id": "reference-box", "name": "참조함 E2E 테스트", "screenshotPolicy": { "onErrorOnly": true, "captureOn": ["error", "fail", "timeout", "404", "500", "blocked"] }, "description": "참조함 페이지의 모든 기능 검증 (탭 전환, 검색, 필터, 정렬, 열람/미열람 처리, 문서 상세)", "baseUrl": "https://dev.codebridge-x.com", "navigation": { "targetUrl": "/approval/reference", "urlPattern": "/approval/reference|/ko/approval/reference", "menuHints": ["참조함", "참조 함", "결재관리"] }, "menuNavigation": { "level1": "결재관리", "level2": "참조함", "expectedUrl": "/ko/approval/reference", "searchWithinParent": true, "closeOtherMenus": true }, "auth": { "username": "TestUser5", "password": "password123!" }, "menuNavigationEnhanced": { "strategy": "scroll-and-search", "description": "사이드바를 스크롤하며 메뉴를 찾고 클릭하여 404를 방지", "level1": "결재관리", "level2": "참조함", "alternativeLevel1Names": ["결재관리", "결재 관리", "Approval", "전자결재"], "alternativeLevel2Names": ["참조함", "참조 함", "Reference", "참조문서", "CC문서"], "scrollConfig": { "sidebarSelector": "nav, aside, [role='navigation'], .sidebar, #sidebar", "menuItemSelector": "a, button, [role='menuitem'], [role='treeitem']", "scrollStep": 200, "maxScrollAttempts": 10, "scrollDelay": 300 } }, "expectedAPIs": [ { "method": "GET", "endpoint": "/api/v1/approvals/reference", "description": "참조함 목록 조회", "queryParams": ["page", "per_page", "search", "is_read", "approval_type", "sort_by", "sort_dir"] }, { "method": "POST", "endpoint": "/api/v1/approvals/{id}/read", "description": "열람 처리" }, { "method": "POST", "endpoint": "/api/v1/approvals/{id}/unread", "description": "미열람 처리" } ], "steps": [ { "id": 0, "name": "사이드바 메뉴 전체 펼치기", "description": "모두 펼치기 버튼을 클릭하여 전체 메뉴를 펼친 후 메뉴 탐색 준비", "actions": [ { "type": "evaluate", "script": "document.querySelector('.sidebar-scroll')?.scrollTo({top:0,behavior:'instant'})" }, { "type": "wait", "duration": 300 }, { "type": "evaluate", "script": "Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click()" }, { "type": "wait", "duration": 2000 } ] }, { "id": 1, "name": "2단계 메뉴 진입: 결재관리 > 참조함", "description": "사이드바를 스크롤하며 결재관리 > 참조함 메뉴를 찾아 클릭", "actions": [ { "type": "scrollAndFind", "target": "결재관리", "alternativeTexts": ["결재관리", "결재 관리", "Approval", "전자결재"], "scrollContainer": "sidebar", "maxAttempts": 10, "description": "스크롤하며 결재관리 메뉴 찾기" }, { "type": "click", "target": "결재관리", "description": "결재관리 메뉴 클릭" }, { "type": "wait", "duration": 500, "description": "서브메뉴 펼쳐지기 대기" }, { "type": "scrollAndFind", "target": "참조함", "alternativeTexts": ["참조함", "참조 함", "Reference", "참조문서"], "scrollContainer": "submenu", "maxAttempts": 5, "description": "서브메뉴에서 참조함 찾기" }, { "type": "click", "target": "참조함", "description": "참조함 메뉴 클릭" }, { "type": "wait", "target": "페이지 로드 완료", "timeout": 10000 } ], "verification": [ "페이지 URL이 /approval/reference인지 확인", "페이지 제목 '참조함' 표시 확인", "설명 텍스트 '참조로 지정된 문서를 확인합니다.' 표시 확인", "통계 카드 3개 표시 (전체, 열람, 미열람)", "날짜 범위 선택기 표시 확인", "검색창 표시 확인 (placeholder: '제목, 기안자, 부서 검색...')", "탭 버튼 3개 표시 (전체, 열람, 미열람)", "필터 드롭다운 표시 (전체, 지출결의서, 품의서, 지출예상내역서)", "정렬 드롭다운 표시 (최신순, 오래된순, 기안일 오름차순, 기안일 내림차순)", "테이블 헤더 확인 (번호, 문서번호, 문서유형, 제목, 기안자, 기안일시, 상태)" ] }, { "id": 2, "name": "데이터 로딩 대기", "action": "3초 대기하여 API 데이터 로드 완료", "verification": [ "테이블에 데이터 행이 표시되는지 확인", "통계 카드에 숫자가 표시되는지 확인 (N건)", "'검색 결과가 없습니다' 메시지가 없는지 확인", "각 문서의 열람 상태 배지 표시 확인 (열람/미열람)" ] }, { "id": 3, "name": "통계 카드 데이터 확인", "action": "통계 카드의 숫자 확인", "verification": [ "전체 건수 = 열람 건수 + 미열람 건수", "각 카드의 아이콘 표시 확인 (Files, Eye, EyeOff)", "스크린샷 촬영하여 초기 상태 저장" ] }, { "id": 4, "name": "탭 전환 - 열람 탭", "action": "'열람' 탭 클릭", "verification": [ "탭 활성화 상태 변경 확인", "테이블에 '열람' 상태 문서만 표시", "모든 행의 상태 배지가 '열람'인지 확인", "표시된 문서 개수가 통계 카드의 '열람' 건수와 일치" ] }, { "id": 5, "name": "탭 전환 - 미열람 탭", "action": "'미열람' 탭 클릭", "verification": [ "탭 활성화 상태 변경 확인", "테이블에 '미열람' 상태 문서만 표시", "모든 행의 상태 배지가 '미열람'인지 확인", "표시된 문서 개수가 통계 카드의 '미열람' 건수와 일치" ] }, { "id": 6, "name": "탭 전환 - 전체 탭으로 복귀", "action": "'전체' 탭 클릭", "verification": [ "탭 활성화 상태 변경 확인", "테이블에 모든 문서 표시 (열람 + 미열람)", "표시된 문서 개수가 통계 카드의 '전체' 건수와 일치" ] }, { "id": 7, "name": "⚠️ 필수 검증: 검색 기능 - 기안자 검색", "actions": [ { "type": "capture", "variable": "beforeSearchCount", "selector": "table tbody tr", "extract": "count", "description": "검색 전 문서 수 저장" }, { "type": "fill", "target": "검색창", "value": "김철수", "description": "기안자 이름 검색" }, { "type": "wait", "duration": 1000, "description": "검색 결과 로딩 대기" }, { "type": "capture", "variable": "afterSearchCount", "selector": "table tbody tr", "extract": "count", "description": "검색 후 문서 수 저장" } ], "verify": { "searchApplied": true, "tableContains": "김철수", "dataChanged": "beforeSearchCount may differ from afterSearchCount" }, "verification": [ "검색창에 입력한 텍스트 표시 확인", "Enter 키 입력 또는 자동 검색 실행", "검색어를 포함한 문서만 필터링되어 표시", "검색 결과 건수 확인" ] }, { "id": "7-1", "name": "검색 결과 데이터 검증", "description": "검색 결과의 모든 행이 검색어를 포함하는지 확인", "verify": { "allRowsContain": "김철수", "columnToCheck": "기안자" } }, { "id": 8, "name": "검색 초기화", "actions": [ { "type": "clear", "target": "검색창" }, { "type": "wait", "duration": 500 }, { "type": "capture", "variable": "afterClearCount", "selector": "table tbody tr", "extract": "count" } ], "verify": { "dataRestored": "afterClearCount should equal beforeSearchCount" }, "verification": [ "전체 문서 목록 복원 확인", "원래 문서 개수로 복원" ] }, { "id": 9, "name": "필터 기능 - 문서유형 선택", "action": "필터 드롭다운에서 '품의서' 선택", "verification": [ "필터 드롭다운 값이 '품의서'로 변경", "테이블에 '품의서' 유형 문서만 표시", "모든 행의 문서유형 배지가 '품의서'인지 확인" ] }, { "id": 10, "name": "필터 초기화", "action": "필터 드롭다운에서 '전체' 선택", "verification": [ "전체 문서 목록 복원 확인" ] }, { "id": 11, "name": "정렬 기능 - 오래된순", "action": "정렬 드롭다운에서 '오래된순' 선택", "verification": [ "정렬 드롭다운 값이 '오래된순'으로 변경", "테이블 데이터가 오래된 날짜부터 표시", "기안일시 컬럼 확인하여 오름차순 정렬 검증" ] }, { "id": 12, "name": "정렬 초기화", "action": "정렬 드롭다운에서 '최신순' 선택", "verification": [ "테이블 데이터가 최신 날짜부터 표시" ] }, { "id": 13, "name": "체크박스 - 단일 선택", "action": "첫 번째 문서의 체크박스 클릭", "verification": [ "체크박스 선택 상태 확인", "'열람' 버튼 표시 확인", "'미열람' 버튼 표시 확인", "조건부 버튼이 헤더 영역에 표시됨" ] }, { "id": 14, "name": "체크박스 - 선택 해제", "action": "첫 번째 문서의 체크박스 다시 클릭", "verification": [ "체크박스 선택 해제 확인", "'열람' 및 '미열람' 버튼 사라짐 확인" ] }, { "id": 15, "name": "체크박스 - 다중 선택", "action": "첫 번째와 두 번째 문서의 체크박스 클릭", "verification": [ "2개 문서 선택 확인", "'열람' 및 '미열람' 버튼 표시 확인" ] }, { "id": 16, "name": "문서 상세 모달 - 열기", "action": "체크박스 선택 해제 후 문서 행 클릭 (체크박스 제외)", "verification": [ "문서 상세 모달 열림 확인", "⚠️ 필수 검증 #5: 목업 페이지 감지", "모달 제목 확인 (문서유형 + ' 상세')", "문서번호 표시 확인", "작성일자 표시 확인", "기안자 정보 표시 확인", "결재선 정보 표시 확인", "PDF/인쇄 버튼 존재 확인" ] }, { "id": "16-pdf-1", "name": "⚠️ 필수 검증: PDF 다운로드 전 모달 스크린샷", "description": "PDF 생성 전 모달 상태를 스크린샷으로 캡처하여 CSS 문제 감지용 기준 이미지 확보", "prerequisite": "step-16의 문서 상세 모달이 열려있는 상태에서 실행", "actions": [ { "type": "screenshot", "name": "pdf-preview-before-download-reference-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": "16-pdf-2", "name": "⚠️ 필수 검증: PDF 다운로드 실행 및 파일 보관", "description": "PDF 다운로드 후 파일을 지정 폴더에 보관하여 수동 검증 가능하게 함", "actions": [ { "type": "verify", "target": "PDF 버튼 존재", "selector": "button:has-text('PDF'), [aria-label*='PDF']", "description": "PDF 다운로드 버튼 존재 확인" }, { "type": "expectResponse", "id": "pdf-download-response-reference-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-reference-box", "checks": { "status": 200, "contentType": "application/pdf" } }, { "type": "saveDownloadedFile", "targetPath": "tests/e2e/results/hotfix/pdf-samples/", "fileNamePattern": "reference-box-{timestamp}.pdf", "description": "다운로드된 PDF 파일을 지정 폴더에 보관" } ], "verify": { "apiSuccess": true, "fileDownloaded": true, "fileSaved": "tests/e2e/results/hotfix/pdf-samples/" } }, { "id": "16-pdf-3", "name": "⚠️ PDF 파일 유효성 검증", "description": "다운로드된 PDF 파일의 기본 유효성 검사", "actions": [ { "type": "verifyDownloadedFile", "checks": { "fileExists": true, "fileSize": "> 1024", "pdfSignature": "%PDF-", "description": "PDF 파일 헤더 검증" } } ], "verify": { "pdfValid": true, "minFileSize": "1KB 이상" } }, { "id": "16-pdf-4", "name": "📋 PDF 스타일 수동 확인 체크리스트", "type": "manualVerification", "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-reference-box-*.png", "pdfFile": "tests/e2e/results/hotfix/pdf-samples/reference-box-*.pdf" }, "reportFlag": { "requiresManualReview": true, "message": "⚠️ PDF 스타일 수동 확인 필요 - 위 체크리스트 항목을 PDF 파일에서 직접 확인하세요" } }, { "id": 17, "name": "문서 상세 모달 - 닫기", "action": "모달 닫기 버튼 (X) 클릭", "verification": [ "모달 닫힘 확인", "원래 참조함 페이지로 복귀", "페이지 URL 유지 (/approval/reference)" ] }, { "id": 18, "name": "미열람 탭으로 이동", "action": "'미열람' 탭 클릭", "verification": [ "미열람 문서만 표시 확인", "모든 문서의 상태가 '미열람'" ] }, { "id": 19, "name": "열람 처리 - 문서 선택", "action": "미열람 탭에서 첫 번째 문서 체크박스 선택", "verification": [ "체크박스 선택 확인", "'열람' 버튼 표시 확인" ] }, { "id": 20, "name": "열람 처리 - 확인 다이얼로그", "action": "'열람' 버튼 클릭", "verification": [ "확인 다이얼로그 표시", "다이얼로그 제목: '열람 처리'", "다이얼로그 메시지: '정말 1건을 열람 처리하시겠습니까?'", "취소 버튼 표시", "확인 버튼 표시" ] }, { "id": 21, "name": "열람 처리 - URL 안정성 검증 (⚠️ 필수 검증 #2)", "action": "현재 URL 저장 후 '확인' 버튼 클릭", "verification": [ "⚠️ URL 변경 여부 확인 (변경되면 안됨)", "⚠️ 에러 페이지 텍스트 검색 ('페이지를 찾을 수 없습니다', '404', 'Not Found' 등)", "⚠️ 원래 페이지 요소 존재 확인 (테이블, 탭 등)", "성공 토스트 메시지 표시: '열람 처리 완료'", "토스트 설명: '열람 처리가 완료되었습니다.'", "다이얼로그 자동 닫힘", "체크박스 선택 해제", "미열람 탭의 문서 개수 1개 감소" ], "criticalCheck": { "type": "URL_STABILITY", "beforeURL": "/approval/reference", "afterURL": "/approval/reference", "errorPageTexts": ["페이지를 찾을 수 없습니다", "404", "Not Found", "서버 에러", "500"], "successToast": "열람 처리 완료" } }, { "id": 22, "name": "열람 처리 후 데이터 검증", "action": "테이블 및 통계 확인", "verification": [ "미열람 탭에서 처리된 문서 제거 확인", "통계 카드의 '미열람' 건수 1개 감소 (실시간 업데이트)", "통계 카드의 '열람' 건수 1개 증가 (실시간 업데이트)" ] }, { "id": 23, "name": "열람 탭으로 이동하여 검증", "action": "'열람' 탭 클릭", "verification": [ "열람 탭에 방금 처리한 문서 표시 확인", "해당 문서의 상태 배지가 '열람'으로 변경" ] }, { "id": 24, "name": "미열람 처리 - 문서 선택", "action": "열람 탭에서 방금 처리한 문서 체크박스 선택", "verification": [ "체크박스 선택 확인", "'미열람' 버튼 표시 확인" ] }, { "id": 25, "name": "미열람 처리 - 확인 다이얼로그", "action": "'미열람' 버튼 클릭", "verification": [ "확인 다이얼로그 표시", "다이얼로그 제목: '미열람 처리'", "다이얼로그 메시지: '정말 1건을 미열람 처리하시겠습니까?'", "취소 버튼 표시", "확인 버튼 표시" ] }, { "id": 26, "name": "미열람 처리 - URL 안정성 검증 (⚠️ 필수 검증 #2)", "action": "현재 URL 저장 후 '확인' 버튼 클릭", "verification": [ "⚠️ URL 변경 여부 확인 (변경되면 안됨)", "⚠️ 에러 페이지 텍스트 검색", "성공 토스트 메시지 표시: '미열람 처리 완료'", "토스트 설명: '미열람 처리가 완료되었습니다.'", "다이얼로그 자동 닫힘", "체크박스 선택 해제", "열람 탭의 문서 개수 1개 감소" ], "criticalCheck": { "type": "URL_STABILITY", "beforeURL": "/approval/reference", "afterURL": "/approval/reference", "errorPageTexts": ["페이지를 찾을 수 없습니다", "404", "Not Found", "서버 에러", "500"], "successToast": "미열람 처리 완료" } }, { "id": 27, "name": "미열람 처리 후 데이터 검증", "action": "테이블 및 통계 확인", "verification": [ "열람 탭에서 처리된 문서 제거 확인", "통계 카드의 '열람' 건수 1개 감소 (실시간 업데이트)", "통계 카드의 '미열람' 건수 1개 증가 (실시간 업데이트)" ] }, { "id": 28, "name": "일괄 열람 처리 - 다중 선택", "action": "'미열람' 탭으로 이동 후 2개 문서 체크박스 선택", "verification": [ "2개 문서 선택 확인", "'열람' 버튼 표시 확인" ] }, { "id": 29, "name": "일괄 열람 처리 - 실행", "action": "'열람' 버튼 클릭 후 확인", "verification": [ "다이얼로그 메시지: '정말 2건을 열람 처리하시겠습니까?'", "확인 버튼 클릭", "⚠️ URL 안정성 확인", "성공 토스트 메시지 표시", "미열람 탭에서 2개 문서 제거", "통계 카드 업데이트 (미열람 -2, 열람 +2)" ] }, { "id": 30, "name": "날짜 범위 선택기 테스트", "action": "날짜 범위 선택기의 '당월' 버튼 클릭", "verification": [ "시작일과 종료일이 당월로 변경", "데이터 재로드 확인 (로딩 인디케이터 또는 데이터 변화)" ] }, { "id": 31, "name": "페이지네이션 테스트", "action": "문서가 20개 이상인 경우 2페이지로 이동", "verification": [ "페이지네이션 컨트롤 표시 확인", "2페이지 버튼 클릭", "페이지 번호 변경 확인", "새로운 데이터 로드 확인" ], "conditional": "문서 개수가 20개 이상인 경우에만 실행" }, { "id": 32, "name": "Console 로그 확인", "action": "브라우저 콘솔 로그 확인", "verification": [ "ERROR 로그 없는지 확인", "WARNING 로그 확인 (접근성 경고 등)", "Network 요청 확인 (GET /api/v1/approvals/reference)" ] }, { "id": 33, "name": "최종 통계 확인", "action": "'전체' 탭으로 이동하여 최종 상태 확인", "verification": [ "전체 문서 목록 표시", "통계 카드 수치 정확성 확인", "전체 = 열람 + 미열람 수식 성립", "스크린샷 촬영하여 최종 상태 저장" ] } ], "mandatoryVerifications": [ { "id": "VERIFICATION_2", "name": "등록/저장 동작 검증 (URL 안정성)", "appliesTo": ["Step 21", "Step 26", "Step 29"], "requirements": [ "URL 변경 여부 확인 (처리 전 URL과 처리 후 URL 비교)", "에러 페이지 텍스트 검색 ('페이지를 찾을 수 없습니다', '404', 'Not Found', '서버 에러', '500')", "원래 페이지 요소 존재 확인 (테이블, 탭, 통계 카드 등)", "성공 토스트 메시지 표시 확인", "다이얼로그 자동 닫힘 확인" ] }, { "id": "VERIFICATION_5", "name": "목업/미완성 페이지 감지", "appliesTo": ["Step 1", "Step 16"], "requirements": [ "입력 필드 존재 여부 확인 (검색창 등)", "동작하는 버튼 확인 (최소 2개 버튼 클릭 테스트)", "API 호출 확인 (Console LOG만 아닌 실제 Network Request)", "데이터 변경 가능 여부 확인 (열람/미열람 처리 등)", "목업 판정 기준: 2개 이상 항목 해당 시 목업으로 판정" ] } ], "bugReportTemplate": { "priority": "Critical/High/Medium/Low", "component": "ReferenceBox", "affectedArea": "react", "relatedFiles": [ "C:\\Users\\codeb\\react\\src\\components\\approval\\ReferenceBox\\index.tsx", "C:\\Users\\codeb\\react\\src\\components\\approval\\ReferenceBox\\actions.ts", "C:\\Users\\codeb\\react\\src\\components\\approval\\ReferenceBox\\types.ts" ], "changeApprovalPolicy": "✅ 즉시 가능 / ⚠️ 컨펌 필요 / 🔴 금지" }, "testData": { "searchKeyword": "김철수", "dateRange": { "startDate": "2025-01-01", "endDate": "2026-01-31" } }, "notes": [ "참조함은 열람/미열람 상태 관리가 핵심 기능입니다.", "결재함과 달리 승인/반려 기능은 없고, 열람/미열람 처리만 가능합니다.", "통계 카드의 실시간 업데이트 확인이 중요합니다.", "URL 안정성 검증(필수 검증 #2)을 모든 처리 동작에서 수행해야 합니다.", "문서 상세 모달은 읽기 전용(mode='reference')으로 표시됩니다." ] }