Files
sam-scenarios/edge-concurrent-action-hr.json
김보곤 21b272702d 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>
2026-02-19 21:55:15 +09:00

54 lines
4.7 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"id": "edge-concurrent-action-hr",
"name": "엣지 케이스: 동시 액션 (인사 > 근태관리)",
"version": "1.0.0",
"auth": {
"role": "admin"
},
"menuNavigation": {
"level1": "인사관리",
"level2": "근태관리"
},
"screenshotPolicy": {
"captureOnFail": true,
"captureOnPass": false
},
"steps": [
{
"id": 1,
"name": "페이지 로드 대기",
"action": "wait",
"timeout": 3000
},
{
"id": 2,
"name": "테이블 로드 대기",
"action": "wait_for_table",
"timeout": 5000
},
{
"id": 3,
"name": "탭/필터 빠른 전환 테스트",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const R={phase:'RAPID_TAB_SWITCH'};const tabs=Array.from(document.querySelectorAll('[role=\"tab\"],button[class*=\"tab\"],a[class*=\"tab\"]')).filter(el=>el.offsetParent!==null);R.tabCount=tabs.length;if(tabs.length<2){ const buttons=Array.from(document.querySelectorAll('button')).filter(b=>b.offsetParent!==null&&!b.disabled); R.fallbackButtonCount=buttons.length; if(buttons.length>=2){ for(let i=0;i<3;i++){buttons[0].click();await w(100);buttons[1].click();await w(100);} R.rapidSwitchCount=6; }else{R.warn='탭/버튼 2개 미만';R.ok=true;return JSON.stringify(R);}}else{ for(let i=0;i<3;i++){tabs[0].click();await w(100);tabs[1%tabs.length].click();await w(100);} R.rapidSwitchCount=6;}await w(2000);const hasError=document.querySelector('[class*=\"error\"],[class*=\"Error\"],[role=\"alert\"]');R.hasError=!!hasError;R.pageStable=!document.querySelector('.loading,.spinner,[class*=\"skeleton\"]');R.ok=!R.hasError;R.info=R.hasError?'❌ 빠른 전환 후 에러 발생':'✅ 빠른 전환 후 정상 상태';return JSON.stringify(R);})()",
"timeout": 15000,
"phase": "RAPID_TAB_SWITCH"
},
{
"id": 4,
"name": "페이지네이션 빠른 클릭",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const R={phase:'RAPID_PAGINATION'};const pageButtons=Array.from(document.querySelectorAll('[class*=\"pagination\"] button,[class*=\"Pagination\"] button,nav button')).filter(el=>el.offsetParent!==null&&!el.disabled);R.paginationButtonCount=pageButtons.length;if(pageButtons.length<2){R.warn='페이지네이션 버튼 부족';R.ok=true;return JSON.stringify(R);}const nextBtn=pageButtons.find(b=>/다음|next|>||»/.test(b.innerText?.trim()||b.getAttribute('aria-label')||''));const prevBtn=pageButtons.find(b=>/이전|prev|<||«/.test(b.innerText?.trim()||b.getAttribute('aria-label')||''));if(nextBtn&&prevBtn){ for(let i=0;i<3;i++){nextBtn.click();await w(50);prevBtn.click();await w(50);} R.rapidNavCount=6;}else if(pageButtons.length>=2){ for(let i=0;i<3;i++){pageButtons[0].click();await w(50);pageButtons[1].click();await w(50);} R.rapidNavCount=6;}await w(2000);const hasError=document.querySelector('[class*=\"error\"],[class*=\"Error\"],[role=\"alert\"]');R.hasError=!!hasError;R.pageStable=!document.querySelector('.loading,.spinner,[class*=\"skeleton\"]');R.ok=!R.hasError;R.info=R.hasError?'❌ 빠른 페이지 전환 후 에러':'✅ 빠른 페이지 전환 후 정상';return JSON.stringify(R);})()",
"timeout": 15000,
"phase": "RAPID_PAGINATION"
},
{
"id": 5,
"name": "다중 버튼 동시 클릭 시뮬레이션",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const R={phase:'MULTI_BUTTON_CLICK'};const buttons=Array.from(document.querySelectorAll('button')).filter(b=>b.offsetParent!==null&&!b.disabled);R.totalButtons=buttons.length;if(buttons.length<3){R.warn='버튼 3개 미만';R.ok=true;return JSON.stringify(R);}const clickTargets=buttons.slice(0,3);for(const btn of clickTargets){btn.click();await w(30);}await w(2000);const hasError=document.querySelector('[class*=\"error\"],[class*=\"Error\"],[role=\"alert\"]');R.hasError=!!hasError;R.pageStable=!document.querySelector('.loading,.spinner,[class*=\"skeleton\"]');const modal=document.querySelector('[role=\"dialog\"],[aria-modal=\"true\"]');if(modal&&modal.offsetParent!==null){ const closeBtn=modal.querySelector('button[class*=\"close\"],[aria-label=\"닫기\"]')||Array.from(modal.querySelectorAll('button')).find(b=>/닫기|취소|Close/.test(b.innerText?.trim())); if(closeBtn){closeBtn.click();await w(500);} else{document.dispatchEvent(new KeyboardEvent('keydown',{key:'Escape',bubbles:true}));await w(500);}}R.ok=!R.hasError;R.info=R.hasError?'❌ 다중 버튼 클릭 후 에러':'✅ 다중 버튼 클릭 후 정상';return JSON.stringify(R);})()",
"timeout": 15000,
"phase": "MULTI_BUTTON_CLICK"
}
]
}