Files
sam-scenarios/draft-box.json
light cff20a6c0e refactor: navigation 속성 추가 (targetUrl, urlPattern, menuHints)
- 54개 시나리오 파일에 URL 기반 메뉴 탐색을 위한 navigation 속성 추가
- targetUrl: 정확한 페이지 URL 경로
- urlPattern: ko 버전 포함 URL 패턴 (regex)
- menuHints: 메뉴명 힌트 배열 (fallback용)

메뉴 탐색 실패율 41.8% → URL 기반 방식으로 개선 예정

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 21:47:29 +09:00

1160 lines
36 KiB
JSON

{
"id": "draft-box",
"name": "기안함 테스트",
"screenshotPolicy": {
"onErrorOnly": true,
"captureOn": ["error", "fail", "timeout", "404", "500", "blocked"]
},
"description": "결재관리 > 기안함 메뉴의 문서 목록 조회, 검색, 필터, 정렬, 문서 상세, 상신, 삭제 기능 테스트",
"baseUrl": "https://dev.codebridge-x.com",
"testFocus": {
"primary": "기안 문서 목록 관리 및 결재 상신 프로세스 검증",
"description": "기안함 목록 표시, 통계 카드, 검색/필터/정렬, 체크박스 선택, 상신/삭제 버튼, 문서 상세 모달, 페이지네이션 동작 확인"
},
"navigation": {
"targetUrl": "/approval/draft",
"urlPattern": "/approval/draft|/ko/approval/draft",
"menuHints": ["기안함", "기안 함", "결재관리"]
},
"menuNavigation": {
"level1": "결재관리",
"level2": "기안함",
"expectedUrl": "/ko/approval/draft"
},
"menuNavigationEnhanced": {
"strategy": "scroll-and-search",
"description": "사이드바를 스크롤하며 메뉴를 찾고 클릭하여 404를 방지",
"level1": "결재관리",
"level2": "기안함",
"alternativeLevel1Names": ["결재관리", "결재 관리", "Approval", "전자결재"],
"alternativeLevel2Names": ["기안함", "기안 함", "Draft", "기안문서", "내 기안"],
"scrollConfig": {
"sidebarSelector": "nav, aside, [role='navigation'], .sidebar, #sidebar",
"menuItemSelector": "a, button, [role='menuitem'], [role='treeitem']",
"scrollStep": 200,
"maxScrollAttempts": 10,
"scrollDelay": 300
}
},
"prerequisites": {
"authentication": true,
"testData": {
"description": "결재 문서 데이터가 최소 1개 이상 존재해야 함 (다양한 상태: 임시저장, 결재대기, 진행중, 완료, 반려)"
}
},
"expectedAPIs": [
{
"method": "GET",
"endpoint": "/api/v1/approvals/drafts",
"params": "page=1&per_page=20&sort_by=created_at&sort_dir=desc",
"description": "기안함 목록 조회 (페이지네이션, 검색, 필터, 정렬)"
},
{
"method": "GET",
"endpoint": "/api/v1/approvals/drafts/summary",
"params": "",
"description": "기안함 통계 카드 (전체, 진행, 완료, 반려, 임시저장 건수)"
},
{
"method": "GET",
"endpoint": "/api/v1/approvals/{id}",
"params": "",
"description": "결재 문서 상세 조회 (content 포함)"
},
{
"method": "POST",
"endpoint": "/api/v1/approvals/{id}/submit",
"params": "",
"description": "결재 상신"
},
{
"method": "DELETE",
"endpoint": "/api/v1/approvals/{id}",
"params": "",
"description": "결재 문서 삭제 (임시저장 상태만)"
}
],
"steps": [
{
"id": "step-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 }
]
},
{
"id": "step-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": ["기안함", "기안 함", "Draft", "내 기안"],
"scrollContainer": "submenu",
"maxAttempts": 5,
"description": "서브메뉴에서 기안함 찾기"
},
{ "type": "click", "target": "기안함", "description": "기안함 메뉴 클릭" },
{ "type": "wait", "target": "페이지 로드 완료", "timeout": 10000 }
],
"expected": {
"url": "/ko/approval/draft",
"pageTitle": "기안함",
"elements": ["통계 카드", "검색바", "테이블", "페이지네이션"]
},
"verification": [
"결재관리 메뉴가 펼쳐졌는지 확인",
"기안함 서브메뉴 클릭 성공",
"404 에러 없이 페이지 로드 완료"
]
},
{
"id": "step-2",
"name": "페이지 구조 확인",
"description": "페이지 타이틀, 설명, 통계 카드, 헤더 액션 버튼 확인",
"actions": [
{
"type": "verify",
"target": "페이지 구조"
}
],
"expected": {
"pageTitle": "기안함",
"pageDescription": "작성한 결재 문서를 관리합니다",
"icon": "FileText",
"statCards": ["진행", "완료", "반려", "임시 저장"],
"headerActions": ["날짜 범위 선택", "문서 작성 버튼"]
}
},
{
"id": "step-3",
"name": "통계 카드 표시 확인",
"description": "4개의 통계 카드(진행, 완료, 반려, 임시 저장) 표시 및 건수 확인",
"actions": [
{
"type": "verify",
"target": "통계 카드"
}
],
"expected": {
"statCards": [
{"label": "진행", "format": "N건", "icon": "FileText", "color": "blue"},
{"label": "완료", "format": "N건", "icon": "FileText", "color": "green"},
{"label": "반려", "format": "N건", "icon": "FileText", "color": "red"},
{"label": "임시 저장", "format": "N건", "icon": "FileText", "color": "gray"}
],
"apiCalled": "GET /api/v1/approvals/drafts/summary"
}
},
{
"id": "step-4",
"name": "테이블 컬럼 구조 확인",
"description": "기안함 테이블의 컬럼 헤더 확인 (8개 컬럼)",
"actions": [
{
"type": "verify",
"target": "table columns"
}
],
"expected": {
"columns": [
"번호",
"문서번호",
"문서유형",
"제목",
"결재자",
"기안일시",
"상태",
"작업"
],
"hasCheckboxColumn": true
}
},
{
"id": "step-5",
"name": "데이터 로드 확인",
"description": "기안 문서 데이터가 테이블에 표시되는지 확인",
"actions": [
{
"type": "verify",
"target": "table data"
}
],
"expected": {
"dataExists": "데이터 행 존재 또는 '데이터가 없습니다' 메시지",
"apiCalled": "GET /api/v1/approvals/drafts?page=1&per_page=20",
"defaultSort": "최신순 (created_at desc)",
"defaultFilter": "전체"
}
},
{
"id": "step-6",
"name": "문서번호 형식 확인",
"description": "문서번호가 정상적으로 표시되는지 확인",
"actions": [
{
"type": "verify",
"target": "document number format"
}
],
"expected": {
"format": "문서번호 형식 (예: DR-2026-001)",
"column": "문서번호"
}
},
{
"id": "step-7",
"name": "문서유형 뱃지 표시 확인",
"description": "문서유형이 뱃지 형태로 표시되는지 확인",
"actions": [
{
"type": "verify",
"target": "document type badge"
}
],
"expected": {
"displayFormat": "Badge (outline)",
"possibleValues": ["품의서", "지출결의서", "예상지출내역"]
}
},
{
"id": "step-8",
"name": "결재자 표시 형식 확인",
"description": "결재자가 '이름 외 N명' 형식으로 표시되는지 확인",
"actions": [
{
"type": "verify",
"target": "approvers format"
}
],
"expected": {
"format": "단일: '홍길동', 복수: '홍길동 외 2명'",
"emptyFormat": "-"
}
},
{
"id": "step-9",
"name": "상태 뱃지 색상 확인",
"description": "문서 상태별로 다른 색상의 뱃지가 표시되는지 확인",
"actions": [
{
"type": "verify",
"target": "status badge colors"
}
],
"expected": {
"statusColors": {
"임시저장": "gray",
"결재대기": "yellow",
"진행중": "blue",
"완료": "green",
"반려": "red"
}
}
},
{
"id": "step-10",
"name": "검색 기능 테스트",
"description": "검색바에 키워드 입력 후 필터링 확인",
"actions": [
{
"type": "input",
"target": "검색 입력 필드",
"value": "테스트"
},
{
"type": "wait",
"target": "검색 결과 로드"
}
],
"expected": {
"searchPlaceholder": "문서번호, 제목, 기안자 검색...",
"apiCalled": "GET /api/v1/approvals/drafts?search=테스트",
"dataFiltered": "검색어 포함된 문서만 표시",
"pageReset": "1페이지로 초기화"
}
},
{
"id": "step-11",
"name": "검색어 초기화",
"description": "검색어를 지우고 전체 목록으로 복귀",
"actions": [
{
"type": "clear",
"target": "검색 입력 필드"
},
{
"type": "wait",
"target": "데이터 로드"
}
],
"expected": {
"dataRestored": "전체 목록 표시",
"apiCalled": "GET /api/v1/approvals/drafts?page=1"
}
},
{
"id": "step-12",
"name": "필터 셀렉트박스 존재 확인",
"description": "상태 필터 드롭다운이 표시되는지 확인",
"actions": [
{
"type": "verify",
"target": "filter select"
}
],
"expected": {
"selectExists": true,
"defaultValue": "전체",
"options": ["전체", "임시저장", "결재대기", "진행중", "완료", "반려"]
}
},
{
"id": "step-13",
"name": "필터 적용 테스트 (임시저장)",
"description": "필터를 '임시저장'으로 변경하여 필터링 확인",
"actions": [
{
"type": "select",
"target": "필터 셀렉트박스",
"value": "임시저장"
},
{
"type": "wait",
"target": "데이터 로드"
}
],
"expected": {
"apiCalled": "GET /api/v1/approvals/drafts?status=draft",
"dataFiltered": "임시저장 상태만 표시",
"pageReset": "1페이지로 초기화"
}
},
{
"id": "step-14",
"name": "필터 초기화",
"description": "필터를 '전체'로 변경하여 전체 목록 표시",
"actions": [
{
"type": "select",
"target": "필터 셀렉트박스",
"value": "전체"
},
{
"type": "wait",
"target": "데이터 로드"
}
],
"expected": {
"apiCalled": "GET /api/v1/approvals/drafts?page=1",
"dataRestored": "전체 상태 표시"
}
},
{
"id": "step-15",
"name": "정렬 셀렉트박스 존재 확인",
"description": "정렬 옵션 드롭다운이 표시되는지 확인",
"actions": [
{
"type": "verify",
"target": "sort select"
}
],
"expected": {
"selectExists": true,
"defaultValue": "최신순",
"options": ["최신순", "오래된순", "제목 오름차순", "제목 내림차순"]
}
},
{
"id": "step-16",
"name": "정렬 변경 테스트 (제목 오름차순)",
"description": "정렬을 '제목 오름차순'으로 변경",
"actions": [
{
"type": "select",
"target": "정렬 셀렉트박스",
"value": "제목 오름차순"
},
{
"type": "wait",
"target": "데이터 로드"
}
],
"expected": {
"apiCalled": "GET /api/v1/approvals/drafts?sort_by=title&sort_dir=asc",
"dataSorted": "제목 알파벳 순서로 정렬",
"pageReset": "1페이지로 초기화"
}
},
{
"id": "step-17",
"name": "정렬 초기화",
"description": "정렬을 '최신순'으로 복귀",
"actions": [
{
"type": "select",
"target": "정렬 셀렉트박스",
"value": "최신순"
},
{
"type": "wait",
"target": "데이터 로드"
}
],
"expected": {
"apiCalled": "GET /api/v1/approvals/drafts?sort_by=created_at&sort_dir=desc",
"dataRestored": "최신순 정렬"
}
},
{
"id": "step-18",
"name": "체크박스 선택 (단일)",
"description": "첫 번째 문서의 체크박스 선택",
"actions": [
{
"type": "click",
"target": "첫 번째 행 체크박스"
}
],
"expected": {
"checkboxChecked": true,
"selectedCount": 1,
"actionButtonsVisible": "상신, 삭제 버튼 표시"
}
},
{
"id": "step-19",
"name": "임시저장 문서 수정/삭제 버튼 표시 확인",
"description": "임시저장 상태 문서 선택 시 작업 컬럼에 수정/삭제 버튼 표시",
"actions": [
{
"type": "verify",
"target": "action buttons for draft status"
}
],
"expected": {
"condition": "status === 'draft' && isSelected",
"buttonsVisible": ["수정 (Pencil 아이콘)", "삭제 (Trash2 아이콘)"],
"buttonColors": {
"수정": "gray",
"삭제": "red"
}
}
},
{
"id": "step-20",
"name": "체크박스 해제",
"description": "선택한 체크박스를 다시 클릭하여 해제",
"actions": [
{
"type": "click",
"target": "첫 번째 행 체크박스"
}
],
"expected": {
"checkboxChecked": false,
"selectedCount": 0,
"actionButtonsHidden": "상신, 삭제 버튼 숨김"
}
},
{
"id": "step-21",
"name": "전체 선택 체크박스 클릭",
"description": "테이블 헤더의 전체 선택 체크박스 클릭",
"actions": [
{
"type": "click",
"target": "헤더 체크박스 (전체 선택)"
}
],
"expected": {
"allCheckboxesChecked": true,
"selectedCount": "현재 페이지의 모든 행 수",
"actionButtonsVisible": "상신, 삭제 버튼 표시"
}
},
{
"id": "step-22",
"name": "전체 선택 해제",
"description": "전체 선택 체크박스를 다시 클릭하여 모두 해제",
"actions": [
{
"type": "click",
"target": "헤더 체크박스 (전체 선택)"
}
],
"expected": {
"allCheckboxesUnchecked": true,
"selectedCount": 0,
"actionButtonsHidden": "상신, 삭제 버튼 숨김"
}
},
{
"id": "step-23",
"name": "문서 작성 버튼 확인",
"description": "헤더 액션에 '문서 작성' 버튼이 표시되는지 확인",
"actions": [
{
"type": "verify",
"target": "문서 작성 버튼"
}
],
"expected": {
"buttonExists": true,
"buttonText": "문서 작성",
"icon": "Plus"
}
},
{
"id": "step-24",
"name": "문서 클릭 (임시저장)",
"description": "임시저장 상태의 문서 행 클릭 (수정 모드로 이동)",
"actions": [
{
"type": "click",
"target": "임시저장 상태의 문서 행"
}
],
"expected": {
"urlChange": "/ko/approval/draft/new?id={id}&mode=edit",
"behavior": "문서 작성 페이지로 이동 (수정 모드)"
}
},
{
"id": "step-25",
"name": "기안함으로 복귀",
"description": "문서 작성 페이지에서 기안함으로 돌아오기",
"actions": [
{
"type": "navigate",
"target": "/ko/approval/draft"
}
],
"expected": {
"url": "/ko/approval/draft",
"dataReloaded": "목록 재로드"
}
},
{
"id": "step-26",
"name": "문서 클릭 (결재대기/진행중/완료)",
"description": "임시저장이 아닌 문서 행 클릭 (상세 모달 오픈)",
"actions": [
{
"type": "click",
"target": "결재대기/진행중/완료 상태의 문서 행"
},
{
"type": "wait",
"target": "모달 오픈 및 상세 데이터 로드"
}
],
"expected": {
"modalOpened": true,
"apiCalled": "GET /api/v1/approvals/{id}",
"modalTitle": "문서 상세"
}
},
{
"id": "step-27",
"name": "문서 상세 모달 구조 확인",
"description": "문서 상세 모달의 구조 및 내용 확인",
"actions": [
{
"type": "verify",
"target": "document detail modal"
}
],
"expected": {
"modalContent": [
"문서번호",
"기안일시",
"결재자 목록 (최대 3명)",
"문서 내용 (문서 유형에 따라 다름)"
],
"documentTypes": ["품의서 (proposal)", "지출결의서 (expenseReport)", "예상지출내역 (expenseEstimate)"]
}
},
{
"id": "step-28",
"name": "모달 수정 버튼 확인",
"description": "모달 하단에 수정 버튼이 표시되는지 확인",
"actions": [
{
"type": "verify",
"target": "modal edit button"
}
],
"expected": {
"buttonExists": true,
"buttonText": "수정",
"behavior": "클릭 시 문서 작성 페이지로 이동 (수정 모드)"
}
},
{
"id": "step-29",
"name": "모달 복제 버튼 확인",
"description": "모달 하단에 복제 버튼이 표시되는지 확인",
"actions": [
{
"type": "verify",
"target": "modal copy button"
}
],
"expected": {
"buttonExists": true,
"buttonText": "복제",
"behavior": "클릭 시 문서 작성 페이지로 이동 (복제 모드, copyFrom 파라미터)"
}
},
{
"id": "step-30",
"name": "모달 상신 버튼 확인 (임시저장 시)",
"description": "임시저장 문서의 모달에서 상신 버튼 확인",
"actions": [
{
"type": "verify",
"target": "modal submit button"
}
],
"expected": {
"buttonExists": "임시저장 상태일 때만",
"buttonText": "상신",
"behavior": "클릭 시 결재 상신 (POST /api/v1/approvals/{id}/submit)"
}
},
{
"id": "step-31",
"name": "모달 닫기",
"description": "문서 상세 모달을 닫기",
"actions": [
{
"type": "click",
"target": "모달 외부 또는 닫기 버튼"
}
],
"expected": {
"modalClosed": true,
"returnToList": "기안함 목록으로 복귀"
}
},
{
"id": "step-31-pdf-1",
"name": "⚠️ 필수 검증: PDF 다운로드 전 모달 스크린샷",
"critical": true,
"description": "PDF 생성 전 모달 상태를 스크린샷으로 캡처하여 CSS 문제 감지용 기준 이미지 확보",
"prerequisite": "step-26의 문서 상세 모달이 열려있는 상태에서 실행",
"actions": [
{
"type": "click",
"target": "결재대기/진행중/완료 상태의 문서 행",
"description": "모달 다시 열기"
},
{
"type": "wait",
"duration": 1000,
"description": "모달 로드 대기"
},
{
"type": "screenshot",
"name": "pdf-preview-before-download-draft-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": "step-31-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-draft-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-draft-box",
"checks": {
"status": 200,
"contentType": "application/pdf"
}
},
{
"type": "saveDownloadedFile",
"targetPath": "tests/e2e/results/hotfix/pdf-samples/",
"fileNamePattern": "draft-box-{timestamp}.pdf",
"description": "다운로드된 PDF 파일을 지정 폴더에 보관"
}
],
"verify": {
"apiSuccess": true,
"fileDownloaded": true,
"fileSaved": "tests/e2e/results/hotfix/pdf-samples/"
}
},
{
"id": "step-31-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": "step-31-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-draft-box-*.png",
"pdfFile": "tests/e2e/results/hotfix/pdf-samples/draft-box-*.pdf"
},
"reportFlag": {
"requiresManualReview": true,
"message": "⚠️ PDF 스타일 수동 확인 필요 - 위 체크리스트 항목을 PDF 파일에서 직접 확인하세요"
}
},
{
"id": "step-31-pdf-5",
"name": "모달 닫기 (PDF 테스트 후)",
"description": "PDF 테스트 완료 후 모달 닫기",
"actions": [
{
"type": "click",
"target": "모달 외부 또는 닫기 버튼"
}
],
"expected": {
"modalClosed": true
}
},
{
"id": "step-32",
"name": "날짜 범위 선택 확인",
"description": "헤더 액션에 날짜 범위 선택 컴포넌트가 표시되는지 확인",
"actions": [
{
"type": "verify",
"target": "date range selector"
}
],
"expected": {
"componentExists": true,
"defaultStartDate": "2025-01-01",
"defaultEndDate": "2025-12-31",
"inputs": ["시작일 입력", "종료일 입력"]
}
},
{
"id": "step-33",
"name": "페이지네이션 존재 확인",
"description": "테이블 하단에 페이지네이션이 표시되는지 확인",
"actions": [
{
"type": "verify",
"target": "pagination component"
}
],
"expected": {
"paginationExists": true,
"showsCurrentPage": "현재 페이지 번호",
"showsTotalPages": "전체 페이지 수",
"showsTotalItems": "전체 항목 수",
"itemsPerPage": 20
}
},
{
"id": "step-34",
"name": "페이지네이션 이동 테스트",
"description": "2페이지가 있는 경우 페이지 이동 테스트",
"actions": [
{
"type": "click",
"target": "페이지 2 버튼 (또는 다음 버튼)"
},
{
"type": "wait",
"target": "데이터 로드"
}
],
"expected": {
"currentPage": 2,
"apiCalled": "GET /api/v1/approvals/drafts?page=2",
"dataChanged": "2페이지 데이터 표시",
"scrollToTop": "페이지 상단으로 스크롤"
}
},
{
"id": "step-35",
"name": "1페이지로 복귀",
"description": "페이지네이션에서 1페이지로 이동",
"actions": [
{
"type": "click",
"target": "페이지 1 버튼"
},
{
"type": "wait",
"target": "데이터 로드"
}
],
"expected": {
"currentPage": 1,
"apiCalled": "GET /api/v1/approvals/drafts?page=1",
"dataRestored": "1페이지 데이터 표시"
}
},
{
"id": "step-36",
"name": "테이블 hover 효과 확인",
"description": "테이블 행에 마우스 오버 시 배경색 변경 확인",
"actions": [
{
"type": "hover",
"target": "첫 번째 테이블 행"
}
],
"expected": {
"hoverEffect": "hover:bg-muted/50",
"backgroundChanges": true,
"cursorPointer": true
}
},
{
"id": "step-37",
"name": "로딩 상태 확인",
"description": "데이터 로드 중 로딩 인디케이터 표시 확인",
"actions": [
{
"type": "verify",
"target": "loading state"
}
],
"expected": {
"loadingIndicator": "스피너 또는 로딩 메시지",
"isLoading": "true during data fetch"
}
},
{
"id": "step-38",
"name": "빈 상태 메시지 확인",
"description": "검색/필터 결과가 없을 때 빈 상태 메시지 표시",
"actions": [
{
"type": "input",
"target": "검색 입력 필드",
"value": "존재하지않는문서번호999999"
},
{
"type": "wait",
"target": "검색 결과"
}
],
"expected": {
"emptyMessage": "데이터가 없습니다.",
"messagePosition": "테이블 중앙"
}
},
{
"id": "step-39",
"name": "검색어 초기화 (빈 상태 해제)",
"description": "검색어를 지워서 전체 목록으로 복귀",
"actions": [
{
"type": "clear",
"target": "검색 입력 필드"
},
{
"type": "wait",
"target": "데이터 로드"
}
],
"expected": {
"dataRestored": "전체 목록 표시"
}
},
{
"id": "step-40",
"name": "콘솔 에러 확인",
"description": "페이지 동작 중 콘솔에 에러가 발생하지 않는지 확인",
"actions": [
{
"type": "verify",
"target": "console errors"
}
],
"expected": {
"noErrors": "콘솔 에러 없음",
"warningsAcceptable": "경고는 허용"
}
},
{
"id": "step-41",
"name": "반응형 레이아웃 확인",
"description": "모바일 뷰에서 카드 레이아웃으로 표시되는지 확인",
"actions": [
{
"type": "verify",
"target": "mobile card layout"
}
],
"expected": {
"mobileCardExists": "화면 크기에 따라",
"cardTitle": "문서 제목",
"cardFields": ["문서번호", "기안일자", "기안자", "결재자"]
}
},
{
"id": "step-42",
"name": "모바일 카드 액션 버튼 확인",
"description": "모바일 카드에서 임시저장 문서 선택 시 수정/삭제 버튼 표시",
"actions": [
{
"type": "verify",
"target": "mobile card actions"
}
],
"expected": {
"condition": "status === 'draft' && isSelected",
"buttons": ["수정", "삭제"],
"buttonIcons": ["Pencil", "Trash2"]
}
},
{
"id": "step-43",
"name": "통계 카드 실시간 업데이트 확인",
"description": "문서 상신/삭제 후 통계 카드가 업데이트되는지 확인",
"actions": [
{
"type": "verify",
"target": "stat cards update after action"
}
],
"expected": {
"updateTriggers": ["상신 성공", "삭제 성공"],
"apiCalled": "GET /api/v1/approvals/drafts/summary"
}
},
{
"id": "step-44",
"name": "IntegratedListTemplateV2 사용 확인",
"description": "IntegratedListTemplateV2 템플릿 컴포넌트 사용 확인",
"actions": [
{
"type": "verify",
"target": "template component"
}
],
"expected": {
"templateComponent": "IntegratedListTemplateV2",
"responsive": "모바일/데스크톱 대응"
}
},
{
"id": "step-45",
"name": "상신 버튼 조건부 표시 확인",
"description": "항목 선택 시에만 상신 버튼이 표시되는지 확인",
"actions": [
{
"type": "verify",
"target": "submit button visibility"
}
],
"expected": {
"condition": "selectedItems.size > 0",
"buttonVisible": true,
"buttonText": "상신",
"icon": "Send"
}
},
{
"id": "step-46",
"name": "삭제 버튼 조건부 표시 확인",
"description": "항목 선택 시에만 삭제 버튼이 표시되는지 확인",
"actions": [
{
"type": "verify",
"target": "delete button visibility"
}
],
"expected": {
"condition": "selectedItems.size > 0",
"buttonVisible": true,
"buttonText": "삭제",
"icon": "Trash2",
"variant": "destructive (red)"
}
},
{
"id": "step-47",
"name": "결재자 상태 뱃지 확인",
"description": "모달 내 결재자 목록의 상태 뱃지 색상 확인",
"actions": [
{
"type": "verify",
"target": "approver status badges in modal"
}
],
"expected": {
"statusColors": {
"none": "gray",
"pending": "yellow",
"approved": "green",
"rejected": "red"
}
}
},
{
"id": "step-48",
"name": "문서 유형별 모달 내용 확인",
"description": "문서 유형(품의서, 지출결의서, 예상지출내역)에 따라 다른 내용 표시",
"actions": [
{
"type": "verify",
"target": "document type specific content"
}
],
"expected": {
"proposal": ["거래처", "거래처 지급일", "제목", "내용", "사유", "예상금액", "첨부파일"],
"expenseReport": ["신청일", "지급일", "지출 내역", "카드 정보", "총액", "첨부파일"],
"expenseEstimate": ["예상지급일", "카테고리", "금액", "거래처", "계좌", "총 지출", "계좌 잔액", "최종 차액"]
}
},
{
"id": "step-49",
"name": "API 응답 구조 확인",
"description": "기안함 목록 API 응답이 올바른 구조인지 확인",
"actions": [
{
"type": "verify",
"target": "API response structure"
}
],
"expected": {
"responseStructure": {
"success": true,
"data": {
"current_page": "number",
"data": "Array<ApprovalApiData>",
"total": "number",
"per_page": "number",
"last_page": "number"
}
}
}
},
{
"id": "step-50",
"name": "데이터 변환 확인",
"description": "API 데이터가 프론트엔드 형식으로 변환되는지 확인",
"actions": [
{
"type": "verify",
"target": "data transformation"
}
],
"expected": {
"apiFormat": "snake_case (document_number, created_at, approval_steps)",
"frontendFormat": "camelCase (documentNo, draftDate, approvers)",
"transformFunction": "transformApiToFrontend",
"statusMapping": {
"draft": "draft",
"pending": "pending",
"in_progress": "inProgress",
"approved": "approved",
"rejected": "rejected"
}
}
}
],
"cleanup": {
"description": "테스트 후 정리 작업 (없음)",
"actions": []
},
"notes": [
"20개씩 페이지네이션 (itemsPerPage: 20)",
"검색 필드: 문서번호, 제목, 기안자 검색 가능",
"필터: 전체, 임시저장, 결재대기, 진행중, 완료, 반려",
"정렬: 최신순, 오래된순, 제목 오름차순, 제목 내림차순",
"체크박스: 개별 선택, 전체 선택 가능",
"상신/삭제: 선택된 항목이 있을 때만 버튼 표시",
"임시저장 문서: 선택 시 작업 컬럼에 수정/삭제 버튼 표시",
"문서 클릭 동작: 임시저장 → 수정 페이지, 그 외 → 상세 모달",
"통계 카드: API summary로 실시간 업데이트",
"IntegratedListTemplateV2 템플릿 사용으로 반응형 지원",
"날짜 범위 선택 기본값: 2025-01-01 ~ 2025-12-31",
"결재자 표시: 단일(이름), 복수(이름 외 N명)",
"모달 버튼: 수정, 복제, 상신(임시저장만)",
"승인/반려 버튼 없음 (기안함에서는 본인 문서 승인/반려 불가)"
]
}