Files
sam-scenarios/input-fields-acc-2.json

103 lines
23 KiB
JSON
Raw Permalink Normal View History

{
"id": "input-fields-acc-2",
"name": "입력 필드 전수 테스트: 거래처(회계)/악성채권 (2/5)",
"version": "1.1.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 urlBefore=location.href;const btns=Array.from(document.querySelectorAll(\"button\")).filter(b=>b.offsetParent!==null&&!b.disabled);const priorities=[ b=>/등록/.test(b.innerText?.trim()), b=>/추가/.test(b.innerText?.trim()), b=>/작성/.test(b.innerText?.trim()), b=>/^\\+/.test(b.innerText?.trim()), b=>/신규/.test(b.innerText?.trim())&&!/신규업체|신규거래/.test(b.innerText?.trim()),];let regBtn=null;for(const pred of priorities){regBtn=btns.find(pred);if(regBtn)break;}if(!regBtn)regBtn=btns.find(b=>/신규/.test(b.innerText?.trim()));if(regBtn){ regBtn.scrollIntoView({block:\"center\"});await w(300); regBtn.click();await w(2500); const modal=document.querySelector(\"[role='dialog'],[aria-modal='true']\"); const hasModal=modal&&modal.offsetParent!==null; const urlChanged=location.href!==urlBefore; const inputs=document.querySelectorAll(\"input,textarea,select,button[role='combobox']\"); const vis=Array.from(inputs).filter(el=>el.offsetParent!==null&&!el.disabled).length; return JSON.stringify({opened:true,hasModal,urlChanged,url:location.pathname+location.search,btnText:regBtn.innerText?.trim().substring(0,30),visibleInputs:vis});}const row=document.querySelector(\"table tbody tr\");if(row){ row.click();await w(2500); const modal=document.querySelector(\"[role='dialog'],[aria-modal='true']\"); const hasModal=modal&&modal.offsetParent!==null; const urlChanged=location.href!==urlBefore; const inputs=document.querySelectorAll(\"input,textarea,select,button[role='combobox']\"); const vis=Array.from(inputs).filter(el=>el.offsetParent!==null&&!el.disabled).length; return JSON.stringify({opened:true,hasModal,urlChanged,usedRowClick:true,visibleInputs:vis});}const form=document.querySelector(\"form\");if(form){return JSON.stringify({opened:true,isInlineForm:true});}return JSON.stringify({opened:false,noBtn:true,available:btns.slice(0,8).map(b=>b.innerText?.trim().substring(0,20)).filter(Boolean)});})()",
"timeout": 15000
},
{
"id": 4,
"name": "[회계관리 > 거래처관리] 폼 렌더링 대기",
"action": "wait",
"timeout": 1500
},
{
"id": 5,
"name": "[회계관리 > 거래처관리] 입력 필드 전수 테스트",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const R={url:location.pathname+location.search,fields:[],summary:{}};const modal=document.querySelector(\"[role='dialog'],[aria-modal='true']\");const hasModal=modal&&modal.offsetParent!==null;const mainContent=document.querySelector(\"main,[class*='content']:not(nav):not(aside),[class*='Content']:not(nav)\");const scope=hasModal?modal:(mainContent||document.body);R.scope=hasModal?\"modal\":mainContent?\"main\":\"body\";const sv=(el,v)=>{ const proto=el.tagName===\"TEXTAREA\"?HTMLTextAreaElement.prototype:HTMLInputElement.prototype; const ns=Object.getOwnPropertyDescriptor(proto,\"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}));};let tested=0,errors=0,skipped=0;const textSel=\"input[type=text],input[type=number],input[type=email],input[type=tel],input[type=url],input:not([type]):not([role])\";const textInputs=scope.querySelectorAll(textSel);for(const el of textInputs){ if(el.offsetParent===null||el.readOnly||el.disabled)continue; if(el.placeholder?.includes(\"검색\")||el.type===\"search\")continue; const label=(el.closest(\"[class*=field],[class*=Field],[class*=form-item],[class*=FormItem]\")?.querySelector(\"label\")?.innerText||el.getAttribute(\"aria-label\")||el.getAttribute(\"placeholder\")||el.name||\"\").substring(0,40); const orig=el.value; try{sv(el,\"E2E_TEST\");await w(80);const ok=el.value===\"E2E_TEST\";sv(el,orig);await w(50); R.fields.push({type:el.type||\"text\",label,ok});tested++; }catch(e){R.fields.push({type:el.type||\"text\",label,err:e.message?.substring(0,60)});errors++;}}const textareas=scope.querySelectorAll(\"textarea\");for(const el of textareas){ if(el.offsetParent===null||el.readOnly||el.disabled)continue; const label=(el.closest(\"[class*=field],[class*=Field],[class*=form-item]\")?.querySelector(\"label\")?.innerText||el.getAttribute(\"placeholder\")||\"\").substring(0,40); const orig=el.value; try{sv(el,\"E2E_TEXTAREA\");await w(80);const ok=el.value===\"E2E_TEXTAREA\";sv(el,orig);await w(50); R.fields.push({type:\"textarea\",label,ok});tested++; }catch(e){R.fields.push({type:\"textarea\",label,err:e.message?.substring(0,60)});errors++;}}const combos=scope.querySelectorAll(\"button[role=combobox]\");for(const cb of combos){ if(cb.offsetParent===null||cb.disabled)continue; const label=(cb.closest(\"[class*=field],[class*=Field],[class*=form-item]\")?.querySelector(\"label\")?.innerText||cb.getAttribute(\"aria-label\")||cb.innerText?.trim()||\"\").substring(0,40); const origText=cb.innerText?.trim(); try{ cb.scrollIntoView({block:\"center\"});await w(200);cb.click();await w(600); const lb=document.querySelector(\"[role=listbox]\"); if(!lb){document.dispatchEvent(new KeyboardEvent(\"keydown\",{key:\"Escape\",bubbles:true}));await w(200); R.fields.push({type:\"combobox\",label,opts:0,err:\"no listbox\"});skipped++;continue;} const opts=Array.from(lb.querySelectorAll(\"[role=option]\")); R.fields.push({type:\"combobox\",label,opts:opts.length,samples:opts.slice(0,5).map(o=>o.innerText?.trim())}); if(opts.length>0){ const pick=opts.find(o=>o.innerText?.trim()!==origText)||opts[0]; pick.click();await w(400); const changed=cb.innerText?.trim()!==origText; R.fields[R.fields.length-1].selected=pick.innerText?.trim().substring(0,30); R.fields[R.fields.length-1].changed=changed; cb.click();await w(400); const lb2=document.querySelector(\"[role=listbox]\"); if(lb2){const r2=Array.from(lb2.querySelectorAll(\"[role=option]\")).find(o=>o.innerText?.trim()===origText)||lb2.querySelector(\"[role=option]\");if(r2)r2.click();await w(300);} else{document.dispatchEvent(new KeyboardEvent(\"keydown\",{key:\"Escape\",bubbles:true}));await w(200);} }else{document.dispatchEvent(new KeyboardEvent(\"keydown\",{key:\"Escape\",bubbles:true}));await w(200);} tested++; }catch(e){document.dispatchEvent(new KeyboardEvent(\"keydown\",{key:\
"timeout": 60000
},
{
"id": 6,
"name": "[회계관리 > 거래처관리] 모달/폼 닫기",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));for(let i=0;i<3;i++){ const modal=document.querySelector(\"[role='dialog'],[aria-modal='true']\"); if(!modal||modal.offsetParent===null)break; const closeBtn=modal.querySelector(\"button[class*=close],[aria-label=닫기],[aria-label=Close]\") ||Array.from(modal.querySelectorAll(\"button\")).find(b=>/닫기|Close|취소|Cancel/.test(b.innerText?.trim())); if(closeBtn){closeBtn.click();await w(500);} else{document.dispatchEvent(new KeyboardEvent(\"keydown\",{key:\"Escape\",keyCode:27,bubbles:true}));await w(500);}}if(/mode=(new|edit)/.test(location.search)){ const cancelBtn=Array.from(document.querySelectorAll(\"button\")).find(b=>/취소|Cancel|목록/.test(b.innerText?.trim())); if(cancelBtn){cancelBtn.click();await w(1500);} else{history.back();await w(1500);}}return JSON.stringify({url:location.pathname+location.search});})()",
"timeout": 10000
},
{
"id": 7,
"name": "[회계관리 > 악성채권추심관리] 메뉴 이동",
"action": "menu_navigate",
"level1": "회계관리",
"level2": "악성채권추심관리"
},
{
"id": 8,
"name": "[회계관리 > 악성채권추심관리] 페이지 로드 대기",
"action": "wait",
"timeout": 3000
},
{
"id": 9,
"name": "[회계관리 > 악성채권추심관리] 테이블 로드 대기",
"action": "wait_for_table",
"timeout": 5000
},
{
"id": 10,
"name": "[회계관리 > 악성채권추심관리] 등록 폼 열기",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const urlBefore=location.href;const btns=Array.from(document.querySelectorAll(\"button\")).filter(b=>b.offsetParent!==null&&!b.disabled);const priorities=[ b=>/등록/.test(b.innerText?.trim()), b=>/추가/.test(b.innerText?.trim()), b=>/작성/.test(b.innerText?.trim()), b=>/^\\+/.test(b.innerText?.trim()), b=>/신규/.test(b.innerText?.trim())&&!/신규업체|신규거래/.test(b.innerText?.trim()),];let regBtn=null;for(const pred of priorities){regBtn=btns.find(pred);if(regBtn)break;}if(!regBtn)regBtn=btns.find(b=>/신규/.test(b.innerText?.trim()));if(regBtn){ regBtn.scrollIntoView({block:\"center\"});await w(300); regBtn.click();await w(2500); const modal=document.querySelector(\"[role='dialog'],[aria-modal='true']\"); const hasModal=modal&&modal.offsetParent!==null; const urlChanged=location.href!==urlBefore; const inputs=document.querySelectorAll(\"input,textarea,select,button[role='combobox']\"); const vis=Array.from(inputs).filter(el=>el.offsetParent!==null&&!el.disabled).length; return JSON.stringify({opened:true,hasModal,urlChanged,url:location.pathname+location.search,btnText:regBtn.innerText?.trim().substring(0,30),visibleInputs:vis});}const row=document.querySelector(\"table tbody tr\");if(row){ row.click();await w(2500); const modal=document.querySelector(\"[role='dialog'],[aria-modal='true']\"); const hasModal=modal&&modal.offsetParent!==null; const urlChanged=location.href!==urlBefore; const inputs=document.querySelectorAll(\"input,textarea,select,button[role='combobox']\"); const vis=Array.from(inputs).filter(el=>el.offsetParent!==null&&!el.disabled).length; return JSON.stringify({opened:true,hasModal,urlChanged,usedRowClick:true,visibleInputs:vis});}const form=document.querySelector(\"form\");if(form){return JSON.stringify({opened:true,isInlineForm:true});}return JSON.stringify({opened:false,noBtn:true,available:btns.slice(0,8).map(b=>b.innerText?.trim().substring(0,20)).filter(Boolean)});})()",
"timeout": 15000
},
{
"id": 11,
"name": "[회계관리 > 악성채권추심관리] 폼 렌더링 대기",
"action": "wait",
"timeout": 1500
},
{
"id": 12,
"name": "[회계관리 > 악성채권추심관리] 입력 필드 전수 테스트",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const R={url:location.pathname+location.search,fields:[],summary:{}};const modal=document.querySelector(\"[role='dialog'],[aria-modal='true']\");const hasModal=modal&&modal.offsetParent!==null;const mainContent=document.querySelector(\"main,[class*='content']:not(nav):not(aside),[class*='Content']:not(nav)\");const scope=hasModal?modal:(mainContent||document.body);R.scope=hasModal?\"modal\":mainContent?\"main\":\"body\";const sv=(el,v)=>{ const proto=el.tagName===\"TEXTAREA\"?HTMLTextAreaElement.prototype:HTMLInputElement.prototype; const ns=Object.getOwnPropertyDescriptor(proto,\"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}));};let tested=0,errors=0,skipped=0;const textSel=\"input[type=text],input[type=number],input[type=email],input[type=tel],input[type=url],input:not([type]):not([role])\";const textInputs=scope.querySelectorAll(textSel);for(const el of textInputs){ if(el.offsetParent===null||el.readOnly||el.disabled)continue; if(el.placeholder?.includes(\"검색\")||el.type===\"search\")continue; const label=(el.closest(\"[class*=field],[class*=Field],[class*=form-item],[class*=FormItem]\")?.querySelector(\"label\")?.innerText||el.getAttribute(\"aria-label\")||el.getAttribute(\"placeholder\")||el.name||\"\").substring(0,40); const orig=el.value; try{sv(el,\"E2E_TEST\");await w(80);const ok=el.value===\"E2E_TEST\";sv(el,orig);await w(50); R.fields.push({type:el.type||\"text\",label,ok});tested++; }catch(e){R.fields.push({type:el.type||\"text\",label,err:e.message?.substring(0,60)});errors++;}}const textareas=scope.querySelectorAll(\"textarea\");for(const el of textareas){ if(el.offsetParent===null||el.readOnly||el.disabled)continue; const label=(el.closest(\"[class*=field],[class*=Field],[class*=form-item]\")?.querySelector(\"label\")?.innerText||el.getAttribute(\"placeholder\")||\"\").substring(0,40); const orig=el.value; try{sv(el,\"E2E_TEXTAREA\");await w(80);const ok=el.value===\"E2E_TEXTAREA\";sv(el,orig);await w(50); R.fields.push({type:\"textarea\",label,ok});tested++; }catch(e){R.fields.push({type:\"textarea\",label,err:e.message?.substring(0,60)});errors++;}}const combos=scope.querySelectorAll(\"button[role=combobox]\");for(const cb of combos){ if(cb.offsetParent===null||cb.disabled)continue; const label=(cb.closest(\"[class*=field],[class*=Field],[class*=form-item]\")?.querySelector(\"label\")?.innerText||cb.getAttribute(\"aria-label\")||cb.innerText?.trim()||\"\").substring(0,40); const origText=cb.innerText?.trim(); try{ cb.scrollIntoView({block:\"center\"});await w(200);cb.click();await w(600); const lb=document.querySelector(\"[role=listbox]\"); if(!lb){document.dispatchEvent(new KeyboardEvent(\"keydown\",{key:\"Escape\",bubbles:true}));await w(200); R.fields.push({type:\"combobox\",label,opts:0,err:\"no listbox\"});skipped++;continue;} const opts=Array.from(lb.querySelectorAll(\"[role=option]\")); R.fields.push({type:\"combobox\",label,opts:opts.length,samples:opts.slice(0,5).map(o=>o.innerText?.trim())}); if(opts.length>0){ const pick=opts.find(o=>o.innerText?.trim()!==origText)||opts[0]; pick.click();await w(400); const changed=cb.innerText?.trim()!==origText; R.fields[R.fields.length-1].selected=pick.innerText?.trim().substring(0,30); R.fields[R.fields.length-1].changed=changed; cb.click();await w(400); const lb2=document.querySelector(\"[role=listbox]\"); if(lb2){const r2=Array.from(lb2.querySelectorAll(\"[role=option]\")).find(o=>o.innerText?.trim()===origText)||lb2.querySelector(\"[role=option]\");if(r2)r2.click();await w(300);} else{document.dispatchEvent(new KeyboardEvent(\"keydown\",{key:\"Escape\",bubbles:true}));await w(200);} }else{document.dispatchEvent(new KeyboardEvent(\"keydown\",{key:\"Escape\",bubbles:true}));await w(200);} tested++; }catch(e){document.dispatchEvent(new KeyboardEvent(\"keydown\",{key:\
"timeout": 60000
},
{
"id": 13,
"name": "[회계관리 > 악성채권추심관리] 모달/폼 닫기",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));for(let i=0;i<3;i++){ const modal=document.querySelector(\"[role='dialog'],[aria-modal='true']\"); if(!modal||modal.offsetParent===null)break; const closeBtn=modal.querySelector(\"button[class*=close],[aria-label=닫기],[aria-label=Close]\") ||Array.from(modal.querySelectorAll(\"button\")).find(b=>/닫기|Close|취소|Cancel/.test(b.innerText?.trim())); if(closeBtn){closeBtn.click();await w(500);} else{document.dispatchEvent(new KeyboardEvent(\"keydown\",{key:\"Escape\",keyCode:27,bubbles:true}));await w(500);}}if(/mode=(new|edit)/.test(location.search)){ const cancelBtn=Array.from(document.querySelectorAll(\"button\")).find(b=>/취소|Cancel|목록/.test(b.innerText?.trim())); if(cancelBtn){cancelBtn.click();await w(1500);} else{history.back();await w(1500);}}return JSON.stringify({url:location.pathname+location.search});})()",
"timeout": 10000
}
]
}