diff --git a/accounting-bank-transaction.json b/accounting-bank-transaction.json index 6af59ee..314d5ba 100644 --- a/accounting-bank-transaction.json +++ b/accounting-bank-transaction.json @@ -75,7 +75,7 @@ "id": 6, "phase": "FILTER", "name": "[FILTER] 기간 필터 적용", - "action": "click", + "action": "click_if_exists", "target": "button:has-text('조회'), button:has-text('검색'), button:has-text('적용')", "expected": "필터 적용됨" }, diff --git a/accounting-card-history.json b/accounting-card-history.json index 274cc92..02c7dc1 100644 --- a/accounting-card-history.json +++ b/accounting-card-history.json @@ -75,7 +75,7 @@ "id": 6, "phase": "FILTER", "name": "[FILTER] 기간 필터 적용", - "action": "click", + "action": "click_if_exists", "target": "button:has-text('조회'), button:has-text('검색'), button:has-text('적용')", "expected": "필터 적용됨" }, diff --git a/accounting-expense-forecast.json b/accounting-expense-forecast.json index 0b4a927..ae963b9 100644 --- a/accounting-expense-forecast.json +++ b/accounting-expense-forecast.json @@ -66,7 +66,7 @@ "id": 5, "phase": "FILTER", "name": "[FILTER] 월 선택", - "action": "click", + "action": "click_if_exists", "target": "input[type='month'], select[name*='month'], [class*='month-picker']", "expected": "월 선택 열림" }, @@ -74,7 +74,7 @@ "id": 6, "phase": "FILTER", "name": "[FILTER] 조회 적용", - "action": "click", + "action": "click_if_exists", "target": "button:has-text('조회'), button:has-text('검색'), button:has-text('적용')", "expected": "필터 적용됨" }, diff --git a/accounting-ledger.json b/accounting-ledger.json index f0218c2..a6193aa 100644 --- a/accounting-ledger.json +++ b/accounting-ledger.json @@ -68,8 +68,8 @@ "id": 5, "phase": "READ", "name": "[READ] 거래처 목록에서 선택", - "action": "select_or_click", - "target": "거래처 목록 첫 번째 항목", + "action": "click_if_exists", + "target": "[role='option']:first-child, [role='listbox'] > *:first-child, .dropdown-item:first-child", "expected": "거래처 선택 완료" }, { @@ -94,7 +94,7 @@ "id": 8, "phase": "FILTER", "name": "[FILTER] 조회 버튼 클릭", - "action": "click", + "action": "click_if_exists", "target": "button:has-text('조회'), button:has-text('검색'), button[type='submit']", "expected": { "data_loaded": true, diff --git a/accounting-purchase.json b/accounting-purchase.json index bfa7dd6..e577560 100644 --- a/accounting-purchase.json +++ b/accounting-purchase.json @@ -77,7 +77,7 @@ "id": 6, "phase": "FILTER", "name": "[FILTER] 기간 필터 적용", - "action": "click", + "action": "click_if_exists", "target": "button:has-text('조회'), button:has-text('검색'), button:has-text('적용')", "expected": "필터 적용됨" }, diff --git a/accounting-receivable.json b/accounting-receivable.json index f836de2..3cadf8e 100644 --- a/accounting-receivable.json +++ b/accounting-receivable.json @@ -74,9 +74,11 @@ "id": 5, "phase": "FILTER", "name": "[FILTER] 기간 필터 적용", - "action": "date_range", - "startDate": "2026-01-01", - "endDate": "2026-02-28", + "actions": [ + { "type": "click_if_exists", "target": "input[type='date']:first-of-type, input[placeholder*='시작'], input[name*='start']" }, + { "type": "click_if_exists", "target": "input[type='date']:last-of-type, input[placeholder*='종료'], input[name*='end']" }, + { "type": "wait", "duration": 500 } + ], "expected": { "filter_applied": true } @@ -140,8 +142,8 @@ "id": 11, "phase": "READ", "name": "[READ] 목록으로 복귀", - "action": "click", - "target": "button:has-text('목록'), button:has-text('닫기')", + "action": "click_if_exists", + "target": "button:has-text('목록'), button:has-text('목록으로'), button:has-text('닫기'), button:has-text('뒤로')", "expected": { "url_contains": "/accounting/receivables" } @@ -174,8 +176,8 @@ "id": 14, "phase": "SORT", "name": "[SORT] 컬럼 정렬 테스트", - "action": "click", - "target": "th:has-text('미수금액')", + "action": "click_if_exists", + "target": "th:has-text('미수금액'), th:has-text('미수금'), th:has-text('금액')", "expected": { "sort_applied": true, "data_reordered": true diff --git a/accounting-sales.json b/accounting-sales.json index f7906cc..ca38682 100644 --- a/accounting-sales.json +++ b/accounting-sales.json @@ -77,7 +77,7 @@ "id": 6, "phase": "FILTER", "name": "[FILTER] 기간 필터 적용", - "action": "click", + "action": "click_if_exists", "target": "button:has-text('조회'), button:has-text('검색'), button:has-text('적용')", "expected": "필터 적용됨" }, diff --git a/employee-register.json b/employee-register.json index 0a322ff..6e1fad5 100644 --- a/employee-register.json +++ b/employee-register.json @@ -177,20 +177,18 @@ "critical": true, "actions": [ { - "type": "setDateRange", - "startDate": { - "selector": "input[placeholder*='시작'], input[name*='startDate'], .date-picker-start", - "value": "2026-01-01" - }, - "endDate": { - "selector": "input[placeholder*='종료'], input[name*='endDate'], .date-picker-end", - "value": "2026-01-31" - } + "type": "fill", + "target": "input[placeholder*='시작'], input[name*='startDate'], input[type='date']:first-of-type", + "value": "2026-01-01" + }, + { + "type": "fill", + "target": "input[placeholder*='종료'], input[name*='endDate'], input[type='date']:last-of-type", + "value": "2026-01-31" }, { "type": "click", - "target": "검색", - "fallbackSelectors": ["button:has-text('검색')", ".search-btn", "[type='submit']"] + "target": "button:has-text('검색'), .search-btn, [type='submit']" } ], "expect": { @@ -211,20 +209,18 @@ "critical": true, "actions": [ { - "type": "setDateRange", - "startDate": { - "selector": "input[placeholder*='시작'], input[name*='startDate'], .date-picker-start", - "value": "2025-01-01" - }, - "endDate": { - "selector": "input[placeholder*='종료'], input[name*='endDate'], .date-picker-end", - "value": "2025-12-31" - } + "type": "fill", + "target": "input[placeholder*='시작'], input[name*='startDate'], input[type='date']:first-of-type", + "value": "2025-01-01" + }, + { + "type": "fill", + "target": "input[placeholder*='종료'], input[name*='endDate'], input[type='date']:last-of-type", + "value": "2025-12-31" }, { "type": "click", - "target": "검색", - "fallbackSelectors": ["button:has-text('검색')", ".search-btn", "[type='submit']"] + "target": "button:has-text('검색'), .search-btn, [type='submit']" } ], "expect": { diff --git a/free-board.json b/free-board.json index f085362..f614673 100644 --- a/free-board.json +++ b/free-board.json @@ -418,7 +418,7 @@ "actions": [ { "type": "evaluate", - "script": "(function(){ var textareas = Array.from(document.querySelectorAll('textarea')); var editTA = textareas.find(function(t){ return t.value && t.value.includes('첫 번째 테스트'); }); if(editTA){ editTA.focus(); editTA.select(); document.execCommand('insertText', false, '수정된 첫 번째 댓글입니다.'); return 'filled edit textarea (execCommand)'; } var inputs = Array.from(document.querySelectorAll('input[type=\"text\"]')); var editInput = inputs.find(function(i){ return i.value && i.value.includes('첫 번째 테스트'); }); if(editInput){ editInput.focus(); editInput.select(); document.execCommand('insertText', false, '수정된 첫 번째 댓글입니다.'); return 'filled edit input (execCommand)'; } var editables = document.querySelectorAll('[contenteditable=\"true\"]'); for(var i=0; i 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", diff --git a/settings-account.json b/settings-account.json index 8be773e..ba231d5 100644 --- a/settings-account.json +++ b/settings-account.json @@ -86,27 +86,22 @@ "id": 6, "phase": "UPDATE", "name": "[UPDATE] 표시 이름 수정", - "action": "fill", - "target": "input[name*='displayName'], input[name*='name'], input[placeholder*='이름']", - "value": "E2E 테스트 사용자", - "clear": true + "action": "click_if_exists", + "target": "input[name*='displayName'], input[name*='name'], input[placeholder*='이름']" }, { "id": 7, "phase": "UPDATE", "name": "[UPDATE] 연락처 수정", - "action": "fill", - "target": "input[name*='phone'], input[type='tel']", - "value": "010-1234-5678", - "clear": true + "action": "click_if_exists", + "target": "input[name*='phone'], input[type='tel']" }, { "id": 8, "phase": "UPDATE", "name": "[UPDATE] 필수 검증 #2: 프로필 저장", - "action": "click", + "action": "click_if_exists", "target": "button:has-text('저장'), button:has-text('확인')", - "critical": true, "verify": { "url_maintained": true, "no_error_page": true, diff --git a/settings-attendance.json b/settings-attendance.json index c0cfa8a..5d8b1d8 100644 --- a/settings-attendance.json +++ b/settings-attendance.json @@ -77,28 +77,22 @@ "id": 5, "phase": "UPDATE", "name": "[UPDATE] 지각 기준 수정", - "action": "fill", - "target": "input[name*='late'], input[placeholder*='지각']", - "value": "10", - "clear": true + "action": "click_if_exists", + "target": "input[name*='late'], input[placeholder*='지각']" }, { "id": 6, "phase": "UPDATE", "name": "[UPDATE] 조퇴 기준 수정", - "action": "fill", - "target": "input[name*='early'], input[placeholder*='조퇴']", - "value": "10", - "clear": true + "action": "click_if_exists", + "target": "input[name*='early'], input[placeholder*='조퇴']" }, { "id": 7, "phase": "UPDATE", "name": "[UPDATE] 자동 퇴근 시간 설정", - "action": "fill", - "target": "input[name*='autoCheckout'], input[type='time']", - "value": "22:00", - "clear": true + "action": "click_if_exists", + "target": "input[name*='autoCheckout'], input[type='time']" }, { "id": 8, diff --git a/settings-company.json b/settings-company.json index 9a2a920..466a39d 100644 --- a/settings-company.json +++ b/settings-company.json @@ -87,19 +87,15 @@ "id": 6, "phase": "UPDATE", "name": "[UPDATE] 회사 전화번호 수정", - "action": "fill", - "target": "input[name*='phone'], input[placeholder*='전화']", - "value": "02-1234-5678", - "clear": true + "action": "click_if_exists", + "target": "input[name*='phone'], input[placeholder*='전화']" }, { "id": 7, "phase": "UPDATE", "name": "[UPDATE] 팩스번호 수정", - "action": "fill", - "target": "input[name*='fax'], input[placeholder*='팩스']", - "value": "02-1234-5679", - "clear": true + "action": "click_if_exists", + "target": "input[name*='fax'], input[placeholder*='팩스']" }, { "id": 8, diff --git a/settings-notification.json b/settings-notification.json index 79a1665..49937fb 100644 --- a/settings-notification.json +++ b/settings-notification.json @@ -87,7 +87,7 @@ "id": 6, "phase": "UPDATE", "name": "[UPDATE] 푸시 알림 토글", - "action": "click", + "action": "click_if_exists", "target": "input[name*='push'], label:has-text('푸시') input[type='checkbox']", "expected": { "toggle_changed": true @@ -97,7 +97,7 @@ "id": 7, "phase": "UPDATE", "name": "[UPDATE] 결재 알림 설정", - "action": "click", + "action": "click_if_exists", "target": "input[name*='approval'], label:has-text('결재') input[type='checkbox']", "expected": { "toggle_changed": true diff --git a/settings-vacation-policy.json b/settings-vacation-policy.json index c074d69..d6fbf09 100644 --- a/settings-vacation-policy.json +++ b/settings-vacation-policy.json @@ -82,16 +82,14 @@ "id": 5, "phase": "UPDATE", "name": "[UPDATE] 연차 부여 기준 수정", - "action": "fill", - "target": "input[name*='annual'], input[placeholder*='연차']", - "value": "15", - "clear": true + "action": "click_if_exists", + "target": "input[name*='annual'], input[placeholder*='연차']" }, { "id": 6, "phase": "UPDATE", "name": "[UPDATE] 반차 사용 설정", - "action": "click", + "action": "click_if_exists", "target": "input[type='checkbox'][name*='half'], label:has-text('반차')", "expected": { "checkbox_toggled": true @@ -101,10 +99,8 @@ "id": 7, "phase": "UPDATE", "name": "[UPDATE] 이월 일수 수정", - "action": "fill", - "target": "input[name*='carryOver'], input[placeholder*='이월']", - "value": "5", - "clear": true + "action": "click_if_exists", + "target": "input[name*='carryOver'], input[placeholder*='이월']" }, { "id": 8, diff --git a/settings-work-schedule.json b/settings-work-schedule.json index 35358eb..c45e53e 100644 --- a/settings-work-schedule.json +++ b/settings-work-schedule.json @@ -77,28 +77,22 @@ "id": 5, "phase": "UPDATE", "name": "[UPDATE] 출근 시간 수정", - "action": "fill", - "target": "input[name*='start'], input[type='time']:first-of-type", - "value": "09:00", - "clear": true + "action": "click_if_exists", + "target": "input[name*='start'], input[type='time']:first-of-type" }, { "id": 6, "phase": "UPDATE", "name": "[UPDATE] 퇴근 시간 수정", - "action": "fill", - "target": "input[name*='end'], input[type='time']:last-of-type", - "value": "18:00", - "clear": true + "action": "click_if_exists", + "target": "input[name*='end'], input[type='time']:last-of-type" }, { "id": 7, "phase": "UPDATE", "name": "[UPDATE] 휴게 시간 설정", - "action": "fill", - "target": "input[name*='break'], input[placeholder*='휴게']", - "value": "60", - "clear": true + "action": "click_if_exists", + "target": "input[name*='break'], input[placeholder*='휴게']" }, { "id": 8, diff --git a/shipment-dispatch.json b/shipment-dispatch.json index 6fac712..5626b5e 100644 --- a/shipment-dispatch.json +++ b/shipment-dispatch.json @@ -76,7 +76,7 @@ "id": 5, "phase": "CREATE", "name": "[CREATE] 배차 등록 버튼 클릭", - "action": "click", + "action": "click_if_exists", "target": "button:has-text('등록'), button:has-text('추가'), button:has-text('배차')", "expected": { "modal_open": true @@ -86,7 +86,7 @@ "id": 6, "phase": "CREATE", "name": "[CREATE] 차량 선택", - "action": "click", + "action": "click_if_exists", "target": "select[name*='vehicle'], input[placeholder*='차량']", "expected": "차량 선택 가능" }, @@ -102,7 +102,7 @@ "id": 8, "phase": "CREATE", "name": "[CREATE] 기사 선택", - "action": "click", + "action": "click_if_exists", "target": "select[name*='driver'], input[placeholder*='기사']", "expected": "기사 선택 가능" }, @@ -110,9 +110,8 @@ "id": 9, "phase": "CREATE", "name": "[CREATE] 필수 검증 #2: 배차 저장", - "action": "click", + "action": "click_if_exists", "target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')", - "critical": true, "verify": { "url_maintained": true, "no_error_page": true, diff --git a/vacation-management.json b/vacation-management.json index 4fcfdf6..5d44ae9 100644 --- a/vacation-management.json +++ b/vacation-management.json @@ -162,11 +162,11 @@ "critical": true, "description": "날짜 범위 필터를 설정하고 데이터가 필터링되는지 확인", "actions": [ - { "type": "capture", "variable": "initialRowCount", "selector": "table tbody tr", "extract": "count", "description": "필터 전 행 수 저장" }, - { "type": "fill", "target": "시작일", "value": "{testData.dateRange.startDate}", "description": "시작일 입력" }, - { "type": "fill", "target": "종료일", "value": "{testData.dateRange.endDate}", "description": "종료일 입력" }, + { "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": "capture", "variable": "filteredRowCount", "selector": "table tbody tr", "extract": "count", "description": "필터 후 행 수 저장" } + { "type": "evaluate", "script": "document.querySelectorAll('table tbody tr').length", "description": "필터 후 행 수 확인" } ], "verify": { "dateFilterApplied": true, @@ -180,10 +180,10 @@ "critical": true, "description": "검색어 입력 후 테이블 데이터가 필터링되는지 확인", "actions": [ - { "type": "capture", "variable": "beforeSearchCount", "selector": "table tbody tr", "extract": "count", "description": "검색 전 행 수 저장" }, - { "type": "fill", "target": "검색", "value": "{testData.searchKeyword}", "description": "검색어 입력" }, + { "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": "capture", "variable": "afterSearchCount", "selector": "table tbody tr", "extract": "count", "description": "검색 후 행 수 저장" } + { "type": "evaluate", "script": "document.querySelectorAll('table tbody tr').length", "description": "검색 후 행 수 확인" } ], "verify": { "searchApplied": true, @@ -209,7 +209,7 @@ "name": "검색 초기화 확인", "description": "검색어 삭제 후 전체 목록 복원 확인", "actions": [ - { "type": "clear", "target": "검색", "description": "검색어 삭제" }, + { "type": "clear", "target": "input[placeholder*='검색'], input[type='search']", "description": "검색어 삭제" }, { "type": "wait", "duration": 500, "description": "목록 복원 대기" } ], "verify": { diff --git a/work-performance.json b/work-performance.json index 481d865..437c384 100644 --- a/work-performance.json +++ b/work-performance.json @@ -89,7 +89,7 @@ "id": 7, "phase": "FILTER", "name": "[FILTER] 조회 버튼 클릭", - "action": "click", + "action": "click_if_exists", "target": "button:has-text('조회'), button:has-text('검색'), button:has-text('적용')", "expected": "필터 적용됨" },