{ "id": "company-info", "name": "설정 - 회사정보", "screenshotPolicy": { "onErrorOnly": true, "captureOn": [ "error", "fail", "timeout", "404", "500", "blocked" ] }, "description": "회사 정보 관리 기능 테스트 - 회사 정보 조회, 수정, 회사 추가 기능", "baseUrl": "https://dev.codebridge-x.com", "navigation": { "targetUrl": "/company-info", "urlPattern": "/company-info|/ko/company-info|/settings/company-info", "menuHints": [ "회사정보", "회사 정보", "설정" ] }, "menuNavigation": { "level1": "설정", "level2": "회사정보", "expectedUrl": "/company-info", "searchWithinParent": true, "closeOtherMenus": true }, "auth": { "username": "TestUser5", "password": "password123!" }, "menuNavigationEnhanced": { "strategy": "scroll-and-search", "description": "사이드바를 스크롤하며 메뉴를 찾고 클릭하여 404를 방지", "level1": "설정", "level2": "회사정보", "alternativeLevel1Names": [ "설정", "Settings", "환경설정", "시스템설정", "관리" ], "alternativeLevel2Names": [ "회사정보", "회사 정보", "Company Info", "회사관리", "기업정보" ], "fallbackUrls": [ "/company-info", "/ko/company-info", "/settings/company-info", "/ko/settings/company-info" ], "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/company-info", "description": "회사 정보 조회" }, { "method": "PUT", "path": "/api/v1/company-info/:id", "description": "회사 정보 수정" }, { "method": "POST", "path": "/api/v1/company-info", "description": "회사 추가" } ], "steps": [ { "id": 1, "name": "사이드바 메뉴 전체 펼치기", "description": "모두 펼치기 버튼을 클릭하여 전체 메뉴를 펼친 후 메뉴 탐색 준비", "action": "evaluate", "script": "(async () => { document.querySelector('.sidebar-scroll')?.scrollTo({top:0,behavior:'instant'}); await new Promise(r=>setTimeout(r,300)); Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click(); await new Promise(r=>setTimeout(r,2000)); return 'menu expanded'; })()", "verification": [ "사이드바가 화면에 보이는지 확인", "모든 메뉴가 펼쳐졌는지 확인" ] }, { "id": 2, "name": "1차 메뉴 찾기: 설정", "description": "사이드바를 스크롤하며 '설정' 메뉴를 찾아 클릭", "action": "menu_navigate", "level1": "설정", "level2": "회사정보", "verification": [ "설정 메뉴가 클릭되었는지 확인", "서브메뉴가 펼쳐졌는지 확인", "하위 메뉴 항목들이 보이는지 확인" ], "fallback": { "if": "메뉴를 찾을 수 없음", "then": "사이드바 전체를 스크롤하며 재탐색" } }, { "id": 3, "name": "페이지 로드 대기", "action": "wait", "duration": 2000, "verification": [ "회사정보 메뉴 클릭 성공", "페이지 이동 또는 컨텐츠 로드" ] }, { "id": 4, "name": "404 에러 감지", "description": "페이지 로드 후 404 에러 여부 확인", "action": "verify_url", "expected": { "no_404": true }, "verification": [ "현재 페이지가 404인지 확인" ], "onError404": { "description": "404 에러 발생 시 대체 URL 시도", "fallbackUrls": [ "/company-info", "/ko/company-info" ] } }, { "id": 5, "name": "페이지 정상 로드 확인", "description": "회사정보 페이지가 정상적으로 로드되었는지 확인", "action": "verify_detail", "checks": [ "visible_text:회사정보", "not_contains:404", "not_contains:찾을 수 없습니다", "not_contains:Not Found" ], "verification": [ "페이지 제목 '회사정보' 또는 관련 텍스트 표시", "404 에러 메시지 미표시", "콘텐츠가 정상 렌더링됨" ], "successCriteria": { "urlPattern": "/company-info", "requiredElements": [ "회사", "회사명", "대표자명" ] } }, { "step": 5, "name": "페이지 제목 확인", "action": "verify", "target": "heading", "expected": "회사정보", "validation": "페이지 제목이 '회사정보'로 표시됨", "id": 6 }, { "step": 6, "name": "회사 추가 버튼 존재 확인", "action": "verify_element", "target": "회사 추가", "expected": "button exists", "validation": "회사 추가 버튼이 표시됨", "id": 7 }, { "step": 7, "name": "수정 버튼 존재 확인", "action": "verify_element", "target": "수정", "expected": "button exists", "validation": "수정 버튼이 표시됨", "id": 8 }, { "step": 8, "name": "회사명 필드 확인", "action": "verify_text", "target": "body", "expected": "회사명", "validation": "회사명이 표시되고 비활성화 상태", "id": 9 }, { "step": 9, "name": "대표자명 필드 확인", "action": "verify_text", "target": "body", "expected": "대표자명", "validation": "대표자명이 표시되고 비활성화 상태", "id": 10 }, { "step": 10, "name": "업태 필드 확인", "action": "verify_text", "target": "body", "expected": "업태", "validation": "업태가 표시되고 비활성화 상태", "id": 11 }, { "step": 11, "name": "업종 필드 확인", "action": "verify_text", "target": "body", "expected": "업종", "validation": "업종이 표시되고 비활성화 상태", "id": 12 }, { "step": 12, "name": "주소 필드 확인", "action": "verify_text", "target": "body", "expected": "주소", "validation": "주소가 표시되고 비활성화 상태", "id": 13 }, { "step": 13, "name": "이메일 필드 확인", "action": "verify_text", "target": "body", "expected": "이메일", "validation": "이메일이 표시되고 비활성화 상태", "id": 14 }, { "step": 14, "name": "사업자등록번호 필드 확인", "action": "verify_text", "target": "body", "expected": "사업자등록번호", "validation": "사업자등록번호가 표시되고 비활성화 상태", "id": 15 }, { "step": 15, "name": "수정 버튼 클릭", "action": "click_if_exists", "target": "수정", "expected": "edit mode enabled", "validation": "수정 모드로 전환됨", "id": 16 }, { "step": 16, "name": "수정 모드 - 필드 활성화 확인", "action": "evaluate", "script": "(()=>{const inputs=document.querySelectorAll('input:not([type=\"hidden\"]):not([disabled])');return inputs.length>0?'enabled: '+inputs.length+' fields':'no enabled fields';})()", "expected": "enabled", "validation": "텍스트 필드들이 활성화됨", "id": 17 }, { "step": 17, "name": "취소 버튼 클릭", "action": "click_if_exists", "target": "취소", "expected": "edit mode disabled", "validation": "조회 모드로 복귀", "id": 18 }, { "step": 18, "name": "회사 추가 버튼 클릭", "action": "click_if_exists", "target": "회사 추가", "expected": "dialog opened", "validation": "회사 추가 다이얼로그가 열림", "id": 19 }, { "step": 19, "name": "회사 추가 다이얼로그 확인", "action": "wait", "timeout": 1000, "id": 20 }, { "step": 20, "name": "다이얼로그 닫기", "action": "click_if_exists", "target": "취소", "expected": "dialog closed", "validation": "다이얼로그가 닫힘", "id": 21 }, { "step": 21, "name": "수정 모드에서 데이터 변경 테스트", "description": "실제 데이터를 수정하고 저장 기능 검증", "action": "click_if_exists", "target": "수정", "expect": { "fieldsEnabled": true }, "id": 22 }, { "step": 22, "name": "업태 필드 수정", "description": "업태 필드 값 변경", "action": "edit_field", "target": "업태", "value": "테스트업태_수정", "id": 23 }, { "step": 23, "name": "저장 버튼 클릭", "description": "수정된 회사 정보 저장", "action": "click_if_exists", "target": "저장", "waitFor": { "type": "apiResponse", "method": "PUT", "timeout": 5000 }, "expect": { "toast": [ "수정", "완료", "성공", "저장" ] }, "id": 24 }, { "step": 24, "name": "⚠️ 필수 검증: 수정 데이터 반영 확인", "note": "토스트 성공 메시지만으로 PASS 판정 불가. 실제 데이터 변경 확인 필수!", "description": "수정된 업태 값이 반영되었는지 확인", "action": "verify_detail", "checks": [ "visible_text:테스트업태_수정" ], "verify": { "fieldValue": { "target": "업태", "expected": "테스트업태_수정" } }, "id": 25 }, { "step": 25, "name": "회사 추가 다이얼로그 열기", "description": "회사 추가 버튼 클릭하여 다이얼로그 열기", "action": "click_if_exists", "target": "회사 추가", "expect": { "dialog": true, "visible": [ "회사명", "대표자명", "사업자등록번호", "등록", "취소" ] }, "id": 26 }, { "step": 26, "name": "새 회사 정보 입력", "description": "회사 추가 다이얼로그에서 필수 정보 입력", "action": "fill_form", "fields": [ { "name": "회사명", "value": "테스트회사_{timestamp}" }, { "name": "대표자명", "value": "테스트대표" }, { "name": "사업자등록번호", "value": "123-45-67890" } ], "id": 27 }, { "step": 27, "name": "회사 등록", "description": "등록 버튼 클릭하여 새 회사 등록", "action": "click_if_exists", "target": "등록", "waitFor": { "type": "apiResponse", "method": "POST", "timeout": 5000 }, "expect": { "toast": [ "등록", "완료", "성공" ], "dialogClosed": true }, "id": 28 }, { "step": 28, "name": "⚠️ 필수 검증: 회사 등록 반영 확인", "note": "토스트 성공 메시지만으로 PASS 판정 불가. 실제 데이터 등록 확인 필수!", "description": "등록된 회사가 목록에 표시되는지 확인", "action": "verify_element", "target": "body", "verify": { "visible": "테스트회사" }, "id": 29 }, { "step": 29, "name": "원복: 업태 필드 원래 값으로 복구", "description": "테스트 후 원래 값으로 복구", "action": "evaluate", "script": "(async () => { const clickBtn = (text) => { const btn = Array.from(document.querySelectorAll('button')).find(b => b.innerText?.trim() === text); if(btn) btn.click(); return !!btn; }; clickBtn('수정'); await new Promise(r=>setTimeout(r,1000)); const inputs = document.querySelectorAll('input:not([type=\"hidden\"])'); let target = null; inputs.forEach(inp => { const labels = document.querySelectorAll('label'); labels.forEach(lbl => { if(lbl.innerText?.includes('업태') && (lbl.htmlFor === inp.id || lbl.contains(inp))) target = inp; }); if(!target && inp.value === '테스트업태_수정') target = inp; }); if(target){ const nset = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype,'value').set; nset.call(target,''); target.dispatchEvent(new Event('input',{bubbles:true})); nset.call(target,'업태명'); target.dispatchEvent(new Event('input',{bubbles:true})); target.dispatchEvent(new Event('change',{bubbles:true})); } await new Promise(r=>setTimeout(r,500)); clickBtn('저장'); await new Promise(r=>setTimeout(r,2000)); return 'restored'; })()", "expect": { "toast": [ "수정", "완료", "성공", "저장" ] }, "id": 30 }, { "id": 31, "name": "콘솔 에러 확인", "action": "verify_element", "target": "body" } ], "notes": [ "직접 URL 접근 금지: 반드시 메뉴 클릭으로 페이지 진입 (404 방지)", "스크롤 필수: 사이드바가 길 경우 메뉴가 화면 밖에 있을 수 있음", "대체 경로: 메뉴명이 변경되었을 수 있으므로 다양한 이름으로 탐색", "메뉴 계층: 설정 > 회사정보" ] }