diff --git a/crud-delete-freeboard.json b/crud-delete-freeboard.json index 6125e82..e91d4c9 100644 --- a/crud-delete-freeboard.json +++ b/crud-delete-freeboard.json @@ -1,527 +1,223 @@ { + "enabled": true, "id": "crud-delete-freeboard", - "name": "자유게시판 CRUD 삭제 기능 테스트", + "name": "자유게시판 CRUD 삭제 테스트", "screenshotPolicy": { "onErrorOnly": true, - "captureOn": [ - "error", - "fail", - "timeout", - "404", - "500", - "blocked" - ] + "captureOn": ["error", "fail", "timeout", "404", "500", "blocked"] }, - "description": "자유게시판에서 생성 → 수정 → 삭제 전체 CRUD 흐름 테스트. 테스트용 게시글을 생성하고, 수정한 후, 삭제하여 기존 데이터에 영향 없이 삭제 기능을 검증", + "description": "자유게시판에서 생성 → 수정 → 삭제 전체 CRUD 흐름 테스트", "baseUrl": "https://dev.codebridge-x.com", "menuNavigation": { "level1": "게시판", "level2": "자유게시판", - "expectedUrl": "/ko/boards/free" + "expectedUrl": "/boards/free", + "searchWithinParent": true, + "closeOtherMenus": true }, "auth": { "username": "TestUser5", "password": "password123!" }, - "testPolicy": { - "deleteAllowed": true, - "deleteCondition": "CRUD 흐름 내에서만 허용 (생성 → 수정 → 삭제)", - "protectExistingData": true, - "description": "이 시나리오에서 생성한 테스트 데이터만 삭제" - }, - "modalHandling": { - "description": "모달 창 처리 규칙", - "closeMethods": [ - { - "priority": 1, - "method": "완료 버튼", - "selector": "button:has-text('확인'), button:has-text('등록'), button:has-text('저장')" - }, - { - "priority": 2, - "method": "취소 버튼", - "selector": "button:has-text('취소'), [class*='cancel']" - }, - { - "priority": 3, - "method": "X 버튼", - "selector": "button[class*='close'], [aria-label='닫기'], [aria-label='Close']" - }, - { - "priority": 4, - "method": "ESC 키", - "action": "press_key", - "value": "Escape" - }, - { - "priority": 5, - "method": "외부 클릭", - "selector": "[class*='backdrop'], [class*='overlay']" - } - ], - "deleteDialogSelector": "[role='alertdialog'] button:has-text('삭제')", - "note": "삭제 확인 다이얼로그는 Playwright 네이티브 셀렉터 사용 필수 (JavaScript click 미동작)", - "rule": "모달이 열린 상태로 다음 단계 진행 금지" - }, "testData": { - "newPost": { - "title": "E2E테스트_삭제용_", - "content": "이 게시글은 E2E 테스트용으로 생성되었습니다. 테스트 완료 후 자동 삭제됩니다." + "create": { + "title": "E2E테스트_삭제용_{timestamp}", + "content": "이 게시글은 E2E 테스트용으로 생성되었습니다." }, - "updateData": { - "title": "E2E테스트_수정완료_" - }, - "uniqueIdentifier": "timestamp를 붙여서 고유성 보장 (MMDDHHmmss)" + "update": { + "title": "E2E테스트_수정완료_{timestamp}" + } }, "steps": [ { - "id": "step-0", - "name": "사이드바 메뉴 탐색", - "description": "게시판 > 자유게시판 메뉴로 이동", - "actions": [ - { - "type": "scroll", - "target": "sidebar", - "direction": "top", - "description": "사이드바 상단으로 스크롤" - }, - { - "type": "wait", - "duration": 300 - }, - { - "type": "click_if_exists", - "target": "게시판", - "description": "1차 메뉴 클릭" - }, - { - "type": "wait", - "duration": 500 - }, - { - "type": "click_if_exists", - "target": "자유게시판", - "description": "2차 메뉴 클릭" - }, - { - "type": "wait", - "duration": 2000 - } - ], - "expect": { - "url": "/ko/boards/free", - "no404": true + "id": 1, + "name": "메뉴 진입: 게시판 > 자유게시판", + "action": "menu_navigate", + "level1": "게시판", + "level2": "자유게시판", + "expected": { + "url_contains": "/boards/free", + "visible": ["자유게시판"] } }, { - "id": "step-1", + "id": 2, "phase": "CREATE", - "name": "[CREATE] 초기 상태 확인", - "description": "등록 전 게시글 수 확인", - "actions": [ - { - "type": "capture", - "variable": "initialRowCount", - "selector": "table tbody tr", - "extract": "count", - "description": "등록 전 행 수 저장" - }, - { - "type": "wait", - "duration": 500 - } - ], - "expect": { - "tableExists": true - } + "name": "[CREATE] 글쓰기 버튼 클릭", + "action": "click_if_exists", + "target": "button:has-text('글쓰기'), button:has-text('등록'), button:has-text('작성')" }, { - "id": "step-2", + "id": 3, "phase": "CREATE", - "name": "[CREATE] 등록 버튼 클릭", - "description": "새 게시글을 등록하기 위해 등록 버튼 클릭", - "actions": [ - { - "type": "click_if_exists", - "target": "button:has-text('등록')", - "description": "등록 버튼 클릭" - }, - { - "type": "wait", - "duration": 1500 - } - ], - "expect": { - "url": "/ko/boards/free/new", - "pageTitle": "게시글 작성" - } + "name": "[CREATE] 작성 페이지 대기", + "action": "wait", + "duration": 2000 }, { - "id": "step-3", + "id": 4, "phase": "CREATE", - "name": "[CREATE] 게시글 정보 입력", - "description": "테스트용 게시글 정보 입력 (타임스탬프로 고유성 보장)", - "actions": [ - { - "type": "generateTimestamp", - "variable": "testTimestamp", - "format": "MMDDHHmmss" - }, - { - "type": "fill", - "target": "input[name='title'], input[placeholder*='제목']", - "value": "E2E테스트_삭제용_{testTimestamp}", - "description": "고유한 제목 입력" - }, - { - "type": "click_if_exists", - "target": "textarea, [class*='editor'], [contenteditable='true']", - "value": "E2E 테스트용 게시글입니다. 자동 삭제 예정.", - "description": "본문 입력" - } - ], - "note": "타임스탬프를 사용하여 매 테스트마다 고유한 데이터 생성" + "name": "[CREATE] 제목 입력", + "action": "fill", + "target": "input#title, input[name='title'], input[placeholder*='제목']", + "value": "E2E테스트_삭제용_{timestamp}", + "clear": true }, { - "id": "step-4", + "id": 5, "phase": "CREATE", - "name": "[CREATE] 등록 실행", - "description": "입력된 정보로 게시글 등록 실행", - "actions": [ - { - "type": "click_if_exists", - "target": "button:has-text('등록')", - "description": "등록 버튼 클릭" - }, - { - "type": "wait", - "duration": 2000 - } - ], - "expect": { - "toast": "등록|완료|성공", - "redirect": "/ko/boards/free" + "name": "[CREATE] 내용 입력", + "action": "fill", + "target": "textarea#content, textarea[name='content'], [contenteditable='true']", + "value": "이 게시글은 E2E 테스트용으로 생성되었습니다.", + "clear": true + }, + { + "id": 6, + "phase": "CREATE", + "name": "[CREATE] 필수 검증 #2: 게시글 등록", + "action": "click_if_exists", + "target": "button:has-text('등록'), button[type='submit']", + "verify": { + "no_error_page": true, + "toast": "등록|완료|성공" }, - "verification": { - "level": 4, - "checks": [ - "성공 토스트 표시", - "목록 페이지로 이동" - ] - } + "expected": "게시글 등록 완료" }, { - "id": "step-5", + "id": 7, + "phase": "CREATE", + "name": "[CREATE] 등록 후 대기", + "action": "wait", + "duration": 2000 + }, + { + "id": 8, "phase": "CREATE", "name": "[CREATE] 등록 결과 확인", - "description": "테이블에 새로 등록한 게시글이 표시되는지 확인", - "actions": [ - { - "type": "wait", - "duration": 1000 - }, - { - "type": "capture", - "variable": "afterCreateCount", - "selector": "table tbody tr", - "extract": "count" - }, - { - "type": "verify", - "condition": "afterCreateCount > initialRowCount", - "description": "행 수 증가 확인" - } + "action": "verify_detail", + "checks": [ + "E2E테스트_삭제용 제목 표시" ], - "expect": { - "rowCountIncreased": true, - "rowContains": "E2E테스트_삭제용" - }, - "verification": { - "level": 4, - "description": "생성된 데이터가 목록에 표시되어야 함" - } + "expected": "게시글 등록 확인" }, { - "id": "step-6", - "phase": "UPDATE", - "name": "[UPDATE] 생성된 게시글 상세 페이지 진입", - "description": "생성한 테스트 게시글의 상세 페이지로 이동", - "actions": [ - { - "type": "click_if_exists", - "target": "table tbody tr:first-child td:nth-child(2)", - "description": "첫 번째 행 (방금 생성한 게시글) 클릭" - }, - { - "type": "wait", - "duration": 2000 - } - ], - "expect": { - "url": "/ko/boards/free/", - "pageContains": "E2E테스트_삭제용" - } - }, - { - "id": "step-7", + "id": 9, "phase": "UPDATE", "name": "[UPDATE] 수정 버튼 클릭", - "description": "수정 버튼을 클릭하여 편집 모드로 전환", - "actions": [ - { - "type": "click_if_exists", - "target": "button:has-text('수정')", - "description": "수정 버튼 클릭" - }, - { - "type": "wait", - "duration": 1500 - } - ], - "expect": { - "url": "/edit", - "fieldsEditable": true - } + "action": "click_if_exists", + "target": "button:has-text('수정')" }, { - "id": "step-8", + "id": 10, + "phase": "UPDATE", + "name": "[UPDATE] 수정 페이지 대기", + "action": "wait", + "duration": 1500 + }, + { + "id": 11, "phase": "UPDATE", "name": "[UPDATE] 제목 수정", - "description": "게시글 제목을 수정하여 UPDATE 동작 확인", - "actions": [ - { - "type": "clear", - "target": "input[name='title'], input[placeholder*='제목']", - "description": "기존 제목 삭제" - }, - { - "type": "fill", - "target": "input[name='title'], input[placeholder*='제목']", - "value": "E2E테스트_수정완료_{testTimestamp}", - "description": "수정된 제목 입력" - } - ] + "action": "fill", + "target": "input#title, input[name='title'], input[placeholder*='제목']", + "value": "E2E테스트_수정완료_{timestamp}", + "clear": true }, { - "id": "step-9", + "id": 12, "phase": "UPDATE", "name": "[UPDATE] 수정 저장", - "description": "수정된 내용 저장", - "actions": [ - { - "type": "click_if_exists", - "target": "button:has-text('수정')", - "description": "수정 버튼 클릭" - }, - { - "type": "wait", - "duration": 2000 - } - ], - "expect": { - "toast": "수정|완료|성공", - "redirect": "/ko/boards/free/" + "action": "click_if_exists", + "target": "button:has-text('저장'), button:has-text('수정'), button[type='submit']", + "verify": { + "toast": "수정|저장|완료|성공" }, - "verification": { - "level": 4, - "description": "수정 성공 토스트 확인" - } + "expected": "수정 완료" }, { - "id": "step-10", + "id": 13, "phase": "UPDATE", - "name": "[UPDATE] 수정 결과 확인", - "description": "수정된 내용이 반영되었는지 확인", - "actions": [ - { - "type": "wait", - "duration": 1000 - }, - { - "type": "verify", - "target": "page", - "contains": "E2E테스트_수정완료", - "description": "수정된 제목 표시 확인" - } - ], - "expect": { - "contains": "E2E테스트_수정완료" - } + "name": "[UPDATE] 수정 후 대기", + "action": "wait", + "duration": 2000 }, { - "id": "step-11", + "id": 14, "phase": "DELETE", "name": "[DELETE] 삭제 버튼 클릭", - "description": "테스트용으로 생성한 게시글 삭제 시작", - "actions": [ - { - "type": "click_if_exists", - "target": "button:has-text('삭제')", - "description": "삭제 버튼 클릭" - }, - { - "type": "wait", - "duration": 500 - } - ], - "expect": { - "confirmDialog": true, - "dialogRole": "alertdialog" - }, - "warning": "이 단계에서 삭제 확인 다이얼로그가 표시되어야 함" - }, - { - "id": "step-12", - "phase": "DELETE", - "name": "[DELETE] 삭제 확인", - "description": "삭제 확인 다이얼로그에서 삭제 버튼 클릭", - "actions": [ - { - "type": "click_if_exists", - "target": "[role='alertdialog'] button:has-text('삭제')", - "usePlaywrightNative": true, - "description": "삭제 확인 클릭 (Playwright 네이티브 셀렉터 필수)" - }, - { - "type": "wait", - "duration": 2000 - } - ], - "expect": { - "toast": "삭제|완료|성공", - "redirect": "/ko/boards/free" - }, - "verification": { - "level": 4, - "checks": [ - "성공 토스트", - "목록 페이지로 리다이렉트" - ] - }, - "note": "JavaScript click()은 동작하지 않음. Playwright playwright_click 사용 필수" - }, - { - "id": "step-13", - "phase": "VERIFY", - "name": "[VERIFY] 삭제 결과 확인", - "description": "삭제된 게시글이 목록에서 제거되었는지 확인", - "actions": [ - { - "type": "wait", - "duration": 1000 - }, - { - "type": "verifyUrl", - "contains": "/ko/boards/free", - "description": "목록 페이지 확인" - }, - { - "type": "capture", - "variable": "afterDeleteCount", - "selector": "table tbody tr", - "extract": "count" - } - ], - "expect": { - "rowCountDecreased": true, - "condition": "afterDeleteCount === initialRowCount" - }, - "verification": { - "level": 4, - "description": "행 수가 원래대로 복구되어야 함" + "action": "click_if_exists", + "target": "button:has-text('삭제')", + "expected": { + "confirm_dialog": true } }, { - "id": "step-14", - "phase": "VERIFY", - "name": "[VERIFY] 최종 검증", - "description": "테스트 데이터가 완전히 삭제되었는지 확인", - "actions": [ - { - "type": "verify", - "target": "table", - "notContains": "E2E테스트_수정완료", - "description": "삭제된 게시글이 목록에 없음 확인" - } - ], - "expect": { - "testDataDeleted": true, - "noTestDataInList": true + "id": 15, + "phase": "DELETE", + "name": "[DELETE] 필수 검증 #6: 삭제 확인", + "action": "click_and_confirm", + "target": "button:has-text('확인'), button:has-text('삭제'), [role='alertdialog'] button:has-text('삭제')", + "verify": { + "toast": "삭제|완료|성공", + "redirect": "/boards/free" }, - "verification": { - "level": 4, - "description": "테스트 데이터가 완전히 삭제되어 목록에 표시되지 않아야 함" + "expected": "삭제 완료 및 목록 복귀" + }, + { + "id": 16, + "phase": "DELETE", + "name": "[DELETE] 삭제 후 대기", + "action": "wait", + "duration": 2000 + }, + { + "id": 17, + "phase": "DELETE", + "name": "[DELETE] 삭제 결과 확인", + "action": "verify_detail", + "search": "E2E테스트_수정완료", + "expected": { + "row_exists": false, + "message": "테스트 게시글이 목록에서 제거됨" } } ], "expectedAPIs": [ { - "phase": "CREATE", "method": "POST", - "endpoint": "/api/v1/free-board", + "endpoint": "/api/v1/boards/free/posts", "description": "게시글 등록" }, { - "phase": "UPDATE", "method": "PUT", - "endpoint": "/api/v1/free-board/{id}", + "endpoint": "/api/v1/boards/free/posts/{id}", "description": "게시글 수정" }, { - "phase": "DELETE", "method": "DELETE", - "endpoint": "/api/v1/free-board/{id}", + "endpoint": "/api/v1/boards/free/posts/{id}", "description": "게시글 삭제" } ], "requiredVerifications": [ - { - "id": 1, - "name": "CREATE - 등록 기능", - "steps": [ - "step-2", - "step-3", - "step-4", - "step-5" - ], - "criteria": "게시글 생성 + 목록에 표시" - }, { "id": 2, - "name": "UPDATE - 수정 기능", - "steps": [ - "step-7", - "step-8", - "step-9", - "step-10" - ], - "criteria": "게시글 수정 + 변경 내용 반영" + "name": "등록/저장 버튼", + "steps": [6, 12], + "criteria": "API 호출 + 성공 토스트 + 데이터 반영" }, { - "id": 3, - "name": "DELETE - 삭제 기능", - "steps": [ - "step-11", - "step-12", - "step-13", - "step-14" - ], - "criteria": "게시글 삭제 + 목록에서 제거" - } - ], - "knownIssues": [ - { - "issue": "삭제 확인 다이얼로그 JavaScript click 미동작", - "description": "JavaScript의 element.click() 또는 dispatchEvent로는 삭제가 실행되지 않음", - "workaround": "Playwright의 playwright_click 도구와 [role='alertdialog'] button:has-text('삭제') 셀렉터 사용", - "testedOn": "2026-01-29" + "id": 6, + "name": "삭제 기능", + "steps": [14, 15, 17], + "criteria": "DELETE API + 목록에서 제거" } ], "rollbackPlan": { - "description": "테스트 실패 시 롤백 계획", - "onCreateFail": "영향 없음 - 다음 테스트 정상 진행", - "onUpdateFail": "테스트 데이터 수동 삭제 필요", - "onDeleteFail": "테스트 데이터 수동 삭제 필요", - "cleanupRequired": "E2E테스트_ 로 시작하는 게시글은 테스트 데이터이므로 수동 삭제 가능" + "onCreateFail": "영향 없음", + "onUpdateFail": "테스트 게시글 수동 삭제 필요", + "onDeleteFail": "테스트 게시글 수동 삭제 필요", + "cleanupRequired": "E2E테스트_ 접두사 게시글은 테스트 데이터" } -} \ No newline at end of file +} diff --git a/crud-delete-vendor.json b/crud-delete-vendor.json deleted file mode 100644 index 66a8e7d..0000000 --- a/crud-delete-vendor.json +++ /dev/null @@ -1,666 +0,0 @@ -{ - "id": "crud-delete-vendor", - "name": "거래처 CRUD 삭제 기능 테스트", - "status": "BLOCKED", - "blockedReason": "거래처관리 페이지에 등록 버튼이 없음 - CREATE 단계 불가", - "discoveredOn": "2026-01-29", - "alternative": "crud-delete-freeboard.json 사용 (자유게시판 CRUD 테스트)", - "screenshotPolicy": { - "onErrorOnly": true, - "captureOn": [ - "error", - "fail", - "timeout", - "404", - "500", - "blocked" - ] - }, - "description": "거래처관리에서 생성 → 수정 → 삭제 전체 CRUD 흐름 테스트. 테스트용 데이터를 생성하고, 수정한 후, 삭제하여 기존 데이터에 영향 없이 삭제 기능을 검증", - "baseUrl": "https://dev.codebridge-x.com", - "menuNavigation": { - "level1": "회계관리", - "level2": "거래처관리", - "expectedUrl": "/ko/accounting/vendors" - }, - "auth": { - "username": "TestUser5", - "password": "password123!" - }, - "testPolicy": { - "deleteAllowed": true, - "deleteCondition": "CRUD 흐름 내에서만 허용 (생성 → 수정 → 삭제)", - "protectExistingData": true, - "description": "이 시나리오에서 생성한 테스트 데이터만 삭제" - }, - "modalHandling": { - "description": "모달 창 처리 규칙", - "closeMethods": [ - { - "priority": 1, - "method": "완료 버튼", - "selector": "button:has-text('확인'), button:has-text('등록'), button:has-text('저장')" - }, - { - "priority": 2, - "method": "취소 버튼", - "selector": "button:has-text('취소'), [class*='cancel']" - }, - { - "priority": 3, - "method": "X 버튼", - "selector": "button[class*='close'], [aria-label='닫기'], [aria-label='Close']" - }, - { - "priority": 4, - "method": "ESC 키", - "action": "press_key", - "value": "Escape" - }, - { - "priority": 5, - "method": "외부 클릭", - "selector": "[class*='backdrop'], [class*='overlay']" - } - ], - "rule": "모달이 열린 상태로 다음 단계 진행 금지" - }, - "testData": { - "newVendor": { - "vendorName": "E2E테스트_삭제용_", - "businessNumber": "123-45-67890", - "representative": "테스트대표", - "vendorType": "매출", - "phone": "02-1234-5678", - "email": "test@e2etest.com", - "address": "서울시 테스트구 테스트동 123" - }, - "updateData": { - "vendorName": "E2E테스트_수정완료_", - "representative": "수정대표" - }, - "uniqueIdentifier": "timestamp를 붙여서 고유성 보장" - }, - "steps": [ - { - "id": "step-0", - "name": "사이드바 메뉴 탐색", - "description": "회계관리 > 거래처관리 메뉴로 이동", - "actions": [ - { - "type": "scroll", - "target": "sidebar", - "direction": "top" - }, - { - "type": "wait", - "duration": 300 - }, - { - "type": "click_if_exists", - "target": "회계관리", - "description": "1차 메뉴 클릭" - }, - { - "type": "wait", - "duration": 500 - }, - { - "type": "click_if_exists", - "target": "거래처관리", - "description": "2차 메뉴 클릭" - }, - { - "type": "wait", - "duration": 2000 - } - ], - "expect": { - "url": "/ko/accounting/vendors", - "no404": true - } - }, - { - "id": "step-1", - "phase": "CREATE", - "name": "📝 [CREATE] 거래처 등록 버튼 클릭", - "description": "새 거래처를 등록하기 위해 등록 버튼 클릭", - "actions": [ - { - "type": "capture", - "variable": "initialRowCount", - "selector": "table tbody tr", - "extract": "count", - "description": "등록 전 행 수 저장" - }, - { - "type": "click_if_exists", - "target": "button:has-text('등록'), button:has-text('추가'), [class*='add'], [class*='register']", - "description": "등록 버튼 클릭" - }, - { - "type": "wait", - "duration": 1000 - } - ], - "expect": { - "modal": true, - "modalTitle": "거래처 등록" - } - }, - { - "id": "step-2", - "phase": "CREATE", - "name": "📝 [CREATE] 등록 모달 - 필수 정보 입력", - "description": "테스트용 거래처 정보 입력 (타임스탬프로 고유성 보장)", - "actions": [ - { - "type": "generateTimestamp", - "variable": "testTimestamp", - "format": "MMDDHHmmss" - }, - { - "type": "click_if_exists", - "target": "거래처명", - "description": "거래처명 입력 필드 확인" - }, - { - "type": "click_if_exists", - "target": "사업자등록번호", - "description": "사업자번호 입력 필드 확인" - }, - { - "type": "click_if_exists", - "target": "대표자명", - "description": "대표자명 입력 필드 확인" - }, - { - "type": "click_if_exists", - "target": "거래처 유형", - "description": "거래처 유형 필드 확인" - }, - { - "type": "click_if_exists", - "target": "전화번호", - "description": "전화번호 입력 필드 확인" - }, - { - "type": "click_if_exists", - "target": "이메일", - "description": "이메일 입력 필드 확인" - } - ], - "note": "타임스탬프를 사용하여 매 테스트마다 고유한 데이터 생성" - }, - { - "id": "step-3", - "phase": "CREATE", - "name": "📝 [CREATE] 등록 모달 - 등록 버튼 클릭", - "description": "입력된 정보로 거래처 등록 실행", - "actions": [ - { - "type": "click_if_exists", - "target": "button:has-text('등록'), button:has-text('저장')", - "description": "모달 내 등록 버튼 클릭" - }, - { - "type": "wait", - "duration": 2000 - } - ], - "expect": { - "toast": "등록|완료|성공", - "modalClosed": true, - "apiCall": "POST /api/v1/clients" - }, - "verification": { - "level": 4, - "checks": [ - "API 호출 확인", - "성공 토스트 표시", - "모달 닫힘" - ] - } - }, - { - "id": "step-3-modal-close", - "phase": "CREATE", - "name": "📝 [CREATE] 모달 닫기 확인", - "description": "모달이 열려있으면 닫기 시도", - "condition": "modalStillOpen", - "actions": [ - { - "type": "click_if_exists", - "target": "[role='dialog'] button[class*='close'], [aria-label='닫기'], [aria-label='Close']", - "description": "모달 닫기 시도" - }, - { - "type": "wait", - "duration": 500 - } - ], - "expect": { - "modalClosed": true - } - }, - { - "id": "step-4", - "phase": "CREATE", - "name": "📝 [CREATE] 등록 결과 확인", - "description": "테이블에 새로 등록한 거래처가 표시되는지 확인", - "actions": [ - { - "type": "fill", - "target": "검색", - "value": "E2E테스트_삭제용", - "description": "생성한 거래처 검색" - }, - { - "type": "pressKey", - "key": "Enter" - }, - { - "type": "wait", - "duration": 1500 - }, - { - "type": "capture", - "variable": "createdVendorRow", - "selector": "table tbody tr", - "extract": "exists", - "description": "테스트 거래처 행 존재 여부 확인" - } - ], - "expect": { - "rowExists": true, - "rowContains": "E2E테스트_삭제용" - }, - "verification": { - "level": 4, - "description": "생성된 데이터가 목록에 표시되어야 함" - } - }, - { - "id": "step-5", - "phase": "UPDATE", - "name": "✏️ [UPDATE] 생성된 거래처 상세 페이지 진입", - "description": "생성한 테스트 거래처의 상세 페이지로 이동", - "actions": [ - { - "type": "click_if_exists", - "target": "table tbody tr", - "description": "첫 번째 거래처 행 클릭" - }, - { - "type": "wait", - "duration": 2000 - } - ], - "expect": { - "url": "/ko/accounting/vendors/", - "pageTitle": "거래처 상세" - } - }, - { - "id": "step-6", - "phase": "UPDATE", - "name": "✏️ [UPDATE] 수정 모드 진입", - "description": "수정 버튼을 클릭하여 편집 모드로 전환", - "actions": [ - { - "type": "click_if_exists", - "target": "button:has-text('수정')", - "description": "수정 버튼 클릭" - }, - { - "type": "wait", - "duration": 1000 - } - ], - "expect": { - "url": "mode=edit", - "fieldsEditable": true - } - }, - { - "id": "step-7", - "phase": "UPDATE", - "name": "✏️ [UPDATE] 거래처명 수정", - "description": "거래처명을 수정하여 UPDATE 동작 확인", - "actions": [ - { - "type": "clear", - "target": "거래처명", - "description": "기존 값 삭제" - }, - { - "type": "fill", - "target": "거래처명", - "value": "E2E테스트_수정완료_{testTimestamp}", - "description": "수정된 거래처명 입력" - }, - { - "type": "fill", - "target": "대표자명", - "value": "수정대표", - "description": "대표자명 수정" - } - ] - }, - { - "id": "step-8", - "phase": "UPDATE", - "name": "✏️ [UPDATE] 수정 저장", - "description": "수정된 내용 저장", - "actions": [ - { - "type": "click_if_exists", - "target": "button:has-text('저장')", - "description": "저장 버튼 클릭" - }, - { - "type": "wait", - "duration": 500 - }, - { - "type": "click_if_exists", - "target": "button:has-text('확인')", - "description": "저장 확인 다이얼로그" - }, - { - "type": "wait", - "duration": 2000 - } - ], - "expect": { - "toast": "수정|완료|성공", - "apiCall": "PUT /api/v1/clients/" - }, - "verification": { - "level": 4, - "description": "수정 API 호출 및 성공 토스트 확인" - } - }, - { - "id": "step-8-modal-close", - "phase": "UPDATE", - "name": "✏️ [UPDATE] 다이얼로그 닫기 확인", - "description": "다이얼로그가 열려있으면 닫기", - "condition": "dialogStillOpen", - "actions": [ - { - "type": "click_if_exists", - "target": "[role='dialog'] button[class*='close'], [aria-label='닫기'], [aria-label='Close']", - "description": "다이얼로그 닫기 시도" - } - ] - }, - { - "id": "step-9", - "phase": "UPDATE", - "name": "✏️ [UPDATE] 수정 결과 확인", - "description": "수정된 내용이 반영되었는지 확인", - "actions": [ - { - "type": "wait", - "duration": 1000 - }, - { - "type": "capture", - "variable": "updatedVendorName", - "selector": "[class*='vendor-name'], h1, h2", - "extract": "text" - } - ], - "expect": { - "contains": "E2E테스트_수정완료" - } - }, - { - "id": "step-10", - "phase": "DELETE", - "name": "🗑️ [DELETE] 삭제 버튼 클릭", - "description": "테스트용으로 생성한 거래처 삭제 시작", - "actions": [ - { - "type": "click_if_exists", - "target": "button:has-text('삭제')", - "description": "삭제 버튼 클릭" - }, - { - "type": "wait", - "duration": 500 - } - ], - "expect": { - "confirmDialog": true, - "dialogMessage": "삭제|정말|확인" - }, - "warning": "이 단계에서 삭제 확인 다이얼로그가 표시되어야 함" - }, - { - "id": "step-11", - "phase": "DELETE", - "name": "🗑️ [DELETE] 삭제 확인 다이얼로그 검증", - "description": "삭제 확인 다이얼로그 UI 요소 확인", - "actions": [ - { - "type": "verify", - "target": "dialog", - "checks": [ - "삭제 확인 메시지", - "취소 버튼", - "확인/삭제 버튼" - ] - } - ], - "expect": { - "dialogElements": [ - "취소", - "확인|삭제" - ] - } - }, - { - "id": "step-12", - "phase": "DELETE", - "name": "🗑️ [DELETE] 삭제 확인 버튼 클릭", - "description": "삭제를 최종 확인하여 실행", - "actions": [ - { - "type": "click_if_exists", - "target": "button:has-text('확인'), button:has-text('삭제')", - "description": "삭제 확인 클릭" - }, - { - "type": "wait", - "duration": 2000 - } - ], - "expect": { - "toast": "삭제|완료|성공", - "apiCall": "DELETE /api/v1/clients/", - "redirect": "/ko/accounting/vendors" - }, - "verification": { - "level": 4, - "checks": [ - "DELETE API 호출", - "성공 토스트", - "목록 페이지로 리다이렉트" - ] - } - }, - { - "id": "step-12-modal-close", - "phase": "DELETE", - "name": "🗑️ [DELETE] 다이얼로그 닫기 확인", - "description": "다이얼로그가 열려있으면 닫기", - "condition": "dialogStillOpen", - "actions": [ - { - "type": "click_if_exists", - "target": "[role='dialog'] button[class*='close'], [aria-label='닫기'], [aria-label='Close']", - "description": "다이얼로그 닫기 시도" - } - ] - }, - { - "id": "step-13", - "phase": "VERIFY", - "name": "✅ [VERIFY] 삭제 결과 확인 - 목록 페이지", - "description": "삭제된 거래처가 목록에서 제거되었는지 확인", - "actions": [ - { - "type": "wait", - "duration": 1000 - }, - { - "type": "verifyUrl", - "contains": "/ko/accounting/vendors", - "description": "목록 페이지 확인" - }, - { - "type": "fill", - "target": "검색", - "value": "E2E테스트_수정완료", - "description": "삭제된 거래처 검색" - }, - { - "type": "pressKey", - "key": "Enter" - }, - { - "type": "wait", - "duration": 1500 - } - ], - "expect": { - "noResults": true, - "rowNotExists": "E2E테스트_수정완료" - } - }, - { - "id": "step-14", - "phase": "VERIFY", - "name": "✅ [VERIFY] 최종 검증 - 데이터 삭제 확인", - "description": "검색 결과에서 테스트 데이터가 없음을 최종 확인", - "actions": [ - { - "type": "capture", - "variable": "searchResultCount", - "selector": "table tbody tr", - "extract": "count" - }, - { - "type": "verify", - "condition": "searchResultCount === 0 OR no row contains 'E2E테스트'" - } - ], - "expect": { - "testDataDeleted": true, - "noTestDataInList": true - }, - "verification": { - "level": 4, - "description": "테스트 데이터가 완전히 삭제되어 검색되지 않아야 함" - } - }, - { - "id": "step-15", - "phase": "CLEANUP", - "name": "🧹 [CLEANUP] 검색 초기화", - "description": "테스트 종료 후 검색어 삭제하여 원래 상태로 복원", - "actions": [ - { - "type": "clear", - "target": "검색" - }, - { - "type": "pressKey", - "key": "Enter" - }, - { - "type": "wait", - "duration": 1000 - } - ], - "expect": { - "originalListRestored": true - } - } - ], - "expectedAPIs": [ - { - "phase": "CREATE", - "method": "POST", - "endpoint": "/api/v1/clients", - "description": "거래처 등록" - }, - { - "phase": "UPDATE", - "method": "PUT", - "endpoint": "/api/v1/clients/{id}", - "description": "거래처 수정" - }, - { - "phase": "DELETE", - "method": "DELETE", - "endpoint": "/api/v1/clients/{id}", - "description": "거래처 삭제" - } - ], - "requiredVerifications": [ - { - "id": 1, - "name": "CREATE - 등록 기능", - "steps": [ - "step-1", - "step-2", - "step-3", - "step-4" - ], - "criteria": "POST API 호출 + 성공 토스트 + 목록에 데이터 표시" - }, - { - "id": 2, - "name": "UPDATE - 수정 기능", - "steps": [ - "step-6", - "step-7", - "step-8", - "step-9" - ], - "criteria": "PUT API 호출 + 성공 토스트 + 데이터 변경 반영" - }, - { - "id": 3, - "name": "DELETE - 삭제 기능", - "steps": [ - "step-10", - "step-11", - "step-12", - "step-13", - "step-14" - ], - "criteria": "DELETE API 호출 + 성공 토스트 + 목록에서 데이터 제거" - }, - { - "id": 4, - "name": "모달/다이얼로그 닫기", - "steps": [ - "step-3-modal-close", - "step-8-modal-close", - "step-12-modal-close" - ], - "criteria": "모든 모달/다이얼로그가 정상적으로 닫혀야 함" - } - ], - "rollbackPlan": { - "description": "테스트 실패 시 롤백 계획", - "onCreateFail": "모달 닫기 → 다음 테스트 영향 없음", - "onUpdateFail": "테스트 데이터 수동 삭제 필요 (DB 또는 UI)", - "onDeleteFail": "테스트 데이터 수동 삭제 필요", - "cleanupRequired": "E2E테스트_ 로 시작하는 거래처는 테스트 데이터이므로 수동 삭제 가능" - } -} diff --git a/customer-inquiry.json b/customer-inquiry.json index 071137b..fcea7aa 100644 --- a/customer-inquiry.json +++ b/customer-inquiry.json @@ -10,7 +10,7 @@ "menuNavigation": { "level1": "고객센터", "level2": "1:1 문의", - "expectedUrl": "/customer-center/inquiry", + "expectedUrl": "/customer-center/qna", "searchWithinParent": true, "closeOtherMenus": true }, diff --git a/customer-notice.json b/customer-notice.json index fc709db..c94c686 100644 --- a/customer-notice.json +++ b/customer-notice.json @@ -10,7 +10,7 @@ "menuNavigation": { "level1": "고객센터", "level2": "공지사항", - "expectedUrl": "/support/notice", + "expectedUrl": "/customer-center/notices", "searchWithinParent": true, "closeOtherMenus": true }, @@ -26,7 +26,7 @@ "level1": "고객센터", "level2": "공지사항", "expected": { - "url_contains": "/support", + "url_contains": "/customer-center/notices", "visible": ["공지사항"] } }, @@ -172,12 +172,12 @@ "expectedAPIs": [ { "method": "GET", - "endpoint": "/api/v1/support/notices", + "endpoint": "/api/v1/customer-center/noticess", "description": "공지사항 목록 조회" }, { "method": "GET", - "endpoint": "/api/v1/support/notices/:id", + "endpoint": "/api/v1/customer-center/noticess/:id", "description": "공지사항 상세 조회" } ], diff --git a/department-add.json b/department-add.json index 77c90c6..76a0c08 100644 --- a/department-add.json +++ b/department-add.json @@ -1,464 +1,183 @@ { + "enabled": true, "id": "department-add", - "name": "부서 추가 테스트 (랜덤 + 하위부서)", + "name": "부서 추가 테스트", "screenshotPolicy": { "onErrorOnly": true, "captureOn": ["error", "fail", "timeout", "404", "500", "blocked"] }, - "description": "랜덤 상위 부서 생성 후 하위 부서까지 추가하는 고도화된 E2E 테스트", + "description": "인사관리 > 부서관리 메뉴에서 부서 추가/수정/삭제 CRUD 테스트", "baseUrl": "https://dev.codebridge-x.com", - "url": "/ko/hr/department-management", - "navigation": { - "targetUrl": "/hr/department-management", - "urlPattern": "/hr/department-management|/ko/hr/department-management", - "menuHints": ["부서관리", "부서 관리", "인사관리"] - }, "menuNavigation": { "level1": "인사관리", "level2": "부서관리", - "expectedUrl": "/ko/hr/department-management", + "expectedUrl": "/hr/department-management", "searchWithinParent": true, "closeOtherMenus": true }, - "menuNavigationEnhanced": { - "strategy": "scroll-and-search", - "scrollContainer": ".sidebar-scroll, [data-sidebar], nav, aside", - "scrollStep": 200, - "maxScrollAttempts": 10, - "waitAfterScroll": 300, - "level1": { - "text": "인사관리", - "fallbackSelectors": [ - "text=인사관리", - "[data-menu='hr']", - "a:has-text('인사관리')", - "button:has-text('인사관리')" - ] - }, - "level2": { - "text": "부서관리", - "fallbackSelectors": [ - "text=부서관리", - "[data-menu='department']", - "a:has-text('부서관리')", - "button:has-text('부서관리')" - ] - }, - "expectedUrl": "/ko/hr/department-management", - "fallbackUrl": "https://dev.codebridge-x.com/ko/hr/department-management" - }, - "timeout": 90000, - "tags": ["hr", "department", "crud", "random", "hierarchy"], - "auth": { "username": "TestUser5", "password": "password123!" }, - - "randomData": { - "parentDepartment": { - "type": "composite", - "pattern": "{prefix}본부_{timestamp}", - "components": { - "prefix": { - "type": "random", - "options": ["신규", "테스트", "개발", "QA", "운영", "전략", "혁신", "글로벌"] - } - } - }, - "childDepartment": { - "type": "composite", - "pattern": "{prefix}팀_{timestamp}", - "components": { - "prefix": { - "type": "random", - "options": ["기획", "개발", "디자인", "마케팅", "영업", "지원", "품질", "연구"] - } - } + "testData": { + "create": { + "departmentName": "E2E_TEST_본부_{timestamp}", + "childName": "E2E_TEST_팀_{timestamp}" } }, - "steps": [ { - "id": "step-0", - "name": "사이드바 메뉴 전체 펼치기", - "description": "모두 펼치기 버튼을 클릭하여 전체 메뉴를 펼친 후 메뉴 탐색 준비", - "actions": [ - { - "type": "evaluate", - "script": "document.querySelector('.sidebar-scroll, [data-sidebar], nav, aside')?.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": "메뉴 진입: 인사관리 > 부서관리", + "action": "menu_navigate", + "level1": "인사관리", + "level2": "부서관리", + "expected": { + "url_contains": "/hr/department-management", + "visible": ["부서관리"] + } + }, + { + "id": 2, + "name": "필수 검증 #5: 목업 페이지 감지", + "action": "verify_not_mockup", + "checks": [ + "부서 목록 또는 트리 표시", + "부서 추가 버튼 존재" ], - "expect": { - "sidebarReady": true - } + "expected": "정상 페이지 (목업 아님)" }, { - "id": "step-1", - "name": "인사관리 메뉴 진입", - "description": "인사관리 > 부서관리 메뉴로 이동 (scrollAndFind 패턴 사용)", - "navigationPattern": "scrollAndFind", - "actions": [ - { - "type": "scrollAndFind", - "container": ".sidebar-scroll, [data-sidebar], nav, aside", - "target": "인사관리", - "scrollStep": 200, - "maxAttempts": 10, - "waitAfterScroll": 300 - }, - { "type": "click_if_exists", "target": "인사관리" }, - { "type": "wait", "duration": 500 }, - { - "type": "scrollAndFind", - "container": ".sidebar-scroll, [data-sidebar], nav, aside", - "target": "부서관리", - "scrollStep": 200, - "maxAttempts": 10, - "waitAfterScroll": 300 - }, - { "type": "click_if_exists", "target": "부서관리" } + "id": 3, + "name": "페이지 요소 확인", + "action": "verify_element", + "checks": [ + "부서 목록 또는 트리 구조 표시", + "추가 버튼 존재" ], - "fallback": { - "type": "navigate", - "url": "https://dev.codebridge-x.com/ko/hr/department-management" - }, - "expect": { - "url": "/hr/department-management", - "visible": ["부서관리", "추가"] + "expected": "부서관리 페이지 정상 표시" + }, + { + "id": 4, + "phase": "CREATE", + "name": "[CREATE] 부서 추가 버튼 클릭", + "action": "click_if_exists", + "target": "button:has-text('추가'), button:has-text('등록'), button:has-text('부서 추가')", + "expected": { + "modal": true } }, { - "id": "step-2", - "name": "현재 부서 개수 저장", - "description": "테스트 전 부서 개수 기록", - "capture": { - "variable": "initialCount", - "selector": "총 *건", - "extract": "number" - } + "id": 5, + "phase": "CREATE", + "name": "[CREATE] 부서명 입력", + "action": "fill", + "target": "input[name*='name'], input[placeholder*='부서명'], [role='dialog'] input", + "value": "E2E_TEST_본부_{timestamp}", + "clear": true }, { - "id": "step-3", - "name": "상위 부서 추가 모달 열기", - "description": "추가 버튼 클릭하여 부서 추가 모달 열기", - "actions": [ - { "type": "click_if_exists", "target": "추가", "description": "부서 추가 모달 열기" } - ], - "modalConfig": { - "containerSelector": "[role='dialog'], .modal", - "animationDelay": 300, - "waitForSelector": "[role='dialog']" - }, - "expect": { - "modal": "부서 추가", - "visible": ["부서명", "등록", "취소"] - } - }, - { - "id": "step-4", - "name": "랜덤 상위 부서명 입력", - "description": "모달 내 부서명 입력", - "actions": [ - { - "type": "fillInModal", - "target": "부서명", - "value": "{randomData.parentDepartment}", - "options": { "waitAfter": 100 } - } - ], - "expect": { - "buttonEnabled": "등록" - } - }, - { - "id": "step-5", - "name": "상위 부서 등록", - "description": "모달 내 등록 버튼 클릭하여 상위 부서 추가 완료", - "actions": [ - { "type": "click_if_exists", "target": "등록", "options": { "waitAfter": 500 } } - ], - "waitFor": { - "type": "modalClose", - "timeout": 5000 - }, - "expect": { - "toast": ["등록", "완료", "성공"], - "visible": ["{randomData.parentDepartment}"] - } - }, - { - "id": "step-6", - "name": "상위 부서 등록 확인", - "description": "목록에서 새로 추가된 상위 부서 확인", + "id": 6, + "phase": "CREATE", + "name": "[CREATE] 필수 검증 #2: 부서 등록", + "action": "click_if_exists", + "target": "button:has-text('등록'), button:has-text('저장'), button:has-text('확인')", "verify": { - "listContains": "{randomData.parentDepartment}", - "countIncreased": "{initialCount} + 1" - } - }, - { - "id": "step-7", - "name": "하위 부서 추가 버튼 클릭", - "description": "생성된 상위 부서의 '하위 부서 추가' 버튼 클릭", - "actions": [ - { - "type": "click_if_exists", - "target": "하위 부서 추가" - } - ], - "expect": { - "modal": "하위 부서 추가", - "visible": ["부서명", "상위 부서", "{randomData.parentDepartment}"] - } - }, - { - "id": "step-8", - "name": "랜덤 하위 부서명 입력", - "description": "모달 내 하위 부서명 입력", - "actions": [ - { - "type": "fillInModal", - "target": "부서명", - "value": "{randomData.childDepartment}", - "options": { "waitAfter": 100 } - } - ], - "expect": { - "buttonEnabled": "등록" - } - }, - { - "id": "step-9", - "name": "하위 부서 등록", - "description": "모달 내 등록 버튼 클릭하여 하위 부서 추가 완료", - "actions": [ - { "type": "click_if_exists", "target": "등록", "options": { "waitAfter": 500 } } - ], - "waitFor": { - "type": "modalClose", - "timeout": 5000 + "toast": "등록|완료|성공" }, - "expect": { - "toast": ["등록", "완료", "성공"], - "visible": ["{randomData.childDepartment}"] + "expected": "부서 등록 완료" + }, + { + "id": "6-modal-close", + "phase": "CREATE", + "name": "[CREATE] 모달 닫기 확인", + "action": "close_modal_if_open", + "expected": "모달 닫힘" + }, + { + "id": 7, + "phase": "CREATE", + "name": "[CREATE] 등록 결과 확인", + "action": "verify_detail", + "checks": [ + "E2E_TEST_본부 목록에 표시" + ], + "expected": "부서 등록 확인" + }, + { + "id": 8, + "phase": "DELETE", + "name": "[DELETE] 부서 삭제 버튼 클릭", + "action": "click_if_exists", + "target": "button:has-text('삭제'), [aria-label='삭제']", + "expected": { + "confirm_dialog": true } }, { - "id": "step-10", - "name": "계층 구조 확인", - "description": "상위 부서 확장하여 하위 부서가 트리 구조로 표시되는지 확인", - "actions": [ - { - "type": "click_if_exists", - "target": "table tbody tr:first-child [class*='expand'], table tbody tr:first-child button" - } - ], + "id": 9, + "phase": "DELETE", + "name": "[DELETE] 필수 검증 #6: 삭제 확인", + "action": "click_and_confirm", + "target": "button:has-text('확인'), button:has-text('삭제')", "verify": { - "hierarchy": { - "parent": "{randomData.parentDepartment}", - "children": ["{randomData.childDepartment}"] - }, - "totalCountIncreased": "{initialCount} + 2" - } - }, - { - "id": "step-11", - "name": "하위 부서 수정 모달 열기", - "description": "하위 부서의 수정 버튼 클릭", - "actions": [ - { - "type": "click_if_exists", - "target": "수정" - } - ], - "expect": { - "modal": "부서 수정", - "visible": ["부서명", "상위 부서", "저장", "취소"] - } - }, - { - "id": "step-12", - "name": "하위 부서명 수정", - "description": "모달 내 하위 부서명 변경", - "actions": [ - { - "type": "fillInModal", - "target": "부서명", - "value": "{randomData.childDepartment}_수정됨", - "options": { "waitAfter": 100 } - } - ], - "expect": { - "buttonEnabled": "저장" - } - }, - { - "id": "step-13", - "name": "부서 수정 저장", - "description": "모달 내 저장 버튼 클릭하여 부서 수정 완료", - "actions": [ - { "type": "click_if_exists", "target": "저장", "options": { "waitAfter": 500 } } - ], - "waitFor": { - "type": "modalClose", - "timeout": 5000 + "toast": "삭제|완료|성공" }, - "expect": { - "toast": ["수정", "완료", "성공", "저장"], - "visible": ["{randomData.childDepartment}_수정됨"] - } + "expected": "부서 삭제 완료" }, { - "id": "step-13-1", - "name": "⚠️ 필수 검증: 수정 데이터 반영 확인", - "note": "토스트 성공 메시지만으로 PASS 판정 불가. 실제 데이터 변경 확인 필수!", - "description": "목록에서 수정된 부서명 확인", - "verify": { - "listContains": "{randomData.childDepartment}_수정됨" - } - }, - { - "id": "step-14", - "name": "하위 부서 삭제", - "description": "하위 부서의 삭제 버튼 클릭", - "actions": [ - { - "type": "click_if_exists", - "target": "삭제" - } + "id": 10, + "phase": "DELETE", + "name": "[DELETE] 삭제 결과 확인", + "action": "verify_detail", + "checks": [ + "E2E_TEST_본부 목록에서 제거" ], - "expect": { - "confirmDialog": true, - "dialogText": ["삭제", "하시겠습니까"] - } - }, - { - "id": "step-15", - "name": "하위 부서 삭제 확인", - "description": "삭제 확인 다이얼로그에서 확인 클릭", - "actions": [ - { "type": "click_if_exists", "target": "확인", "description": "삭제 확인" } - ], - "waitFor": { - "type": "apiResponse", - "method": "DELETE", - "timeout": 5000 - }, - "expect": { - "toast": ["삭제", "완료", "성공"] - } - }, - { - "id": "step-15-1", - "name": "⚠️ 필수 검증: 하위 부서 삭제 반영 확인", - "description": "목록에서 삭제된 하위 부서가 없어졌는지 확인", - "verify": { - "listNotContains": "{randomData.childDepartment}_수정됨" - } - }, - { - "id": "step-16", - "name": "상위 부서 삭제", - "description": "상위 부서의 삭제 버튼 클릭", - "actions": [ - { - "type": "click_if_exists", - "target": "삭제" - } - ], - "expect": { - "confirmDialog": true, - "dialogText": ["삭제", "하시겠습니까"] - } - }, - { - "id": "step-17", - "name": "상위 부서 삭제 확인", - "description": "삭제 확인 다이얼로그에서 확인 클릭", - "actions": [ - { "type": "click_if_exists", "target": "확인", "description": "삭제 확인" } - ], - "waitFor": { - "type": "apiResponse", - "method": "DELETE", - "timeout": 5000 - }, - "expect": { - "toast": ["삭제", "완료", "성공"] - } - }, - { - "id": "step-18", - "name": "⚠️ 필수 검증: 상위 부서 삭제 반영 확인", - "note": "토스트 성공 메시지만으로 PASS 판정 불가. 실제 데이터 삭제 확인 필수!", - "description": "목록에서 삭제된 상위 부서가 없어졌는지 확인", - "verify": { - "listNotContains": "{randomData.parentDepartment}", - "countRestored": "{initialCount}" + "expected": { + "row_exists": false } } ], - - "assertions": [ + "expectedAPIs": [ { - "type": "url", - "expected": "/hr/department-management", - "message": "부서관리 페이지에 머물러야 함" + "method": "GET", + "endpoint": "/api/v1/departments", + "description": "부서 목록 조회" }, { - "type": "elementExists", - "selector": "text={randomData.parentDepartment}", - "message": "상위 부서가 목록에 표시되어야 함" + "method": "POST", + "endpoint": "/api/v1/departments", + "description": "부서 등록" }, { - "type": "elementExists", - "selector": "text={randomData.childDepartment}", - "message": "하위 부서가 목록에 표시되어야 함" - }, - { - "type": "hierarchy", - "parent": "{randomData.parentDepartment}", - "child": "{randomData.childDepartment}", - "message": "하위 부서가 상위 부서 아래에 트리 구조로 표시되어야 함" + "method": "DELETE", + "endpoint": "/api/v1/departments/{id}", + "description": "부서 삭제" } ], - - "cleanup": { - "enabled": false, - "description": "테스트 후 생성된 부서 삭제 (필요시 활성화)", - "order": "childFirst", - "steps": [ - { - "action": "delete", - "target": "{randomData.childDepartment}", - "description": "하위 부서 먼저 삭제" - }, - { - "action": "delete", - "target": "{randomData.parentDepartment}", - "description": "상위 부서 삭제" - } - ] - }, - - "notes": { - "testScope": "상위 부서 생성 → 하위 부서 추가 → 계층 구조 검증까지 전체 플로우 테스트", - "randomGeneration": { - "parent": "prefix(신규,테스트,개발 등) + '본부' + timestamp", - "child": "prefix(기획,개발,디자인 등) + '팀' + timestamp" + "requiredVerifications": [ + { + "id": 2, + "name": "등록/저장 버튼", + "steps": [6], + "criteria": "API 호출 + 성공 토스트 + 데이터 반영" }, - "duplicateHandling": "timestamp 포함으로 중복 방지", - "prerequisites": "로그인된 사용자에게 부서 추가 권한 필요", - "uiElements": { - "addButton": "상단 '추가' 버튼 - 최상위 부서 추가", - "subAddButton": "각 행의 '하위 부서 추가' 아이콘 버튼", - "expandButton": "트리 구조 확장/축소 버튼" + { + "id": 5, + "name": "목업 페이지 감지", + "steps": [2], + "criteria": "부서 목록, 추가 버튼 존재" + }, + { + "id": 6, + "name": "삭제 기능", + "steps": [8, 9, 10], + "criteria": "DELETE API + 목록에서 제거" } + ], + "rollbackPlan": { + "onCreateFail": "모달 닫기", + "onDeleteFail": "E2E_TEST_ 접두사 부서 수동 삭제 필요", + "cleanupRequired": "E2E_TEST_ 접두사 부서는 테스트 데이터" } } diff --git a/draft-box.json b/draft-box.json index ba37992..f71c4ac 100644 --- a/draft-box.json +++ b/draft-box.json @@ -1,36 +1,17 @@ { + "enabled": true, "id": "draft-box", "name": "기안함 테스트", "screenshotPolicy": { "onErrorOnly": true, - "captureOn": [ - "error", - "fail", - "timeout", - "404", - "500", - "blocked" - ] + "captureOn": ["error", "fail", "timeout", "404", "500", "blocked"] }, - "description": "결재관리 > 기안함 메뉴의 문서 목록 조회, 검색, 필터, 정렬, 문서 상세, 상신, 삭제 기능 테스트", + "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", + "expectedUrl": "/approval/draft", "searchWithinParent": true, "closeOtherMenus": true }, @@ -38,1323 +19,170 @@ "username": "TestUser5", "password": "password123!" }, - "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 + "steps": [ + { + "id": 1, + "name": "메뉴 진입: 결재관리 > 기안함", + "action": "menu_navigate", + "level1": "결재관리", + "level2": "기안함", + "expected": { + "url_contains": "/approval/draft", + "visible": ["기안함"] + } + }, + { + "id": 2, + "name": "필수 검증 #5: 목업 페이지 감지", + "action": "verify_not_mockup", + "checks": [ + "기안함 목록 표시", + "검색/필터 기능 존재", + "문서 작성 버튼 존재" + ], + "expected": "정상 페이지 (목업 아님)" + }, + { + "id": 3, + "name": "통계 카드 확인", + "action": "verify_element", + "checks": [ + "진행 카드 표시", + "완료 카드 표시", + "반려 카드 표시", + "임시 저장 카드 표시" + ], + "expected": "통계 카드 4개 표시" + }, + { + "id": 4, + "name": "기안함 테이블 구조 확인", + "action": "verify_table", + "checks": [ + "문서번호 컬럼", + "문서유형 컬럼", + "제목 컬럼", + "결재자 컬럼", + "기안일시 컬럼", + "상태 컬럼" + ], + "expected": "기안함 테이블 컬럼 정상 표시" + }, + { + "id": 5, + "name": "데이터 로드 확인", + "action": "verify_detail", + "checks": [ + "기안 문서 데이터 행 존재 또는 '데이터가 없습니다' 메시지" + ], + "expected": "기안 문서 데이터 표시" + }, + { + "id": 6, + "phase": "SEARCH", + "name": "[SEARCH] 검색 기능 테스트", + "action": "fill", + "target": "input[type='search'], input[placeholder*='검색']", + "value": "테스트", + "submit": true + }, + { + "id": 7, + "phase": "SEARCH", + "name": "[SEARCH] 검색 결과 확인", + "action": "verify_detail", + "checks": [ + "검색 결과 표시 또는 결과 없음 메시지" + ], + "expected": "검색 기능 동작" + }, + { + "id": 8, + "phase": "SEARCH", + "name": "[SEARCH] 검색 초기화", + "action": "click_if_exists", + "target": "button:has-text('초기화'), button:has-text('전체'), button[class*='clear']", + "expected": "검색 초기화" + }, + { + "id": 9, + "name": "필터 기능 테스트", + "action": "click_if_exists", + "target": "select, [role='combobox'], button:has-text('임시저장')", + "expected": "필터 옵션 표시" + }, + { + "id": 10, + "phase": "READ", + "name": "[READ] 문서 상세 보기", + "action": "click_if_exists", + "target": "table tbody tr:first-child td:nth-child(2), table tbody tr:first-child", + "expected": { + "detail_view": true + } + }, + { + "id": 11, + "name": "상세 페이지/모달 확인", + "action": "verify_element", + "checks": [ + "문서 상세 정보 표시", + "문서번호 또는 제목 표시" + ], + "expected": "상세 정보 표시" + }, + { + "id": 12, + "name": "모달/상세 닫기", + "action": "close_modal_if_open", + "expected": "모달 닫힘" + }, + { + "id": 13, + "name": "페이지네이션 확인", + "action": "verify_element", + "checks": [ + "페이지 번호 또는 이전/다음 버튼" + ], + "expected": "페이지네이션 표시" + }, + { + "id": 14, + "name": "문서 작성 버튼 확인", + "action": "verify_element", + "checks": [ + "문서 작성 또는 신규 작성 버튼 존재" + ], + "expected": "문서 작성 버튼 확인" } - }, - "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": "기안함 목록 조회 (페이지네이션, 검색, 필터, 정렬)" + "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": "결재 문서 삭제 (임시저장 상태만)" + "description": "기안함 통계 카드" } ], - "steps": [ + "requiredVerifications": [ { - "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": 3, + "name": "검색/필터", + "steps": [6, 7, 8], + "criteria": "검색 기능 동작" }, { - "id": "step-1", - "name": "2단계 메뉴 진입: 결재관리 > 기안함", - "description": "사이드바를 스크롤하며 결재관리 > 기안함 메뉴를 찾아 클릭", - "actions": [ - { - "type": "scrollAndFind", - "target": "결재관리", - "alternativeTexts": [ - "결재관리", - "결재 관리", - "Approval", - "전자결재" - ], - "scrollContainer": "sidebar", - "maxAttempts": 10, - "description": "스크롤하며 결재관리 메뉴 찾기" - }, - { - "type": "click_if_exists", - "target": "결재관리", - "description": "결재관리 메뉴 클릭" - }, - { - "type": "wait", - "duration": 500, - "description": "서브메뉴 펼쳐지기 대기" - }, - { - "type": "scrollAndFind", - "target": "기안함", - "alternativeTexts": [ - "기안함", - "기안 함", - "Draft", - "내 기안" - ], - "scrollContainer": "submenu", - "maxAttempts": 5, - "description": "서브메뉴에서 기안함 찾기" - }, - { - "type": "click_if_exists", - "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": "click_if_exists", - "target": "검색 입력 필드", - "value": "테스트" - }, - { - "type": "wait", - "target": "검색 결과 로드" - } - ], - "expected": { - "searchPlaceholder": "문서번호, 제목, 기안자 검색...", - "apiCalled": "GET /api/v1/approvals/drafts?search=테스트", - "dataFiltered": "검색어 포함된 문서만 표시", - "pageReset": "1페이지로 초기화" - } - }, - { - "id": "step-11", - "name": "검색어 초기화", - "description": "검색어를 지우고 전체 목록으로 복귀", - "actions": [ - { - "type": "click_if_exists", - "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": "click_if_exists", - "target": "필터 셀렉트박스", - "value": "임시저장" - }, - { - "type": "wait", - "target": "데이터 로드" - } - ], - "expected": { - "apiCalled": "GET /api/v1/approvals/drafts?status=draft", - "dataFiltered": "임시저장 상태만 표시", - "pageReset": "1페이지로 초기화" - } - }, - { - "id": "step-14", - "name": "필터 초기화", - "description": "필터를 '전체'로 변경하여 전체 목록 표시", - "actions": [ - { - "type": "click_if_exists", - "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": "click_if_exists", - "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": "click_if_exists", - "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_if_exists", - "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_if_exists", - "target": "첫 번째 행 체크박스" - } - ], - "expected": { - "checkboxChecked": false, - "selectedCount": 0, - "actionButtonsHidden": "상신, 삭제 버튼 숨김" - } - }, - { - "id": "step-21", - "name": "전체 선택 체크박스 클릭", - "description": "테이블 헤더의 전체 선택 체크박스 클릭", - "actions": [ - { - "type": "click_if_exists", - "target": "헤더 체크박스 (전체 선택)" - } - ], - "expected": { - "allCheckboxesChecked": true, - "selectedCount": "현재 페이지의 모든 행 수", - "actionButtonsVisible": "상신, 삭제 버튼 표시" - } - }, - { - "id": "step-22", - "name": "전체 선택 해제", - "description": "전체 선택 체크박스를 다시 클릭하여 모두 해제", - "actions": [ - { - "type": "click_if_exists", - "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_if_exists", - "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_if_exists", - "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_if_exists", - "target": "모달 외부 또는 닫기 버튼" - } - ], - "expected": { - "modalClosed": true, - "returnToList": "기안함 목록으로 복귀" - } - }, - { - "id": "step-31-pdf-1", - "name": "⚠️ 필수 검증: PDF 다운로드 전 모달 스크린샷", - "description": "PDF 생성 전 모달 상태를 스크린샷으로 캡처하여 CSS 문제 감지용 기준 이미지 확보", - "prerequisite": "step-26의 문서 상세 모달이 열려있는 상태에서 실행", - "actions": [ - { - "type": "click_if_exists", - "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 다운로드 실행 및 파일 보관", - "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_if_exists", - "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 파일 유효성 검증", - "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", - "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_if_exists", - "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_if_exists", - "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_if_exists", - "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": "click_if_exists", - "target": "검색 입력 필드", - "value": "존재하지않는문서번호999999" - }, - { - "type": "wait", - "target": "검색 결과" - } - ], - "expected": { - "emptyMessage": "데이터가 없습니다.", - "messagePosition": "테이블 중앙" - } - }, - { - "id": "step-39", - "name": "검색어 초기화 (빈 상태 해제)", - "description": "검색어를 지워서 전체 목록으로 복귀", - "actions": [ - { - "type": "click_if_exists", - "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", - "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" - } - } + "id": 5, + "name": "목업 페이지 감지", + "steps": [2], + "criteria": "기안함 목록, 검색 기능, 문서 작성 버튼 존재" } ], - "cleanup": { - "description": "테스트 후 정리 작업 (없음)", - "actions": [] - }, - "notes": [ - "20개씩 페이지네이션 (itemsPerPage: 20)", - "검색 필드: 문서번호, 제목, 기안자 검색 가능", - "필터: 전체, 임시저장, 결재대기, 진행중, 완료, 반려", - "정렬: 최신순, 오래된순, 제목 오름차순, 제목 내림차순", - "체크박스: 개별 선택, 전체 선택 가능", - "상신/삭제: 선택된 항목이 있을 때만 버튼 표시", - "임시저장 문서: 선택 시 작업 컬럼에 수정/삭제 버튼 표시", - "문서 클릭 동작: 임시저장 → 수정 페이지, 그 외 → 상세 모달", - "통계 카드: API summary로 실시간 업데이트", - "IntegratedListTemplateV2 템플릿 사용으로 반응형 지원", - "날짜 범위 선택 기본값: 2025-01-01 ~ 2025-12-31", - "결재자 표시: 단일(이름), 복수(이름 외 N명)", - "모달 버튼: 수정, 복제, 상신(임시저장만)", - "승인/반려 버튼 없음 (기안함에서는 본인 문서 승인/반려 불가)" - ] -} \ No newline at end of file + "rollbackPlan": { + "note": "조회 전용 테스트로 데이터 변경 없음" + } +} diff --git a/free-board.json b/free-board.json index 73ee1b6..92324d6 100644 --- a/free-board.json +++ b/free-board.json @@ -1,21 +1,17 @@ { + "enabled": true, "id": "free-board", "name": "자유게시판 E2E 테스트", "screenshotPolicy": { "onErrorOnly": true, "captureOn": ["error", "fail", "timeout", "404", "500", "blocked"] }, - "description": "자유게시판의 목록, 게시글 작성, 상세, 수정, 삭제, 댓글 CRUD 전체 워크플로우 테스트", - "url": "/ko/boards/free", - "navigation": { - "targetUrl": "/boards/free", - "urlPattern": "/boards/free|/ko/boards/free", - "menuHints": ["자유게시판", "자유 게시판", "게시판"] - }, + "description": "자유게시판의 목록, 게시글 작성, 상세, 수정, 삭제 전체 CRUD 워크플로우 테스트", + "baseUrl": "https://dev.codebridge-x.com", "menuNavigation": { "level1": "게시판", "level2": "자유게시판", - "expectedUrl": "/ko/boards/free", + "expectedUrl": "/boards/free", "searchWithinParent": true, "closeOtherMenus": true }, @@ -23,723 +19,274 @@ "username": "TestUser5", "password": "password123!" }, - "menuNavigationEnhanced": { - "strategy": "scroll-and-search", - "level1": { - "text": "게시판", - "scrollContainer": ".sidebar-scroll, [data-sidebar='content'], nav", - "maxScrollAttempts": 5, - "scrollStep": 200 + "testData": { + "create": { + "title": "E2E_TEST_게시글_{timestamp}", + "content": "E2E 자동화 테스트를 위한 게시글입니다." }, - "level2": { - "text": "자유게시판", - "waitAfterLevel1Click": 500 - }, - "expectedUrl": "/ko/boards/free", - "fallbackUrl": "/ko/boards/free" + "update": { + "title": "E2E_TEST_수정완료_{timestamp}", + "content": "수정된 내용입니다." + } }, "steps": [ { - "step": 0, - "name": "사이드바 메뉴 전체 펼치기", - "description": "모두 펼치기 버튼을 클릭하여 전체 메뉴를 펼친 후 메뉴 탐색 준비", - "actions": [ - { - "type": "evaluate", - "script": "document.querySelector('.sidebar-scroll, [data-sidebar=\"content\"], nav')?.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": "메뉴 진입: 게시판 > 자유게시판", + "action": "menu_navigate", + "level1": "게시판", + "level2": "자유게시판", + "expected": { + "url_contains": "/boards/free", + "visible": ["자유게시판"] + } }, { - "step": 1, - "name": "2단계 메뉴 진입: 게시판 > 자유게시판", - "description": "게시판 > 자유게시판 메뉴로 이동하여 페이지 로드 확인", - "actions": [ - { - "type": "scrollAndFind", - "target": "게시판", - "container": ".sidebar-scroll, [data-sidebar='content'], nav", - "maxAttempts": 5, - "scrollStep": 200 - }, - { - "type": "click_if_exists", - "target": "게시판" - }, - { - "type": "wait", - "duration": 500 - }, - { - "type": "click_if_exists", - "target": "자유게시판" - }, - { - "type": "wait", - "target": "페이지 로드 완료" - } + "id": 2, + "name": "필수 검증 #5: 목업 페이지 감지", + "action": "verify_not_mockup", + "checks": [ + "게시글 목록 표시", + "글쓰기 버튼 존재", + "검색 기능 존재" ], - "verification": { - "title_contains": "자유게시판", - "elements": ["table", "button:has-text('글쓰기')"] - } + "expected": "정상 페이지 (목업 아님)" }, { - "step": 2, - "name": "초기 게시글 목록 확인", - "action": "verify_table_structure", - "verification": { - "columns": ["No.", "제목", "작성자", "조회수", "상태", "등록일"], - "min_rows": 0 - } + "id": 3, + "name": "게시판 테이블 구조 확인", + "action": "verify_table", + "checks": [ + "제목 컬럼", + "작성자 컬럼", + "등록일 컬럼" + ], + "expected": "게시판 테이블 표시" }, { - "step": 3, - "name": "게시글 총 건수 확인", - "action": "verify_text", - "verification": { - "text_pattern": "총 \\d+건" - } - }, - { - "step": 4, - "name": "검색 기능 확인 (검색창 존재)", - "action": "verify_element", - "target": "input[placeholder*='제목']", - "verification": { - "exists": true - } - }, - { - "step": 5, - "name": "필터 드롭다운 확인 (상태)", - "action": "verify_element", - "target": "select, [role='combobox']:has-text('상태')", - "verification": { - "exists": true - } - }, - { - "step": 6, - "name": "정렬 드롭다운 확인", - "action": "verify_element", - "target": "select, [role='combobox']:has-text('최신순')", - "verification": { - "exists": true - } - }, - { - "step": 7, - "name": "날짜 범위 선택기 확인", - "action": "verify_element", - "target": "input[type='date']", - "verification": { - "count": 2 - } - }, - { - "step": 8, - "name": "검색 테스트 (제목)", - "action": "fill_and_wait", - "target": "input[placeholder*='제목']", + "id": 4, + "phase": "SEARCH", + "name": "[SEARCH] 검색 기능 테스트", + "action": "fill", + "target": "input[placeholder*='제목'], input[type='search'], input[placeholder*='검색']", "value": "테스트", - "verification": { - "wait_for_data_change": true - } + "submit": true }, { - "step": 9, - "name": "검색 결과 확인", - "action": "verify_table_data", - "verification": { - "filtered": true - } + "id": 5, + "phase": "SEARCH", + "name": "[SEARCH] 검색 결과 확인", + "action": "verify_detail", + "checks": [ + "검색 결과 표시 또는 결과 없음 메시지" + ], + "expected": "검색 기능 동작" }, { - "step": 10, - "name": "검색어 초기화", - "action": "fill", - "target": "input[placeholder*='제목']", - "value": "" - }, - { - "step": 11, - "name": "상태 필터 테스트 (게시됨)", - "action": "select_dropdown", - "target": "[role='combobox']:has-text('전체')", - "value": "게시됨", - "verification": { - "wait_for_data_change": true - } - }, - { - "step": 12, - "name": "상태 필터 초기화 (전체)", - "action": "select_dropdown", - "target": "[role='combobox']", - "value": "전체" - }, - { - "step": 13, - "name": "정렬 변경 (오래된순)", - "action": "select_dropdown", - "target": "[role='combobox']:has-text('최신순')", - "value": "오래된순", - "verification": { - "wait_for_data_change": true - } - }, - { - "step": 14, - "name": "정렬 복원 (최신순)", - "action": "select_dropdown", - "target": "[role='combobox']:has-text('오래된순')", - "value": "최신순" - }, - { - "step": 15, - "name": "글쓰기 버튼 클릭", + "id": 6, + "phase": "CREATE", + "name": "[CREATE] 글쓰기 버튼 클릭", "action": "click_if_exists", - "target": "button:has-text('글쓰기')" + "target": "button:has-text('글쓰기'), button:has-text('등록'), button:has-text('작성')" }, { - "step": 16, - "name": "게시글 작성 페이지 진입 확인", - "action": "verify_url", - "verification": { - "url_pattern": "/boards/free\\?mode=new|/boards/free/create", - "title_contains": "자유게시판" - } + "id": 7, + "phase": "CREATE", + "name": "[CREATE] 작성 페이지 대기", + "action": "wait", + "duration": 2000 }, { - "step": 17, - "name": "제목 필드 확인", - "action": "verify_element", - "target": "input#title", - "verification": { - "exists": true, - "required": true - } - }, - { - "step": 18, - "name": "내용 필드 확인", - "action": "verify_element", - "target": "textarea#content", - "verification": { - "exists": true, - "required": true - } - }, - { - "step": 19, - "name": "게시글 제목 입력", + "id": 8, + "phase": "CREATE", + "name": "[CREATE] 제목 입력", "action": "fill", - "target": "input#title", - "value": "E2E 테스트 게시글" + "target": "input#title, input[name='title'], input[placeholder*='제목']", + "value": "E2E_TEST_게시글_{timestamp}", + "clear": true }, { - "step": 20, - "name": "게시글 내용 입력", + "id": 9, + "phase": "CREATE", + "name": "[CREATE] 내용 입력", "action": "fill", - "target": "textarea#content", - "value": "이것은 E2E 자동화 테스트를 위한 게시글입니다." + "target": "textarea#content, textarea[name='content'], [contenteditable='true']", + "value": "E2E 자동화 테스트를 위한 게시글입니다.", + "clear": true }, { - "step": 21, - "name": "현재 URL 저장 (등록 전)", - "action": "save_url", - "variable": "url_before_submit" - }, - { - "step": 22, - "name": "게시글 등록 버튼 클릭", + "id": 10, + "phase": "CREATE", + "name": "[CREATE] 필수 검증 #2: 게시글 등록", "action": "click_if_exists", - "target": "button:has-text('등록')" - }, - { - "step": 23, - "name": "게시글 등록 완료 (URL 안정성 검증)", - "action": "verify_url_stability", - "verification": { - "expected_url_pattern": "/boards/free/\\d+", - "no_404": true, + "target": "button:has-text('등록'), button[type='submit']", + "verify": { + "url_maintained": false, "no_error_page": true, - "success_condition": "url_changed_to_detail" + "toast": "등록|완료|성공" }, - "notes": "필수 검증 #2: 등록 후 상세 페이지로 이동해야 하며 404 에러 페이지가 나오면 안 됨" + "expected": "게시글 등록 완료" }, { - "step": 24, - "name": "게시글 상세 페이지 진입 확인", - "action": "verify_page", - "verification": { - "title": "E2E 테스트 게시글", - "content_contains": "E2E 자동화 테스트" + "id": 11, + "phase": "CREATE", + "name": "[CREATE] 등록 후 대기", + "action": "wait", + "duration": 2000 + }, + { + "id": 12, + "phase": "READ", + "name": "[READ] 게시글 상세 확인", + "action": "verify_detail", + "checks": [ + "E2E_TEST_게시글 제목 표시", + "게시글 내용 표시" + ], + "expected": "게시글 상세 페이지 표시" + }, + { + "id": 13, + "phase": "UPDATE", + "name": "[UPDATE] 수정 버튼 클릭", + "action": "click_if_exists", + "target": "button:has-text('수정'), button:has-text('편집')", + "expected": { + "edit_mode": true } }, { - "step": 25, - "name": "게시글 ID 저장", - "action": "extract_from_url", - "pattern": "/ko/boards/free/(\\d+)", - "variable": "post_id" + "id": 14, + "phase": "UPDATE", + "name": "[UPDATE] 수정 페이지 대기", + "action": "wait", + "duration": 1500 }, { - "step": 26, - "name": "작성자 정보 표시 확인", - "action": "verify_element", - "target": "text=/\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}/", - "verification": { - "exists": true - } + "id": 15, + "phase": "UPDATE", + "name": "[UPDATE] 제목 수정", + "action": "fill", + "target": "input#title, input[name='title'], input[placeholder*='제목']", + "value": "E2E_TEST_수정완료_{timestamp}", + "clear": true }, { - "step": 27, - "name": "조회수 표시 확인", - "action": "verify_element", - "target": "svg.lucide-eye", - "verification": { - "exists": true - } + "id": 16, + "phase": "UPDATE", + "name": "[UPDATE] 필수 검증 #2: 수정 저장", + "action": "click_if_exists", + "target": "button:has-text('저장'), button:has-text('수정'), button[type='submit']", + "verify": { + "no_error_page": true, + "toast": "수정|저장|완료|성공" + }, + "expected": "수정 완료" }, { - "step": 28, - "name": "수정 버튼 존재 확인 (작성자)", - "action": "verify_element", - "target": "button:has-text('수정')", - "verification": { - "exists": true - } + "id": 17, + "phase": "UPDATE", + "name": "[UPDATE] 수정 후 대기", + "action": "wait", + "duration": 2000 }, { - "step": 29, - "name": "삭제 버튼 존재 확인 (작성자)", - "action": "verify_element", + "id": 18, + "phase": "UPDATE", + "name": "[UPDATE] 수정 결과 확인", + "action": "verify_detail", + "checks": [ + "E2E_TEST_수정완료 제목 표시" + ], + "expected": "수정된 데이터 반영" + }, + { + "id": 19, + "phase": "DELETE", + "name": "[DELETE] 삭제 버튼 클릭", + "action": "click_if_exists", "target": "button:has-text('삭제')", - "verification": { - "exists": true + "expected": { + "confirm_dialog": true } }, { - "step": 30, - "name": "댓글 섹션 확인", - "action": "verify_element", - "target": "text=/댓글/", - "verification": { - "exists": true - } - }, - { - "step": 31, - "name": "댓글 입력란 확인", - "action": "verify_element", - "target": "textarea[placeholder*='댓글']", - "verification": { - "exists": true - } - }, - { - "step": 32, - "name": "첫 번째 댓글 작성", - "action": "fill", - "target": "textarea[placeholder*='댓글']", - "value": "첫 번째 테스트 댓글입니다." - }, - { - "step": 33, - "name": "댓글 등록 버튼 클릭", - "action": "click_if_exists", - "target": "button:has-text('댓글 등록'), button:has-text('등록')" - }, - { - "step": 34, - "name": "댓글 등록 확인", - "action": "verify_text", - "verification": { - "text": "첫 번째 테스트 댓글입니다.", - "exists": true - } - }, - { - "step": 35, - "name": "댓글 수 업데이트 확인", - "action": "evaluate", - "script": "(function(){ var t = document.body.innerText; var m = t.match(/댓글[\\s(]*\\d+/); return m ? m[0] : 'comment section found: ' + (t.includes('댓글') ? 'yes' : 'no'); })()" - }, - { - "step": 36, - "name": "두 번째 댓글 작성", - "action": "fill", - "target": "textarea[placeholder*='댓글']", - "value": "두 번째 테스트 댓글입니다." - }, - { - "step": 37, - "name": "두 번째 댓글 등록", - "action": "click_if_exists", - "target": "button:has-text('댓글 등록'), button:has-text('등록')" - }, - { - "step": 38, - "name": "두 번째 댓글 등록 확인", - "action": "verify_text", - "verification": { - "text": "두 번째 테스트 댓글입니다.", - "exists": true - } - }, - { - "step": 39, - "name": "첫 번째 댓글 수정 버튼 클릭", - "description": "댓글 영역 내의 수정 버튼을 찾아 클릭 (게시글 수정 버튼과 구별)", - "actions": [ - { - "type": "evaluate", - "script": "(function(){ var allBtns = Array.from(document.querySelectorAll('button')).filter(function(b){ return b.innerText && b.innerText.trim() === '수정'; }); var commentBtn = allBtns.filter(function(b){ return b.closest('[class*=\"comment\"], [class*=\"Comment\"], [class*=\"reply\"]'); }); if(commentBtn.length > 0){ commentBtn[0].click(); return 'clicked comment edit btn'; } if(allBtns.length >= 2){ allBtns[allBtns.length - 1].click(); return 'clicked last edit btn (assumed comment)'; } return 'no comment edit btn found'; })()" - }, - { "type": "wait", "duration": 1000 } - ] - }, - { - "step": 40, - "name": "댓글 수정 내용 입력", - "description": "인라인 편집 또는 별도 textarea에 수정 내용 입력", - "actions": [ - { - "type": "evaluate", - "script": "(function(){ var newVal = '수정된 첫 번째 댓글입니다.'; var textareas = Array.from(document.querySelectorAll('textarea')); var editTA = textareas.find(function(t){ return t.value && t.value.includes('첫 번째 테스트'); }); if(editTA){ var rk = Object.keys(editTA).find(function(k){ return k.indexOf('__reactProps$')===0; }); if(rk && editTA[rk] && typeof editTA[rk].onChange==='function'){ var setter = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype,'value').set; setter.call(editTA, newVal); editTA[rk].onChange({target:editTA,currentTarget:editTA}); return 'filled via reactProps (value='+editTA.value+')'; } editTA.focus(); editTA.select(); document.execCommand('insertText',false,newVal); return 'filled via execCommand (value='+editTA.value+')'; } var inputs = Array.from(document.querySelectorAll('input[type=\"text\"]')); var editInput = inputs.find(function(i){ return i.value && i.value.includes('첫 번째 테스트'); }); if(editInput){ var rk2 = Object.keys(editInput).find(function(k){ return k.indexOf('__reactProps$')===0; }); if(rk2 && editInput[rk2] && typeof editInput[rk2].onChange==='function'){ var setter2 = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype,'value').set; setter2.call(editInput, newVal); editInput[rk2].onChange({target:editInput,currentTarget:editInput}); return 'filled input via reactProps (value='+editInput.value+')'; } editInput.focus(); editInput.select(); document.execCommand('insertText',false,newVal); return 'filled input via execCommand (value='+editInput.value+')'; } var editables = document.querySelectorAll('[contenteditable=\"true\"]'); for(var i=0; i 0){ commentBtns[commentBtns.length-1].click(); return 'clicked last comment delete btn'; } if(allBtns.length >= 2){ allBtns[allBtns.length-1].click(); return 'clicked last delete btn (assumed comment)'; } return 'no comment delete btn found'; })()" - }, - { "type": "wait", "duration": 500 } - ] - }, - { - "step": 44, - "name": "댓글 삭제 확인 다이얼로그 처리", - "actions": [ - { - "type": "evaluate", - "script": "(function(){ var dialog = document.querySelector('[role=\"dialog\"], [role=\"alertdialog\"], [class*=\"modal\"]:not([class*=\"tooltip\"])'); if(dialog && dialog.offsetParent !== null){ var confirmBtn = Array.from(dialog.querySelectorAll('button')).find(function(b){ return ['확인','삭제','예','OK','Yes'].some(function(t){ return b.innerText && b.innerText.includes(t); }); }); if(confirmBtn){ confirmBtn.click(); return 'confirmed delete dialog'; } } return 'no dialog or auto-handled'; })()" - }, - { "type": "wait", "duration": 1500 } - ] - }, - { - "step": 45, - "name": "댓글 삭제 확인", - "action": "verify_text", - "verification": { - "text": "두 번째 테스트 댓글", - "exists": false - } - }, - { - "step": 46, - "name": "댓글 수 확인 (삭제 후)", - "action": "evaluate", - "script": "(function(){ var t = document.body.innerText; var m = t.match(/댓글[\\s(]*\\d+/); return m ? m[0] : 'comment section: ' + (t.includes('댓글') ? 'exists' : 'not found'); })()" - }, - { - "step": 47, - "name": "게시글 수정 버튼 클릭", - "action": "click_if_exists", - "target": "button:has-text('수정')" - }, - { - "step": 48, - "name": "게시글 수정 페이지 진입 확인", - "action": "verify_url", - "verification": { - "url_pattern": "/(ko/)?boards/free/\\d+\\?mode=edit" - } - }, - { - "step": 49, - "name": "제목 필드에 기존 값 확인", - "action": "verify_input_value", - "target": "input#title", - "verification": { - "value": "E2E 테스트 게시글" - } - }, - { - "step": 50, - "name": "제목 수정", - "action": "fill", - "target": "input#title", - "value": "E2E 테스트 게시글 (수정됨)" - }, - { - "step": 51, - "name": "내용 수정", - "action": "fill", - "target": "textarea#content", - "value": "수정된 내용입니다. E2E 자동화 테스트를 위한 게시글입니다." - }, - { - "step": 52, - "name": "현재 URL 저장 (수정 전)", - "action": "save_url", - "variable": "url_before_update" - }, - { - "step": 53, - "name": "수정 저장 버튼 클릭", - "action": "click_if_exists", - "target": "button[type='submit']:has-text('저장'), button:has-text('수정')" - }, - { - "step": 54, - "name": "게시글 수정 완료 (URL 안정성 검증)", - "action": "verify_url_stability", - "verification": { - "expected_url_pattern": "/boards/free/\\d+", - "no_404": true, - "no_error_page": true, - "success_condition": "url_back_to_detail" + "id": 20, + "phase": "DELETE", + "name": "[DELETE] 필수 검증 #6: 삭제 확인", + "action": "click_and_confirm", + "target": "button:has-text('확인'), button:has-text('삭제')", + "verify": { + "toast": "삭제|완료|성공", + "redirect": "/boards/free" }, - "notes": "필수 검증 #2: 수정 후 상세 페이지로 돌아가야 하며 404 에러 페이지가 나오면 안 됨" + "expected": "삭제 완료 및 목록 복귀" }, { - "step": 55, - "name": "수정된 제목 확인", - "action": "verify_text", - "verification": { - "text": "E2E 테스트 게시글 (수정됨)", - "exists": true - } + "id": 21, + "phase": "DELETE", + "name": "[DELETE] 삭제 후 대기", + "action": "wait", + "duration": 2000 }, { - "step": 56, - "name": "수정된 내용 확인", - "action": "verify_text", - "verification": { - "text": "수정된 내용입니다", - "exists": true - } - }, - { - "step": 57, - "name": "목록으로 이동 버튼 클릭", - "action": "click_if_exists", - "target": "button:has-text('목록으로')" - }, - { - "step": 58, - "name": "목록 페이지 복귀 확인", - "action": "verify_url", - "verification": { - "url": "/boards/free" - } - }, - { - "step": 59, - "name": "수정된 게시글 목록 확인", - "action": "verify_text", - "verification": { - "text": "E2E 테스트 게시글 (수정됨)", - "exists": true - } - }, - { - "step": 60, - "name": "게시글 클릭하여 상세 진입", - "action": "click_if_exists", - "target": "text=E2E 테스트 게시글 (수정됨)" - }, - { - "step": 61, - "name": "상세 페이지 진입 확인", - "action": "verify_url", - "verification": { - "url_pattern": "/(ko/)?boards/free/\\d+" - } - }, - { - "step": 62, - "name": "조회수 증가 확인", - "action": "verify_element", - "target": "svg.lucide-eye ~ text", - "verification": { - "text_pattern": "\\d+", - "notes": "조회수가 표시되는지 확인" - } - }, - { - "step": 63, - "name": "게시글 삭제 버튼 클릭", - "action": "click_if_exists", - "target": "button:has-text('삭제')" - }, - { - "step": 64, - "name": "삭제 확인 다이얼로그 표시 확인", - "action": "verify_dialog", - "verification": { - "title": "게시글 삭제", - "content_contains": "삭제하시겠습니까" - } - }, - { - "step": 65, - "name": "현재 URL 저장 (삭제 전)", - "action": "save_url", - "variable": "url_before_delete" - }, - { - "step": 66, - "name": "삭제 확인 버튼 클릭", - "action": "click_if_exists", - "target": "button:has-text('삭제'):last-of-type" - }, - { - "step": 67, - "name": "게시글 삭제 완료 (URL 안정성 검증)", - "action": "verify_url_stability", - "verification": { - "expected_url": "/boards/free", - "no_404": true, - "no_error_page": true, - "success_condition": "url_back_to_list" - }, - "notes": "필수 검증 #2: 삭제 후 목록 페이지로 돌아가야 하며 404 에러 페이지가 나오면 안 됨" - }, - { - "step": 68, - "name": "목록 페이지 복귀 확인", - "action": "verify_url", - "verification": { - "url": "/boards/free" - } - }, - { - "step": 69, - "name": "삭제된 게시글 목록에서 제거 확인", - "action": "verify_text", - "verification": { - "text": "E2E 테스트 게시글 (수정됨)", - "exists": false - } - }, - { - "step": 70, - "name": "콘솔 에러 확인", - "action": "verify_element", - "target": "body", - "verification": { - "no_errors": true + "id": 22, + "phase": "DELETE", + "name": "[DELETE] 삭제 결과 확인", + "action": "verify_detail", + "search": "E2E_TEST_수정완료", + "expected": { + "row_exists": false, + "message": "테스트 게시글이 목록에서 제거됨" } } ], "expectedAPIs": [ { - "endpoint": "GET /api/v1/boards/free", - "description": "자유게시판 정보 조회" + "method": "GET", + "endpoint": "/api/v1/boards/free/posts", + "description": "게시글 목록 조회" }, { - "endpoint": "GET /api/v1/boards/free/posts", - "description": "게시글 목록 조회 (per_page=100)" + "method": "POST", + "endpoint": "/api/v1/boards/free/posts", + "description": "게시글 등록" }, { - "endpoint": "POST /api/v1/boards/free/posts", - "description": "게시글 등록", - "payload": { - "title": "string", - "content": "string", - "is_secret": "boolean" - } + "method": "PUT", + "endpoint": "/api/v1/boards/free/posts/{id}", + "description": "게시글 수정" }, { - "endpoint": "GET /api/v1/boards/free/posts/{id}", - "description": "게시글 상세 조회 (조회수 증가)" - }, - { - "endpoint": "GET /api/v1/boards/free/posts/{id}/comments", - "description": "댓글 목록 조회" - }, - { - "endpoint": "POST /api/v1/boards/free/posts/{id}/comments", - "description": "댓글 등록", - "payload": { - "content": "string" - } - }, - { - "endpoint": "PUT /api/v1/boards/free/posts/{id}/comments/{commentId}", - "description": "댓글 수정", - "payload": { - "content": "string" - } - }, - { - "endpoint": "DELETE /api/v1/boards/free/posts/{id}/comments/{commentId}", - "description": "댓글 삭제" - }, - { - "endpoint": "PUT /api/v1/boards/free/posts/{id}", - "description": "게시글 수정", - "payload": { - "title": "string", - "content": "string", - "is_secret": "boolean" - } - }, - { - "endpoint": "DELETE /api/v1/boards/free/posts/{id}", + "method": "DELETE", + "endpoint": "/api/v1/boards/free/posts/{id}", "description": "게시글 삭제" } ], - "notes": [ - "자유게시판은 boardCode='free'를 사용하는 동적 게시판입니다.", - "게시글 등록/수정/삭제 시 반드시 URL 안정성 검증 수행 (필수 검증 #2)", - "댓글 CRUD 기능 모두 테스트해야 합니다.", - "IntegratedListTemplateV2 템플릿 사용으로 반응형 디자인 (데스크톱/모바일)", - "페이지네이션은 10개 단위로 동작 (10개 미만 시 미표시)", - "검색은 제목, 작성자명으로 필터링됩니다.", - "상태 필터: 전체, 게시됨, 임시저장", - "정렬: 최신순, 오래된순", - "조회수는 게시글 상세 조회 시마다 증가합니다.", - "작성자만 수정/삭제 버튼이 표시됩니다.", - "댓글도 작성자만 수정/삭제 가능합니다.", - "댓글 수정은 인라인 편집 방식 (별도 textarea 삽입이 아닌 기존 요소 내 편집)", - "댓글 삭제 시 확인 다이얼로그가 표시될 수 있음", - "게시글 내용은 HTML로 저장되며 dangerouslySetInnerHTML로 렌더링됩니다." - ] + "requiredVerifications": [ + { + "id": 2, + "name": "등록/저장 버튼", + "steps": [10, 16], + "criteria": "API 호출 + 성공 토스트 + 데이터 반영" + }, + { + "id": 5, + "name": "목업 페이지 감지", + "steps": [2], + "criteria": "게시글 목록, 글쓰기 버튼, 검색 기능 존재" + }, + { + "id": 6, + "name": "삭제 기능", + "steps": [19, 20, 22], + "criteria": "DELETE API + 목록에서 제거" + } + ], + "rollbackPlan": { + "onCreateFail": "영향 없음", + "onUpdateFail": "테스트 게시글 수동 삭제 필요", + "onDeleteFail": "테스트 게시글 수동 삭제 필요", + "cleanupRequired": "E2E_TEST_ 접두사 게시글은 테스트 데이터" + } } diff --git a/inventory-status.json b/inventory-status.json index d224a69..3ad0a6a 100644 --- a/inventory-status.json +++ b/inventory-status.json @@ -7,16 +7,16 @@ }, "description": "자재관리 > 재고현황 페이지의 재고 조회 및 엑셀 다운로드 기능을 테스트하는 E2E 테스트", "baseUrl": "https://dev.codebridge-x.com", - "url": "/material/inventory", + "url": "/material/stock-status", "navigation": { - "targetUrl": "/material/inventory", - "urlPattern": "/material/inventory|/ko/material/inventory", + "targetUrl": "/material/stock-status", + "urlPattern": "/material/stock-status|/ko/material/stock-status", "menuHints": ["재고현황", "재고 현황", "자재관리"] }, "menuNavigation": { "level1": "자재관리", "level2": "재고현황", - "expectedUrl": "/material/inventory", + "expectedUrl": "/material/stock-status", "searchWithinParent": true, "closeOtherMenus": true }, @@ -37,8 +37,8 @@ "text": "재고현황", "waitAfterClick": 300 }, - "fallbackUrl": "/material/inventory", - "expectedUrl": "/material/inventory" + "fallbackUrl": "/material/stock-status", + "expectedUrl": "/material/stock-status" }, "timeout": 90000, "tags": ["material", "inventory", "read-only"], @@ -83,12 +83,12 @@ { "type": "click_if_exists", "target": "재고현황" } ], "expect": { - "url": "/material/inventory", + "url": "/material/stock-status", "visible": ["재고 목록", "엑셀 다운로드"] }, "fallback": { "type": "navigate", - "url": "/material/inventory" + "url": "/material/stock-status" } }, { @@ -165,7 +165,7 @@ "noErrorPage": true }, "verify": { - "apiCall": "GET /api/material/inventory/export" + "apiCall": "GET /api/material/stock-status/export" } }, { @@ -209,7 +209,7 @@ "assertions": [ { "type": "url", - "expected": "/material/inventory", + "expected": "/material/stock-status", "message": "재고현황 페이지에 머물러야 함" }, { diff --git a/permission-management.json b/permission-management.json deleted file mode 100644 index 2251381..0000000 --- a/permission-management.json +++ /dev/null @@ -1,590 +0,0 @@ -{ - "id": "permission-management", - "name": "설정 - 권한관리", - "screenshotPolicy": { - "onErrorOnly": true, - "captureOn": [ - "error", - "fail", - "timeout", - "404", - "500", - "blocked" - ] - }, - "url": "/ko/settings/permissions", - "navigation": { - "targetUrl": "/settings/permissions", - "urlPattern": "/settings/permissions|/ko/settings/permissions", - "menuHints": [ - "권한관리", - "권한 관리", - "설정" - ] - }, - "menuNavigation": { - "level1": "설정", - "level2": "권한관리", - "expectedUrl": "/ko/settings/permissions", - "searchWithinParent": true, - "closeOtherMenus": true - }, - "auth": { - "username": "TestUser5", - "password": "password123!" - }, - "menuNavigationEnhanced": { - "strategy": "scroll-and-search", - "description": "사이드바를 스크롤하며 메뉴를 찾고 클릭하여 404를 방지", - "level1": "설정", - "level2": "권한관리", - "alternativeLevel1Names": [ - "설정", - "Settings", - "환경설정", - "시스템설정", - "관리" - ], - "alternativeLevel2Names": [ - "권한관리", - "권한 관리", - "Permissions", - "역할관리", - "Role Management" - ], - "scrollConfig": { - "sidebarSelector": "nav, aside, [role='navigation'], .sidebar, #sidebar", - "menuItemSelector": "a, button, [role='menuitem'], [role='treeitem']", - "scrollStep": 200, - "maxScrollAttempts": 10, - "scrollDelay": 300 - } - }, - "expectedAPIs": [ - { - "method": "GET", - "path": "/api/roles", - "description": "역할 목록 조회" - }, - { - "method": "GET", - "path": "/api/roles/stats", - "description": "역할 통계 조회" - }, - { - "method": "POST", - "path": "/api/roles", - "description": "역할 생성" - }, - { - "method": "GET", - "path": "/api/roles/{id}", - "description": "역할 상세 조회" - }, - { - "method": "PUT", - "path": "/api/roles/{id}", - "description": "역할 수정" - }, - { - "method": "DELETE", - "path": "/api/roles/{id}", - "description": "역할 삭제" - }, - { - "method": "GET", - "path": "/api/roles/{id}/permissions", - "description": "역할별 권한 매트릭스 조회" - }, - { - "method": "PUT", - "path": "/api/roles/{id}/permissions", - "description": "역할별 권한 저장" - } - ], - "steps": [ - { - "id": "step-00", - "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": "step-01", - "name": "2단계 메뉴 진입: 설정 > 권한관리", - "description": "사이드바를 스크롤하며 설정 > 권한관리 메뉴를 찾아 클릭", - "actions": [ - { - "type": "scrollAndFind", - "target": "설정", - "alternativeTexts": [ - "설정", - "Settings", - "환경설정", - "시스템설정" - ], - "scrollContainer": "sidebar", - "maxAttempts": 10, - "description": "스크롤하며 설정 메뉴 찾기" - }, - { - "type": "click_if_exists", - "target": "설정", - "description": "설정 메뉴 클릭" - }, - { - "type": "wait", - "duration": 500, - "description": "서브메뉴 펼쳐지기 대기" - }, - { - "type": "scrollAndFind", - "target": "권한관리", - "alternativeTexts": [ - "권한관리", - "권한 관리", - "Permissions", - "역할관리" - ], - "scrollContainer": "submenu", - "maxAttempts": 5, - "description": "서브메뉴에서 권한관리 찾기" - }, - { - "type": "click_if_exists", - "target": "권한관리", - "description": "권한관리 메뉴 클릭" - }, - { - "type": "wait", - "target": "페이지 로드 완료", - "timeout": 10000 - } - ], - "expected": { - "url": "/ko/settings/permissions", - "title": "권한관리", - "authenticated": true - }, - "verification": [ - "설정 메뉴가 펼쳐졌는지 확인", - "권한관리 서브메뉴 클릭 성공", - "페이지 타이틀 '권한관리' 확인", - "설명 '역할 기반 권한을 관리합니다' 확인", - "Shield 아이콘 표시", - "404 에러 없이 페이지 로드 완료" - ] - }, - { - "id": "step-02", - "name": "통계 카드 확인", - "action": "verify", - "verification": [ - "통계 카드 4개 표시: 전체 역할, 공개, 숨김, 사용 중", - "각 카드에 아이콘과 숫자 표시" - ] - }, - { - "id": "step-03", - "name": "탭 확인", - "action": "verify", - "verification": [ - "탭 3개 표시: 전체, 공개, 숨김", - "각 탭에 카운트 표시" - ] - }, - { - "id": "step-04", - "name": "테이블 구조 확인", - "action": "verify", - "verification": [ - "테이블 컬럼 확인: 체크박스, 번호, 역할, 설명, 상태, 등록일", - "역할 등록 버튼 존재", - "검색창 존재 (placeholder: '역할명, 설명 검색...')" - ] - }, - { - "id": "step-05", - "name": "탭 필터 테스트 - 공개", - "action": "click_if_exists", - "target": "공개 탭", - "verification": [ - "공개 탭 활성화", - "공개 상태 역할만 표시", - "데이터 필터링 확인" - ] - }, - { - "id": "step-06", - "name": "탭 필터 테스트 - 숨김", - "action": "click_if_exists", - "target": "숨김 탭", - "verification": [ - "숨김 탭 활성화", - "숨김 상태 역할만 표시", - "데이터 필터링 확인" - ] - }, - { - "id": "step-07", - "name": "탭 필터 테스트 - 전체", - "action": "click_if_exists", - "target": "전체 탭", - "verification": [ - "전체 탭 활성화", - "모든 역할 표시" - ] - }, - { - "id": "step-08", - "name": "검색 기능 테스트", - "action": "click_if_exists", - "target": "검색 입력 필드", - "value": "관리자", - "verification": [ - "'관리자' 포함된 역할만 표시", - "실시간 필터링 동작" - ] - }, - { - "id": "step-09", - "name": "검색 초기화", - "action": "click_if_exists", - "target": "검색 입력 필드", - "verification": [ - "검색어 제거됨", - "전체 목록 복원" - ] - }, - { - "id": "step-10", - "name": "역할 등록 페이지 이동", - "action": "click_if_exists", - "target": "역할 등록 버튼", - "verification": [ - "URL 변경: /settings/permissions?mode=new", - "페이지 타이틀 변경 확인" - ] - }, - { - "id": "step-11", - "name": "역할명 입력", - "action": "click_if_exists", - "target": "권한명 입력 필드", - "value": "E2E 테스트 역할", - "verification": [ - "입력 값 반영 확인" - ] - }, - { - "id": "step-12", - "name": "설명 입력", - "action": "click_if_exists", - "target": "설명 입력 필드 (있는 경우)", - "value": "E2E 테스트를 위한 역할입니다", - "verification": [ - "입력 값 반영 확인" - ] - }, - { - "id": "step-13", - "name": "상태 선택", - "action": "click_if_exists", - "target": "상태 드롭다운", - "value": "공개", - "verification": [ - "상태 선택 확인" - ] - }, - { - "id": "step-14", - "name": "역할 등록", - "action": "click_if_exists", - "target": "등록 버튼", - "verification": [ - "현재 URL 저장", - "등록 버튼 클릭", - "URL 변경 여부 확인 (에러 페이지 이동 방지)", - "에러 텍스트 없음 ('페이지를 찾을 수 없습니다', '404', 'Not Found' 등)", - "API 호출 확인: POST /api/roles", - "API 응답 200 OK 확인", - "목록 페이지로 리다이렉트 또는 상세 페이지 이동", - "성공 토스트 메시지 확인" - ] - }, - { - "id": "step-15", - "name": "목록에서 신규 역할 확인", - "action": "verify", - "verification": [ - "목록 페이지 진입 (URL: /settings/permissions)", - "'E2E 테스트 역할' 목록에 표시", - "통계 카드 숫자 증가 확인" - ] - }, - { - "id": "step-16", - "name": "역할 상세 페이지 이동", - "action": "click_if_exists", - "target": "E2E 테스트 역할 행", - "verification": [ - "URL 변경: /settings/permissions/{id}", - "페이지 타이틀 '권한 상세' 확인", - "기본 정보 섹션 표시", - "메뉴별 권한 테이블 표시" - ] - }, - { - "id": "step-17", - "name": "기본 정보 확인", - "action": "verify", - "verification": [ - "권한명 입력 필드에 'E2E 테스트 역할' 표시", - "상태 드롭다운에 '공개' 선택됨", - "삭제 버튼 존재", - "수정 버튼 존재", - "목록으로 버튼 존재" - ] - }, - { - "id": "step-18", - "name": "권한 테이블 구조 확인", - "action": "verify", - "verification": [ - "테이블 헤더: 메뉴, 조회, 생성, 수정, 삭제, 승인, 내보내기, 관리", - "각 헤더에 전체 선택 체크박스 존재", - "메뉴 목록 표시 (부모 메뉴 접기/펼치기 아이콘 있음)", - "각 메뉴별 권한 체크박스 존재" - ] - }, - { - "id": "step-19", - "name": "부모 메뉴 펼치기", - "action": "click_if_exists", - "target": "첫 번째 부모 메뉴 펼치기 아이콘", - "verification": [ - "자식 메뉴 목록 표시", - "아이콘이 ChevronDown으로 변경", - "자식 메뉴는 들여쓰기되어 표시" - ] - }, - { - "id": "step-20", - "name": "개별 권한 체크박스 토글", - "action": "click_if_exists", - "target": "첫 번째 메뉴의 '조회' 체크박스", - "verification": [ - "체크박스 상태 변경", - "자동 저장 동작 (API 호출 확인)" - ] - }, - { - "id": "step-21", - "name": "컬럼 전체 선택", - "action": "click_if_exists", - "target": "'조회' 헤더 체크박스", - "verification": [ - "모든 메뉴의 '조회' 권한 체크", - "자동 저장 동작 확인" - ] - }, - { - "id": "step-22", - "name": "권한명 수정", - "action": "click_if_exists", - "target": "권한명 입력 필드", - "value": "E2E 테스트 역할 (수정됨)", - "verification": [ - "입력 값 변경 확인" - ] - }, - { - "id": "step-23", - "name": "권한명 수정 저장 (blur)", - "action": "blur", - "target": "권한명 입력 필드", - "verification": [ - "자동 저장 동작 (API 호출)", - "PUT /api/roles/{id} 확인" - ] - }, - { - "id": "step-24", - "name": "상태 변경", - "action": "click_if_exists", - "target": "상태 드롭다운", - "value": "숨김", - "verification": [ - "상태 변경 확인", - "자동 저장 동작" - ] - }, - { - "id": "step-25", - "name": "목록으로 이동", - "action": "click_if_exists", - "target": "목록으로 버튼", - "verification": [ - "URL 변경: /settings/permissions", - "목록 페이지 표시" - ] - }, - { - "id": "step-26", - "name": "수정된 역할 확인", - "action": "verify", - "verification": [ - "'E2E 테스트 역할 (수정됨)' 목록에 표시", - "상태 Badge '숨김'으로 표시" - ] - }, - { - "id": "step-27", - "name": "숨김 탭으로 이동", - "action": "click_if_exists", - "target": "숨김 탭", - "verification": [ - "숨김 상태 역할만 표시", - "'E2E 테스트 역할 (수정됨)' 표시됨" - ] - }, - { - "id": "step-28", - "name": "전체 탭으로 복귀", - "action": "click_if_exists", - "target": "전체 탭", - "verification": [ - "모든 역할 표시" - ] - }, - { - "id": "step-29", - "name": "체크박스 선택", - "action": "click_if_exists", - "target": "E2E 테스트 역할 체크박스", - "verification": [ - "체크박스 선택됨", - "'1개 항목 선택됨' 표시", - "'선택 삭제 (1)' 버튼 표시", - "작업 컬럼 추가 (권한 설정, 수정, 삭제 버튼)" - ] - }, - { - "id": "step-30", - "name": "단일 삭제 - 작업 컬럼 삭제 버튼", - "action": "click_if_exists", - "target": "작업 컬럼의 삭제 버튼", - "verification": [ - "삭제 확인 다이얼로그 표시", - "다이얼로그 제목: '역할 삭제'", - "경고 메시지: '이 역할을 사용 중인 사원이 있으면 해당 사원의 역할이 초기화됩니다.'" - ] - }, - { - "id": "step-31", - "name": "삭제 취소", - "action": "click_if_exists", - "target": "다이얼로그 취소 버튼", - "verification": [ - "다이얼로그 닫힘", - "역할 삭제되지 않음" - ] - }, - { - "id": "step-32", - "name": "일괄 삭제 버튼 클릭", - "action": "click_if_exists", - "target": "선택 삭제 버튼", - "verification": [ - "삭제 확인 다이얼로그 표시", - "'선택한 1개의 역할을 삭제하시겠습니까?' 메시지" - ] - }, - { - "id": "step-33", - "name": "일괄 삭제 실행", - "action": "click_if_exists", - "target": "다이얼로그 삭제 버튼", - "verification": [ - "삭제 중 로딩 표시 ('삭제 중...')", - "API 호출: DELETE /api/roles/{id}", - "API 응답 200 OK 확인", - "다이얼로그 닫힘", - "성공 토스트 메시지 확인", - "목록에서 삭제된 역할 제거됨", - "통계 카드 숫자 감소 확인" - ] - }, - { - "id": "step-34", - "name": "체크박스 전체 선택", - "action": "click_if_exists", - "target": "테이블 헤더 체크박스", - "verification": [ - "현재 페이지의 모든 항목 선택", - "'N개 항목 선택됨' 표시", - "'선택 삭제 (N)' 버튼 표시" - ] - }, - { - "id": "step-35", - "name": "전체 선택 해제", - "action": "click_if_exists", - "target": "테이블 헤더 체크박스", - "verification": [ - "모든 선택 해제", - "'선택 삭제' 버튼 숨김", - "작업 컬럼 제거" - ] - }, - { - "id": "step-36", - "name": "페이지네이션 테스트 (데이터 충분 시)", - "action": "verify", - "verification": [ - "페이지네이션 컨트롤 존재 여부 확인", - "페이지당 20개 항목 표시", - "총 페이지 수 표시" - ] - }, - { - "id": "step-37", - "name": "반응형 테스트 - 모바일", - "action": "resize", - "width": 375, - "height": 667, - "verification": [ - "모바일 카드 레이아웃으로 변경", - "각 카드에 역할명, 상태, 설명, 등록일 표시", - "카드에 권한 설정, 수정 버튼 존재" - ] - } - ], - "testData": { - "role": { - "name": "E2E 테스트 역할", - "description": "E2E 테스트를 위한 역할입니다", - "status": "active" - } - }, - "cleanup": { - "description": "Step-33에서 테스트 데이터 삭제 완료" - } -} \ No newline at end of file diff --git a/price-management.json b/price-management.json index 380052d..33930e1 100644 --- a/price-management.json +++ b/price-management.json @@ -7,16 +7,16 @@ }, "description": "판매관리 > 단가관리 페이지의 품목별 단가 조회/등록/수정 기능을 테스트하는 E2E 테스트", "baseUrl": "https://dev.codebridge-x.com", - "url": "/sales/price", + "url": "/sales/pricing-management", "navigation": { - "targetUrl": "/sales/price", - "urlPattern": "/sales/price|/ko/sales/price", + "targetUrl": "/sales/pricing-management", + "urlPattern": "/sales/pricing-management|/ko/sales/pricing-management", "menuHints": ["단가관리", "단가 관리", "판매관리"] }, "menuNavigation": { "level1": "판매관리", "level2": "단가관리", - "expectedUrl": "/sales/price", + "expectedUrl": "/sales/pricing-management", "searchWithinParent": true, "closeOtherMenus": true }, @@ -37,8 +37,8 @@ "text": "단가관리", "waitAfterClick": 300 }, - "fallbackUrl": "/sales/price", - "expectedUrl": "/sales/price" + "fallbackUrl": "/sales/pricing-management", + "expectedUrl": "/sales/pricing-management" }, "timeout": 90000, "tags": ["sales", "price", "crud"], @@ -92,12 +92,12 @@ { "type": "click_if_exists", "target": "단가관리" } ], "expect": { - "url": "/sales/price", + "url": "/sales/pricing-management", "visible": ["단가 목록", "품목 마스터 동기화"] }, "fallback": { "type": "navigate", - "url": "/sales/price" + "url": "/sales/pricing-management" } }, { @@ -186,7 +186,7 @@ "toast": ["등록", "저장", "완료", "성공"] }, "verify": { - "apiCall": "POST /api/sales/price" + "apiCall": "POST /api/sales/pricing-management" } }, { @@ -269,7 +269,7 @@ "assertions": [ { "type": "url", - "expected": "/sales/price", + "expected": "/sales/pricing-management", "message": "단가관리 페이지에 머물러야 함" }, { diff --git a/production-dashboard.json b/production-dashboard.json index 2f23134..1effe62 100644 --- a/production-dashboard.json +++ b/production-dashboard.json @@ -1,5 +1,5 @@ { - "enabled": false, + "enabled": true, "id": "production-dashboard", "name": "생산 현황판 테스트", "screenshotPolicy": { diff --git a/production-item.json b/production-item.json index 9fd2f7f..a2f234d 100644 --- a/production-item.json +++ b/production-item.json @@ -1,5 +1,5 @@ { - "enabled": false, + "enabled": true, "id": "production-item", "name": "생산품목관리 테스트", "screenshotPolicy": { diff --git a/production-work-order.json b/production-work-order.json index c8a1de6..bc9e21a 100644 --- a/production-work-order.json +++ b/production-work-order.json @@ -1,5 +1,5 @@ { - "enabled": false, + "enabled": true, "id": "production-work-order", "name": "작업지시 관리 테스트", "screenshotPolicy": { diff --git a/production-work-result.json b/production-work-result.json index 50e2ee4..e967e80 100644 --- a/production-work-result.json +++ b/production-work-result.json @@ -1,5 +1,5 @@ { - "enabled": false, + "enabled": true, "id": "production-work-result", "name": "작업실적 테스트", "screenshotPolicy": { diff --git a/production-worker.json b/production-worker.json index 2478ade..e916dd0 100644 --- a/production-worker.json +++ b/production-worker.json @@ -1,5 +1,5 @@ { - "enabled": false, + "enabled": true, "id": "production-worker", "name": "작업자 화면 테스트", "screenshotPolicy": { diff --git a/purchase-client.json b/purchase-client.json deleted file mode 100644 index 663721a..0000000 --- a/purchase-client.json +++ /dev/null @@ -1,264 +0,0 @@ -{ - "enabled": false, - "id": "purchase-client", - "name": "구매거래처관리 테스트", - "screenshotPolicy": { - "onErrorOnly": true, - "captureOn": [ - "error", - "fail", - "timeout", - "404", - "500", - "blocked" - ] - }, - "description": "구매관리 > 거래처관리 메뉴의 구매 거래처 CRUD 기능 테스트", - "baseUrl": "https://dev.codebridge-x.com", - "menuNavigation": { - "level1": "구매관리", - "level2": "거래처관리", - "expectedUrl": "/purchase/supplier-management", - "searchWithinParent": true, - "closeOtherMenus": true - }, - "auth": { - "username": "TestUser5", - "password": "password123!" - }, - "testData": { - "create": { - "supplierName": "E2E_TEST_구매처_{timestamp}", - "businessNumber": "123-45-67890", - "representative": "테스트 대표" - } - }, - "steps": [ - { - "id": 1, - "name": "메뉴 진입: 구매관리 > 거래처관리", - "action": "menu_navigate", - "level1": "구매관리", - "level2": "거래처관리", - "expected": { - "url_contains": "/purchase", - "visible": [ - "거래처관리", - "거래처" - ] - } - }, - { - "id": 2, - "name": "필수 검증 #5: 목업 페이지 감지", - "action": "verify_not_mockup", - "checks": [ - "거래처 목록 표시", - "거래처 등록 버튼 존재", - "검색 기능 존재" - ], - "expected": "정상 페이지 (목업 아님)" - }, - { - "id": 3, - "name": "거래처 테이블 구조 확인", - "action": "verify_table", - "checks": [ - "거래처명 컬럼", - "사업자번호 컬럼", - "대표자 컬럼", - "연락처 컬럼" - ], - "expected": "거래처 테이블 표시" - }, - { - "id": 4, - "phase": "CREATE", - "name": "[CREATE] 거래처 등록 버튼 클릭", - "action": "click_if_exists", - "target": "button:has-text('등록'), button:has-text('추가'), button:has-text('신규')", - "expected": { - "modal_open": true - } - }, - { - "id": 5, - "phase": "CREATE", - "name": "[CREATE] 거래처명 입력", - "action": "click_if_exists", - "target": "input[name*='name'], input[placeholder*='거래처명']" - }, - { - "id": 6, - "phase": "CREATE", - "name": "[CREATE] 사업자번호 입력", - "action": "click_if_exists", - "target": "input[name*='business'], input[placeholder*='사업자']" - }, - { - "id": 7, - "phase": "CREATE", - "name": "[CREATE] 대표자명 입력", - "action": "click_if_exists", - "target": "input[name*='representative'], input[placeholder*='대표']" - }, - { - "id": 8, - "phase": "CREATE", - "name": "[CREATE] 필수 검증 #2: 거래처 저장", - "action": "click_if_exists", - "target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')", - "verify": { - "url_maintained": true, - "no_error_page": true, - "api_call": "POST /api/v1/purchase/suppliers", - "toast": "등록|저장|완료|성공" - }, - "expected": "거래처 등록 완료" - }, - { - "id": 9, - "phase": "READ", - "name": "[READ] 등록된 거래처 검색", - "action": "click_if_exists", - "target": "input[type='search'], input[placeholder*='검색']" - }, - { - "id": 10, - "phase": "READ", - "name": "[READ] 등록된 거래처 확인", - "action": "verify_detail", - "checks": [ - "E2E_TEST_구매처 목록에 표시" - ], - "expected": "등록된 거래처 확인" - }, - { - "id": 11, - "phase": "READ", - "name": "[READ] 거래처 상세 조회", - "action": "click_if_exists", - "target": "table tbody tr:has-text('E2E_TEST')", - "expected": { - "detail_view": true - } - }, - { - "id": 12, - "phase": "UPDATE", - "name": "[UPDATE] 거래처 수정 모드 진입", - "action": "click_if_exists", - "target": "button:has-text('수정'), button:has-text('편집')", - "expected": { - "edit_mode": true - } - }, - { - "id": 13, - "phase": "UPDATE", - "name": "[UPDATE] 대표자명 수정", - "action": "click_if_exists", - "target": "input[name*='representative'], input[placeholder*='대표']" - }, - { - "id": 14, - "phase": "UPDATE", - "name": "[UPDATE] 거래처 저장", - "action": "click_if_exists", - "target": "button:has-text('저장'), button:has-text('확인')", - "verify": { - "api_call": "PUT /api/v1/purchase/suppliers", - "toast": "수정|저장|완료|성공" - }, - "expected": "거래처 수정 완료" - }, - { - "id": 15, - "phase": "DELETE", - "name": "[DELETE] 거래처 삭제", - "action": "click_if_exists", - "target": "button:has-text('삭제'), button:has-text('제거')", - "expected": { - "confirm_dialog": true - } - }, - { - "id": 16, - "phase": "DELETE", - "name": "[DELETE] 삭제 확인", - "action": "click_if_exists", - "target": "[role='alertdialog'] button:has-text('확인'), [role='dialog'] button:has-text('삭제')", - "verify": { - "api_call": "DELETE /api/v1/purchase/suppliers", - "toast": "삭제|제거|완료|성공" - }, - "expected": "거래처 삭제 완료" - }, - { - "id": 17, - "phase": "DELETE", - "name": "[DELETE] 삭제 확인", - "action": "verify_detail", - "checks": [ - "E2E_TEST_구매처 목록에서 제거" - ], - "expected": "거래처 삭제 반영" - }, - { - "id": 18, - "name": "엑셀 다운로드 확인", - "action": "verify_elements", - "checks": [ - "엑셀 다운로드 버튼 존재" - ], - "expected": "엑셀 다운로드 기능 표시" - } - ], - "expectedAPIs": [ - { - "method": "GET", - "endpoint": "/api/v1/purchase/suppliers", - "description": "거래처 목록 조회" - }, - { - "method": "POST", - "endpoint": "/api/v1/purchase/suppliers", - "description": "거래처 등록" - }, - { - "method": "PUT", - "endpoint": "/api/v1/purchase/suppliers/:id", - "description": "거래처 수정" - }, - { - "method": "DELETE", - "endpoint": "/api/v1/purchase/suppliers/:id", - "description": "거래처 삭제" - } - ], - "requiredVerifications": [ - { - "id": 2, - "name": "저장 버튼", - "steps": [ - 8, - 14 - ], - "criteria": "API 호출 + 성공 토스트 + 데이터 반영" - }, - { - "id": 5, - "name": "목업 페이지 감지", - "steps": [ - 2 - ], - "criteria": "거래처 목록, 등록 버튼, 검색 기능 존재" - } - ], - "rollbackPlan": { - "onCreateFail": "등록 모달 닫고 재시도", - "onUpdateFail": "페이지 새로고침 후 재시도", - "onDeleteFail": "수동 삭제 필요", - "cleanupRequired": "E2E_TEST_구매처_* 패턴 데이터 삭제" - } -} \ No newline at end of file diff --git a/purchase-order.json b/purchase-order.json deleted file mode 100644 index 0ac1bba..0000000 --- a/purchase-order.json +++ /dev/null @@ -1,331 +0,0 @@ -{ - "enabled": false, - "id": "purchase-order", - "name": "발주관리 테스트", - "screenshotPolicy": { - "onErrorOnly": true, - "captureOn": [ - "error", - "fail", - "timeout", - "404", - "500", - "blocked" - ] - }, - "description": "구매관리 > 발주관리 메뉴의 발주 조회/등록/수정/삭제 전체 CRUD 테스트", - "baseUrl": "https://dev.codebridge-x.com", - "menuNavigation": { - "level1": "구매관리", - "level2": "발주관리", - "expectedUrl": "/purchase/purchase-order", - "searchWithinParent": true, - "closeOtherMenus": true - }, - "auth": { - "username": "TestUser5", - "password": "password123!" - }, - "testData": { - "create": { - "vendorName": "E2E_TEST_거래처", - "itemName": "테스트품목", - "quantity": "300", - "unitPrice": "5000", - "deliveryDate": "2026-02-20", - "memo": "E2E 자동화 테스트 발주" - }, - "update": { - "quantity": "350", - "memo": "E2E 수정된 발주 메모" - } - }, - "steps": [ - { - "id": 1, - "name": "메뉴 진입: 구매관리 > 발주관리", - "action": "menu_navigate", - "level1": "구매관리", - "level2": "발주관리", - "expected": { - "url_contains": "/purchase", - "visible": [ - "발주관리", - "발주" - ] - } - }, - { - "id": 2, - "name": "필수 검증 #5: 목업 페이지 감지", - "action": "verify_not_mockup", - "checks": [ - "발주 목록 표시", - "발주 등록 버튼 존재", - "검색/필터 기능 존재" - ], - "expected": "정상 페이지 (목업 아님)" - }, - { - "id": 3, - "name": "발주 테이블 구조 확인", - "action": "verify_table", - "checks": [ - "발주번호 컬럼", - "거래처 컬럼", - "품목 컬럼", - "수량 컬럼", - "금액 컬럼", - "상태 컬럼" - ], - "expected": "발주 테이블 컬럼 정상 표시" - }, - { - "id": 4, - "name": "검색 기능 테스트", - "action": "click_if_exists", - "target": "input[placeholder*='검색']", - "value": "테스트", - "expected": { - "data_filtered": true - } - }, - { - "id": 5, - "phase": "CREATE", - "name": "[CREATE] 발주 등록 버튼 클릭", - "action": "click_if_exists", - "target": "button:has-text('등록'), button:has-text('발주 등록'), button:has-text('추가')", - "expected": { - "modal_or_page": true, - "title": "발주 등록" - } - }, - { - "id": 6, - "phase": "CREATE", - "name": "[CREATE] 발주 정보 입력", - "action": "click_if_exists", - "target": "form, [role=\"dialog\"], .modal" - }, - { - "id": 7, - "phase": "CREATE", - "name": "[CREATE] 필수 검증 #2: 등록 저장", - "action": "click_if_exists", - "target": "button:has-text('저장'), button:has-text('등록')", - "verify": { - "url_maintained": true, - "no_error_page": true, - "api_call": "POST /api/v1/purchase-orders", - "toast": "등록|완료|성공" - }, - "expected": "발주 등록 완료" - }, - { - "id": "7-modal-close", - "phase": "CREATE", - "name": "[CREATE] 모달 닫기 확인", - "action": "close_modal_if_open", - "expected": "모달 닫힘" - }, - { - "id": 8, - "phase": "CREATE", - "name": "[CREATE] 등록 결과 확인", - "action": "verify_detail", - "search": "E2E 자동화 테스트 발주", - "expected": { - "row_exists": true, - "contains": [ - "E2E", - "300", - "1,500,000" - ] - } - }, - { - "id": 9, - "phase": "READ", - "name": "[READ] 발주 상세 페이지 진입", - "action": "click_if_exists", - "target": "table tbody tr:has-text('E2E')", - "expected": { - "url_contains": "/purchase", - "visible": [ - "발주 상세", - "수정", - "삭제" - ] - } - }, - { - "id": 10, - "phase": "READ", - "name": "[READ] 상세 정보 확인", - "action": "verify_detail", - "checks": [ - "거래처: E2E_TEST_거래처", - "수량: 300", - "금액: 1,500,000", - "납기일: 2026-02-20" - ], - "expected": "입력한 데이터와 일치" - }, - { - "id": 11, - "phase": "UPDATE", - "name": "[UPDATE] 수정 모드 진입", - "action": "click_if_exists", - "target": "button:has-text('수정')", - "expected": { - "url_contains": "mode=edit", - "fields_editable": true - } - }, - { - "id": 12, - "phase": "UPDATE", - "name": "[UPDATE] 수량 수정", - "action": "click_if_exists", - "target": "input[name*='quantity'], input[placeholder*='수량']" - }, - { - "id": 13, - "phase": "UPDATE", - "name": "[UPDATE] 메모 수정", - "action": "click_if_exists", - "target": "textarea[name*='memo'], input[placeholder*='메모']" - }, - { - "id": 14, - "phase": "UPDATE", - "name": "[UPDATE] 필수 검증 #2: 수정 저장", - "action": "click_if_exists", - "target": "button:has-text('저장')", - "verify": { - "url_maintained": true, - "no_error_page": true, - "api_call": "PUT /api/v1/purchase-orders/", - "toast": "수정|완료|성공" - }, - "expected": "수정 완료" - }, - { - "id": 15, - "phase": "UPDATE", - "name": "[UPDATE] 수정 결과 확인", - "action": "verify_detail", - "checks": [ - "수량: 350", - "금액: 1,750,000" - ], - "expected": "수정된 데이터 반영" - }, - { - "id": 16, - "phase": "DELETE", - "name": "[DELETE] 삭제 버튼 클릭", - "action": "click_if_exists", - "target": "button:has-text('삭제')", - "expected": { - "confirm_dialog": true, - "dialog_message": "삭제|정말" - } - }, - { - "id": 17, - "phase": "DELETE", - "name": "[DELETE] 필수 검증 #6: 삭제 확인", - "action": "click_if_exists", - "target": "button:has-text('확인'), button:has-text('삭제')", - "verify": { - "api_call": "DELETE /api/v1/purchase-orders/", - "toast": "삭제|완료|성공", - "redirect": "/purchase" - }, - "expected": "삭제 완료 및 목록 복귀" - }, - { - "id": 18, - "phase": "DELETE", - "name": "[DELETE] 삭제 결과 확인", - "action": "verify_detail", - "search": "E2E 수정된 발주", - "expected": { - "row_exists": false, - "message": "테스트 발주가 목록에서 제거됨" - } - } - ], - "expectedAPIs": [ - { - "method": "GET", - "endpoint": "/api/v1/purchase-orders", - "description": "발주 목록 조회" - }, - { - "method": "POST", - "endpoint": "/api/v1/purchase-orders", - "description": "발주 등록" - }, - { - "method": "GET", - "endpoint": "/api/v1/purchase-orders/{id}", - "description": "발주 상세 조회" - }, - { - "method": "PUT", - "endpoint": "/api/v1/purchase-orders/{id}", - "description": "발주 수정" - }, - { - "method": "DELETE", - "endpoint": "/api/v1/purchase-orders/{id}", - "description": "발주 삭제" - } - ], - "requiredVerifications": [ - { - "id": 2, - "name": "등록/저장 버튼", - "steps": [ - 7, - 14 - ], - "criteria": "API 호출 + 성공 토스트 + 데이터 반영" - }, - { - "id": 3, - "name": "검색/필터", - "steps": [ - 4 - ], - "criteria": "검색 기능 동작" - }, - { - "id": 5, - "name": "목업 페이지 감지", - "steps": [ - 2 - ], - "criteria": "발주 목록, 등록 버튼, 필터 존재" - }, - { - "id": 6, - "name": "삭제 기능", - "steps": [ - 16, - 17, - 18 - ], - "criteria": "DELETE API + 목록에서 제거" - } - ], - "rollbackPlan": { - "onCreateFail": "모달 닫기", - "onUpdateFail": "테스트 발주 수동 삭제 필요", - "onDeleteFail": "테스트 발주 수동 삭제 필요", - "cleanupRequired": "E2E_TEST_ 접두사 발주는 테스트 데이터" - } -} \ No newline at end of file diff --git a/purchase-pricing.json b/purchase-pricing.json deleted file mode 100644 index f6774b4..0000000 --- a/purchase-pricing.json +++ /dev/null @@ -1,270 +0,0 @@ -{ - "enabled": false, - "id": "purchase-pricing", - "name": "구매 단가관리 테스트", - "screenshotPolicy": { - "onErrorOnly": true, - "captureOn": [ - "error", - "fail", - "timeout", - "404", - "500", - "blocked" - ] - }, - "description": "구매관리 > 단가관리 메뉴의 구매 단가 CRUD 기능 테스트", - "baseUrl": "https://dev.codebridge-x.com", - "menuNavigation": { - "level1": "구매관리", - "level2": "단가관리", - "expectedUrl": "/purchase/pricing-management", - "searchWithinParent": true, - "closeOtherMenus": true - }, - "auth": { - "username": "TestUser5", - "password": "password123!" - }, - "testData": { - "create": { - "itemName": "E2E_TEST_품목_{timestamp}", - "price": "10000", - "unit": "EA" - } - }, - "steps": [ - { - "id": 1, - "name": "메뉴 진입: 구매관리 > 단가관리", - "action": "menu_navigate", - "level1": "구매관리", - "level2": "단가관리", - "expected": { - "url_contains": "/purchase", - "visible": [ - "단가관리", - "단가" - ] - } - }, - { - "id": 2, - "name": "필수 검증 #5: 목업 페이지 감지", - "action": "verify_not_mockup", - "checks": [ - "단가 목록 표시", - "단가 등록 버튼 존재", - "검색 기능 존재" - ], - "expected": "정상 페이지 (목업 아님)" - }, - { - "id": 3, - "name": "단가 테이블 구조 확인", - "action": "verify_table", - "checks": [ - "품목 컬럼", - "거래처 컬럼", - "단가 컬럼", - "적용기간 컬럼" - ], - "expected": "단가 테이블 표시" - }, - { - "id": 4, - "phase": "CREATE", - "name": "[CREATE] 단가 등록 버튼 클릭", - "action": "click_if_exists", - "target": "button:has-text('등록'), button:has-text('추가'), button:has-text('신규')", - "expected": { - "modal_open": true - } - }, - { - "id": 5, - "phase": "CREATE", - "name": "[CREATE] 품목 선택", - "action": "click_if_exists", - "target": "select[name*='item'], button:has-text('품목'), input[placeholder*='품목']", - "expected": "품목 선택 가능" - }, - { - "id": 6, - "phase": "CREATE", - "name": "[CREATE] 거래처 선택", - "action": "click_if_exists", - "target": "select[name*='supplier'], button:has-text('거래처'), input[placeholder*='거래처']", - "expected": "거래처 선택 가능" - }, - { - "id": 7, - "phase": "CREATE", - "name": "[CREATE] 단가 입력", - "action": "click_if_exists", - "target": "input[name*='price'], input[placeholder*='단가']", - "value": "10000", - "clear": true - }, - { - "id": 8, - "phase": "CREATE", - "name": "[CREATE] 필수 검증 #2: 단가 저장", - "action": "click_if_exists", - "target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')", - "verify": { - "url_maintained": true, - "no_error_page": true, - "api_call": "POST /api/v1/purchase/pricing", - "toast": "등록|저장|완료|성공" - }, - "expected": "단가 등록 완료" - }, - { - "id": 9, - "phase": "READ", - "name": "[READ] 등록된 단가 확인", - "action": "verify_detail", - "checks": [ - "등록한 단가 목록에 표시" - ], - "expected": "등록된 단가 확인" - }, - { - "id": 10, - "phase": "READ", - "name": "[READ] 단가 상세 조회", - "action": "click_if_exists", - "target": "table tbody tr:first-child", - "expected": { - "detail_view": true - } - }, - { - "id": 11, - "name": "단가 상세 정보 확인", - "action": "verify_detail", - "checks": [ - "품목 정보", - "거래처 정보", - "단가", - "적용기간" - ], - "expected": "단가 상세 정보 표시" - }, - { - "id": 12, - "phase": "UPDATE", - "name": "[UPDATE] 단가 수정 모드 진입", - "action": "click_if_exists", - "target": "button:has-text('수정'), button:has-text('편집')", - "expected": { - "edit_mode": true - } - }, - { - "id": 13, - "phase": "UPDATE", - "name": "[UPDATE] 단가 수정", - "action": "click_if_exists", - "target": "input[name*='price'], input[placeholder*='단가']", - "value": "12000", - "clear": true - }, - { - "id": 14, - "phase": "UPDATE", - "name": "[UPDATE] 단가 저장", - "action": "click_if_exists", - "target": "button:has-text('저장'), button:has-text('확인')", - "verify": { - "api_call": "PUT /api/v1/purchase/pricing", - "toast": "수정|저장|완료|성공" - }, - "expected": "단가 수정 완료" - }, - { - "id": 15, - "name": "단가 이력 조회", - "action": "verify_elements", - "checks": [ - "단가 변동 이력 조회 가능" - ], - "expected": "단가 이력 기능 확인" - }, - { - "id": 16, - "name": "엑셀 다운로드", - "action": "click_if_exists", - "target": "button:has-text('엑셀'), button:has-text('Excel'), button:has-text('다운로드')", - "verify": { - "file_download": true - }, - "expected": "엑셀 파일 다운로드" - }, - { - "id": 17, - "name": "단가 비교 기능", - "action": "verify_elements", - "checks": [ - "거래처별 단가 비교 기능" - ], - "expected": "단가 비교 기능 확인" - }, - { - "id": 18, - "name": "일괄 등록 기능", - "action": "verify_elements", - "checks": [ - "엑셀 일괄 등록 버튼 존재 여부" - ], - "expected": "일괄 등록 기능 확인" - } - ], - "expectedAPIs": [ - { - "method": "GET", - "endpoint": "/api/v1/purchase/pricing", - "description": "단가 목록 조회" - }, - { - "method": "POST", - "endpoint": "/api/v1/purchase/pricing", - "description": "단가 등록" - }, - { - "method": "PUT", - "endpoint": "/api/v1/purchase/pricing/:id", - "description": "단가 수정" - }, - { - "method": "GET", - "endpoint": "/api/v1/purchase/pricing/history", - "description": "단가 이력 조회" - } - ], - "requiredVerifications": [ - { - "id": 2, - "name": "저장 버튼", - "steps": [ - 8, - 14 - ], - "criteria": "API 호출 + 성공 토스트 + 데이터 반영" - }, - { - "id": 5, - "name": "목업 페이지 감지", - "steps": [ - 2 - ], - "criteria": "단가 목록, 등록 버튼, 검색 기능 존재" - } - ], - "rollbackPlan": { - "onCreateFail": "등록 모달 닫고 재시도", - "onUpdateFail": "페이지 새로고침 후 재시도", - "note": "단가 삭제는 일반적으로 비활성화 처리" - } -} \ No newline at end of file diff --git a/purchase-status.json b/purchase-status.json deleted file mode 100644 index 435385f..0000000 --- a/purchase-status.json +++ /dev/null @@ -1,220 +0,0 @@ -{ - "enabled": false, - "id": "purchase-status", - "name": "구매현황 테스트", - "screenshotPolicy": { - "onErrorOnly": true, - "captureOn": [ - "error", - "fail", - "timeout", - "404", - "500", - "blocked" - ] - }, - "description": "구매관리 > 구매현황 메뉴의 구매 현황 조회/필터/통계 기능 테스트", - "baseUrl": "https://dev.codebridge-x.com", - "menuNavigation": { - "level1": "구매관리", - "level2": "구매현황", - "expectedUrl": "/purchase/status", - "searchWithinParent": true, - "closeOtherMenus": true - }, - "auth": { - "username": "TestUser5", - "password": "password123!" - }, - "steps": [ - { - "id": 1, - "name": "메뉴 진입: 구매관리 > 구매현황", - "action": "menu_navigate", - "level1": "구매관리", - "level2": "구매현황", - "expected": { - "url_contains": "/purchase", - "visible": [ - "구매현황", - "구매" - ] - } - }, - { - "id": 2, - "name": "필수 검증 #5: 목업 페이지 감지", - "action": "verify_not_mockup", - "checks": [ - "구매 현황 표시", - "기간 필터 존재", - "통계 또는 차트 존재" - ], - "expected": "정상 페이지 (목업 아님)" - }, - { - "id": 3, - "name": "구매현황 페이지 구조 확인", - "action": "verify_elements", - "checks": [ - "구매 통계 카드", - "기간 선택 필터", - "구매 목록 테이블 또는 차트" - ], - "expected": "구매현황 페이지 정상 표시" - }, - { - "id": 4, - "phase": "READ", - "name": "[READ] 구매 통계 확인", - "action": "verify_detail", - "checks": [ - "총 구매금액", - "구매 건수", - "평균 구매금액" - ], - "expected": "구매 통계 표시" - }, - { - "id": 5, - "phase": "FILTER", - "name": "[FILTER] 기간 필터 - 시작일", - "action": "click_if_exists", - "target": "input[type='date']:first-of-type, input[name*='start']" - }, - { - "id": 6, - "phase": "FILTER", - "name": "[FILTER] 기간 필터 - 종료일", - "action": "click_if_exists", - "target": "input[type='date']:last-of-type, input[name*='end']" - }, - { - "id": 7, - "phase": "FILTER", - "name": "[FILTER] 조회 실행", - "action": "click_if_exists", - "target": "button:has-text('조회'), button:has-text('검색')", - "expected": { - "data_loaded": true, - "api_call": "GET /api/v1/purchase/status" - } - }, - { - "id": 8, - "name": "구매 현황 테이블 확인", - "action": "verify_table", - "checks": [ - "발주일 컬럼", - "거래처 컬럼", - "품목 컬럼", - "금액 컬럼", - "상태 컬럼" - ], - "expected": "구매 현황 테이블 표시" - }, - { - "id": 9, - "name": "상태별 필터 확인", - "action": "verify_elements", - "checks": [ - "진행중/완료/취소 상태 필터" - ], - "expected": "상태 필터 표시" - }, - { - "id": 10, - "name": "거래처별 통계 확인", - "action": "verify_elements", - "checks": [ - "거래처별 구매금액 표시" - ], - "expected": "거래처별 통계 표시" - }, - { - "id": 11, - "name": "품목별 통계 확인", - "action": "verify_elements", - "checks": [ - "품목별 구매금액 표시" - ], - "expected": "품목별 통계 표시" - }, - { - "id": 12, - "name": "월별 추이 차트 확인", - "action": "verify_elements", - "checks": [ - "월별 구매 추이 차트" - ], - "expected": "추이 차트 표시" - }, - { - "id": 13, - "name": "필수 검증 #1: 엑셀 다운로드", - "action": "click_if_exists", - "target": "button:has-text('엑셀'), button:has-text('Excel'), button:has-text('다운로드')", - "verify": { - "api_call": "GET /api/v1/purchase/status/export", - "file_download": true - }, - "expected": "엑셀 파일 다운로드" - }, - { - "id": 14, - "name": "인쇄 기능 확인", - "action": "verify_elements", - "checks": [ - "인쇄 버튼 존재" - ], - "expected": "인쇄 기능 표시" - }, - { - "id": 15, - "name": "전년 대비 비교 확인", - "action": "verify_elements", - "checks": [ - "전년 동기 대비 증감 표시" - ], - "expected": "비교 분석 표시" - } - ], - "expectedAPIs": [ - { - "method": "GET", - "endpoint": "/api/v1/purchase/status", - "description": "구매현황 조회" - }, - { - "method": "GET", - "endpoint": "/api/v1/purchase/statistics", - "description": "구매 통계 조회" - }, - { - "method": "GET", - "endpoint": "/api/v1/purchase/status/export", - "description": "구매현황 엑셀 다운로드" - } - ], - "requiredVerifications": [ - { - "id": 1, - "name": "엑셀 다운로드", - "steps": [ - 13 - ], - "criteria": "API 호출 + 파일 다운로드" - }, - { - "id": 5, - "name": "목업 페이지 감지", - "steps": [ - 2 - ], - "criteria": "구매 현황, 기간 필터, 통계/차트 존재" - } - ], - "rollbackPlan": { - "note": "조회 전용 페이지로 데이터 변경 없음" - } -} \ No newline at end of file diff --git a/quality-certification.json b/quality-certification.json index c06ae82..6c0df6c 100644 --- a/quality-certification.json +++ b/quality-certification.json @@ -1,5 +1,5 @@ { - "enabled": false, + "enabled": true, "id": "quality-certification", "name": "품질인정심사 시스템 테스트", "screenshotPolicy": { @@ -11,7 +11,7 @@ "menuNavigation": { "level1": "품질관리", "level2": "품질인정심사 시스템", - "expectedUrl": "/quality/certification", + "expectedUrl": "/quality/qms", "searchWithinParent": true, "closeOtherMenus": true }, diff --git a/quality-inspection.json b/quality-inspection.json index 330fe2f..ec8d42b 100644 --- a/quality-inspection.json +++ b/quality-inspection.json @@ -1,5 +1,5 @@ { - "enabled": false, + "enabled": true, "id": "quality-inspection", "name": "제품검사관리 테스트", "screenshotPolicy": { diff --git a/rank-management.json b/rank-management.json deleted file mode 100644 index 24a85bf..0000000 --- a/rank-management.json +++ /dev/null @@ -1,622 +0,0 @@ -{ - "id": "rank-management", - "name": "설정 - 직급관리", - "screenshotPolicy": { - "onErrorOnly": true, - "captureOn": [ - "error", - "fail", - "timeout", - "404", - "500", - "blocked" - ] - }, - "url": "/ko/settings/ranks", - "navigation": { - "targetUrl": "/settings/ranks", - "urlPattern": "/settings/ranks|/ko/settings/ranks", - "menuHints": [ - "직급관리", - "직급 관리", - "설정" - ] - }, - "menuNavigation": { - "level1": "설정", - "level2": "직급관리", - "expectedUrl": "/ko/settings/ranks", - "searchWithinParent": true, - "closeOtherMenus": true - }, - "auth": { - "username": "TestUser5", - "password": "password123!" - }, - "menuNavigationEnhanced": { - "strategy": "scroll-and-search", - "description": "사이드바를 스크롤하며 메뉴를 찾고 클릭하여 404를 방지", - "level1": "설정", - "level2": "직급관리", - "alternativeLevel1Names": [ - "설정", - "Settings", - "환경설정", - "시스템설정", - "관리" - ], - "alternativeLevel2Names": [ - "직급관리", - "직급 관리", - "Ranks", - "직급", - "Position Management" - ], - "scrollConfig": { - "sidebarSelector": "nav, aside, [role='navigation'], .sidebar, #sidebar", - "menuItemSelector": "a, button, [role='menuitem'], [role='treeitem']", - "scrollStep": 200, - "maxScrollAttempts": 10, - "scrollDelay": 300 - } - }, - "expectedAPIs": [ - { - "method": "GET", - "path": "/api/v1/positions?type=rank", - "description": "직급 목록 조회" - }, - { - "method": "POST", - "path": "/api/v1/positions", - "description": "직급 생성" - }, - { - "method": "PUT", - "path": "/api/v1/positions/{id}", - "description": "직급 수정" - }, - { - "method": "DELETE", - "path": "/api/v1/positions/{id}", - "description": "직급 삭제" - }, - { - "method": "PUT", - "path": "/api/v1/positions/reorder", - "description": "직급 순서 변경" - } - ], - "steps": [ - { - "id": "step-00", - "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": "step-01", - "name": "2단계 메뉴 진입: 설정 > 직급관리", - "description": "사이드바를 스크롤하며 설정 > 직급관리 메뉴를 찾아 클릭", - "actions": [ - { - "type": "scrollAndFind", - "target": "설정", - "alternativeTexts": [ - "설정", - "Settings", - "환경설정", - "시스템설정" - ], - "scrollContainer": "sidebar", - "maxAttempts": 10, - "description": "스크롤하며 설정 메뉴 찾기" - }, - { - "type": "click_if_exists", - "target": "설정", - "description": "설정 메뉴 클릭" - }, - { - "type": "wait", - "duration": 500, - "description": "서브메뉴 펼쳐지기 대기" - }, - { - "type": "scrollAndFind", - "target": "직급관리", - "alternativeTexts": [ - "직급관리", - "직급 관리", - "Ranks", - "직급" - ], - "scrollContainer": "submenu", - "maxAttempts": 5, - "description": "서브메뉴에서 직급관리 찾기" - }, - { - "type": "click_if_exists", - "target": "직급관리", - "description": "직급관리 메뉴 클릭" - }, - { - "type": "wait", - "target": "페이지 로드 완료", - "timeout": 10000 - } - ], - "expected": { - "url": "/ko/settings/ranks", - "title": "직급관리", - "authenticated": true - }, - "verification": [ - "설정 메뉴가 펼쳐졌는지 확인", - "직급관리 서브메뉴 클릭 성공", - "페이지 타이틀 '직급관리' 확인", - "설명 '사원의 직급을 관리합니다. 드래그하여 순서를 변경할 수 있습니다.' 확인", - "Award 아이콘 표시", - "404 에러 없이 페이지 로드 완료" - ] - }, - { - "id": "step-02", - "name": "직급 추가 입력 영역 확인", - "action": "verify", - "verification": [ - "입력 필드 존재 (placeholder: '직급명을 입력하세요')", - "추가 버튼 존재 (disabled 상태)", - "Plus 아이콘 표시" - ] - }, - { - "id": "step-03", - "name": "직급 목록 카드 확인", - "action": "verify", - "verification": [ - "직급 목록 카드 표시", - "기존 직급 목록 로드 확인", - "각 직급 항목 구조: 드래그 핸들, 순서 번호, 직급명, 수정 버튼, 삭제 버튼" - ] - }, - { - "id": "step-04", - "name": "드래그 핸들 아이콘 확인", - "action": "verify", - "verification": [ - "각 직급 항목에 GripVertical 아이콘 표시", - "순서 번호 표시 (1, 2, 3...)", - "cursor-move 스타일 적용 확인" - ] - }, - { - "id": "step-05", - "name": "안내 문구 확인", - "action": "verify", - "verification": [ - "하단 안내 문구 표시: '※ 직급 순서는 드래그 앤 드롭으로 변경할 수 있습니다.'" - ] - }, - { - "id": "step-06", - "name": "직급 추가 - 빈 값 입력 시도", - "action": "click_if_exists", - "target": "직급명 입력 필드", - "value": "", - "verification": [ - "추가 버튼 disabled 상태 유지", - "입력 불가 확인" - ] - }, - { - "id": "step-07", - "name": "직급 추가 - 공백만 입력 시도", - "action": "click_if_exists", - "target": "직급명 입력 필드", - "value": " ", - "verification": [ - "추가 버튼 클릭 가능하나 실제 추가 안됨", - "입력 필드 값 유지 또는 초기화" - ] - }, - { - "id": "step-08", - "name": "직급 추가 - 정상 입력", - "action": "click_if_exists", - "target": "직급명 입력 필드", - "value": "E2E 테스트 직급1", - "verification": [ - "입력 값 반영 확인", - "추가 버튼 활성화 (enabled)" - ] - }, - { - "id": "step-09", - "name": "직급 추가 실행 (버튼 클릭)", - "action": "click_if_exists", - "target": "추가 버튼", - "verification": [ - "추가 버튼 클릭", - "로딩 상태 표시 (Loader2 아이콘)", - "API 호출: POST /api/v1/positions", - "API 응답 200 OK 확인", - "성공 토스트 메시지: '직급이 추가되었습니다.'", - "입력 필드 초기화", - "추가 버튼 다시 disabled 상태", - "목록에 신규 직급 표시 (하단에 추가)" - ] - }, - { - "id": "step-10", - "name": "신규 직급 확인", - "action": "verify", - "verification": [ - "'E2E 테스트 직급1' 목록에 표시", - "순서 번호 자동 할당 (마지막 순서)", - "드래그 핸들, 수정/삭제 버튼 존재" - ] - }, - { - "id": "step-11", - "name": "직급 추가 - Enter 키로 등록", - "action": "click_if_exists", - "target": "직급명 입력 필드", - "value": "E2E 테스트 직급2", - "verification": [ - "입력 값 반영 확인" - ] - }, - { - "id": "step-12", - "name": "Enter 키 입력", - "action": "keypress", - "target": "직급명 입력 필드", - "key": "Enter", - "verification": [ - "Enter 키로 직급 추가 실행", - "API 호출: POST /api/v1/positions", - "성공 토스트 메시지 확인", - "입력 필드 초기화", - "'E2E 테스트 직급2' 목록에 추가" - ] - }, - { - "id": "step-13", - "name": "세 번째 직급 추가 (드래그 테스트용)", - "action": "click_if_exists", - "target": "직급명 입력 필드", - "value": "E2E 테스트 직급3", - "verification": [ - "입력 후 추가 버튼 클릭", - "API 호출 및 성공 확인", - "'E2E 테스트 직급3' 목록에 추가" - ] - }, - { - "id": "step-14", - "name": "직급 목록 상태 확인", - "action": "verify", - "verification": [ - "총 N개 직급 표시 (기존 + 신규 3개)", - "각 직급의 순서 번호 연속적 (1, 2, 3...)", - "신규 직급들이 하단에 순서대로 추가됨" - ] - }, - { - "id": "step-15", - "name": "직급 수정 다이얼로그 열기", - "action": "click_if_exists", - "target": "E2E 테스트 직급1의 수정 버튼", - "verification": [ - "수정 다이얼로그 표시", - "다이얼로그 제목: '직급 수정'", - "직급명 입력 필드에 현재 값 표시: 'E2E 테스트 직급1'", - "취소 버튼 존재", - "수정 버튼 존재" - ] - }, - { - "id": "step-16", - "name": "직급명 수정 입력", - "action": "click_if_exists", - "target": "다이얼로그 직급명 입력 필드", - "value": "E2E 테스트 직급1 (수정됨)", - "verification": [ - "입력 값 반영 확인", - "수정 버튼 활성화" - ] - }, - { - "id": "step-17", - "name": "직급 수정 실행", - "action": "click_if_exists", - "target": "다이얼로그 수정 버튼", - "verification": [ - "수정 버튼 클릭", - "로딩 상태 표시", - "API 호출: PUT /api/v1/positions/{id}", - "API 응답 200 OK 확인", - "성공 토스트 메시지: '직급이 수정되었습니다.'", - "다이얼로그 닫힘", - "목록에서 직급명 변경 확인: 'E2E 테스트 직급1 (수정됨)'" - ] - }, - { - "id": "step-18", - "name": "수정 취소 테스트 - 다이얼로그 열기", - "action": "click_if_exists", - "target": "E2E 테스트 직급2의 수정 버튼", - "verification": [ - "다이얼로그 표시", - "현재 값: 'E2E 테스트 직급2'" - ] - }, - { - "id": "step-19", - "name": "수정 취소", - "action": "click_if_exists", - "target": "다이얼로그 취소 버튼", - "verification": [ - "다이얼로그 닫힘", - "직급명 변경 없음 (API 호출 없음)" - ] - }, - { - "id": "step-20", - "name": "드래그 앤 드롭 - 첫 번째 항목 선택", - "action": "drag_start", - "target": "목록 마지막 직급 (E2E 테스트 직급3)", - "verification": [ - "드래그 시작", - "해당 항목 opacity 50% 및 배경색 변경", - "cursor-move 활성화" - ] - }, - { - "id": "step-21", - "name": "드래그 앤 드롭 - 상단으로 이동", - "action": "drag_over", - "target": "목록 첫 번째 위치", - "verification": [ - "드래그 중 위치 변경 시각적 피드백", - "실시간 순서 변경 (로컬 상태)" - ] - }, - { - "id": "step-22", - "name": "드래그 앤 드롭 - 드롭 실행", - "action": "drag_end", - "verification": [ - "드래그 종료", - "API 호출: PUT /api/v1/positions/reorder", - "Request body에 전체 직급의 새로운 순서 포함", - "API 응답 200 OK 확인", - "성공 토스트 메시지: '순서가 변경되었습니다.'", - "순서 번호 업데이트 확인", - "'E2E 테스트 직급3'이 최상단으로 이동" - ] - }, - { - "id": "step-23", - "name": "순서 변경 확인", - "action": "verify", - "verification": [ - "변경된 순서가 화면에 반영됨", - "각 항목의 순서 번호 재할당 (1, 2, 3...)", - "드래그한 항목이 목표 위치에 정확히 배치" - ] - }, - { - "id": "step-24", - "name": "삭제 확인 다이얼로그 열기", - "action": "click_if_exists", - "target": "E2E 테스트 직급3의 삭제 버튼", - "verification": [ - "삭제 확인 다이얼로그 표시", - "다이얼로그 제목: '직급 삭제'", - "메시지: '\"E2E 테스트 직급3\" 직급을 삭제하시겠습니까?'", - "경고 메시지: '이 직급을 사용 중인 사원이 있으면 해당 사원의 직급이 초기화됩니다.' (빨간색)", - "취소 버튼 존재", - "삭제 버튼 존재 (빨간색)" - ] - }, - { - "id": "step-25", - "name": "삭제 취소", - "action": "click_if_exists", - "target": "다이얼로그 취소 버튼", - "verification": [ - "다이얼로그 닫힘", - "직급 삭제되지 않음 (API 호출 없음)", - "목록에 여전히 존재" - ] - }, - { - "id": "step-26", - "name": "삭제 실행 - 다이얼로그 재열기", - "action": "click_if_exists", - "target": "E2E 테스트 직급3의 삭제 버튼", - "verification": [ - "삭제 확인 다이얼로그 표시" - ] - }, - { - "id": "step-27", - "name": "삭제 확인 실행", - "action": "click_if_exists", - "target": "다이얼로그 삭제 버튼", - "verification": [ - "삭제 버튼 클릭", - "로딩 상태 표시 (Loader2 아이콘)", - "API 호출: DELETE /api/v1/positions/{id}", - "API 응답 200 OK 확인", - "성공 토스트 메시지: '직급이 삭제되었습니다.'", - "다이얼로그 닫힘", - "목록에서 'E2E 테스트 직급3' 제거됨", - "순서 번호 재정렬" - ] - }, - { - "id": "step-28", - "name": "나머지 테스트 직급 삭제 - 직급2", - "action": "click_if_exists", - "target": "E2E 테스트 직급2의 삭제 버튼", - "verification": [ - "삭제 다이얼로그 표시 → 삭제 버튼 클릭", - "API 호출 및 성공 확인", - "목록에서 제거" - ] - }, - { - "id": "step-29", - "name": "나머지 테스트 직급 삭제 - 직급1 (수정됨)", - "action": "click_if_exists", - "target": "E2E 테스트 직급1 (수정됨)의 삭제 버튼", - "verification": [ - "삭제 다이얼로그 표시 → 삭제 버튼 클릭", - "API 호출 및 성공 확인", - "목록에서 제거", - "테스트 데이터 완전 정리" - ] - }, - { - "id": "step-30", - "name": "최종 상태 확인", - "action": "verify", - "verification": [ - "기존 직급만 남음 (테스트 데이터 모두 삭제)", - "순서 번호 정상", - "페이지 정상 동작" - ] - }, - { - "id": "step-31", - "name": "빈 목록 상태 테스트 (선택)", - "action": "verify", - "verification": [ - "만약 모든 직급 삭제 시: '등록된 직급이 없습니다.' 메시지 표시", - "입력 필드와 추가 버튼은 정상 표시" - ] - }, - { - "id": "step-32", - "name": "페이지 새로고침 후 데이터 확인", - "action": "reload", - "verification": [ - "페이지 새로고침", - "GET /api/v1/positions?type=rank 호출", - "저장된 순서대로 직급 목록 로드", - "이전 상태 유지 확인" - ] - }, - { - "id": "step-33", - "name": "한글 IME 입력 테스트", - "action": "click_if_exists", - "target": "직급명 입력 필드", - "value": "부장", - "verification": [ - "한글 조합 중 Enter 키 입력 시 조합 완료 대기", - "조합 완료 후 추가 동작", - "isComposing 이벤트 처리 확인" - ] - }, - { - "id": "step-34", - "name": "특수문자 입력 테스트", - "action": "click_if_exists", - "target": "직급명 입력 필드", - "value": "직급@#$%", - "verification": [ - "특수문자 포함 직급명 입력", - "추가 버튼 클릭", - "API 호출 및 저장 여부 확인", - "성공 시 목록에 표시, 실패 시 에러 메시지" - ] - }, - { - "id": "step-35", - "name": "긴 직급명 입력 테스트", - "action": "click_if_exists", - "target": "직급명 입력 필드", - "value": "매우긴직급명테스트매우긴직급명테스트매우긴직급명테스트매우긴직급명테스트", - "verification": [ - "긴 직급명 입력", - "추가 시도", - "API 응답 확인 (길이 제한 있을 경우 에러)", - "UI에서 텍스트 오버플로우 처리 확인" - ] - }, - { - "id": "step-36", - "name": "중복 직급명 입력 테스트", - "action": "click_if_exists", - "target": "직급명 입력 필드", - "value": "과장", - "verification": [ - "기존 직급명과 동일한 이름 입력", - "추가 버튼 클릭", - "API 응답 확인", - "중복 허용 시 성공, 중복 불가 시 에러 메시지" - ] - }, - { - "id": "step-37", - "name": "로딩 중 상태 테스트", - "action": "verify", - "verification": [ - "API 호출 중 버튼 disabled 상태", - "Loader2 아이콘 표시", - "중복 클릭 방지 확인" - ] - }, - { - "id": "step-38", - "name": "에러 처리 테스트 (네트워크 오류 시뮬레이션)", - "action": "verify", - "verification": [ - "API 호출 실패 시 에러 토스트 표시", - "에러 메시지 명확성 확인", - "페이지 상태 유지 (크래시 없음)" - ] - } - ], - "testData": { - "ranks": [ - { - "name": "E2E 테스트 직급1", - "expected_order": "last" - }, - { - "name": "E2E 테스트 직급2", - "expected_order": "last" - }, - { - "name": "E2E 테스트 직급3", - "expected_order": "last → first (after drag)" - } - ] - }, - "cleanup": { - "description": "Step-27~29에서 테스트 데이터 삭제 완료", - "method": "각 직급의 삭제 버튼 클릭 → 확인 다이얼로그에서 삭제 확인" - } -} \ No newline at end of file diff --git a/receiving-management.json b/receiving-management.json index 05a012b..3c69f16 100644 --- a/receiving-management.json +++ b/receiving-management.json @@ -1,5 +1,5 @@ { - "enabled": false, + "enabled": true, "id": "receiving-management", "name": "입고관리 테스트", "screenshotPolicy": { @@ -8,16 +8,16 @@ }, "description": "자재관리 > 입고관리 페이지의 입고 조회 및 상태별 필터링 기능을 테스트하는 E2E 테스트", "baseUrl": "https://dev.codebridge-x.com", - "url": "/material/receiving", + "url": "/material/receiving-management", "navigation": { - "targetUrl": "/material/receiving", - "urlPattern": "/material/receiving|/ko/material/receiving", + "targetUrl": "/material/receiving-management", + "urlPattern": "/material/receiving-management|/ko/material/receiving-management", "menuHints": ["입고관리", "입고 관리", "자재관리"] }, "menuNavigation": { "level1": "자재관리", "level2": "입고관리", - "expectedUrl": "/material/receiving", + "expectedUrl": "/material/receiving-management", "searchWithinParent": true, "closeOtherMenus": true }, @@ -38,8 +38,8 @@ "text": "입고관리", "waitAfterClick": 300 }, - "fallbackUrl": "/material/receiving", - "expectedUrl": "/material/receiving" + "fallbackUrl": "/material/receiving-management", + "expectedUrl": "/material/receiving-management" }, "timeout": 90000, "tags": ["material", "receiving", "read-only"], @@ -84,12 +84,12 @@ { "type": "click_if_exists", "target": "입고관리" } ], "expect": { - "url": "/material/receiving", + "url": "/material/receiving-management", "visible": ["입고 목록"] }, "fallback": { "type": "navigate", - "url": "/material/receiving" + "url": "/material/receiving-management" } }, { @@ -162,7 +162,7 @@ "assertions": [ { "type": "url", - "expected": "/material/receiving", + "expected": "/material/receiving-management", "message": "입고관리 페이지에 머물러야 함" }, { diff --git a/salary-management.json b/salary-management.json deleted file mode 100644 index 75f6f20..0000000 --- a/salary-management.json +++ /dev/null @@ -1,406 +0,0 @@ -{ - "id": "salary-management", - "name": "급여관리 테스트", - "screenshotPolicy": { - "onErrorOnly": true, - "captureOn": ["error", "fail", "timeout", "404", "500", "blocked"] - }, - "description": "급여 현황 조회, 상태 변경, 엑셀 다운로드 기능을 테스트하는 E2E 테스트", - "baseUrl": "https://dev.codebridge-x.com", - "url": "/hr/salary-management", - "navigation": { - "targetUrl": "/hr/salary-management", - "urlPattern": "/hr/salary-management|/ko/hr/salary-management", - "menuHints": ["급여관리", "급여 관리", "인사관리"] - }, - "menuNavigation": { - "level1": "인사관리", - "level2": "급여관리", - "expectedUrl": "/hr/salary-management", - "searchWithinParent": true, - "closeOtherMenus": true - }, - "menuNavigationEnhanced": { - "strategy": "scroll-and-search", - "sidebar": { - "scrollContainer": ".sidebar-scroll", - "scrollStep": 200, - "maxScrollAttempts": 5, - "waitAfterScroll": 300 - }, - "level1": { - "text": "인사관리", - "expandable": true, - "waitAfterClick": 500 - }, - "level2": { - "text": "급여관리", - "waitAfterClick": 300 - }, - "fallbackUrl": "/hr/salary-management", - "expectedUrl": "/hr/salary-management" - }, - "timeout": 90000, - "tags": ["hr", "salary", "payroll", "management"], - - "auth": { - "username": "TestUser5", - "password": "password123!" - }, - - "testData": { - "searchKeyword": "홍", - "dateRange": { - "startDate": "2025-12-01", - "endDate": "2025-12-31" - } - }, - - "steps": [ - { - "id": "step-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 } - ], - "expect": { - "sidebarReady": true - } - }, - { - "id": "step-1", - "name": "인사관리 메뉴 진입", - "description": "인사관리 > 급여관리 메뉴로 이동 (scrollAndFind 패턴 사용)", - "actions": [ - { - "type": "scrollAndFind", - "container": ".sidebar-scroll", - "target": "인사관리", - "scrollStep": 200, - "maxAttempts": 5 - }, - { "type": "click_if_exists", "target": "인사관리" }, - { "type": "wait", "duration": 500 }, - { - "type": "scrollAndFind", - "container": ".sidebar-scroll", - "target": "급여관리", - "scrollStep": 200, - "maxAttempts": 5 - }, - { "type": "click_if_exists", "target": "급여관리" } - ], - "expect": { - "url": "/hr/salary-management", - "visible": ["급여관리", "엑셀 다운로드"] - }, - "fallback": { - "type": "navigate", - "url": "/ko/hr/salary-management" - } - }, - { - "id": "step-2", - "name": "필수 검증 #5: 목업 페이지 감지", - "description": "페이지가 목업인지 실제 동작하는 페이지인지 감지", - "verify": { - "mockupDetection": { - "inputFields": ["검색창", "날짜 필터"], - "functionalButtons": ["엑셀 다운로드", "지급완료", "지급예정", "수정"], - "apiCalls": true, - "dataChangePossible": true - } - } - }, - { - "id": "step-3", - "name": "급여 현황 대시보드 확인", - "description": "총 실지급액, 총 기본급, 총 수당, 초과근무, 상여, 총 공제 카드 표시 확인", - "verify": { - "visible": ["총 실지급액", "총 기본급", "총 수당", "초과근무", "상여", "총 공제"], - "statsCards": true - } - }, - { - "id": "step-4", - "name": "급여 테이블 구조 확인", - "description": "테이블 컬럼 구조 검증", - "verify": { - "tableColumns": ["부서", "직책", "이름", "직급", "기본급", "수당", "초과근무", "상여", "공제", "실지급액", "일자", "상태", "작업"] - } - }, - { - "id": "step-5", - "name": "날짜 필터 확인", - "description": "시작일/종료일 날짜 필터 필드 확인", - "verify": { - "dateInputs": 2, - "dateRange": { - "startDate": "2025-12-01", - "endDate": "2025-12-31" - } - } - }, - { - "id": "step-5-1", - "name": "⚠️ 필수 검증: 날짜 필터 검색", - "description": "날짜 범위 필터를 설정하고 데이터가 필터링되는지 확인", - "actions": [ - { "type": "evaluate", "script": "document.querySelectorAll('table tbody tr').length", "description": "필터 전 행 수 저장" }, - { "type": "fill", "target": "input[type='date']:first-of-type, input[placeholder*='시작']", "value": "2025-12-01", "description": "시작일 입력" }, - { "type": "fill", "target": "input[type='date']:last-of-type, input[placeholder*='종료']", "value": "2025-12-31", "description": "종료일 입력" }, - { "type": "wait", "duration": 500, "description": "필터 적용 대기" }, - { "type": "evaluate", "script": "document.querySelectorAll('table tbody tr').length", "description": "필터 후 행 수 확인" } - ], - "verify": { - "dateFilterApplied": true, - "dataChanged": "initialRowCount may differ from filteredRowCount" - }, - "note": "날짜 필터가 실제로 데이터를 필터링하는지 확인 - 단순 UI 변경만 확인하면 FAIL" - }, - { - "id": "step-6", - "name": "⚠️ 필수 검증: 검색 기능 확인", - "description": "검색어 입력 후 테이블 데이터가 필터링되는지 확인", - "actions": [ - { "type": "evaluate", "script": "document.querySelectorAll('table tbody tr').length", "description": "검색 전 행 수 확인" }, - { "type": "fill", "target": "input[placeholder*='검색'], input[type='search']", "value": "홍", "description": "검색어 입력" }, - { "type": "wait", "duration": 500, "description": "검색 결과 대기" }, - { "type": "evaluate", "script": "document.querySelectorAll('table tbody tr').length", "description": "검색 후 행 수 확인" } - ], - "verify": { - "searchApplied": true, - "tableContains": "{testData.searchKeyword}", - "dataFiltered": "검색 결과에 검색어가 포함된 행만 표시되어야 함" - }, - "expect": { - "searchPlaceholder": "이름, 부서 검색..." - }, - "note": "⚠️ 검색어 입력 후 테이블 데이터가 변경되지 않으면 FAIL" - }, - { - "id": "step-6-1", - "name": "검색 결과 데이터 검증", - "description": "검색 결과의 각 행에 검색어가 포함되어 있는지 확인", - "verify": { - "allRowsContain": "{testData.searchKeyword}", - "verifyMethod": "테이블의 모든 행이 검색어를 포함하는지 확인" - } - }, - { - "id": "step-6-2", - "name": "검색 초기화 확인", - "description": "검색어 삭제 후 전체 목록 복원 확인", - "actions": [ - { "type": "clear", "target": "input[placeholder*='검색'], input[type='search']", "description": "검색어 삭제" }, - { "type": "wait", "duration": 500, "description": "목록 복원 대기" } - ], - "verify": { - "dataRestored": true, - "rowCountRestored": "beforeSearchCount와 유사한 행 수로 복원" - } - }, - { - "id": "step-7", - "name": "정렬 옵션 확인", - "description": "정렬 드롭다운 옵션 확인", - "actions": [ - { "type": "click_if_exists", "target": "정렬", "role": "combobox" } - ], - "verify": { - "options": ["직급순", "이름순", "부서순", "지급일순", "지급액순"] - } - }, - { - "id": "step-8", - "name": "급여 항목 선택", - "description": "체크박스로 급여 항목 선택", - "actions": [ - { "type": "evaluate", "script": "(function(){ var cb = document.querySelector('table tbody tr:first-child input[type=\"checkbox\"], table tbody tr:first-child [role=\"checkbox\"]'); if(cb){ cb.click(); return 'checked'; } return 'no checkbox'; })()" } - ], - "expect": { - "visible": ["지급완료", "지급예정"], - "buttonsEnabled": true - } - }, - { - "id": "step-9", - "name": "필수 검증 #2: 지급완료 버튼 동작 확인", - "description": "지급완료 버튼 클릭 시 실제 상태 변경 확인", - "actions": [ - { "type": "click_if_exists", "target": "지급완료" } - ], - "expect": { - "urlMaintained": true, - "noErrorPage": true, - "toast": "지급완료 처리되었습니다", - "apiCall": "bulkUpdateSalaryStatus" - } - }, - { - "id": "step-10", - "name": "수정 버튼 클릭 - 상세 다이얼로그 열기", - "description": "급여 항목의 수정 버튼 클릭하여 상세 다이얼로그 열기", - "actions": [ - { "type": "evaluate", "script": "(function(){ var btns = Array.from(document.querySelectorAll('table tbody tr:first-child button, table tbody tr:first-child a')); var editBtn = btns.find(b => b.innerText?.includes('수정') || b.querySelector('svg')); if(editBtn){ editBtn.click(); return 'clicked edit'; } var actionBtn = document.querySelector('table tbody tr:first-child td:last-child button'); if(actionBtn){ actionBtn.click(); return 'clicked action btn'; } return 'no edit btn found'; })()" }, - { "type": "wait", "duration": 500 } - ], - "modalConfig": { - "containerSelector": "[role='dialog'], .modal", - "animationDelay": 300, - "waitForSelector": "[role='dialog']" - }, - "expect": { - "modal": "급여 상세", - "visible": ["기본급", "수당", "초과근무", "상여", "공제", "실지급액"] - } - }, - { - "id": "step-11", - "name": "필수 검증 #4: 상세 다이얼로그 저장", - "description": "모달 내 급여 상세 저장 버튼 동작 확인", - "actions": [ - { "type": "click_if_exists", "target": "저장", "options": { "waitAfter": 500 } } - ], - "expect": { - "urlMaintained": true, - "noErrorPage": true, - "modalClosed": true, - "toast": "저장되었습니다" - } - }, - { - "id": "step-12", - "name": "상세 다이얼로그 닫기", - "description": "다이얼로그 닫기", - "actions": [ - { "type": "press", "key": "Escape" } - ], - "expect": { - "modalClosed": true - } - }, - { - "id": "step-13", - "name": "필수 검증 #1: 엑셀 다운로드", - "description": "엑셀 다운로드 버튼 클릭 시 실제 다운로드 발생 확인", - "actions": [ - { "type": "click_if_exists", "target": "엑셀 다운로드" } - ], - "verify": { - "networkRequest": { - "type": "click_if_exists", - "apiPattern": "/api/export|/api/download|/api/salary" - }, - "downloadEvent": true - }, - "note": "⚠️ Console LOG만 출력되면 FAIL - Network API 호출 필수 확인" - } - ], - - "assertions": [ - { - "type": "url", - "expected": "/hr/salary-management", - "message": "급여관리 페이지에 머물러야 함" - }, - { - "type": "elementExists", - "selector": "button:has-text('엑셀 다운로드')", - "message": "엑셀 다운로드 버튼이 표시되어야 함" - }, - { - "type": "tableExists", - "message": "급여 목록 테이블이 표시되어야 함" - } - ], - - "mandatoryVerifications": { - "description": "E2E_TEST_CONFIG.md 기준 필수 검증 항목", - "items": [ - { - "id": 1, - "name": "파일 다운로드", - "trigger": "엑셀 다운로드 버튼", - "verification": "Network API 호출 + 실제 파일 다운로드 확인", - "failCondition": "Console LOG만 존재, API 미호출" - }, - { - "id": 2, - "name": "등록/저장 버튼", - "trigger": "지급완료, 지급예정, 저장 버튼", - "verification": "URL 유지 + 에러 페이지 없음 + 성공 토스트", - "failCondition": "404/500 에러 페이지 이동" - }, - { - "id": 3, - "name": "검색/필터", - "trigger": "검색창, 날짜 필터, 정렬", - "verification": "데이터 변화 확인", - "failCondition": "필터 적용 후 데이터 무변화" - }, - { - "id": 4, - "name": "모달 등록 완료", - "trigger": "급여 상세 다이얼로그 저장", - "verification": "실제 저장 동작 + 결과 확인", - "failCondition": "열기/닫기만 테스트" - }, - { - "id": 5, - "name": "목업/미완성 페이지 감지", - "trigger": "페이지 로드 시", - "verification": "입력 필드 + 동작하는 버튼 + API 호출 확인", - "failCondition": "버튼만 있고 입력 불가, Console LOG만 출력" - } - ] - }, - - "cleanup": { - "enabled": false, - "description": "조회/상태변경 테스트이므로 cleanup 불필요" - }, - - "notes": { - "testScope": "급여관리 페이지 UI 요소 및 기능 검증", - "features": { - "dashboard": "총 실지급액/기본급/수당/초과근무/상여/공제 현황 카드", - "dateFilter": "시작일~종료일 날짜 범위 필터", - "search": "이름, 부서 검색", - "sort": "직급순/이름순/부서순/지급일순/지급액순 정렬", - "statusChange": "지급완료/지급예정 일괄 상태 변경", - "detailDialog": "급여 상세 조회/수정 다이얼로그", - "export": "엑셀 다운로드" - }, - "tableColumns": { - "부서": "소속 부서", - "직책": "직책명", - "이름": "직원 이름", - "직급": "직급명", - "기본급": "기본급 금액", - "수당": "수당 금액", - "초과근무": "초과근무 수당", - "상여": "상여금", - "공제": "공제 금액", - "실지급액": "실제 지급 금액", - "일자": "지급 일자", - "상태": "지급완료/지급예정", - "작업": "수정 버튼" - }, - "knownIssues": [ - "엑셀 다운로드 기능이 toast.info('준비 중') 상태일 수 있음 - 목업 가능성", - "지급항목 추가 기능이 미구현 상태" - ], - "prerequisites": "로그인된 사용자에게 급여 관리 권한 필요" - } -} diff --git a/sales-client.json b/sales-client.json index 2424b47..b5784a5 100644 --- a/sales-client.json +++ b/sales-client.json @@ -1,5 +1,5 @@ { - "enabled": false, + "enabled": true, "id": "sales-client", "name": "판매거래처관리 테스트", "screenshotPolicy": { @@ -18,7 +18,7 @@ "menuNavigation": { "level1": "판매관리", "level2": "거래처관리", - "expectedUrl": "/sales/client-management", + "expectedUrl": "/sales/client-management-sales-admin", "searchWithinParent": true, "closeOtherMenus": true }, diff --git a/sales-management.json b/sales-management.json index 6bb954a..0095315 100644 --- a/sales-management.json +++ b/sales-management.json @@ -1,5 +1,5 @@ { - "enabled": false, + "enabled": true, "id": "sales-management", "name": "매출관리 테스트", "screenshotPolicy": { diff --git a/sales-order.json b/sales-order.json index 14b2684..e2d0a7c 100644 --- a/sales-order.json +++ b/sales-order.json @@ -1,5 +1,5 @@ { - "enabled": false, + "enabled": true, "id": "sales-order", "name": "수주관리 테스트", "screenshotPolicy": { diff --git a/sales-pricing.json b/sales-pricing.json index 5db9f75..0689128 100644 --- a/sales-pricing.json +++ b/sales-pricing.json @@ -1,5 +1,5 @@ { - "enabled": false, + "enabled": true, "id": "sales-pricing", "name": "단가관리 테스트", "screenshotPolicy": { diff --git a/sales-quotation.json b/sales-quotation.json index 1454bc4..2b39076 100644 --- a/sales-quotation.json +++ b/sales-quotation.json @@ -1,5 +1,5 @@ { - "enabled": false, + "enabled": true, "id": "sales-quotation", "name": "견적관리 테스트", "screenshotPolicy": { diff --git a/sales-site.json b/sales-site.json deleted file mode 100644 index 5d7bae3..0000000 --- a/sales-site.json +++ /dev/null @@ -1,264 +0,0 @@ -{ - "enabled": false, - "id": "sales-site", - "name": "현장관리 테스트", - "screenshotPolicy": { - "onErrorOnly": true, - "captureOn": [ - "error", - "fail", - "timeout", - "404", - "500", - "blocked" - ] - }, - "description": "판매관리 > 현장관리 메뉴의 현장 CRUD 기능 테스트", - "baseUrl": "https://dev.codebridge-x.com", - "menuNavigation": { - "level1": "판매관리", - "level2": "현장관리", - "expectedUrl": "/sales/site-management", - "searchWithinParent": true, - "closeOtherMenus": true - }, - "auth": { - "username": "TestUser5", - "password": "password123!" - }, - "testData": { - "create": { - "siteName": "E2E_TEST_현장_{timestamp}", - "address": "테스트 주소", - "manager": "테스트 담당자" - } - }, - "steps": [ - { - "id": 1, - "name": "메뉴 진입: 판매관리 > 현장관리", - "action": "menu_navigate", - "level1": "판매관리", - "level2": "현장관리", - "expected": { - "url_contains": "/sales", - "visible": [ - "현장관리", - "현장" - ] - } - }, - { - "id": 2, - "name": "필수 검증 #5: 목업 페이지 감지", - "action": "verify_not_mockup", - "checks": [ - "현장 목록 표시", - "현장 등록 버튼 존재", - "검색 기능 존재" - ], - "expected": "정상 페이지 (목업 아님)" - }, - { - "id": 3, - "name": "현장 테이블 구조 확인", - "action": "verify_table", - "checks": [ - "현장명 컬럼", - "주소 컬럼", - "담당자 컬럼", - "상태 컬럼" - ], - "expected": "현장 테이블 표시" - }, - { - "id": 4, - "phase": "CREATE", - "name": "[CREATE] 현장 등록 버튼 클릭", - "action": "click_if_exists", - "target": "button:has-text('등록'), button:has-text('추가'), button:has-text('신규')", - "expected": { - "modal_open": true - } - }, - { - "id": 5, - "phase": "CREATE", - "name": "[CREATE] 현장명 입력", - "action": "click_if_exists", - "target": "input[name*='name'], input[placeholder*='현장명']" - }, - { - "id": 6, - "phase": "CREATE", - "name": "[CREATE] 주소 입력", - "action": "click_if_exists", - "target": "input[name*='address'], input[placeholder*='주소']" - }, - { - "id": 7, - "phase": "CREATE", - "name": "[CREATE] 담당자 입력", - "action": "click_if_exists", - "target": "input[name*='manager'], input[placeholder*='담당']" - }, - { - "id": 8, - "phase": "CREATE", - "name": "[CREATE] 필수 검증 #2: 현장 저장", - "action": "click_if_exists", - "target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')", - "verify": { - "url_maintained": true, - "no_error_page": true, - "api_call": "POST /api/v1/sales/sites", - "toast": "등록|저장|완료|성공" - }, - "expected": "현장 등록 완료" - }, - { - "id": 9, - "phase": "READ", - "name": "[READ] 등록된 현장 검색", - "action": "click_if_exists", - "target": "input[type='search'], input[placeholder*='검색']" - }, - { - "id": 10, - "phase": "READ", - "name": "[READ] 등록된 현장 확인", - "action": "verify_detail", - "checks": [ - "E2E_TEST_현장 목록에 표시" - ], - "expected": "등록된 현장 확인" - }, - { - "id": 11, - "phase": "READ", - "name": "[READ] 현장 상세 조회", - "action": "click_if_exists", - "target": "table tbody tr:has-text('E2E_TEST')", - "expected": { - "detail_view": true - } - }, - { - "id": 12, - "phase": "UPDATE", - "name": "[UPDATE] 현장 수정 모드 진입", - "action": "click_if_exists", - "target": "button:has-text('수정'), button:has-text('편집')", - "expected": { - "edit_mode": true - } - }, - { - "id": 13, - "phase": "UPDATE", - "name": "[UPDATE] 담당자 수정", - "action": "click_if_exists", - "target": "input[name*='manager'], input[placeholder*='담당']" - }, - { - "id": 14, - "phase": "UPDATE", - "name": "[UPDATE] 현장 저장", - "action": "click_if_exists", - "target": "button:has-text('저장'), button:has-text('확인')", - "verify": { - "api_call": "PUT /api/v1/sales/sites", - "toast": "수정|저장|완료|성공" - }, - "expected": "현장 수정 완료" - }, - { - "id": 15, - "phase": "DELETE", - "name": "[DELETE] 현장 삭제", - "action": "click_if_exists", - "target": "button:has-text('삭제'), button:has-text('제거')", - "expected": { - "confirm_dialog": true - } - }, - { - "id": 16, - "phase": "DELETE", - "name": "[DELETE] 삭제 확인", - "action": "click_if_exists", - "target": "[role='alertdialog'] button:has-text('확인'), [role='dialog'] button:has-text('삭제')", - "verify": { - "api_call": "DELETE /api/v1/sales/sites", - "toast": "삭제|제거|완료|성공" - }, - "expected": "현장 삭제 완료" - }, - { - "id": 17, - "phase": "DELETE", - "name": "[DELETE] 삭제 확인", - "action": "verify_detail", - "checks": [ - "E2E_TEST_현장 목록에서 제거" - ], - "expected": "현장 삭제 반영" - }, - { - "id": 18, - "name": "엑셀 다운로드 확인", - "action": "verify_elements", - "checks": [ - "엑셀 다운로드 버튼 존재" - ], - "expected": "엑셀 다운로드 기능 표시" - } - ], - "expectedAPIs": [ - { - "method": "GET", - "endpoint": "/api/v1/sales/sites", - "description": "현장 목록 조회" - }, - { - "method": "POST", - "endpoint": "/api/v1/sales/sites", - "description": "현장 등록" - }, - { - "method": "PUT", - "endpoint": "/api/v1/sales/sites/:id", - "description": "현장 수정" - }, - { - "method": "DELETE", - "endpoint": "/api/v1/sales/sites/:id", - "description": "현장 삭제" - } - ], - "requiredVerifications": [ - { - "id": 2, - "name": "저장 버튼", - "steps": [ - 8, - 14 - ], - "criteria": "API 호출 + 성공 토스트 + 데이터 반영" - }, - { - "id": 5, - "name": "목업 페이지 감지", - "steps": [ - 2 - ], - "criteria": "현장 목록, 등록 버튼, 검색 기능 존재" - } - ], - "rollbackPlan": { - "onCreateFail": "등록 모달 닫고 재시도", - "onUpdateFail": "페이지 새로고침 후 재시도", - "onDeleteFail": "수동 삭제 필요", - "cleanupRequired": "E2E_TEST_현장_* 패턴 데이터 삭제" - } -} \ No newline at end of file diff --git a/settings-account.json b/settings-account.json index 81c7ab8..517466f 100644 --- a/settings-account.json +++ b/settings-account.json @@ -10,7 +10,7 @@ "menuNavigation": { "level1": "설정", "level2": "계정정보", - "expectedUrl": "/settings/account", + "expectedUrl": "/settings/account-info", "searchWithinParent": true, "closeOtherMenus": true }, @@ -32,7 +32,7 @@ "level1": "설정", "level2": "계정정보", "expected": { - "url_contains": "/settings/account", + "url_contains": "/settings/account-info", "visible": ["계정정보", "프로필"] } }, diff --git a/settings-attendance.json b/settings-attendance.json index c3c32fa..b45c06e 100644 --- a/settings-attendance.json +++ b/settings-attendance.json @@ -10,7 +10,7 @@ "menuNavigation": { "level1": "설정", "level2": "근태설정", - "expectedUrl": "/settings/attendance", + "expectedUrl": "/settings/attendance-settings", "searchWithinParent": true, "closeOtherMenus": true }, @@ -34,7 +34,7 @@ "level1": "설정", "level2": "근태설정", "expected": { - "url_contains": "/settings/attendance", + "url_contains": "/settings/attendance-settings", "visible": ["근태설정", "근태"] } }, diff --git a/settings-bank-account.json b/settings-bank-account.json index c93e877..ca1b97d 100644 --- a/settings-bank-account.json +++ b/settings-bank-account.json @@ -17,7 +17,7 @@ "menuNavigation": { "level1": "설정", "level2": "계좌관리", - "expectedUrl": "/settings/bank-accounts", + "expectedUrl": "/settings/accounts", "searchWithinParent": true, "closeOtherMenus": true }, @@ -46,7 +46,7 @@ "level1": "설정", "level2": "계좌관리", "expected": { - "url_contains": "/settings/bank", + "url_contains": "/settings/accounts", "visible": [ "계좌관리", "계좌" @@ -173,7 +173,7 @@ "action": "click_if_exists", "target": "table tbody tr:has-text('E2E_TEST')", "expected": { - "url_contains": "/settings/bank", + "url_contains": "/settings/accounts", "visible": [ "계좌 상세", "수정", @@ -267,7 +267,7 @@ "verify": { "api_call": "DELETE /api/v1/bank-accounts/", "toast": "삭제|완료|성공", - "redirect": "/settings/bank-accounts" + "redirect": "/settings/accounts" }, "expected": "삭제 완료 및 목록 복귀" }, diff --git a/settings-notification.json b/settings-notification.json index 1ad0d1f..30b2658 100644 --- a/settings-notification.json +++ b/settings-notification.json @@ -10,7 +10,7 @@ "menuNavigation": { "level1": "설정", "level2": "알림설정", - "expectedUrl": "/settings/notifications", + "expectedUrl": "/settings/notification-settings", "searchWithinParent": true, "closeOtherMenus": true }, @@ -34,7 +34,7 @@ "level1": "설정", "level2": "알림설정", "expected": { - "url_contains": "/settings/notification", + "url_contains": "/settings/notification-settings", "visible": ["알림설정", "알림"] } }, diff --git a/settings-position.json b/settings-position.json index 46ffbea..3f9e8c8 100644 --- a/settings-position.json +++ b/settings-position.json @@ -10,7 +10,7 @@ "menuNavigation": { "level1": "설정", "level2": "직책관리", - "expectedUrl": "/settings/positions", + "expectedUrl": "/settings/titles", "searchWithinParent": true, "closeOtherMenus": true }, @@ -38,7 +38,7 @@ "level1": "설정", "level2": "직책관리", "expected": { - "url_contains": "/settings/positions", + "url_contains": "/settings/titles", "visible": ["직책관리", "직책"] } }, @@ -137,7 +137,7 @@ "action": "click_if_exists", "target": "table tbody tr:has-text('E2E_TEST')", "expected": { - "url_contains": "/settings/positions", + "url_contains": "/settings/titles", "visible": ["직책 상세", "수정", "삭제"] } }, @@ -227,7 +227,7 @@ "verify": { "api_call": "DELETE /api/v1/positions/", "toast": "삭제|완료|성공", - "redirect": "/settings/positions" + "redirect": "/settings/titles" }, "expected": "삭제 완료 및 목록 복귀" }, diff --git a/settings-vacation-policy.json b/settings-vacation-policy.json index 5758aca..ef33a43 100644 --- a/settings-vacation-policy.json +++ b/settings-vacation-policy.json @@ -10,7 +10,7 @@ "menuNavigation": { "level1": "설정", "level2": "휴가정책", - "expectedUrl": "/settings/vacation-policy", + "expectedUrl": "/settings/leave-policy", "searchWithinParent": true, "closeOtherMenus": true }, @@ -39,7 +39,7 @@ "level1": "설정", "level2": "휴가정책", "expected": { - "url_contains": "/settings/vacation", + "url_contains": "/settings/leave-policy", "visible": ["휴가정책", "휴가"] } }, diff --git a/shipment-dispatch.json b/shipment-dispatch.json deleted file mode 100644 index 59261fa..0000000 --- a/shipment-dispatch.json +++ /dev/null @@ -1,265 +0,0 @@ -{ - "enabled": false, - "id": "shipment-dispatch", - "name": "배차차량관리 테스트", - "screenshotPolicy": { - "onErrorOnly": true, - "captureOn": ["error", "fail", "timeout", "404", "500", "blocked"] - }, - "description": "출고관리 > 배차차량관리 메뉴의 배차 CRUD 기능 테스트", - "baseUrl": "https://dev.codebridge-x.com", - "menuNavigation": { - "level1": "출고관리", - "level2": "배차차량관리", - "expectedUrl": "/outbound/vehicle-dispatches", - "searchWithinParent": true, - "closeOtherMenus": true - }, - "auth": { - "username": "TestUser5", - "password": "password123!" - }, - "testData": { - "create": { - "vehicleNumber": "E2E_99가9999", - "dispatchDate": "{today}", - "driver": "E2E_TEST_기사" - } - }, - "steps": [ - { - "id": 1, - "name": "메뉴 진입: 출고관리 > 배차차량관리", - "action": "menu_navigate", - "level1": "출고관리", - "level2": "배차차량관리", - "expected": { - "url_contains": "/outbound", - "visible": ["배차", "차량"] - } - }, - { - "id": 2, - "name": "필수 검증 #5: 목업 페이지 감지", - "action": "verify_not_mockup", - "checks": [ - "배차 목록 표시", - "배차 등록 버튼 존재", - "날짜 필터 존재" - ], - "expected": "정상 페이지 (목업 아님)" - }, - { - "id": 3, - "name": "배차 테이블 구조 확인", - "action": "verify_table", - "checks": [ - "차량번호 컬럼", - "배차일 컬럼", - "기사명 컬럼", - "상태 컬럼", - "출고지/도착지 컬럼" - ], - "expected": "배차 테이블 표시" - }, - { - "id": 4, - "name": "배차 통계 확인", - "action": "verify_elements", - "checks": [ - "금일 배차 현황", - "출고 대기 건수", - "배차 완료 건수" - ], - "expected": "배차 통계 표시" - }, - { - "id": 5, - "phase": "CREATE", - "name": "[CREATE] 배차 등록 버튼 클릭", - "action": "click_if_exists", - "target": "button:has-text('등록'), button:has-text('추가'), button:has-text('배차')", - "expected": { - "modal_open": true - } - }, - { - "id": 6, - "phase": "CREATE", - "name": "[CREATE] 차량 선택", - "action": "click_if_exists", - "target": "select[name*='vehicle'], input[placeholder*='차량']", - "expected": "차량 선택 가능" - }, - { - "id": 7, - "phase": "CREATE", - "name": "[CREATE] 배차일 입력", - "action": "click_if_exists", - "target": "input[type='date'], input[name*='date']", - "expected": "배차일 선택" - }, - { - "id": 8, - "phase": "CREATE", - "name": "[CREATE] 기사 선택", - "action": "click_if_exists", - "target": "select[name*='driver'], input[placeholder*='기사']", - "expected": "기사 선택 가능" - }, - { - "id": 9, - "phase": "CREATE", - "name": "[CREATE] 필수 검증 #2: 배차 저장", - "action": "click_if_exists", - "target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')", - "verify": { - "url_maintained": true, - "no_error_page": true, - "api_call": "POST /api/v1/outbound/dispatches", - "toast": "등록|저장|완료|성공" - }, - "expected": "배차 등록 완료" - }, - { - "id": 10, - "phase": "READ", - "name": "[READ] 등록된 배차 검색", - "action": "click_if_exists", - "target": "input[type='search'], input[placeholder*='검색']", - "value": "E2E_99가", - "submit": true - }, - { - "id": 11, - "phase": "READ", - "name": "[READ] 등록된 배차 확인", - "action": "verify_detail", - "checks": [ - "E2E_99가 목록에 표시" - ], - "expected": "등록된 배차 확인" - }, - { - "id": 12, - "phase": "READ", - "name": "[READ] 배차 상세 조회", - "action": "click_if_exists", - "target": "table tbody tr:has-text('E2E_99가')", - "expected": { - "detail_view": true - } - }, - { - "id": 13, - "name": "상세 정보 확인", - "action": "verify_elements", - "checks": [ - "차량 정보 표시", - "기사 정보 표시", - "출고 품목 정보" - ], - "expected": "상세 정보 표시" - }, - { - "id": 14, - "phase": "UPDATE", - "name": "[UPDATE] 배차 수정", - "action": "click_if_exists", - "target": "button:has-text('수정'), button:has-text('편집')", - "expected": { - "edit_mode": true - } - }, - { - "id": 15, - "phase": "UPDATE", - "name": "[UPDATE] 정보 변경", - "action": "click_if_exists", - "target": "textarea[name*='memo'], textarea[placeholder*='비고']", - "value": "E2E 테스트 배차 메모", - "clear": true - }, - { - "id": 16, - "phase": "UPDATE", - "name": "[UPDATE] 변경 저장", - "action": "click_if_exists", - "target": "button:has-text('저장'), button:has-text('확인')", - "verify": { - "api_call": "PUT /api/v1/outbound/dispatches", - "toast": "수정|저장|완료|성공" - }, - "expected": "배차 수정 완료" - }, - { - "id": 17, - "phase": "DELETE", - "name": "[DELETE] 배차 취소/삭제", - "action": "click_if_exists", - "target": "button:has-text('삭제'), button:has-text('취소'), button:has-text('제거')", - "expected": { - "confirm_dialog": true - } - }, - { - "id": 18, - "phase": "DELETE", - "name": "[DELETE] 삭제 확인", - "action": "click_if_exists", - "target": "[role='alertdialog'] button:has-text('확인'), [role='dialog'] button:has-text('삭제')", - "verify": { - "api_call": "DELETE /api/v1/outbound/dispatches", - "toast": "삭제|취소|완료|성공" - }, - "expected": "배차 삭제 완료" - } - ], - "expectedAPIs": [ - { - "method": "GET", - "endpoint": "/api/v1/outbound/dispatches", - "description": "배차 목록 조회" - }, - { - "method": "POST", - "endpoint": "/api/v1/outbound/dispatches", - "description": "배차 등록" - }, - { - "method": "GET", - "endpoint": "/api/v1/outbound/dispatches/:id", - "description": "배차 상세 조회" - }, - { - "method": "PUT", - "endpoint": "/api/v1/outbound/dispatches/:id", - "description": "배차 수정" - }, - { - "method": "DELETE", - "endpoint": "/api/v1/outbound/dispatches/:id", - "description": "배차 삭제" - } - ], - "requiredVerifications": [ - { - "id": 2, - "name": "저장 버튼", - "steps": [9, 16], - "criteria": "API 호출 + 성공 토스트 + 데이터 반영" - }, - { - "id": 5, - "name": "목업 페이지 감지", - "steps": [2], - "criteria": "배차 목록, 등록 버튼, 날짜 필터 존재" - } - ], - "rollbackPlan": { - "onCreateFail": "등록 모달 닫고 재시도", - "onUpdateFail": "페이지 새로고침 후 재시도", - "onDeleteFail": "수동 삭제 필요", - "cleanupRequired": "E2E_99가* 패턴 배차 데이터 삭제" - } -} diff --git a/shipment-management.json b/shipment-management.json index f219b53..88d84f3 100644 --- a/shipment-management.json +++ b/shipment-management.json @@ -1,5 +1,5 @@ { - "enabled": false, + "enabled": true, "id": "shipment-management", "name": "출고관리 테스트", "screenshotPolicy": { @@ -18,7 +18,7 @@ "menuNavigation": { "level1": "출고관리", "level2": "출고관리", - "expectedUrl": "/outbound/outbound-management", + "expectedUrl": "/outbound/shipments", "searchWithinParent": true, "closeOtherMenus": true }, diff --git a/subscription-management.json b/subscription-management.json deleted file mode 100644 index 477da94..0000000 --- a/subscription-management.json +++ /dev/null @@ -1,197 +0,0 @@ -{ - "enabled": false, - "id": "subscription-management", - "name": "구독관리 테스트", - "screenshotPolicy": { - "onErrorOnly": true, - "captureOn": ["error", "fail", "timeout", "404", "500", "blocked"] - }, - "description": "설정 > 구독관리 페이지의 구독 정보 조회 및 자료 내보내기 기능을 테스트하는 E2E 테스트", - "baseUrl": "https://dev.codebridge-x.com", - "url": "/settings/subscription", - "navigation": { - "targetUrl": "/subscription", - "urlPattern": "/subscription|/ko/subscription|/settings/subscription", - "menuHints": ["구독관리", "구독 관리", "설정"] - }, - "menuNavigation": { - "level1": "설정", - "level2": "구독관리", - "expectedUrl": "/settings/subscription", - "searchWithinParent": true, - "closeOtherMenus": true - }, - "menuNavigationEnhanced": { - "strategy": "scroll-and-search", - "sidebar": { - "scrollContainer": ".sidebar-scroll", - "scrollStep": 200, - "maxScrollAttempts": 5, - "waitAfterScroll": 300 - }, - "level1": { - "text": "설정", - "expandable": true, - "waitAfterClick": 500 - }, - "level2": { - "text": "구독관리", - "waitAfterClick": 300 - }, - "fallbackUrl": "/settings/subscription", - "expectedUrl": "/settings/subscription" - }, - "timeout": 90000, - "tags": ["settings", "subscription", "read-only"], - - "auth": { - "username": "TestUser5", - "password": "password123!" - }, - - "steps": [ - { - "id": "step-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": "step-1", - "name": "설정 메뉴 진입", - "description": "설정 > 구독관리 메뉴로 이동", - "actions": [ - { - "type": "scrollAndFind", - "container": ".sidebar-scroll", - "target": "설정", - "scrollStep": 200, - "maxAttempts": 5 - }, - { "type": "click_if_exists", "target": "설정" }, - { "type": "wait", "duration": 500 }, - { "type": "click_if_exists", "target": "구독관리" } - ], - "expect": { - "url": "/settings/subscription", - "visible": ["구독관리", "구독 정보"] - }, - "fallback": { - "type": "navigate", - "url": "/settings/subscription" - } - }, - { - "id": "step-2", - "name": "페이지 구조 확인", - "description": "구독 정보 필드 및 버튼 확인", - "verify": { - "visible": ["구독관리", "최근 결제일시", "다음 결제일시", "구독금액", "구독 정보"], - "buttons": ["자료 내보내기", "서비스 해지"] - } - }, - { - "id": "step-3", - "name": "결제 정보 확인", - "description": "결제 관련 정보 표시 확인", - "verify": { - "visible": ["최근 결제일시", "다음 결제일시", "구독금액"] - } - }, - { - "id": "step-4", - "name": "사용량 정보 확인", - "description": "사용자 수, 저장 공간, API 호출 정보 확인", - "verify": { - "visible": ["사용자 수", "저장 공간", "AI API 호출"] - } - }, - { - "id": "step-5", - "name": "필수 검증 #1: 자료 내보내기 버튼 동작", - "description": "자료 내보내기 버튼 클릭하여 다운로드 확인", - "actions": [ - { "type": "click_if_exists", "target": "자료 내보내기" }, - { "type": "wait", "duration": 1000 } - ], - "expect": { - "downloadTriggered": true, - "noErrorPage": true - }, - "verify": { - "apiCall": "GET /api/settings/subscription/export" - } - }, - { - "id": "step-6", - "name": "서비스 해지 버튼 확인", - "description": "서비스 해지 버튼 존재 확인 (클릭하지 않음)", - "verify": { - "buttonExists": "서비스 해지" - } - }, - { - "id": "step-7", - "name": "구독 플랜 정보 확인", - "description": "현재 구독 플랜 정보 표시 확인", - "verify": { - "visible": ["무료", "무제한"] - } - } - ], - - "assertions": [ - { - "type": "url", - "expected": "/settings/subscription", - "message": "구독관리 페이지에 머물러야 함" - }, - { - "type": "elementExists", - "selector": "button:has-text('자료 내보내기')", - "message": "자료 내보내기 버튼이 표시되어야 함" - } - ], - - "mandatoryVerifications": { - "description": "E2E_TEST_CONFIG.md 기준 필수 검증 항목", - "items": [ - { - "id": 1, - "name": "파일 다운로드", - "trigger": "자료 내보내기 버튼", - "verification": "Network API + 실제 다운로드 확인", - "failCondition": "Console LOG만으로 PASS 금지" - }, - { - "id": 5, - "name": "목업/미완성 페이지 감지", - "trigger": "페이지 로드 시", - "verification": "실제 구독 정보 표시 + 동작하는 버튼 확인", - "failCondition": "더미 데이터만 표시" - } - ] - }, - - "notes": { - "testScope": "구독 정보 조회 및 자료 내보내기 테스트", - "pageFeatures": { - "paymentInfo": ["최근 결제일시", "다음 결제일시", "구독금액"], - "usageInfo": ["사용자 수", "저장 공간", "AI API 호출"], - "buttons": ["자료 내보내기", "서비스 해지"] - }, - "caution": "서비스 해지 버튼은 테스트 계정 보호를 위해 클릭하지 않음", - "prerequisites": "로그인된 사용자" - } -} diff --git a/vacation-management.json b/vacation-management.json deleted file mode 100644 index cf59afc..0000000 --- a/vacation-management.json +++ /dev/null @@ -1,879 +0,0 @@ -{ - "id": "vacation-management", - "name": "휴가관리 테스트", - "screenshotPolicy": { - "onErrorOnly": true, - "captureOn": [ - "error", - "fail", - "timeout", - "404", - "500", - "blocked" - ] - }, - "description": "휴가 사용현황, 부여현황, 신청현황 탭 기능과 부여등록/휴가신청 다이얼로그를 테스트하는 E2E 테스트", - "baseUrl": "https://dev.codebridge-x.com", - "url": "/ko/hr/vacation-management", - "navigation": { - "targetUrl": "/hr/vacation-management", - "urlPattern": "/hr/vacation-management|/ko/hr/vacation-management", - "menuHints": [ - "휴가관리", - "휴가 관리", - "인사관리" - ] - }, - "menuNavigation": { - "level1": "인사관리", - "level2": "휴가관리", - "expectedUrl": "/ko/hr/vacation-management", - "searchWithinParent": true, - "closeOtherMenus": true - }, - "menuNavigationEnhanced": { - "strategy": "scroll-and-search", - "sidebarSelector": ".sidebar-scroll, [data-sidebar], nav[class*='sidebar']", - "scrollConfig": { - "scrollStep": 200, - "maxScrollAttempts": 10, - "scrollDelay": 300 - }, - "level1": { - "text": "인사관리", - "selectors": [ - "button:has-text('인사관리')", - "[data-menu='hr']", - "a:has-text('인사관리')" - ] - }, - "level2": { - "text": "휴가관리", - "selectors": [ - "a:has-text('휴가관리')", - "[href*='vacation-management']", - "button:has-text('휴가관리')" - ] - }, - "fallbackUrl": "/ko/hr/vacation-management" - }, - "timeout": 120000, - "tags": [ - "hr", - "vacation", - "leave", - "management" - ], - "auth": { - "username": "TestUser5", - "password": "password123!" - }, - "testData": { - "searchKeyword": "홍", - "grantData": { - "vacationType": "annual", - "grantDays": 3, - "reason": "E2E 테스트 부여" - }, - "requestData": { - "leaveType": "annual", - "daysRange": 2 - }, - "dateRange": { - "startDate": "2025-12-01", - "endDate": "2025-12-31" - } - }, - "steps": [ - { - "id": "step-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 - } - ], - "expect": { - "sidebarReady": true - } - }, - { - "id": "step-1", - "name": "인사관리 메뉴 진입", - "description": "인사관리 > 휴가관리 메뉴로 이동 (scrollAndFind 패턴 사용)", - "navigationPattern": "scrollAndFind", - "actions": [ - { - "type": "scrollAndFind", - "target": "인사관리", - "container": ".sidebar-scroll, [data-sidebar], nav[class*='sidebar']", - "scrollStep": 200, - "maxAttempts": 10 - }, - { - "type": "click_if_exists", - "target": "인사관리" - }, - { - "type": "wait", - "duration": 300 - }, - { - "type": "scrollAndFind", - "target": "휴가관리", - "container": ".sidebar-scroll, [data-sidebar], nav[class*='sidebar']", - "scrollStep": 200, - "maxAttempts": 10 - }, - { - "type": "click_if_exists", - "target": "휴가관리" - } - ], - "fallback": { - "type": "navigate", - "url": "/ko/hr/vacation-management" - }, - "expect": { - "url": "/hr/vacation-management", - "visible": [ - "휴가관리", - "휴가 사용현황" - ] - } - }, - { - "id": "step-2", - "name": "필수 검증 #5: 목업 페이지 감지", - "description": "페이지가 목업인지 실제 동작하는 페이지인지 감지", - "verify": { - "mockupDetection": { - "inputFields": [ - "검색창", - "날짜 필터" - ], - "functionalButtons": [ - "부여등록", - "휴가신청", - "승인", - "거절" - ], - "apiCalls": true, - "dataChangePossible": true - } - } - }, - { - "id": "step-3", - "name": "통계 카드 대시보드 확인", - "description": "휴가 승인 대기, 연차, 경조사, 연간 연차 사용률 카드 표시 확인", - "verify": { - "visible": [ - "휴가 승인 대기", - "연차", - "경조사", - "연간 연차 사용률" - ], - "statsCards": true - } - }, - { - "id": "step-4", - "name": "휴가 사용현황 탭 확인 (기본 탭)", - "description": "휴가 사용현황 탭의 테이블 컬럼 구조 검증", - "verify": { - "activeTab": "휴가 사용현황", - "tableColumns": [ - "번호", - "부서", - "직책", - "이름", - "직급", - "입사일", - "기본", - "부여", - "사용", - "잔여" - ] - } - }, - { - "id": "step-4-1", - "name": "⚠️ 필수 검증: 날짜 필터 검색", - "description": "날짜 범위 필터를 설정하고 데이터가 필터링되는지 확인", - "actions": [ - { - "type": "evaluate", - "script": "document.querySelectorAll('table tbody tr').length", - "description": "필터 전 행 수 확인" - }, - { - "type": "fill", - "target": "input[type='date']:first-of-type, input[placeholder*='시작']", - "value": "2025-12-01", - "description": "시작일 입력" - }, - { - "type": "fill", - "target": "input[type='date']:last-of-type, input[placeholder*='종료']", - "value": "2025-12-31", - "description": "종료일 입력" - }, - { - "type": "wait", - "duration": 500, - "description": "필터 적용 대기" - }, - { - "type": "evaluate", - "script": "document.querySelectorAll('table tbody tr').length", - "description": "필터 후 행 수 확인" - } - ], - "verify": { - "dateFilterApplied": true, - "dataChanged": "필터 적용 후 데이터가 변경되어야 함" - }, - "note": "날짜 필터가 실제로 데이터를 필터링하는지 확인" - }, - { - "id": "step-5", - "name": "⚠️ 필수 검증: 검색 기능 확인 (사용현황)", - "description": "검색어 입력 후 테이블 데이터가 필터링되는지 확인", - "actions": [ - { - "type": "evaluate", - "script": "document.querySelectorAll('table tbody tr').length", - "description": "검색 전 행 수 확인" - }, - { - "type": "fill", - "target": "input[placeholder*='검색'], input[type='search']", - "value": "홍", - "description": "검색어 입력" - }, - { - "type": "wait", - "duration": 500, - "description": "검색 결과 대기" - }, - { - "type": "evaluate", - "script": "document.querySelectorAll('table tbody tr').length", - "description": "검색 후 행 수 확인" - } - ], - "verify": { - "searchApplied": true, - "tableContains": "{testData.searchKeyword}", - "dataFiltered": "검색 결과에 검색어가 포함된 행만 표시" - }, - "expect": { - "searchPlaceholder": "이름, 부서 검색..." - }, - "note": "⚠️ 검색어 입력 후 테이블에 검색어가 포함된 행만 표시되어야 함" - }, - { - "id": "step-5-1", - "name": "검색 결과 데이터 검증", - "description": "검색 결과의 각 행에 검색어가 포함되어 있는지 확인", - "verify": { - "allRowsContain": "{testData.searchKeyword}", - "verifyMethod": "테이블의 모든 행이 검색어를 포함하는지 확인" - } - }, - { - "id": "step-5-2", - "name": "검색 초기화 확인", - "description": "검색어 삭제 후 전체 목록 복원 확인", - "actions": [ - { - "type": "clear", - "target": "input[placeholder*='검색'], input[type='search']", - "description": "검색어 삭제" - }, - { - "type": "wait", - "duration": 500, - "description": "목록 복원 대기" - } - ], - "verify": { - "dataRestored": true - } - }, - { - "id": "step-6", - "name": "휴가 부여현황 탭 전환", - "description": "휴가 부여현황 탭 클릭 및 테이블 구조 확인", - "actions": [ - { - "type": "click_if_exists", - "target": "휴가 부여현황" - } - ], - "verify": { - "activeTab": "휴가 부여현황", - "tableColumns": [ - "번호", - "부서", - "직책", - "이름", - "직급", - "유형", - "부여일", - "부여휴가일수", - "사유" - ], - "visible": [ - "부여등록" - ] - } - }, - { - "id": "step-7", - "name": "부여등록 다이얼로그 열기", - "description": "부여등록 버튼 클릭하여 다이얼로그 열기", - "actions": [ - { - "type": "click_if_exists", - "target": "부여등록", - "description": "부여등록 버튼 클릭" - } - ], - "expect": { - "modal": "휴가 부여 등록", - "visible": [ - "사원 선택", - "휴가 유형", - "부여일", - "부여 일수", - "사유" - ] - } - }, - { - "id": "step-8", - "name": "부여등록 다이얼로그 입력 필드 확인", - "description": "다이얼로그 내 입력 필드들이 정상 동작하는지 확인", - "actions": [ - { - "type": "click_if_exists", - "target": "사원 선택", - "options": { - "waitAfter": 200 - } - } - ], - "verify": { - "comboboxOptions": true, - "inputFields": [ - "사원 선택", - "휴가 유형", - "부여일", - "부여 일수", - "사유" - ] - } - }, - { - "id": "step-9", - "name": "필수 검증 #4: 부여등록 저장", - "description": "모달 내 부여등록 실제 등록 수행", - "actions": [ - { - "type": "click_if_exists", - "target": "사원 선택", - "options": { - "waitAfter": 200 - }, - "description": "사원 선택 요소 존재 확인" - }, - { - "type": "click_if_exists", - "target": "휴가 유형", - "options": { - "waitAfter": 200 - }, - "description": "휴가 유형 요소 존재 확인" - }, - { - "type": "click_if_exists", - "target": "부여 일수", - "options": { - "waitAfter": 100 - }, - "description": "부여 일수 요소 존재 확인" - }, - { - "type": "click_if_exists", - "target": "사유", - "options": { - "waitAfter": 100 - }, - "description": "사유 요소 존재 확인" - }, - { - "type": "click_if_exists", - "target": "등록", - "options": { - "waitAfter": 500 - } - } - ], - "expect": { - "urlMaintained": true, - "noErrorPage": true, - "modalClosed": true, - "apiCall": "createLeaveGrant" - } - }, - { - "id": "step-10", - "name": "부여등록 다이얼로그 취소 테스트", - "description": "다이얼로그 취소 버튼 동작 확인", - "actions": [ - { - "type": "click_if_exists", - "target": "부여등록" - }, - { - "type": "click_if_exists", - "target": "취소" - } - ], - "expect": { - "modalClosed": true - } - }, - { - "id": "step-11", - "name": "휴가 신청현황 탭 전환", - "description": "휴가 신청현황 탭 클릭 및 테이블 구조 확인", - "actions": [ - { - "type": "click_if_exists", - "target": "휴가 신청현황" - } - ], - "verify": { - "activeTab": "휴가 신청현황", - "tableColumns": [ - "번호", - "부서", - "직책", - "이름", - "직급", - "휴가기간", - "휴가일수", - "상태", - "신청일" - ], - "visible": [ - "휴가신청" - ] - } - }, - { - "id": "step-12", - "name": "휴가신청 다이얼로그 열기", - "description": "휴가신청 버튼 클릭하여 다이얼로그 열기", - "actions": [ - { - "type": "click_if_exists", - "target": "휴가신청", - "description": "휴가신청 버튼 클릭" - } - ], - "expect": { - "modal": "휴가 신청", - "visible": [ - "사원 선택", - "휴가 유형", - "시작일", - "종료일" - ] - } - }, - { - "id": "step-13", - "name": "휴가신청 다이얼로그 입력 필드 확인", - "description": "다이얼로그 내 입력 필드들이 정상 동작하는지 확인 (캘린더 포함)", - "actions": [ - { - "type": "click_if_exists", - "target": "사원 선택", - "options": { - "waitAfter": 200 - } - } - ], - "verify": { - "comboboxOptions": true, - "inputFields": [ - "사원 선택", - "휴가 유형", - "시작일", - "종료일" - ] - } - }, - { - "id": "step-14", - "name": "필수 검증 #4: 휴가신청 등록", - "description": "모달 내 휴가신청 실제 등록 수행", - "actions": [ - { - "type": "click_if_exists", - "target": "사원 선택", - "options": { - "waitAfter": 200 - }, - "description": "사원 선택 요소 존재 확인" - }, - { - "type": "click_if_exists", - "target": "휴가 유형", - "options": { - "waitAfter": 200 - }, - "description": "휴가 유형 요소 존재 확인" - }, - { - "type": "click_if_exists", - "target": "시작일 선택", - "options": { - "waitAfter": 200 - } - }, - { - "type": "click_if_exists", - "target": "캘린더 날짜 선택", - "options": { - "waitAfter": 200 - } - }, - { - "type": "click_if_exists", - "target": "종료일 선택", - "options": { - "waitAfter": 200 - } - }, - { - "type": "click_if_exists", - "target": "캘린더 날짜 선택", - "options": { - "waitAfter": 200 - } - }, - { - "type": "click_if_exists", - "target": "신청", - "options": { - "waitAfter": 500 - } - } - ], - "expect": { - "urlMaintained": true, - "noErrorPage": true, - "modalClosed": true, - "apiCall": "createLeave" - } - }, - { - "id": "step-15", - "name": "휴가신청 다이얼로그 취소 테스트", - "description": "다이얼로그 취소 버튼 동작 확인", - "actions": [ - { - "type": "click_if_exists", - "target": "휴가신청" - }, - { - "type": "click_if_exists", - "target": "취소" - } - ], - "expect": { - "modalClosed": true - } - }, - { - "id": "step-16", - "name": "필수 검증 #2: 휴가 승인 버튼 동작", - "description": "신청현황에서 체크박스 선택 후 승인 버튼 동작 확인", - "actions": [ - { - "type": "click_if_exists", - "target": "첫번째 행 체크박스" - }, - { - "type": "click_if_exists", - "target": "승인" - } - ], - "expect": { - "modal": "휴가 승인", - "visible": [ - "승인하시겠습니까" - ] - } - }, - { - "id": "step-17", - "name": "승인 확인 다이얼로그 동작", - "description": "승인 확인 다이얼로그에서 승인 버튼 클릭", - "actions": [ - { - "type": "click_if_exists", - "target": "승인", - "context": "dialog" - } - ], - "expect": { - "urlMaintained": true, - "noErrorPage": true, - "modalClosed": true, - "apiCall": "approveLeavesMany" - } - }, - { - "id": "step-18", - "name": "필수 검증 #2: 휴가 거절 버튼 동작", - "description": "신청현황에서 체크박스 선택 후 거절 버튼 동작 확인", - "actions": [ - { - "type": "click_if_exists", - "target": "첫번째 행 체크박스" - }, - { - "type": "click_if_exists", - "target": "거절" - } - ], - "expect": { - "modal": "휴가 거절", - "visible": [ - "거절하시겠습니까" - ] - } - }, - { - "id": "step-19", - "name": "거절 확인 다이얼로그 취소", - "description": "거절 확인 다이얼로그에서 취소 버튼 클릭", - "actions": [ - { - "type": "click_if_exists", - "target": "취소", - "context": "dialog" - } - ], - "expect": { - "modalClosed": true - } - }, - { - "id": "step-20", - "name": "필터 및 정렬 셀렉트 동작 확인", - "description": "필터 및 정렬 셀렉트박스가 정상 동작하는지 확인", - "actions": [ - { - "type": "click_if_exists", - "target": "필터 선택 콤보박스" - } - ], - "verify": { - "comboboxOptions": [ - "전체", - "대기중", - "승인됨", - "거절됨" - ] - } - }, - { - "id": "step-21", - "name": "날짜 범위 필터 확인", - "description": "시작일/종료일 날짜 필터 필드 동작 확인", - "verify": { - "dateInputs": 2, - "dateRange": { - "startDate": "2025-12-01", - "endDate": "2025-12-31" - } - } - } - ], - "assertions": [ - { - "type": "url", - "expected": "/hr/vacation-management", - "message": "휴가관리 페이지에 머물러야 함" - }, - { - "type": "tabsExist", - "expected": [ - "휴가 사용현황", - "휴가 부여현황", - "휴가 신청현황" - ], - "message": "3개의 탭이 모두 표시되어야 함" - }, - { - "type": "tableExists", - "message": "휴가 목록 테이블이 표시되어야 함" - } - ], - "mandatoryVerifications": { - "description": "E2E_TEST_CONFIG.md 기준 필수 검증 항목", - "items": [ - { - "id": 2, - "name": "등록/저장 버튼", - "trigger": "부여등록, 휴가신청, 승인, 거절 버튼", - "verification": "URL 유지 + 에러 페이지 없음 + 모달 닫힘", - "failCondition": "404/500 에러 페이지 이동" - }, - { - "id": 3, - "name": "검색/필터", - "trigger": "검색창, 날짜 필터, 탭 전환", - "verification": "데이터 변화 확인", - "failCondition": "필터 적용 후 데이터 무변화" - }, - { - "id": 4, - "name": "모달 등록 완료", - "trigger": "부여등록/휴가신청 다이얼로그", - "verification": "실제 등록 동작 + API 호출 확인", - "failCondition": "열기/닫기만 테스트" - }, - { - "id": 5, - "name": "목업/미완성 페이지 감지", - "trigger": "페이지 로드 시", - "verification": "입력 필드 + 동작하는 버튼 + API 호출 확인", - "failCondition": "버튼만 있고 입력 불가, Console LOG만 출력" - } - ] - }, - "cleanup": { - - "description": "테스트 데이터는 수동 정리 필요" - }, - "notes": { - "testScope": "휴가관리 페이지 UI 요소 및 기능 검증", - "features": { - "tabs": "휴가 사용현황 / 휴가 부여현황 / 휴가 신청현황", - "statsCards": "휴가 승인 대기 / 연차 / 경조사 / 연간 연차 사용률", - "grantDialog": "부여등록 다이얼로그 (사원 선택, 휴가 유형, 부여일, 부여 일수, 사유)", - "requestDialog": "휴가신청 다이얼로그 (사원 선택, 휴가 유형, 시작일, 종료일, 캘린더)", - "approveReject": "신청현황 탭에서 승인/거절 버튼", - "dateFilter": "시작일~종료일 날짜 범위 필터", - "search": "이름, 부서 검색", - "filterSort": "필터 및 정렬 셀렉트박스" - }, - "tableColumns": { - "usage": [ - "번호", - "부서", - "직책", - "이름", - "직급", - "입사일", - "기본", - "부여", - "사용", - "잔여" - ], - "grant": [ - "번호", - "부서", - "직책", - "이름", - "직급", - "유형", - "부여일", - "부여휴가일수", - "사유" - ], - "request": [ - "번호", - "부서", - "직책", - "이름", - "직급", - "휴가기간", - "휴가일수", - "상태", - "신청일" - ] - }, - "dialogs": { - "grantDialog": { - "title": "휴가 부여 등록", - "fields": [ - "사원 선택", - "휴가 유형", - "부여일", - "부여 일수", - "사유" - ], - "buttons": [ - "취소", - "등록" - ] - }, - "requestDialog": { - "title": "휴가 신청", - "fields": [ - "사원 선택", - "휴가 유형", - "시작일", - "종료일" - ], - "buttons": [ - "취소", - "신청" - ], - "note": "캘린더 컴포넌트 사용" - }, - "approveDialog": { - "title": "휴가 승인", - "buttons": [ - "취소", - "승인" - ] - }, - "rejectDialog": { - "title": "휴가 거절", - "buttons": [ - "취소", - "거절" - ] - } - }, - "knownIssues": [ - "엑셀 다운로드 버튼이 주석처리 되어 있음 (미구현)", - "휴가 유형 옵션: annual(연차), sick(병가), personal(개인사유), condolence(경조사), maternity(출산휴가), reward(포상휴가)" - ], - "prerequisites": "로그인된 사용자에게 휴가 관리 권한 필요" - } -} diff --git a/vendor-ledger.json b/vendor-ledger.json index 40d0183..137f70f 100644 --- a/vendor-ledger.json +++ b/vendor-ledger.json @@ -1,5 +1,5 @@ { - "enabled": false, + "enabled": true, "id": "vendor-ledger", "name": "거래처원장 테스트", "screenshotPolicy": { diff --git a/withdrawal-management.json b/withdrawal-management.json index f88af5a..499bd59 100644 --- a/withdrawal-management.json +++ b/withdrawal-management.json @@ -1,5 +1,5 @@ { - "enabled": false, + "enabled": true, "id": "withdrawal-management", "name": "출금관리 테스트", "screenshotPolicy": { diff --git a/work-performance.json b/work-performance.json deleted file mode 100644 index 6c392a7..0000000 --- a/work-performance.json +++ /dev/null @@ -1,214 +0,0 @@ -{ - "enabled": false, - "id": "work-performance", - "name": "작업실적 테스트", - "screenshotPolicy": { - "onErrorOnly": true, - "captureOn": ["error", "fail", "timeout", "404", "500", "blocked"] - }, - "description": "생산관리 > 작업실적 메뉴의 작업실적 조회/필터/검색/엑셀다운로드 기능 테스트", - "baseUrl": "https://dev.codebridge-x.com", - "menuNavigation": { - "level1": "생산관리", - "level2": "작업실적", - "expectedUrl": "/production/performance", - "searchWithinParent": true, - "closeOtherMenus": true - }, - "auth": { - "username": "TestUser5", - "password": "password123!" - }, - "steps": [ - { - "id": 1, - "name": "메뉴 진입: 생산관리 > 작업실적", - "action": "menu_navigate", - "level1": "생산관리", - "level2": "작업실적", - "expected": { - "url_contains": "/production/performance", - "visible": ["작업실적", "조회"] - } - }, - { - "id": 2, - "name": "필수 검증 #5: 목업 페이지 감지", - "action": "verify_not_mockup", - "checks": [ - "작업실적 테이블 표시", - "검색/필터 영역 존재", - "엑셀 다운로드 버튼 존재" - ], - "expected": "정상 페이지 (목업 아님)" - }, - { - "id": 3, - "name": "통계 카드 확인", - "action": "verify_elements", - "checks": [ - "총 생산수량 카드", - "양품수량 카드", - "불량수량 카드", - "불량률 카드" - ], - "expected": "통계 카드 표시" - }, - { - "id": 4, - "name": "작업실적 테이블 구조 확인", - "action": "verify_table", - "checks": [ - "로트번호 컬럼", - "작업일 컬럼", - "작업지시번호 컬럼", - "공정 컬럼", - "품목명 컬럼", - "생산수량 컬럼", - "양품수량 컬럼", - "불량수량 컬럼" - ], - "expected": "작업실적 테이블 표시" - }, - { - "id": 5, - "phase": "FILTER", - "name": "[FILTER] 기간 필터 - 시작일", - "action": "click_if_exists", - "target": "input[type='date']:first-of-type, input[name*='start'], input[placeholder*='시작']", - "expected": "시작일 선택 열림" - }, - { - "id": 6, - "phase": "FILTER", - "name": "[FILTER] 기간 필터 - 종료일", - "action": "click_if_exists", - "target": "input[type='date']:last-of-type, input[name*='end'], input[placeholder*='종료']", - "expected": "종료일 선택 열림" - }, - { - "id": 7, - "phase": "FILTER", - "name": "[FILTER] 조회 버튼 클릭", - "action": "click_if_exists", - "target": "button:has-text('조회'), button:has-text('검색'), button:has-text('적용')", - "expected": "필터 적용됨" - }, - { - "id": 8, - "phase": "FILTER", - "name": "[FILTER] 필터 결과 확인", - "action": "verify_detail", - "checks": [ - "선택한 기간의 작업실적 데이터 표시 또는 검색 결과 없음" - ], - "expected": "필터 동작 확인" - }, - { - "id": 9, - "name": "공정 필터 확인", - "action": "verify_elements", - "checks": [ - "공정 선택 드롭다운 또는 필터" - ], - "expected": "공정 필터 존재" - }, - { - "id": 10, - "phase": "READ", - "name": "[READ] 작업실적 행 상세 조회", - "action": "click_if_exists", - "target": "table tbody tr:first-child", - "expected": { - "detail_view": true - } - }, - { - "id": 11, - "name": "상세 정보 확인", - "action": "verify_detail", - "checks": [ - "로트번호 표시", - "작업일 표시", - "생산수량 표시", - "양품수량 표시", - "불량수량 표시" - ], - "expected": "상세 정보 표시" - }, - { - "id": 12, - "name": "필수 검증 #1: 엑셀 다운로드", - "action": "click_if_exists", - "target": "button:has-text('엑셀'), button:has-text('Excel'), button:has-text('다운로드')", - "verify": { - "api_call": "GET /api/v1/production/performance/export", - "download_triggered": true - }, - "expected": "엑셀 파일 다운로드" - }, - { - "id": 13, - "name": "페이지네이션 확인", - "action": "verify_elements", - "checks": [ - "페이지 번호 또는 더보기 버튼" - ], - "expected": "페이지네이션 표시" - }, - { - "id": 14, - "name": "인쇄 버튼 확인", - "action": "verify_elements", - "checks": [ - "인쇄 버튼 존재" - ], - "expected": "인쇄 기능 표시" - } - ], - "expectedAPIs": [ - { - "method": "GET", - "endpoint": "/api/v1/production/performance", - "description": "작업실적 목록 조회" - }, - { - "method": "GET", - "endpoint": "/api/v1/production/performance/:id", - "description": "작업실적 상세 조회" - }, - { - "method": "GET", - "endpoint": "/api/v1/production/performance/export", - "description": "작업실적 엑셀 다운로드" - }, - { - "method": "GET", - "endpoint": "/api/v1/production/performance/stats", - "description": "작업실적 통계 조회" - } - ], - "requiredVerifications": [ - { - "id": 1, - "name": "파일 다운로드", - "steps": [12], - "criteria": "Network API 호출 + 실제 다운로드 확인" - }, - { - "id": 3, - "name": "검색/필터", - "steps": [5, 6, 7, 8], - "criteria": "기간 필터 동작" - }, - { - "id": 5, - "name": "목업 페이지 감지", - "steps": [2], - "criteria": "테이블, 필터, 다운로드 버튼 존재" - } - ], - "rollbackPlan": { - "note": "조회 전용 페이지로 데이터 변경 없음" - } -}