{ "enabled": true, "id": "vendor-ledger", "name": "거래처원장 테스트", "screenshotPolicy": { "onErrorOnly": true, "captureOn": [ "error", "fail", "timeout", "404", "500", "blocked" ] }, "description": "회계관리 > 거래처원장 메뉴의 기간 설정, 검색, 테이블, 다운로드, 상세 페이지 기능 테스트", "baseUrl": "https://dev.codebridge-x.com", "navigation": { "targetUrl": "/accounting/vendor-ledger", "urlPattern": "/accounting/vendor-ledger|/ko/accounting/vendor-ledger", "menuHints": [ "거래처원장", "거래처 원장", "회계관리" ] }, "menuNavigation": { "level1": "회계관리", "level2": "거래처원장", "expectedUrl": "/ko/accounting/vendor-ledger", "searchWithinParent": true, "closeOtherMenus": true }, "menuNavigationEnhanced": { "strategy": "scroll-and-search", "level1": { "text": "회계관리", "alternativeNames": [ "회계", "Accounting" ], "scrollConfig": { "direction": "down", "maxScrollAttempts": 5, "scrollAmount": 200 } }, "level2": { "text": "거래처원장", "alternativeNames": [ "거래처 원장", "Vendor Ledger" ], "scrollConfig": { "direction": "down", "maxScrollAttempts": 3, "scrollAmount": 150 } }, "expectedUrl": "/ko/accounting/vendor-ledger", "fallbackUrl": "/ko/accounting/vendor-ledger" }, "auth": { "username": "TestUser5", "password": "password123!" }, "steps": [ { "id": 1, "name": "사이드바 메뉴 전체 펼치기", "description": "모두 펼치기 버튼을 클릭하여 전체 메뉴를 펼친 후 메뉴 탐색 준비", "action": "evaluate", "script": "(async () => { document.querySelector('.sidebar-scroll')?.scrollTo({top:0,behavior:'instant'}); await new Promise(r=>setTimeout(r,300)); Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click(); await new Promise(r=>setTimeout(r,2000)); return 'menu expanded'; })()", "expected": "사이드바 전체 메뉴가 펼쳐짐" }, { "id": 2, "name": "로그인 상태 확인", "action": "verify_page", "expected": "이미 로그인된 상태" }, { "id": 3, "name": "2단계 메뉴 진입: 회계관리 > 거래처원장", "description": "회계관리 > 거래처원장 메뉴로 이동하여 페이지 로드 확인", "action": "menu_navigate", "level1": "회계관리", "level2": "거래처원장", "expected": { "url": "/ko/accounting/vendor-ledger", "pageTitle": "거래처원장", "elements": [ "통계 카드", "테이블" ] } }, { "id": 4, "name": "필수 검증 #5: 목업 페이지 감지", "action": "verify_not_mockup", "checks": [ "입력 필드 존재 (검색창, 날짜 선택)", "동작하는 버튼 존재 (엑셀 다운로드)", "테이블 데이터 표시", "API 호출 확인" ], "expected": "정상 페이지 (목업 아님)" }, { "id": 5, "name": "통계 카드 확인", "action": "verify_elements", "checks": [ "전기 이월 카드 표시", "매출 카드 표시", "수금 카드 표시", "잔액 카드 표시" ], "expected": "4개 통계 카드 모두 표시, 금액 형식 확인" }, { "id": 6, "name": "테이블 구조 확인", "action": "verify_table", "checks": [ "체크박스 컬럼", "No. 컬럼", "거래처명 컬럼", "이월잔액 컬럼", "매출 컬럼", "수금 컬럼", "잔액 컬럼", "결제일 컬럼" ], "expected": "8개 컬럼 존재, 합계 행 표시" }, { "id": 7, "name": "기간 설정 - 시작일 변경", "action": "click_if_exists", "target": "startDate", "value": "2025-01-01", "expected": "시작일 변경 후 데이터 재조회" }, { "id": 8, "name": "기간 설정 - 종료일 변경", "action": "click_if_exists", "target": "endDate", "value": "2025-12-31", "expected": "종료일 변경 후 데이터 재조회" }, { "id": 9, "name": "기간 설정 - 데이터 변화 확인", "action": "verify_detail", "checks": [ "테이블 데이터 갱신", "통계 카드 값 갱신", "합계 행 값 갱신" ], "expected": "기간에 맞는 데이터로 변경됨" }, { "id": 10, "name": "⚠️ 필수 검증: 검색 기능 테스트", "action": "evaluate", "script": "(async () => { const beforeCount = document.querySelectorAll('table tbody tr').length; const inp = document.querySelector('input[type=\"search\"], input[placeholder*=\"검색\"]'); if(inp){ inp.click(); await new Promise(r=>setTimeout(r,1000)); } const afterCount = document.querySelectorAll('table tbody tr').length; return JSON.stringify({ beforeSearchCount: beforeCount, afterSearchCount: afterCount, inputFound: !!inp }); })()", "verify": { "searchApplied": true, "tableContains": "{testData.searchKeyword}", "dataChanged": "beforeSearchCount may differ from afterSearchCount" }, "expected": "검색어에 맞는 거래처만 필터링" }, { "id": 11, "name": "검색 결과 데이터 검증", "description": "검색 결과의 모든 행이 검색어를 포함하는지 확인", "action": "verify_detail", "checks": [ "visible_text:{testData.searchKeyword}" ], "verify": { "allRowsContain": "{testData.searchKeyword}", "columnToCheck": "거래처명" } }, { "id": 12, "name": "검색 결과 확인", "action": "verify_search_result", "checks": [ "테이블 행 수 변화", "검색어 포함 거래처명 표시" ], "expected": "검색 결과 정상 표시" }, { "id": 13, "name": "검색 초기화", "action": "evaluate", "script": "(async () => { const inp = document.querySelector('input[type=\"search\"], input[placeholder*=\"검색\"]'); if(inp){ inp.click(); await new Promise(r=>setTimeout(r,500)); } const afterClearCount = document.querySelectorAll('table tbody tr').length; return JSON.stringify({ afterClearCount: afterClearCount, inputFound: !!inp }); })()", "verify": { "dataRestored": "afterClearCount should equal beforeSearchCount" }, "expected": "전체 데이터 다시 표시" }, { "id": 14, "name": "체크박스 선택", "action": "click_if_exists", "target": "first_row", "expected": "첫 번째 행 체크박스 선택됨" }, { "id": 15, "name": "전체 선택 체크박스", "action": "click_if_exists", "target": "select_all", "expected": "모든 행 체크박스 선택됨" }, { "id": 16, "name": "전체 선택 해제", "action": "click_if_exists", "target": "select_all", "expected": "모든 행 체크박스 해제됨" }, { "id": 17, "name": "필수 검증 #1: 엑셀 다운로드", "action": "click_download", "target": "엑셀 다운로드", "checks": [ "버튼 클릭", "Network API 호출 확인 (/api/v1/vendor-ledger/export)", "Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "파일 다운로드 이벤트 발생", "성공 토스트 메시지 (엑셀 파일이 다운로드되었습니다)" ], "expected": "엑셀 파일 다운로드 완료" }, { "id": 18, "name": "테이블 행 클릭 - 상세 페이지 이동", "action": "click_if_exists", "target": "table tbody tr:first-child", "expected": "거래처원장 상세 페이지로 이동" }, { "id": 19, "name": "상세 페이지 - URL 파라미터 확인", "action": "verify_url", "checks": [ "URL에 거래처 ID 포함", "start_date 파라미터 포함", "end_date 파라미터 포함" ], "expected": "URL 파라미터 정상 전달" }, { "id": 20, "name": "상세 페이지 - 헤더 확인", "action": "verify_elements", "checks": [ "거래처원장 상세 (거래명세서별) 타이틀", "목록 버튼 존재" ], "expected": "상세 페이지 헤더 정상 표시" }, { "id": 21, "name": "상세 페이지 - 거래처 정보 카드 확인", "action": "verify_vendor_info", "checks": [ "회사명 표시", "사업자등록번호 표시", "대표자 표시", "전화번호 표시", "모바일 표시", "팩스 표시", "이메일 표시", "주소 표시", "기간 표시" ], "expected": "거래처 정보 모두 표시" }, { "id": 22, "name": "상세 페이지 - 요약 통계 확인", "action": "verify_summary", "checks": [ "이월잔액 표시", "매출 표시 (녹색)", "수금 표시 (파란색)", "잔액 표시" ], "expected": "4개 요약 통계 정상 표시" }, { "id": 23, "name": "상세 페이지 - 판매/수금 내역 테이블 확인", "action": "verify_transaction_table", "checks": [ "일자 컬럼", "적요 컬럼", "판매 컬럼", "수금 컬럼", "잔액 컬럼", "작업 컬럼" ], "expected": "판매/수금 내역 테이블 정상 표시" }, { "id": 24, "name": "상세 페이지 - 기간 변경", "action": "click_if_exists", "startDate": "2025-06-01", "endDate": "2025-06-30", "expected": "기간 변경 후 거래 내역 재조회", "target": "input[type='date'], [class*='date-picker']" }, { "id": 25, "name": "상세 페이지 - 거래 내역 데이터 변화 확인", "action": "verify_transactions_update", "checks": [ "테이블 데이터 갱신", "요약 통계 값 갱신" ], "expected": "변경된 기간의 데이터 표시" }, { "id": 26, "name": "⚠️ 필수 검증: PDF 다운로드 전 페이지 스크린샷", "description": "PDF 생성 전 페이지 상태를 스크린샷으로 캡처하여 CSS 문제 감지용 기준 이미지 확보", "action": "evaluate", "script": "(() => 'screenshot placeholder: pdf-preview-before-download, pdf-content-area')()", "verify": { "screenshotCaptured": true, "purpose": "PDF CSS 문제 감지를 위한 기준 이미지" } }, { "id": 27, "name": "⚠️ 필수 검증: PDF 다운로드 실행 및 파일 보관", "description": "PDF 다운로드 후 파일을 지정 폴더에 보관하여 수동 검증 가능하게 함", "action": "evaluate", "script": "(async () => { const btn = Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('PDF') || b.innerText?.includes('pdf')); if(btn){ btn.click(); await new Promise(r=>setTimeout(r,3000)); return 'PDF download button clicked'; } return 'PDF download button not found'; })()", "verify": { "apiSuccess": true, "fileDownloaded": true, "fileSaved": "tests/e2e/results/hotfix/pdf-samples/" } }, { "id": 28, "name": "⚠️ PDF 파일 유효성 검증", "description": "다운로드된 PDF 파일의 기본 유효성 검사", "action": "evaluate", "script": "(() => 'PDF file validity check placeholder')()", "verify": { "pdfValid": true, "minFileSize": "1KB 이상" } }, { "id": 29, "name": "📋 PDF 스타일 수동 확인 체크리스트", "description": "개발자가 다운로드된 PDF를 열어 시각적으로 확인해야 하는 항목", "action": "evaluate", "script": "(() => 'Manual PDF style verification required')()", "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-*.png", "pdfFile": "tests/e2e/results/hotfix/pdf-samples/vendor-ledger-*.pdf" }, "reportFlag": { "requiresManualReview": true, "message": "⚠️ PDF 스타일 수동 확인 필요 - 위 체크리스트 항목을 PDF 파일에서 직접 확인하세요" } }, { "id": 30, "name": "상세 페이지 - 작업 버튼 확인 (어음 항목)", "action": "verify_action_buttons", "checks": [ "어음 관련 항목에 수정 버튼(Pencil 아이콘) 존재", "일반 항목에는 작업 버튼 없음" ], "expected": "hasAction=true인 항목에만 버튼 표시" }, { "id": 31, "name": "상세 페이지 - 목록 버튼 클릭", "action": "click_if_exists", "target": "목록", "expected": "거래처원장 목록 페이지로 복귀" }, { "id": 32, "name": "목록 페이지 복귀 확인", "action": "verify_url", "target": "/ko/accounting/vendor-ledger", "expected": "목록 페이지 정상 표시" }, { "id": 33, "name": "페이지네이션 동작 확인", "action": "verify_pagination", "checks": [ "현재 페이지 표시", "전체 페이지 수 표시", "페이지 이동 버튼 동작" ], "expected": "페이지네이션 정상 동작" }, { "id": 34, "name": "콘솔 에러 확인", "action": "verify_element", "target": "body" } ], "requiredVerifications": [ { "id": 1, "name": "파일 다운로드 (엑셀/PDF)", "steps": [ 15, 24, "24-1", "24-2", "24-3" ], "criteria": "Network API 호출 + 실제 파일 다운로드 + 성공 토스트 + PDF 스타일 검증" }, { "id": "PDF-STYLE", "name": "PDF 스타일/CSS 검증", "steps": [ 24, "24-1", "24-2", "24-3" ], "criteria": "스크린샷 캡처 + PDF 파일 보관 + 수동 체크리스트 확인", "manualReviewRequired": true, "outputPaths": { "screenshots": "tests/e2e/results/hotfix/screenshots/", "pdfFiles": "tests/e2e/results/hotfix/pdf-samples/" } }, { "id": 2, "name": "등록/저장 버튼", "steps": [], "criteria": "해당 없음 (조회 전용 페이지)" }, { "id": 3, "name": "검색/필터", "steps": [ 6, 7, 8, 9, 10, 11 ], "criteria": "기간 설정 및 검색 시 데이터 변화 확인" }, { "id": 4, "name": "모달 등록 완료", "steps": [], "criteria": "해당 없음 (조회 전용 페이지)" }, { "id": 5, "name": "목업 페이지 감지", "steps": [ 3 ], "criteria": "입력 필드, 동작 버튼, API 호출 확인" } ], "testData": { "searchKeyword": "테스트", "dateRange": { "start": "2025-01-01", "end": "2025-12-31" }, "detailDateRange": { "start": "2025-06-01", "end": "2025-06-30" } }, "expectedAPIs": [ { "method": "GET", "endpoint": "/api/v1/vendor-ledger", "description": "거래처원장 목록 조회" }, { "method": "GET", "endpoint": "/api/v1/vendor-ledger/summary", "description": "거래처원장 요약 통계 조회" }, { "method": "GET", "endpoint": "/api/v1/vendor-ledger/{id}", "description": "거래처원장 상세 조회" }, { "method": "GET", "endpoint": "/api/v1/vendor-ledger/export", "description": "거래처원장 엑셀 다운로드" }, { "method": "GET", "endpoint": "/api/v1/vendor-ledger/{id}/export-pdf", "description": "거래처원장 상세 PDF 다운로드" } ] }