{ "id": "item-management", "name": "품목관리 (Item Management)", "screenshotPolicy": { "onErrorOnly": true, "captureOn": ["error", "fail", "timeout", "404", "500", "blocked"] }, "description": "생산관리 - 품목관리 메뉴의 전체 기능 테스트: 품목 조회, 검색, 필터, 등록, 상세보기, 수정, 삭제", "priority": "High", "baseUrl": "https://dev.codebridge-x.com", "menuNavigation": { "level1": "생산관리", "level2": "품목관리", "expectedUrl": "/ko/production/screen-production", "searchWithinParent": true, "closeOtherMenus": true }, "auth": { "username": "TestUser5", "password": "password123!" }, "selectors": { "statCard": ".card, [class*='stat'], [class*='summary'], [class*='kpi']", "searchInput": "input[type='search'], input[type='text'][placeholder*='검색'], input[placeholder*='Search'], input[placeholder*='품목']", "tabButtons": "button[role='tab'], [class*='tab'] button, [class*='filter'] button", "tableHeader": "table thead th, table th, [role='columnheader']", "tableRow": "table tbody tr, [role='row']:not(:first-child)", "pagination": "[class*='pagination'], [class*='Pagination'], nav[aria-label*='page']", "actionButtons": "button:has-text('상세'), button:has-text('수정'), button:has-text('삭제')", "registerButton": "button:has-text('품목 등록'), button:has-text('등록'), button[class*='add']", "saveButton": "button:has-text('저장'), button[type='submit']", "cancelButton": "button:has-text('취소'), button:has-text('닫기')", "toast": "[class*='toast'], [class*='Toast'], [role='alert'], [class*='notification']", "modal": "[role='dialog'], [class*='modal'], [class*='Modal']", "formField": "input:not([type='hidden']), textarea, select", "combobox": "select, [role='combobox'], [class*='select'], [class*='dropdown']", "pageTitle": "h1, h2, [class*='title'], [class*='Title']" }, "steps": [ { "id": 0, "name": "사이드바 메뉴 전체 펼치기", "actions": [ { "type": "evaluate", "script": "document.querySelector('.sidebar-scroll')?.scrollTo({top:0,behavior:'instant'})" }, { "type": "wait", "duration": 300 }, { "type": "evaluate", "script": "Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click()" }, { "type": "wait", "duration": 2000 } ] }, { "id": 1, "name": "2단계 메뉴 진입: 생산관리 > 품목관리", "action": "menu_navigate", "level1": "생산관리", "level2": "품목관리", "expected": { "url_contains": "/production" } }, { "id": 2, "name": "페이지 로드 및 404 확인", "action": "evaluate", "script": "(() => { const url = window.location.href; const text = document.body.innerText; return !text.includes('404') && !text.includes('Not Found') && (url.includes('production') || text.includes('품목')); })()" }, { "id": 3, "name": "통계 카드 영역 존재 확인", "action": "verify_element", "target": "statCard" }, { "id": 4, "name": "통계 카드 숫자 데이터 확인", "action": "evaluate", "script": "(() => { const cards = document.querySelectorAll('.card, [class*=\"stat\"]'); let hasNum = false; cards.forEach(c => { if (/\\d+/.test(c.innerText)) hasNum = true; }); return hasNum || document.body.innerText.includes('전체'); })()" }, { "id": 5, "name": "품목 등록 버튼 존재 확인", "action": "verify_element", "target": "registerButton" }, { "id": 6, "name": "검색 입력 필드 존재 확인", "action": "evaluate", "script": "(() => { const hasInput = document.querySelector('input[type=\"search\"], input[placeholder*=\"검색\"], input[placeholder*=\"품목\"]'); return hasInput || document.body.innerText.includes('검색'); })()" }, { "id": 7, "name": "탭/필터 버튼 존재 확인", "action": "evaluate", "script": "(() => { const text = document.body.innerText; return text.includes('전체') && (text.includes('제품') || text.includes('부품') || text.includes('소모품')); })()" }, { "id": 8, "name": "데이터 테이블 헤더 확인", "action": "evaluate", "script": "(() => { const th = document.querySelectorAll('table th, thead th, [role=\"columnheader\"]'); return th.length > 0 || document.body.innerText.includes('품목코드'); })()" }, { "id": 9, "name": "데이터 행 존재 확인", "action": "evaluate", "script": "(() => { const rows = document.querySelectorAll('table tbody tr, [role=\"row\"]:not(:first-child)'); return rows.length > 0 || document.body.innerText.includes('데이터가 없습니다'); })()" }, { "id": 10, "name": "페이지네이션 존재 확인", "action": "evaluate", "script": "(() => { const pag = document.querySelector('[class*=\"pagination\"], [class*=\"Pagination\"], nav[aria-label*=\"page\"]'); const hasPageNum = document.body.innerText.match(/\\d+\\s*-\\s*\\d+|페이지|Page/); return pag || hasPageNum; })()" }, { "id": 11, "phase": "FILTER", "name": "[FILTER] 검색 기능 테스트 - 검색어 입력", "action": "evaluate", "script": "(() => { const input = document.querySelector('input[type=\"search\"], input[placeholder*=\"검색\"], input[placeholder*=\"품목\"]'); if (input) { input.value = 'CS-001'; input.dispatchEvent(new Event('input', {bubbles:true})); return true; } return document.body.innerText.includes('품목'); })()" }, { "id": 12, "phase": "FILTER", "name": "[FILTER] 검색 결과 대기", "action": "wait", "duration": 1500 }, { "id": 13, "phase": "FILTER", "name": "[FILTER] 검색 결과 테이블 확인", "action": "evaluate", "script": "(() => { const rows = document.querySelectorAll('table tbody tr'); return rows.length >= 0; })()" }, { "id": 14, "phase": "FILTER", "name": "[FILTER] 검색 초기화 - 검색창 클리어", "action": "evaluate", "script": "(() => { const input = document.querySelector('input[type=\"search\"], input[placeholder*=\"검색\"], input[placeholder*=\"품목\"]'); if (input) { input.value = ''; input.dispatchEvent(new Event('input', {bubbles:true})); return true; } return true; })()" }, { "id": 15, "phase": "FILTER", "name": "[FILTER] 제품 탭 클릭", "action": "click_if_exists", "target": "button:has-text('제품'), [class*='tab']:has-text('제품')" }, { "id": 16, "phase": "FILTER", "name": "[FILTER] 필터 결과 대기", "action": "wait", "duration": 1000 }, { "id": 17, "phase": "FILTER", "name": "[FILTER] 전체 탭 클릭 (초기화)", "action": "click_if_exists", "target": "button:has-text('전체'), [class*='tab']:has-text('전체')" }, { "id": 18, "name": "페이지네이션 - 2페이지 이동", "action": "click_if_exists", "target": "button:has-text('2'), [class*='pagination'] button:has-text('2'), a:has-text('2')" }, { "id": 19, "name": "2페이지 로드 대기", "action": "wait", "duration": 1000 }, { "id": 20, "name": "1페이지로 복귀", "action": "click_if_exists", "target": "button:has-text('1'), [class*='pagination'] button:has-text('1'), a:has-text('1')" }, { "id": 21, "phase": "CREATE", "name": "[CREATE] 품목 등록 버튼 클릭", "action": "click", "target": "registerButton" }, { "id": 22, "phase": "CREATE", "name": "[CREATE] 등록 페이지/모달 로드 대기", "action": "wait", "duration": 1500 }, { "id": 23, "phase": "CREATE", "name": "[CREATE] 등록 폼 존재 확인", "action": "evaluate", "script": "(() => { const hasForm = document.querySelectorAll('input, select, textarea').length > 0; const hasText = document.body.innerText.includes('등록') || document.body.innerText.includes('품목'); return hasForm || hasText; })()" }, { "id": 24, "phase": "CREATE", "name": "[CREATE] 품목 유형 선택 영역 확인", "action": "verify_element", "target": "combobox" }, { "id": 25, "phase": "CREATE", "name": "[CREATE] 품목 유형 드롭다운 클릭", "action": "click_if_exists", "target": "select, [class*='select'], [role='combobox']" }, { "id": 26, "phase": "CREATE", "name": "[CREATE] 제품 옵션 선택", "action": "click_if_exists", "target": "option:has-text('제품'), [role='option']:has-text('제품'), li:has-text('제품')" }, { "id": 27, "phase": "CREATE", "name": "[CREATE] 필수 입력 필드 존재 확인", "action": "verify_element", "target": "formField" }, { "id": 28, "phase": "CREATE", "name": "[CREATE] 취소 버튼 클릭 (등록 취소)", "action": "click_if_exists", "target": "cancelButton" }, { "id": 29, "phase": "CREATE", "name": "[CREATE] 목록 페이지 복귀 대기", "action": "wait", "duration": 1000 }, { "id": 30, "phase": "READ", "name": "[READ] 첫 번째 행 상세보기 버튼 클릭", "action": "click_if_exists", "target": "button:has-text('상세'), button:has-text('보기'), table tbody tr:first-child button" }, { "id": 31, "phase": "READ", "name": "[READ] 상세 정보 로드 대기", "action": "wait", "duration": 1000 }, { "id": 32, "phase": "READ", "name": "[READ] 상세 정보 표시 확인", "action": "evaluate", "script": "(() => { const text = document.body.innerText; return text.includes('품목') || text.includes('코드') || text.includes('상세') || document.querySelector('[role=\"dialog\"]'); })()" }, { "id": 33, "phase": "READ", "name": "[READ] 상세 모달/페이지 닫기", "action": "click_if_exists", "target": "button:has-text('닫기'), button:has-text('Close'), [class*='close'], button[aria-label='Close']" }, { "id": 34, "phase": "READ", "name": "[READ] 목록 페이지 복귀 대기", "action": "wait", "duration": 500 }, { "id": 35, "name": "테이블 구조 최종 확인", "action": "verify_element", "target": "table, [role='grid'], [class*='table']" }, { "id": 36, "name": "액션 버튼 존재 확인", "action": "evaluate", "script": "(() => { const text = document.body.innerText; return text.includes('상세') || text.includes('수정') || text.includes('삭제'); })()" }, { "id": 37, "name": "페이지 정상 동작 최종 확인", "action": "evaluate", "script": "(() => { const text = document.body.innerText; return text.includes('품목') || text.includes('전체') || text.includes('제품') || text.includes('부품'); })()" } ], "expectedAPIs": [ { "method": "GET", "endpoint": "/api/items", "description": "품목 목록 조회" } ], "rollbackPlan": { "note": "테스트 데이터 생성하지 않음 - 조회 및 UI 검증만 수행" } }