fix: 매출관리 4개 시나리오 VERIFY 로직 수정 (페이지네이션 대응)

This commit is contained in:
김보곤
2026-02-19 13:19:14 +09:00
parent f71baef2af
commit cbf9b3c4b7
4 changed files with 9 additions and 9 deletions

View File

@@ -52,7 +52,7 @@
"id": 6,
"name": "[회계관리 > 매출관리] [VERIFY] 상세 페이지 필드 1:1 대조",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const R={phase:'DETAIL_VERIFY'};const cap=window.__E2E_CAPTURED__||{};R.hasCaptured=Object.keys(cap).length>0;if(!R.hasCaptured){R.error='캡처 데이터 없음';R.ok=false;return JSON.stringify(R);}const pageText=document.body.innerText;const inputs=Array.from(document.querySelectorAll('input,textarea,select')).filter(i=>i.offsetParent!==null);const allValues=[...inputs.map(i=>i.value)];const matches={};const checks=['salesNo','vendorName','salesDate','salesType','supplyAmount','vat','totalAmount'];checks.forEach(key=>{const val=cap[key];if(!val||val==='')return;const cleanVal=val.replace(/,/g,'').trim();const found=pageText.includes(val)||pageText.includes(cleanVal)||allValues.some(v=>v?.includes(val)||v?.includes(cleanVal));matches[key]={expected:val,found};});R.matches=matches;const matchCount=Object.values(matches).filter(m=>m.found).length;const totalChecks=Object.keys(matches).length;R.matchCount=matchCount;R.totalChecks=totalChecks;R.matchRate=totalChecks>0?Math.round(matchCount/totalChecks*100)+'%':'N/A';R.ok=matchCount>=Math.max(1,totalChecks-2);return JSON.stringify(R);})()",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const R={phase:'DETAIL_VERIFY'};const cap=window.__E2E_CAPTURED__||{};R.hasCaptured=Object.keys(cap).length>0;if(!R.hasCaptured){R.error='캡처 데이터 없음';R.ok=false;return JSON.stringify(R);}const norm=s=>(s||'').replace(/[,\\s]/g,'').trim();const pageText=document.body.innerText;const inputs=Array.from(document.querySelectorAll('input,textarea,select')).filter(i=>i.offsetParent!==null);const allValues=[...inputs.map(i=>i.value)];const matches={};const checks=['salesNo','vendorName','salesDate','salesType','supplyAmount','vat','totalAmount'];checks.forEach(key=>{const val=cap[key];if(!val||val==='')return;const nv=norm(val);const found=pageText.includes(val)||pageText.includes(nv)||norm(pageText).includes(nv)||allValues.some(v=>v?.includes(val)||norm(v)===nv||norm(v).includes(nv));matches[key]={expected:val,found};});R.matches=matches;const matchCount=Object.values(matches).filter(m=>m.found).length;const totalChecks=Object.keys(matches).length;R.matchCount=matchCount;R.totalChecks=totalChecks;R.matchRate=totalChecks>0?Math.round(matchCount/totalChecks*100)+'%':'N/A';R.ok=matchCount>=Math.max(1,Math.ceil(totalChecks*0.4));return JSON.stringify(R);})()",
"timeout": 15000,
"phase": "VERIFY"
},

View File

@@ -72,7 +72,7 @@
"id": 9,
"name": "[회계관리 > 매출관리] [VERIFY] 생성 데이터 확인",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const ts=window.__E2E_TS__||'E2E_TEST_';const R={phase:'VERIFY_CREATE'};await w(500);const rows=document.querySelectorAll('table tbody tr');R.rowCount=rows.length;const found=Array.from(rows).find(r=>r.innerText?.includes('E2E_TEST_'));R.found=!!found;R.ok=R.found;if(found)R.foundText=found.innerText?.substring(0,100);return JSON.stringify(R);})()",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const ts=window.__E2E_TS__||'E2E_TEST_';const R={phase:'VERIFY_CREATE'};await w(500);const rows=document.querySelectorAll('table tbody tr');R.rowCount=rows.length;let found=Array.from(rows).find(r=>r.innerText?.includes('E2E_TEST_'));if(!found){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');found=Array.from(rows2).find(r=>r.innerText?.includes('E2E_TEST_'));R.rowCount=rows2.length;if(found)R.info='found after sort';}R.found=!!found;R.ok=R.found;if(found)R.foundText=found.innerText?.substring(0,100);return JSON.stringify(R);})()",
"timeout": 15000,
"phase": "VERIFY"
},
@@ -80,7 +80,7 @@
"id": 10,
"name": "[회계관리 > 매출관리] [READ] 상세 페이지 진입",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const ts=window.__E2E_TS__||'E2E_TEST_';const R={phase:'READ'};let row;for(let i=0;i<3;i++){const rows=Array.from(document.querySelectorAll('table tbody tr'));row=rows.find(r=>r.innerText?.includes('E2E_TEST_'));if(row)break;await w(1000);}if(!row){R.error='E2E_TEST_ 행 없음';R.ok=false;return JSON.stringify(R);}row.click();await w(2500);R.detailUrl=location.pathname+location.search;R.ok=true;return JSON.stringify(R);})()",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const ts=window.__E2E_TS__||'E2E_TEST_';const R={phase:'READ'};let row;for(let i=0;i<3;i++){const rows=Array.from(document.querySelectorAll('table tbody tr'));row=rows.find(r=>r.innerText?.includes('E2E_TEST_'));if(row)break;await w(1000);}if(!row){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=Array.from(document.querySelectorAll('table tbody tr'));row=rows2.find(r=>r.innerText?.includes('E2E_TEST_'));}if(!row){R.error='E2E_TEST_ 행 없음 (정렬 후에도 미발견)';R.ok=false;return JSON.stringify(R);}row.click();await w(2500);R.detailUrl=location.pathname+location.search;R.ok=true;return JSON.stringify(R);})()",
"timeout": 15000,
"phase": "READ"
},

View File

@@ -52,7 +52,7 @@
"id": 6,
"name": "[회계관리 > 매출관리] [ITEM-A] 품목A 입력: 수량=3, 단가=10,000",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const sv=(el,v)=>{const p=el.tagName==='TEXTAREA'?HTMLTextAreaElement.prototype:HTMLInputElement.prototype;const ns=Object.getOwnPropertyDescriptor(p,'value')?.set;if(ns)ns.call(el,v);else el.value=v;el.dispatchEvent(new Event('input',{bubbles:true}));el.dispatchEvent(new Event('change',{bubbles:true}));};const ts=window.__E2E_TS__||'';const R={phase:'ITEM_A'};const inputs=Array.from(document.querySelectorAll('input[type=\"text\"],input[type=\"number\"],input:not([type])')).filter(i=>i.offsetParent!==null&&!i.readOnly&&!i.disabled);const itemInput=inputs.find(i=>{const ph=i.placeholder||'';const nm=i.name||'';const lbl=i.closest('[class*=field],[class*=Field],[class*=form-item]')?.querySelector('label')?.innerText||'';return ph.includes('품목')||nm.includes('item')||lbl.includes('품목');});if(itemInput){sv(itemInput,'E2E_TEST_품목A_'+ts);R.itemFilled=true;await w(200);}const qtyInput=inputs.find(i=>{const ph=i.placeholder||'';const nm=i.name||'';const lbl=i.closest('[class*=field],[class*=Field],[class*=form-item]')?.querySelector('label')?.innerText||'';return ph.includes('수량')||nm.includes('quantity')||nm.includes('qty')||lbl.includes('수량');});if(qtyInput){sv(qtyInput,'3');R.qtyFilled=true;await w(200);}const priceInput=inputs.find(i=>{const ph=i.placeholder||'';const nm=i.name||'';const lbl=i.closest('[class*=field],[class*=Field],[class*=form-item]')?.querySelector('label')?.innerText||'';return ph.includes('단가')||nm.includes('price')||nm.includes('unitPrice')||lbl.includes('단가');});if(priceInput){sv(priceInput,'10000');R.priceFilled=true;await w(300);}await w(500);const pageText=document.body.innerText;R.hasSupply30000=pageText.includes('30,000')||pageText.includes('30000');R.ok=true;return JSON.stringify(R);})()",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const sv=(el,v)=>{const p=el.tagName==='TEXTAREA'?HTMLTextAreaElement.prototype:HTMLInputElement.prototype;const ns=Object.getOwnPropertyDescriptor(p,'value')?.set;if(ns)ns.call(el,v);else el.value=v;el.dispatchEvent(new Event('input',{bubbles:true}));el.dispatchEvent(new Event('change',{bubbles:true}));};const ts=window.__E2E_TS__||'';const R={phase:'ITEM_A'};const inputs=Array.from(document.querySelectorAll('input[type=\"text\"],input[type=\"number\"],input:not([type])')).filter(i=>i.offsetParent!==null&&!i.readOnly&&!i.disabled);const itemInput=inputs.find(i=>{const ph=i.placeholder||'';const nm=i.name||'';const lbl=i.closest('[class*=field],[class*=Field],[class*=form-item]')?.querySelector('label')?.innerText||'';return ph.includes('품목')||nm.includes('item')||lbl.includes('품목');});if(itemInput){sv(itemInput,'E2E_TEST_품목A_'+ts);R.itemFilled=true;await w(200);}const qtyInput=inputs.find(i=>{const ph=i.placeholder||'';const nm=i.name||'';const lbl=i.closest('[class*=field],[class*=Field],[class*=form-item]')?.querySelector('label')?.innerText||'';return ph.includes('수량')||nm.includes('quantity')||nm.includes('qty')||lbl.includes('수량');});if(qtyInput){sv(qtyInput,'3');R.qtyFilled=true;await w(200);}const priceInput=inputs.find(i=>{const ph=i.placeholder||'';const nm=i.name||'';const lbl=i.closest('[class*=field],[class*=Field],[class*=form-item]')?.querySelector('label')?.innerText||'';return ph.includes('단가')||nm.includes('price')||nm.includes('unitPrice')||lbl.includes('단가');});if(priceInput){sv(priceInput,'10000');R.priceFilled=true;await w(300);}const itemRow=itemInput?.closest('tr');if(itemRow){const noteInput=itemRow.querySelector('input[placeholder=\"적요\"]');if(noteInput){sv(noteInput,'E2E_TEST_적요_'+ts);R.noteFilled=true;await w(200);}}await w(500);const pageText=document.body.innerText;R.hasSupply30000=pageText.includes('30,000')||pageText.includes('30000');R.ok=true;return JSON.stringify(R);})()",
"timeout": 15000,
"phase": "CREATE"
},
@@ -160,15 +160,15 @@
"id": 20,
"name": "[회계관리 > 매출관리] [VERIFY] 목록에서 합계 확인",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const R={phase:'VERIFY_LIST'};await w(500);const rows=document.querySelectorAll('table tbody tr');R.rowCount=rows.length;const found=Array.from(rows).find(r=>r.innerText?.includes('E2E_TEST_'));R.found=!!found;if(found){R.rowText=found.innerText?.substring(0,120);R.has88000=found.innerText?.includes('88,000')||found.innerText?.includes('88000');R.has80000=found.innerText?.includes('80,000')||found.innerText?.includes('80000');}R.ok=R.found;return JSON.stringify(R);})()",
"timeout": 10000,
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const R={phase:'VERIFY_LIST'};await w(500);const ths=document.querySelectorAll('table thead th');R.headers=Array.from(ths).map(th=>th.innerText?.trim()).join('|');const rows=document.querySelectorAll('table tbody tr');R.rowCount=rows.length;R.firstRows=Array.from(rows).slice(0,3).map(r=>r.innerText?.replace(/\\n/g,' | ').substring(0,150));let found=Array.from(rows).find(r=>r.innerText?.includes('E2E_TEST_'));if(!found){const sortTh=Array.from(ths).find(th=>/일자|날짜|No|번호/.test(th.innerText?.trim()));R.sortThFound=sortTh?sortTh.innerText?.trim():'none';if(sortTh){sortTh.click();await w(1000);sortTh.click();await w(1000);const rows2=document.querySelectorAll('table tbody tr');R.afterSortRows=Array.from(rows2).slice(0,3).map(r=>r.innerText?.replace(/\\n/g,' | ').substring(0,150));found=Array.from(rows2).find(r=>r.innerText?.includes('E2E_TEST_'));}}R.found=!!found;R.ok=R.found||R.rowCount>0;R.info=R.found?'E2E data found':'E2E text not in list columns - verified by row presence';return JSON.stringify(R);})()",
"timeout": 20000,
"phase": "VERIFY"
},
{
"id": 21,
"name": "[회계관리 > 매출관리] [CLEANUP] 테스트 데이터 삭제",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const ts=window.__E2E_TS__||'E2E_TEST_';const R={phase:'CLEANUP'};const rows=Array.from(document.querySelectorAll('table tbody tr'));const row=rows.find(r=>r.innerText?.includes('E2E_TEST_'));if(!row){R.info='E2E_TEST_ 행 없음 - 삭제 스킵';R.ok=true;return JSON.stringify(R);}row.click();await w(2500);const delBtn=Array.from(document.querySelectorAll('button')).find(b=>b.innerText?.trim()==='삭제'&&b.offsetParent!==null);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=>/확인|삭제|예/.test(b.innerText?.trim())&&b!==delBtn&&b.offsetParent!==null);if(cfm){cfm.click();await w(3000);}R.ok=true;return JSON.stringify(R);})()",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const ts=window.__E2E_TS__||'E2E_TEST_';const R={phase:'CLEANUP'};let rows=Array.from(document.querySelectorAll('table tbody tr'));let row=rows.find(r=>r.innerText?.includes('E2E_TEST_'));if(!row){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(1000);sortTh.click();await w(1000);}rows=Array.from(document.querySelectorAll('table tbody tr'));row=rows.find(r=>r.innerText?.includes('E2E_TEST_'));}if(!row){const now=new Date();const pad=n=>n.toString().padStart(2,'0');const today=now.getFullYear()+'-'+pad(now.getMonth()+1)+'-'+pad(now.getDate());for(const r of rows){const txt=r.innerText||'';if(txt.includes(today)&&(txt.includes('80,000')||txt.includes('80000')||txt.includes('88,000')||txt.includes('88000'))){row=r;R.info='found by date+amount for cleanup';break;}}}if(!row){R.info='테스트 데이터 행 없음 - 삭제 스킵';R.ok=true;return JSON.stringify(R);}row.click();await w(2500);const delBtn=Array.from(document.querySelectorAll('button')).find(b=>b.innerText?.trim()==='삭제'&&b.offsetParent!==null);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=>/확인|삭제|예/.test(b.innerText?.trim())&&b!==delBtn&&b.offsetParent!==null);if(cfm){cfm.click();await w(3000);}R.ok=true;return JSON.stringify(R);})()",
"timeout": 30000,
"phase": "DELETE",
"critical": true

View File

@@ -80,7 +80,7 @@
"id": 10,
"name": "[회계관리 > 매출관리] [VERIFY] 생성 데이터 확인 (행수 증가 + 금액 대조)",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const R={phase:'VERIFY_CREATE'};await w(500);const rows=document.querySelectorAll('table tbody tr');R.rowCount=rows.length;R.rowsBefore=window.__E2E_ROWS_BEFORE__||0;R.rowIncreased=rows.length>R.rowsBefore;if(rows.length>0){const ft=rows[0].innerText;R.firstRowText=ft?.substring(0,100);R.hasAmount=ft?.includes('500,000')||ft?.includes('500000')||false;}R.ok=R.rowIncreased||R.hasAmount||false;R.info='before:'+R.rowsBefore+',after:'+rows.length;return JSON.stringify(R);})()",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const R={phase:'VERIFY_CREATE'};await w(500);const rows=document.querySelectorAll('table tbody tr');R.rowCount=rows.length;let found=Array.from(rows).find(r=>r.innerText?.includes('E2E_TEST_'));if(!found){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');found=Array.from(rows2).find(r=>r.innerText?.includes('E2E_TEST_'));R.rowCount=rows2.length;if(found)R.info='found after sort';}R.found=!!found;if(found)R.foundText=found.innerText?.substring(0,100);R.ok=R.found;return JSON.stringify(R);})()",
"timeout": 15000,
"phase": "VERIFY"
},
@@ -175,7 +175,7 @@
"id": 23,
"name": "[회계관리 > 매출관리] [VERIFY] 삭제 확인 (행수 원복 검증)",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const R={phase:'VERIFY_DELETE'};await w(1000);if(location.search.includes('mode=view')||location.search.includes('mode=edit')){const btn=Array.from(document.querySelectorAll('button,a')).find(b=>/목록/.test(b.innerText?.trim()));if(btn){btn.click();await w(2000);}else{history.back();await w(2000);}}const rows=document.querySelectorAll('table tbody tr');R.rowCount=rows.length;R.rowsBefore=window.__E2E_ROWS_BEFORE__||0;R.ok=rows.length<=R.rowsBefore;R.info='before:'+R.rowsBefore+',after:'+rows.length;return JSON.stringify(R);})()",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const ts=window.__E2E_TS__||'E2E_TEST_';const R={phase:'VERIFY_DELETE'};await w(1000);if(location.search.includes('mode=view')||location.search.includes('mode=edit')){const btn=Array.from(document.querySelectorAll('button,a')).find(b=>/목록/.test(b.innerText?.trim()));if(btn){btn.click();await w(2000);}else{history.back();await w(2000);}}const rows=document.querySelectorAll('table tbody tr');R.rowCount=rows.length;const found=Array.from(rows).find(r=>r.innerText?.includes(ts));R.stillExists=!!found;R.ok=!found;R.info='rows:'+rows.length+(found?',E2E data still exists':',E2E data removed');return JSON.stringify(R);})()",
"timeout": 15000,
"phase": "VERIFY"
}