fix: 검색 시나리오 결론 동적 판정 (실시간 필터링 검색버튼 불필요 반영)

- search-bug-draft.json: 결론 스텝에서 실시간 입력/Enter 키 검색 동작 시 정상 판정
- search-bug-salary.json: 동일 패턴 적용
- 검색 버튼 미존재 시 SKIP→OK 변경 (실시간 필터링 방식 가능성 안내)
- 하드코딩된 '미구현 버그 판정' 제거, 실제 행 변화 기반 동적 결론 생성
This commit is contained in:
김보곤
2026-02-14 16:46:25 +09:00
parent 0b79a9da40
commit 96f9aee967
2 changed files with 6 additions and 6 deletions

View File

@@ -1,7 +1,7 @@
{
"id": "search-bug-draft",
"name": "기안함 검색 버그 상세 검증",
"description": "결재관리 > 기안함 검색 기능 미동작 버그 상세 분석. 검색어 입력 → 행 수 변화 → API 호출 → 필터 연동 등 전방위 검증",
"description": "결재관리 > 기안함 검색 기능 전방위 검증. 실시간 입력 필터링·Enter 키·버튼 클릭·React onChange 등 모든 검색 방식 테스트. 검색 버튼 없이 실시간 필터링도 정상으로 판정",
"baseUrl": "https://dev.codebridge-x.com",
"menuNavigation": {
"level1": "결재관리",
@@ -43,7 +43,7 @@
"id": 5,
"name": "[테스트3] 검색 버튼 클릭으로 검색",
"action": "evaluate",
"script": "(async()=>{const R={test:'search_via_button'};const btns=Array.from(document.querySelectorAll('button,a[role=\"button\"]'));const searchBtn=btns.find(b=>['검색','조회','Search'].some(t=>b.innerText?.trim()===t||b.getAttribute('aria-label')?.includes(t)));const iconBtn=!searchBtn?document.querySelector('button svg[class*=\"search\"],button svg[class*=\"Search\"],button [class*=\"magnif\"]')?.closest('button'):null;const btn=searchBtn||iconBtn;R.buttonFound=!!btn;R.buttonText=btn?.innerText?.trim().substring(0,20)||btn?.getAttribute('aria-label')||'none';if(btn){const rowsBefore=document.querySelectorAll('table tbody tr').length;R.rowsBefore=rowsBefore;btn.click();await new Promise(r=>setTimeout(r,2000));const rowsAfter=document.querySelectorAll('table tbody tr').length;R.rowsAfter=rowsAfter;R.filtered=rowsBefore!==rowsAfter;R.verdict=R.filtered?'PASS: 버튼 검색 동작':'FAIL: 버튼 클릭 후에도 행 수 불변 ('+rowsBefore+'→'+rowsAfter+')';}else{R.verdict='SKIP: 검색 버튼 없음';}return JSON.stringify(R)})()"
"script": "(async()=>{const R={test:'search_via_button'};const btns=Array.from(document.querySelectorAll('button,a[role=\"button\"]'));const searchBtn=btns.find(b=>['검색','조회','Search'].some(t=>b.innerText?.trim()===t||b.getAttribute('aria-label')?.includes(t)));const iconBtn=!searchBtn?document.querySelector('button svg[class*=\"search\"],button svg[class*=\"Search\"],button [class*=\"magnif\"]')?.closest('button'):null;const btn=searchBtn||iconBtn;R.buttonFound=!!btn;R.buttonText=btn?.innerText?.trim().substring(0,20)||btn?.getAttribute('aria-label')||'none';if(btn){const rowsBefore=document.querySelectorAll('table tbody tr').length;R.rowsBefore=rowsBefore;btn.click();await new Promise(r=>setTimeout(r,2000));const rowsAfter=document.querySelectorAll('table tbody tr').length;R.rowsAfter=rowsAfter;R.filtered=rowsBefore!==rowsAfter;R.verdict=R.filtered?'PASS: 버튼 검색 동작':'FAIL: 버튼 클릭 후에도 행 수 불변 ('+rowsBefore+'→'+rowsAfter+')';}else{R.verdict='OK: 검색 버튼 없음 (실시간 입력 필터링 방식일 수 있음)';}return JSON.stringify(R)})()"
},
{
"id": 6,
@@ -79,7 +79,7 @@
"id": 11,
"name": "[결론] 검색 기능 최종 판정",
"action": "evaluate",
"script": "(async()=>{const si=['input[type=\"search\"]','input[placeholder*=\"검색\"]','input[role=\"searchbox\"]','[class*=\"search\"] input'];let el=null;for(const s of si){el=document.querySelector(s);if(el)break;}const R={page:'기안함',url:location.href,searchInputExists:!!el,searchPlaceholder:el?.placeholder||'none',totalRows:document.querySelectorAll('table tbody tr').length,headers:Array.from(document.querySelectorAll('table thead th')).map(h=>h.innerText?.trim().substring(0,15)),filters:document.querySelectorAll('select,[role=\"combobox\"]').length,tabs:Array.from(document.querySelectorAll('[role=\"tab\"]')).map(t=>t.innerText?.trim().substring(0,15))};R.conclusion='기안함 페이지에 검색 입력란(placeholder: '+R.searchPlaceholder+')이 존재하지만, input/change/Enter/button/React onChange 어떤 방식으로도 테이블 행 필터링이 발생하지 않음. 검색 관련 API 호출도 미감지. 검색 기능 미구현 또는 이벤트 바인딩 누락 버그로 판정.';return JSON.stringify(R)})()"
"script": "(async()=>{const si=['input[type=\"search\"]','input[placeholder*=\"검색\"]','input[role=\"searchbox\"]','[class*=\"search\"] input'];let el=null;for(const s of si){el=document.querySelector(s);if(el)break;}const R={page:'기안함',url:location.href,searchInputExists:!!el,searchPlaceholder:el?.placeholder||'none',totalRows:document.querySelectorAll('table tbody tr').length,headers:Array.from(document.querySelectorAll('table thead th')).map(h=>h.innerText?.trim().substring(0,15)),filters:document.querySelectorAll('select,[role=\"combobox\"]').length,tabs:Array.from(document.querySelectorAll('[role=\"tab\"]')).map(t=>t.innerText?.trim().substring(0,15))};if(!el){R.conclusion='검색 입력란 없음. 검색 UI 미구현.';return JSON.stringify(R);}const nativeSetter=Object.getOwnPropertyDescriptor(HTMLInputElement.prototype,'value')?.set;const initRows=document.querySelectorAll('table tbody tr').length;if(nativeSetter)nativeSetter.call(el,'');else el.value='';el.dispatchEvent(new Event('input',{bubbles:true}));el.dispatchEvent(new Event('change',{bubbles:true}));await new Promise(r=>setTimeout(r,1000));const resetRows=document.querySelectorAll('table tbody tr').length;if(nativeSetter)nativeSetter.call(el,'zzz_conclusion_test');else el.value='zzz_conclusion_test';const rk=Object.keys(el).find(k=>k.startsWith('__reactProps$'));if(rk&&el[rk]?.onChange){el[rk].onChange({target:el,currentTarget:el});}el.dispatchEvent(new Event('input',{bubbles:true}));el.dispatchEvent(new Event('change',{bubbles:true}));await new Promise(r=>setTimeout(r,2000));const afterInput=document.querySelectorAll('table tbody tr').length;R.inputTest={before:resetRows,after:afterInput,filtered:resetRows!==afterInput};if(R.inputTest.filtered){R.conclusion='검색 기능 정상 동작. 실시간 입력 필터링 방식 (검색 버튼 불필요). 입력 시 즉시 테이블 행 필터링 발생 ('+resetRows+'→'+afterInput+').';R.searchType='realtime_input';if(nativeSetter)nativeSetter.call(el,'');else el.value='';if(rk&&el[rk]?.onChange)el[rk].onChange({target:el,currentTarget:el});el.dispatchEvent(new Event('input',{bubbles:true}));return JSON.stringify(R);}el.dispatchEvent(new KeyboardEvent('keydown',{key:'Enter',code:'Enter',keyCode:13,bubbles:true}));await new Promise(r=>setTimeout(r,2000));const afterEnter=document.querySelectorAll('table tbody tr').length;R.enterTest={before:resetRows,after:afterEnter,filtered:resetRows!==afterEnter};if(R.enterTest.filtered){R.conclusion='검색 기능 정상 동작. Enter 키 검색 방식 (검색 버튼 불필요). Enter 입력 시 테이블 행 필터링 발생 ('+resetRows+'→'+afterEnter+').';R.searchType='enter_key';if(nativeSetter)nativeSetter.call(el,'');else el.value='';el.dispatchEvent(new Event('input',{bubbles:true}));return JSON.stringify(R);}const btns=Array.from(document.querySelectorAll('button'));const searchBtn=btns.find(b=>['검색','조회','Search'].some(t=>b.innerText?.trim()===t));R.searchButtonExists=!!searchBtn;R.conclusion='기안함 페이지에 검색 입력란(placeholder: '+R.searchPlaceholder+')이 존재하지만, input/change/Enter/React onChange 어떤 방식으로도 테이블 행 필터링이 발생하지 않음 ('+resetRows+'→'+afterEnter+'). 검색 기능 미동작 또는 프론트엔드 클라이언트 필터링 미구현.';R.searchType='not_working';if(nativeSetter)nativeSetter.call(el,'');else el.value='';el.dispatchEvent(new Event('input',{bubbles:true}));return JSON.stringify(R)})()"
}
]
}