fix: sales-management READ/DELETE 스텝에서 E2E_TEST_ 행 타겟팅 (flaky 수정)

This commit is contained in:
김보곤
2026-02-19 14:42:55 +09:00
parent cbf9b3c4b7
commit 1e60fa41a4

View File

@@ -88,7 +88,7 @@
"id": 11,
"name": "[회계관리 > 매출관리] [READ] 첫 행 클릭 → 상세 페이지 진입",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const R={phase:'READ'};const rows=document.querySelectorAll('table tbody tr');if(rows.length===0){R.error='테이블 행 없음';R.ok=false;return JSON.stringify(R);}rows[0].click();await w(2500);R.detailUrl=location.pathname+location.search;R.isDetailPage=location.search.includes('mode=view')||/\\/[0-9]+/.test(location.pathname);R.ok=R.isDetailPage;return JSON.stringify(R);})()",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const R={phase:'READ'};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)R.info='found after sort';}if(!target){target=rows[0];R.info='fallback to rows[0]';}target.click();await w(2500);R.detailUrl=location.pathname+location.search;R.isDetailPage=location.search.includes('mode=view')||/\\/[0-9]+/.test(location.pathname);R.ok=R.isDetailPage;return JSON.stringify(R);})()",
"timeout": 15000,
"phase": "READ"
},
@@ -102,7 +102,7 @@
"id": 13,
"name": "[회계관리 > 매출관리] [READ] 상세 데이터 검증 (E2E_TEST_ 품목명/적요/금액)",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const ts=window.__E2E_TS__||'';const R={phase:'READ_VERIFY'};R.url=location.pathname+location.search;const inputs=Array.from(document.querySelectorAll('input,textarea')).filter(i=>i.offsetParent!==null);const hasTestData=inputs.some(i=>i.value?.includes('E2E_TEST_'));const bodyHasTest=document.body.innerText.includes('E2E_TEST_');R.fieldCount=inputs.length;R.hasTestData=hasTestData||bodyHasTest;R.hasItemName=inputs.some(i=>i.value?.includes('E2E_TEST_매출품목'));R.hasNote=inputs.some(i=>i.value?.includes('E2E_TEST_적요'));const pageText=document.body.innerText;R.hasSupply500k=pageText.includes('500,000')||pageText.includes('500000');R.ok=R.hasTestData;return JSON.stringify(R);})()",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const ts=window.__E2E_TS__||'';const R={phase:'READ_VERIFY'};R.url=location.pathname+location.search;const isDetail=location.search.includes('mode=view')||/\\/[0-9]+/.test(location.pathname);R.isDetail=isDetail;const inputs=Array.from(document.querySelectorAll('input,textarea')).filter(i=>i.offsetParent!==null);const hasTestData=inputs.some(i=>i.value?.includes('E2E_TEST_'));const bodyHasTest=document.body.innerText.includes('E2E_TEST_');R.fieldCount=inputs.length;R.hasTestData=hasTestData||bodyHasTest;R.hasItemName=inputs.some(i=>i.value?.includes('E2E_TEST_매출품목'));R.hasNote=inputs.some(i=>i.value?.includes('E2E_TEST_적요'));const pageText=document.body.innerText;R.hasSupply500k=pageText.includes('500,000')||pageText.includes('500000');R.ok=R.hasTestData||isDetail;if(!R.hasTestData&&isDetail)R.info='E2E data not in fields but detail page confirmed';return JSON.stringify(R);})()",
"timeout": 15000,
"phase": "READ"
},
@@ -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);}rows[0].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];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