fix: employee-register, workflow-employee-onboarding 시나리오 수정
employee-register.json: - Step 9: 고유 식별자(타임스탬프) 생성으로 중복 등록 방지 - Steps 10-11: 등록 후 대기/테이블 로드 추가 - Step 15: 직원 행 검색 재시도 로직 강화 - Steps 20-21: 삭제+확인 병합, window.confirm 오버라이드 지원 workflow-employee-onboarding.json: - Step 3: CAPTURE_EMPLOYEE 필터 강화 (true/false, 숫자만 제외) - Step 14: 급여관리 미발견 시 warn으로 변경 (급여 데이터 미자동생성) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -185,12 +185,25 @@
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"name": "등록 완료",
|
||||
"action": "click_if_exists",
|
||||
"target": "등록"
|
||||
"name": "고유 식별자 설정 및 등록",
|
||||
"description": "중복 방지를 위해 이메일/사원코드/아이디를 타임스탬프 기반 고유값으로 교체 후 등록",
|
||||
"action": "evaluate",
|
||||
"script": "(async () => { const ts = Date.now().toString(36); const setByValue = (oldVal, newVal) => { const inputs = Array.from(document.querySelectorAll('input')); const input = inputs.find(i => i.value === oldVal); if (input) { const ns = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')?.set; if (ns) ns.call(input, newVal); else input.value = newVal; input.dispatchEvent(new Event('input', {bubbles:true})); input.dispatchEvent(new Event('change', {bubbles:true})); return true; } return false; }; const r1 = setByValue('e2e_test_employee@codebridge-x.com', 'e2e_' + ts + '@test.com'); const r2 = setByValue('E2E_TEST_EMP001', 'E2E_EMP_' + ts); const r3 = setByValue('e2e_test_user001', 'e2e_usr_' + ts); await new Promise(r => setTimeout(r, 500)); const btn = Array.from(document.querySelectorAll('button')).find(b => b.innerText?.trim() === '등록' || (b.innerText?.includes('등록') && !b.innerText?.includes('사원 등록'))); if (btn) { btn.click(); await new Promise(r => setTimeout(r, 2000)); return JSON.stringify({ok:true, info:'등록 클릭 완료 (ts=' + ts + ', email=' + r1 + ', code=' + r2 + ', user=' + r3 + ')'}); } return JSON.stringify({ok:false, error:'등록 버튼 미발견'}); })()"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"name": "등록 후 페이지 전환 대기",
|
||||
"action": "wait",
|
||||
"timeout": 3000
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"name": "직원 목록 테이블 로드 대기",
|
||||
"action": "wait_for_table",
|
||||
"timeout": 10000
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"name": "검색 기간 설정 - 유효 기간",
|
||||
"description": "등록된 사원의 입사일(2026-01-14)이 포함되는 기간으로 검색",
|
||||
"action": "evaluate",
|
||||
@@ -203,7 +216,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"id": 13,
|
||||
"name": "검색 기간 설정 - 범위 외 기간",
|
||||
"description": "등록된 사원의 입사일이 포함되지 않는 기간으로 검색하여 검색되지 않음을 확인",
|
||||
"action": "evaluate",
|
||||
@@ -216,7 +229,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"id": 14,
|
||||
"name": "검색 기간 초기화 및 전체 조회",
|
||||
"description": "검색 조건 초기화하여 등록된 사원이 다시 표시되는지 확인",
|
||||
"action": "evaluate",
|
||||
@@ -229,21 +242,21 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"id": 15,
|
||||
"name": "등록된 직원 상세 페이지 이동",
|
||||
"description": "등록된 직원을 클릭하여 상세 페이지로 이동",
|
||||
"action": "click_if_exists",
|
||||
"target": "table tbody tr:has-text('E2E_TEST_사원')"
|
||||
"description": "등록된 직원을 클릭하여 상세 페이지로 이동 (검색 시도 포함)",
|
||||
"action": "evaluate",
|
||||
"script": "(async () => { const w = ms => new Promise(r => setTimeout(r, ms)); const findRow = () => { const rows = Array.from(document.querySelectorAll('table tbody tr, [class*=table] [class*=row], tr')).filter(r => r.offsetParent !== null); return rows.find(r => r.innerText?.includes('E2E_TEST_사원')); }; let targetRow = findRow(); if (!targetRow) { const searchBtn = Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('검색')); if (searchBtn) { searchBtn.click(); await w(2000); } targetRow = findRow(); } if (!targetRow) { for (let i = 0; i < 5; i++) { await w(2000); targetRow = findRow(); if (targetRow) break; } } if (targetRow) { targetRow.click(); await w(2000); return JSON.stringify({ok:true, info:'직원 행 클릭 완료'}); } const pageText = document.body.innerText.substring(0, 500); return JSON.stringify({ok:false, warn:'E2E_TEST_사원 행 미발견', pageSnippet: pageText}); })()"
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"id": 16,
|
||||
"name": "직원 수정 모드 전환",
|
||||
"description": "수정 버튼 클릭하여 편집 모드로 전환",
|
||||
"action": "click_if_exists",
|
||||
"target": "수정"
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"id": 17,
|
||||
"name": "직원 정보 수정",
|
||||
"description": "휴대폰 번호 변경",
|
||||
"action": "fill_form",
|
||||
@@ -257,14 +270,14 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 16,
|
||||
"id": 18,
|
||||
"name": "수정 저장",
|
||||
"description": "수정된 직원 정보 저장",
|
||||
"action": "click_if_exists",
|
||||
"target": "저장"
|
||||
},
|
||||
{
|
||||
"id": 17,
|
||||
"id": 19,
|
||||
"name": "필수 검증: 수정 데이터 반영 확인",
|
||||
"note": "토스트 성공 메시지만으로 PASS 판정 불가. 실제 데이터 변경 확인 필수!",
|
||||
"description": "상세 페이지에서 수정된 휴대폰 번호 확인",
|
||||
@@ -273,21 +286,15 @@
|
||||
"휴대폰: 010-9999-8888"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 18,
|
||||
"name": "직원 삭제",
|
||||
"description": "삭제 버튼 클릭하여 직원 삭제",
|
||||
"action": "click_if_exists",
|
||||
"target": "삭제"
|
||||
},
|
||||
{
|
||||
"id": 19,
|
||||
"name": "삭제 확인",
|
||||
"description": "삭제 확인 다이얼로그에서 확인 클릭",
|
||||
"action": "click_dialog_confirm"
|
||||
},
|
||||
{
|
||||
"id": 20,
|
||||
"name": "직원 삭제 및 확인",
|
||||
"description": "window.confirm 오버라이드 후 삭제 버튼 클릭, DOM 다이얼로그도 처리",
|
||||
"action": "evaluate",
|
||||
"script": "(async () => { const w = ms => new Promise(r => setTimeout(r, ms)); let nativeConfirmCalled = false; const origConfirm = window.confirm; window.confirm = () => { nativeConfirmCalled = true; return true; }; const origAlert = window.alert; window.alert = () => true; try { const delBtn = Array.from(document.querySelectorAll('button')).find(b => b.innerText?.trim() === '삭제' || b.innerText?.includes('삭제')); if (!delBtn) { window.confirm = origConfirm; window.alert = origAlert; return JSON.stringify({ok:false, error:'삭제 버튼 미발견'}); } delBtn.click(); await w(1000); if (nativeConfirmCalled) { window.confirm = origConfirm; window.alert = origAlert; await w(2000); return JSON.stringify({ok:true, info:'삭제 완료 (native confirm 자동 승인)'}); } for (let i = 0; i < 10; i++) { const dialog = document.querySelector('[role=\"alertdialog\"], [role=\"dialog\"], [class*=\"modal\"]:not([class*=\"tooltip\"]), [class*=\"Modal\"], [class*=\"Dialog\"]'); if (dialog && dialog.offsetParent !== null) { const confirmBtn = Array.from(dialog.querySelectorAll('button')).find(b => ['확인', '예', '삭제', 'OK', 'Yes', 'Delete'].some(t => b.innerText?.trim().includes(t))); if (confirmBtn) { confirmBtn.click(); await w(1000); window.confirm = origConfirm; window.alert = origAlert; return JSON.stringify({ok:true, info:'삭제 완료 (DOM 다이얼로그 확인)'}); } } await w(500); } window.confirm = origConfirm; window.alert = origAlert; return JSON.stringify({ok:true, warn:'삭제 버튼 클릭됨, 다이얼로그 미발견 (직접 삭제 가능성)'}); } catch(e) { window.confirm = origConfirm; window.alert = origAlert; return JSON.stringify({ok:false, error:e.message}); } })()"
|
||||
},
|
||||
{
|
||||
"id": 21,
|
||||
"name": "필수 검증: 삭제 데이터 반영 확인",
|
||||
"note": "토스트 성공 메시지만으로 PASS 판정 불가. 실제 데이터 삭제 확인 필수!",
|
||||
"description": "목록에서 삭제된 직원이 없어졌는지 확인",
|
||||
@@ -298,7 +305,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 21,
|
||||
"id": 22,
|
||||
"name": "콘솔 에러 확인",
|
||||
"action": "verify_element",
|
||||
"target": "body"
|
||||
|
||||
Reference in New Issue
Block a user