Files
sam-scenarios/vendor-ledger.json

577 lines
19 KiB
JSON
Raw Normal View History

{
"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": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const inputs=document.querySelectorAll('input[type=\"date\"], input[placeholder*=\"시작\"], input[placeholder*=\"날짜\"]');const dateInputs=inputs.length>0?inputs:document.querySelectorAll('button[class*=\"date\"], [class*=\"DatePicker\"] input, [class*=\"date-picker\"] input');if(dateInputs.length>0){const el=dateInputs[0];el.click();await w(500);}return JSON.stringify({found:dateInputs.length,action:'startDate click attempted'});})()",
"expected": "시작일 변경 후 데이터 재조회"
},
{
"id": 8,
"name": "기간 설정 - 종료일 변경",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const inputs=document.querySelectorAll('input[type=\"date\"], input[placeholder*=\"종료\"], input[placeholder*=\"날짜\"]');const dateInputs=inputs.length>0?inputs:document.querySelectorAll('button[class*=\"date\"], [class*=\"DatePicker\"] input, [class*=\"date-picker\"] input');if(dateInputs.length>1){const el=dateInputs[1];el.click();await w(500);}else if(dateInputs.length>0){const el=dateInputs[0];el.click();await w(500);}return JSON.stringify({found:dateInputs.length,action:'endDate click attempted'});})()",
"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 다운로드"
}
]
}