refactor: 44개 시나리오 품질 개선 (false positive 제거 + flaky 수정 + E2E_TEST_ 표준화)

Phase 1 - False Positive 제거 (36개):
- R.ok=true 무조건 반환 → 조건부 검증으로 교체
- 영향: edge-*, form-validation-*, pagination-sort-*, search-*, reload-persist-*,
  batch-create-*, detail-roundtrip-*, workflow-*, cross-module-*

Phase 2 - Flaky rows[0] 패턴 수정 (7개):
- detail-verify-acc-sales.json: CAPTURE/READ 스텝 E2E_TEST_ 타겟팅
- vendor-management.json: 행 클릭 E2E_TEST_ 타겟팅
- batch-update-account-sales.json: CAPTURE/SELECT/VERIFY/RESTORE 스텝
- sales-management.json: DELETE fallback 경고 로깅

Phase 3 - E2E_TEST_ 접두사 표준화 (1개):
- employee-register.json: 홍길동→E2E_TEST_사원, EMP2026001→E2E_TEST_EMP001

테스트 결과: 175 PASS / 9 FAIL (숨겨진 실제 버그 5건 노출)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
김보곤
2026-02-19 21:55:15 +09:00
parent 1e60fa41a4
commit 21b272702d
44 changed files with 170 additions and 243 deletions

View File

@@ -146,7 +146,7 @@
"id": 19,
"name": "[회계관리 > 매출관리] [DELETE] 데이터 삭제 (첫 행 → 상세 → 삭제 → 확인)",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const ts=window.__E2E_TS__||'';const toastInfo=()=>{const t=document.querySelectorAll('[data-sonner-toast],[role=\"status\"],[class*=\"toast\"],[class*=\"Toast\"],[class*=\"Toaster\"] [data-content]');return{count:t.length,text:t.length>0?Array.from(t).pop()?.innerText?.trim().substring(0,100):''};};const R={phase:'DELETE'};if(!location.search.includes('mode=view')&&!location.search.includes('mode=edit')){const rows=document.querySelectorAll('table tbody tr');if(rows.length===0){R.error='테이블 행 없음';R.ok=false;return JSON.stringify(R);}let target=Array.from(rows).find(r=>r.innerText?.includes('E2E_TEST_'));if(!target){const ths=document.querySelectorAll('table thead th');const sortTh=Array.from(ths).find(th=>/일자|날짜|No|번호/.test(th.innerText?.trim()));if(sortTh){sortTh.click();await w(1500);sortTh.click();await w(1500);}const rows2=document.querySelectorAll('table tbody tr');target=Array.from(rows2).find(r=>r.innerText?.includes('E2E_TEST_'));}if(!target)target=rows[0];target.click();await w(2500);}const delBtn=Array.from(document.querySelectorAll('button')).find(b=>b.innerText?.trim()==='삭제');if(!delBtn){R.error='삭제 버튼 없음';R.ok=false;return JSON.stringify(R);}delBtn.click();await w(1000);const cfm=Array.from(document.querySelectorAll('[role=\"alertdialog\"] button,[role=\"dialog\"] button,button')).find(b=>/확인|삭제|예|Yes/.test(b.innerText?.trim())&&b!==delBtn&&b.offsetParent!==null);if(cfm){cfm.click();await w(3000);}R.toast=toastInfo();R.ok=true;return JSON.stringify(R);})()",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const ts=window.__E2E_TS__||'';const toastInfo=()=>{const t=document.querySelectorAll('[data-sonner-toast],[role=\"status\"],[class*=\"toast\"],[class*=\"Toast\"],[class*=\"Toaster\"] [data-content]');return{count:t.length,text:t.length>0?Array.from(t).pop()?.innerText?.trim().substring(0,100):''};};const R={phase:'DELETE'};if(!location.search.includes('mode=view')&&!location.search.includes('mode=edit')){const rows=document.querySelectorAll('table tbody tr');if(rows.length===0){R.error='테이블 행 없음';R.ok=false;return JSON.stringify(R);}let target=Array.from(rows).find(r=>r.innerText?.includes('E2E_TEST_'));if(!target){const ths=document.querySelectorAll('table thead th');const sortTh=Array.from(ths).find(th=>/일자|날짜|No|번호/.test(th.innerText?.trim()));if(sortTh){sortTh.click();await w(1500);sortTh.click();await w(1500);}const rows2=document.querySelectorAll('table tbody tr');target=Array.from(rows2).find(r=>r.innerText?.includes('E2E_TEST_'));}if(!target){target=rows[0];R.warn='E2E_TEST_ 행 미발견, fallback to rows[0]';}target.click();await w(2500);}const delBtn=Array.from(document.querySelectorAll('button')).find(b=>b.innerText?.trim()==='삭제');if(!delBtn){R.error='삭제 버튼 없음';R.ok=false;return JSON.stringify(R);}delBtn.click();await w(1000);const cfm=Array.from(document.querySelectorAll('[role=\"alertdialog\"] button,[role=\"dialog\"] button,button')).find(b=>/확인|삭제|예|Yes/.test(b.innerText?.trim())&&b!==delBtn&&b.offsetParent!==null);if(cfm){cfm.click();await w(3000);}R.toast=toastInfo();R.ok=true;return JSON.stringify(R);})()",
"timeout": 35000,
"phase": "DELETE",
"critical": true