Files
sam-scenarios/department-add.json

465 lines
14 KiB
JSON

{
"id": "department-add",
"name": "부서 추가 테스트 (랜덤 + 하위부서)",
"screenshotPolicy": {
"onErrorOnly": true,
"captureOn": ["error", "fail", "timeout", "404", "500", "blocked"]
},
"description": "랜덤 상위 부서 생성 후 하위 부서까지 추가하는 고도화된 E2E 테스트",
"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",
"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": ["기획", "개발", "디자인", "마케팅", "영업", "지원", "품질", "연구"]
}
}
}
},
"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 }
],
"expect": {
"sidebarReady": true
}
},
{
"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", "target": "인사관리" },
{ "type": "wait", "duration": 500 },
{
"type": "scrollAndFind",
"container": ".sidebar-scroll, [data-sidebar], nav, aside",
"target": "부서관리",
"scrollStep": 200,
"maxAttempts": 10,
"waitAfterScroll": 300
},
{ "type": "click", "target": "부서관리" }
],
"fallback": {
"type": "navigate",
"url": "https://dev.codebridge-x.com/ko/hr/department-management"
},
"expect": {
"url": "/hr/department-management",
"visible": ["부서관리", "추가"]
}
},
{
"id": "step-2",
"name": "현재 부서 개수 저장",
"description": "테스트 전 부서 개수 기록",
"capture": {
"variable": "initialCount",
"selector": "총 *건",
"extract": "number"
}
},
{
"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": "clickInModal", "target": "등록", "options": { "waitAfter": 500 } }
],
"waitFor": {
"type": "modalClose",
"timeout": 5000
},
"expect": {
"toast": ["등록", "완료", "성공"],
"visible": ["{randomData.parentDepartment}"]
}
},
{
"id": "step-6",
"name": "상위 부서 등록 확인",
"description": "목록에서 새로 추가된 상위 부서 확인",
"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": "clickInModal", "target": "등록", "options": { "waitAfter": 500 } }
],
"waitFor": {
"type": "modalClose",
"timeout": 5000
},
"expect": {
"toast": ["등록", "완료", "성공"],
"visible": ["{randomData.childDepartment}"]
}
},
{
"id": "step-10",
"name": "계층 구조 확인",
"description": "상위 부서 확장하여 하위 부서가 트리 구조로 표시되는지 확인",
"actions": [
{
"type": "click_if_exists",
"target": "table tbody tr:first-child [class*='expand'], table tbody tr:first-child button"
}
],
"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": "clickInModal", "target": "저장", "options": { "waitAfter": 500 } }
],
"waitFor": {
"type": "modalClose",
"timeout": 5000
},
"expect": {
"toast": ["수정", "완료", "성공", "저장"],
"visible": ["{randomData.childDepartment}_수정됨"]
}
},
{
"id": "step-13-1",
"name": "⚠️ 필수 검증: 수정 데이터 반영 확인",
"note": "토스트 성공 메시지만으로 PASS 판정 불가. 실제 데이터 변경 확인 필수!",
"description": "목록에서 수정된 부서명 확인",
"verify": {
"listContains": "{randomData.childDepartment}_수정됨"
}
},
{
"id": "step-14",
"name": "하위 부서 삭제",
"description": "하위 부서의 삭제 버튼 클릭",
"actions": [
{
"type": "click_if_exists",
"target": "삭제"
}
],
"expect": {
"confirmDialog": true,
"dialogText": ["삭제", "하시겠습니까"]
}
},
{
"id": "step-15",
"name": "하위 부서 삭제 확인",
"description": "삭제 확인 다이얼로그에서 확인 클릭",
"actions": [
{ "type": "click", "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", "target": "확인", "description": "삭제 확인" }
],
"waitFor": {
"type": "apiResponse",
"method": "DELETE",
"timeout": 5000
},
"expect": {
"toast": ["삭제", "완료", "성공"]
}
},
{
"id": "step-18",
"name": "⚠️ 필수 검증: 상위 부서 삭제 반영 확인",
"note": "토스트 성공 메시지만으로 PASS 판정 불가. 실제 데이터 삭제 확인 필수!",
"description": "목록에서 삭제된 상위 부서가 없어졌는지 확인",
"verify": {
"listNotContains": "{randomData.parentDepartment}",
"countRestored": "{initialCount}"
}
}
],
"assertions": [
{
"type": "url",
"expected": "/hr/department-management",
"message": "부서관리 페이지에 머물러야 함"
},
{
"type": "elementExists",
"selector": "text={randomData.parentDepartment}",
"message": "상위 부서가 목록에 표시되어야 함"
},
{
"type": "elementExists",
"selector": "text={randomData.childDepartment}",
"message": "하위 부서가 목록에 표시되어야 함"
},
{
"type": "hierarchy",
"parent": "{randomData.parentDepartment}",
"child": "{randomData.childDepartment}",
"message": "하위 부서가 상위 부서 아래에 트리 구조로 표시되어야 함"
}
],
"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"
},
"duplicateHandling": "timestamp 포함으로 중복 방지",
"prerequisites": "로그인된 사용자에게 부서 추가 권한 필요",
"uiElements": {
"addButton": "상단 '추가' 버튼 - 최상위 부서 추가",
"subAddButton": "각 행의 '하위 부서 추가' 아이콘 버튼",
"expandButton": "트리 구조 확장/축소 버튼"
}
}
}