fix: 급여 장기요양 셀렉터 수정(label→span) + 달력 토스트 스텝 제거

- hr-salary-long-term-care: steps 8,9,13,14 셀렉터를 label→span으로 변경, container를 [class*=field]→[class*=flex]로 변경 (실제 DOM 구조 반영)
- settings-calendar-crud: toast verify steps 3개 제거 (Server Actions는 토스트 미사용), 19→16 스텝
This commit is contained in:
김보곤
2026-03-05 21:51:41 +09:00
parent b95f7fc132
commit 4b5bf7a873
2 changed files with 16 additions and 39 deletions

View File

@@ -1,7 +1,7 @@
{
"id": "hr-salary-long-term-care",
"name": "급여 장기요양보험 필드 검증 테스트",
"version": "1.1.0",
"version": "1.2.0",
"enabled": true,
"screenshotPolicy": {
"captureOnFail": true,
@@ -68,14 +68,14 @@
"name": "[READ] 장기요양보험 필드 존재 확인 (상세)",
"phase": "READ",
"action": "evaluate",
"script": "(()=>{const R={phase:'DETAIL_LTC_CHECK'};const modal=document.querySelector('[role=\"dialog\"],[aria-modal=\"true\"],[class*=\"Dialog\"]');const scope=modal||document;const bodyText=scope.innerText||'';R.hasLongTermCare=bodyText.includes('장기요양')||bodyText.includes('장기요양보험');const labels=Array.from(scope.querySelectorAll('label,dt,[class*=\"label\"],[class*=\"Label\"]'));const ltcLabel=labels.find(l=>l.innerText?.includes('장기요양'));R.labelFound=!!ltcLabel;if(ltcLabel){const container=ltcLabel.closest('[class*=\"field\"],[class*=\"Field\"],[class*=\"form-item\"],[class*=\"row\"]');if(container){const valueEl=container.querySelector('input,span,dd,[class*=\"value\"],[class*=\"Value\"]');R.value=valueEl?.value||valueEl?.innerText?.trim()||'N/A';}}R.ok=R.hasLongTermCare||R.labelFound;R.info=R.ok?'pass: 장기요양보험 필드 발견':'fail: 장기요양보험 필드 미발견';return JSON.stringify(R);})()"
"script": "(()=>{const R={phase:'DETAIL_LTC_CHECK'};const modal=document.querySelector('[role=\"dialog\"],[aria-modal=\"true\"],[class*=\"Dialog\"]');const scope=modal||document;const bodyText=scope.innerText||'';R.hasLongTermCare=bodyText.includes('장기요양')||bodyText.includes('장기요양보험');const allEls=Array.from(scope.querySelectorAll('span,label,dt'));const ltcEl=allEls.find(l=>/^장기요양(보험)?$/.test(l.innerText?.trim()));R.labelFound=!!ltcEl;if(ltcEl){const container=ltcEl.closest('[class*=\"flex\"]')||ltcEl.parentElement;if(container){const valSpans=Array.from(container.querySelectorAll('span,div')).filter(el=>el!==ltcEl&&/[0-9]/.test(el.innerText||''));if(valSpans.length>0)R.value=valSpans[valSpans.length-1].innerText?.trim()||'N/A';}}R.ok=R.hasLongTermCare||R.labelFound;R.info=R.ok?'pass: 장기요양보험 필드 발견'+(R.value?' ('+R.value+')':''):'fail: 장기요양보험 필드 미발견';return JSON.stringify(R);})()"
},
{
"id": 9,
"name": "[READ] 건강보험/장기요양 값 비교 (자동계산 검증)",
"phase": "READ",
"action": "evaluate",
"script": "(()=>{const R={phase:'CALC_VERIFY'};const modal=document.querySelector('[role=\"dialog\"],[aria-modal=\"true\"],[class*=\"Dialog\"]');const scope=modal||document;const labels=Array.from(scope.querySelectorAll('label,dt,[class*=\"label\"],[class*=\"Label\"]'));const getVal=keyword=>{const lbl=labels.find(l=>l.innerText?.includes(keyword));if(!lbl)return null;const container=lbl.closest('[class*=\"field\"],[class*=\"Field\"],[class*=\"form-item\"],[class*=\"row\"]');if(!container)return null;const valEl=container.querySelector('input,span,dd,[class*=\"value\"]');const raw=valEl?.value||valEl?.innerText?.trim()||'';return parseInt(raw.replace(/[^0-9]/g,''))||null;};R.healthInsurance=getVal('건강보험');R.longTermCare=getVal('장기요양');if(R.healthInsurance&&R.longTermCare){const expected=Math.round(R.healthInsurance*0.1281);R.expectedLTC=expected;R.tolerance=Math.abs(R.longTermCare-expected);R.isCorrect=R.tolerance<=10;R.info=R.isCorrect?'pass: 장기요양='+R.longTermCare+' (건강보험 '+R.healthInsurance+'×12.81%='+expected+')':'warn: 장기요양='+R.longTermCare+' vs 예상='+expected+' (차이='+R.tolerance+')';}else{R.info='warn: 건강보험('+R.healthInsurance+') 또는 장기요양('+R.longTermCare+') 값 미확인';}R.ok=true;return JSON.stringify(R);})()"
"script": "(()=>{const R={phase:'CALC_VERIFY'};const modal=document.querySelector('[role=\"dialog\"],[aria-modal=\"true\"],[class*=\"Dialog\"]');const scope=modal||document;const allEls=Array.from(scope.querySelectorAll('span,label,dt'));const getVal=keyword=>{const lbl=allEls.find(l=>l.innerText?.trim()===keyword);if(!lbl)return null;const container=lbl.closest('[class*=\"flex\"]')||lbl.parentElement;if(!container)return null;const valEls=Array.from(container.querySelectorAll('span,div')).filter(el=>el!==lbl&&/[0-9]/.test(el.innerText||''));if(valEls.length===0)return null;const raw=valEls[valEls.length-1].innerText?.trim()||'';return parseInt(raw.replace(/[^0-9]/g,''))||null;};R.healthInsurance=getVal('건강보험');R.longTermCare=getVal('장기요양보험')||getVal('장기요양');if(R.healthInsurance&&R.longTermCare){const expected=Math.round(R.healthInsurance*0.1281);R.expectedLTC=expected;R.tolerance=Math.abs(R.longTermCare-expected);R.isCorrect=R.tolerance<=10;R.info=R.isCorrect?'pass: 장기요양='+R.longTermCare+' (건강보험 '+R.healthInsurance+'×12.81%='+expected+')':'warn: 장기요양='+R.longTermCare+' vs 예상='+expected+' (차이='+R.tolerance+')';}else{R.info='warn: 건강보험('+R.healthInsurance+') 또는 장기요양('+R.longTermCare+') 값 미확인';}R.ok=true;return JSON.stringify(R);})()"
},
{
"id": 10,
@@ -104,14 +104,14 @@
"name": "[CREATE] 등록 폼에서 장기요양보험 필드 확인",
"phase": "CREATE",
"action": "evaluate",
"script": "(()=>{const R={phase:'CREATE_LTC_CHECK'};const modal=document.querySelector('[role=\"dialog\"],[aria-modal=\"true\"],[class*=\"Dialog\"]');const scope=modal||document;const bodyText=scope.innerText||'';R.hasLongTermCare=bodyText.includes('장기요양')||bodyText.includes('장기요양보험');const labels=Array.from(scope.querySelectorAll('label'));const ltcLabel=labels.find(l=>l.innerText?.includes('장기요양'));R.labelFound=!!ltcLabel;if(ltcLabel){const container=ltcLabel.closest('[class*=\"field\"],[class*=\"Field\"],[class*=\"form-item\"],[class*=\"row\"]');if(container){const input=container.querySelector('input');R.hasInput=!!input;R.inputReadOnly=input?.readOnly||false;R.inputValue=input?.value||'';}}R.ok=R.hasLongTermCare||R.labelFound;R.info=R.ok?'pass: 등록 폼에 장기요양보험 필드 존재'+(R.inputReadOnly?' (자동계산, readOnly)':' (입력 가능)'):'fail: 등록 폼에 장기요양보험 필드 미발견';return JSON.stringify(R);})()"
"script": "(()=>{const R={phase:'CREATE_LTC_CHECK'};const modal=document.querySelector('[role=\"dialog\"],[aria-modal=\"true\"],[class*=\"Dialog\"]');const scope=modal||document;const bodyText=scope.innerText||'';R.hasLongTermCare=bodyText.includes('장기요양')||bodyText.includes('장기요양보험');const allEls=Array.from(scope.querySelectorAll('span,label,dt'));const ltcEl=allEls.find(l=>/^장기요양(보험)?$/.test(l.innerText?.trim()));R.labelFound=!!ltcEl;if(ltcEl){const container=ltcEl.closest('[class*=\"flex\"]')||ltcEl.parentElement;if(container){const input=container.querySelector('input');R.hasInput=!!input;R.inputReadOnly=input?.readOnly||false;R.inputValue=input?.value||'';}}R.ok=R.hasLongTermCare||R.labelFound;R.info=R.ok?'pass: 등록 폼에 장기요양보험 필드 존재'+(R.inputReadOnly?' (자동계산, readOnly)':' (입력 가능)'):'fail: 등록 폼에 장기요양보험 필드 미발견';return JSON.stringify(R);})()"
},
{
"id": 14,
"name": "[CREATE] 건강보험 입력 → 장기요양 자동계산 검증",
"phase": "CREATE",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const sv=(el,v)=>{const ns=Object.getOwnPropertyDescriptor(HTMLInputElement.prototype,'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 R={phase:'AUTO_CALC'};const modal=document.querySelector('[role=\"dialog\"],[aria-modal=\"true\"],[class*=\"Dialog\"]');const scope=modal||document;const labels=Array.from(scope.querySelectorAll('label'));const healthLabel=labels.find(l=>l.innerText?.includes('건강보험')&&!l.innerText?.includes('장기'));if(!healthLabel){R.info='건강보험 입력 필드 미발견';R.ok=true;return JSON.stringify(R);}const healthContainer=healthLabel.closest('[class*=\"field\"],[class*=\"Field\"],[class*=\"form-item\"],[class*=\"row\"]');const healthInput=healthContainer?.querySelector('input');if(!healthInput||healthInput.readOnly||healthInput.disabled){R.info='건강보험 입력 불가 (readOnly)';R.ok=true;return JSON.stringify(R);}sv(healthInput,'100000');await w(800);const ltcLabel=labels.find(l=>l.innerText?.includes('장기요양'));if(ltcLabel){const ltcContainer=ltcLabel.closest('[class*=\"field\"],[class*=\"Field\"],[class*=\"form-item\"],[class*=\"row\"]');const ltcEl=ltcContainer?.querySelector('input,span,[class*=\"value\"]');const ltcVal=ltcEl?.value||ltcEl?.innerText?.trim()||'';const numVal=parseInt(ltcVal.replace(/[^0-9]/g,''))||0;R.healthInput=100000;R.longTermCareOutput=numVal;R.expected=Math.round(100000*0.1281);R.isAutoCalculated=Math.abs(numVal-R.expected)<=10;R.info=R.isAutoCalculated?'pass: 건강보험 100,000 → 장기요양 '+numVal+' (예상 '+R.expected+')':'warn: 장기요양='+numVal+' vs 예상='+R.expected;}else{R.info='장기요양 필드 미발견';}R.ok=true;return JSON.stringify(R);})()",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const sv=(el,v)=>{const ns=Object.getOwnPropertyDescriptor(HTMLInputElement.prototype,'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 R={phase:'AUTO_CALC'};const modal=document.querySelector('[role=\"dialog\"],[aria-modal=\"true\"],[class*=\"Dialog\"]');const scope=modal||document;const allEls=Array.from(scope.querySelectorAll('span,label,dt'));const healthEl=allEls.find(l=>l.innerText?.trim()==='건강보험');if(!healthEl){R.info='건강보험 입력 필드 미발견';R.ok=true;return JSON.stringify(R);}const healthContainer=healthEl.closest('[class*=\"flex\"]')||healthEl.parentElement;const healthInput=healthContainer?.querySelector('input');if(!healthInput||healthInput.readOnly||healthInput.disabled){R.info='건강보험 입력 불가 (readOnly)';R.ok=true;return JSON.stringify(R);}sv(healthInput,'100000');await w(800);const ltcEl=allEls.find(l=>/^장기요양(보험)?$/.test(l.innerText?.trim()));if(ltcEl){const ltcContainer=ltcEl.closest('[class*=\"flex\"]')||ltcEl.parentElement;const ltcInput=ltcContainer?.querySelector('input');const ltcValEl=ltcInput||Array.from(ltcContainer?.querySelectorAll('span,div')||[]).find(el=>el!==ltcEl&&/[0-9]/.test(el.innerText||''));const ltcVal=ltcInput?.value||ltcValEl?.innerText?.trim()||'';const numVal=parseInt(ltcVal.replace(/[^0-9]/g,''))||0;R.healthInput=100000;R.longTermCareOutput=numVal;R.expected=Math.round(100000*0.1281);R.isAutoCalculated=Math.abs(numVal-R.expected)<=10;R.info=R.isAutoCalculated?'pass: 건강보험 100,000 → 장기요양 '+numVal+' (예상 '+R.expected+')':'warn: 장기요양='+numVal+' vs 예상='+R.expected;}else{R.info='장기요양 필드 미발견';}R.ok=true;return JSON.stringify(R);})()",
"timeout": 10000
},
{