Files
sam-scenarios/pagination-sort-hr.json

98 lines
13 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"id": "pagination-sort-hr",
"name": "페이지네이션 & 정렬 검증: 인사/게시판",
"version": "1.0.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 R={phase:'ROW_COUNT'};const rows=document.querySelectorAll('table tbody tr');R.rowCount=rows.length;const pageInfo=document.body.innerText.match(new RegExp('(\\\\d+)\\\\s*[-~]\\\\s*(\\\\d+)\\\\s*(of|중|개|건|/|총)\\\\s*(\\\\d+)','i'));if(pageInfo){R.pageInfoText=pageInfo[0];R.totalItems=parseInt(pageInfo[4]);}const totalBadge=Array.from(document.querySelectorAll('[class*=\"badge\"],[class*=\"count\"],[class*=\"total\"]')).find(e=>/\\d+/.test(e.innerText));if(totalBadge)R.totalBadgeText=totalBadge.innerText?.trim();const emptyRows=Array.from(rows).filter(r=>r.innerText?.trim().length===0);R.emptyRowCount=emptyRows.length;if(emptyRows.length>0)R.warn='⚠️ 빈 행 '+emptyRows.length+'개 발견 (렌더링 버그 의심)';const rowTexts=Array.from(rows).map(r=>r.innerText?.trim().substring(0,80));const duplicates=rowTexts.filter((t,i)=>rowTexts.indexOf(t)!==i);R.duplicateCount=duplicates.length;if(duplicates.length>0)R.warn=(R.warn||'')+' ⚠️ 중복 행 '+duplicates.length+'개 발견';R.ok=true;return JSON.stringify(R);})()",
"timeout": 10000,
"phase": "VERIFY"
},
{
"id": 4,
"name": "[인사관리 > 사원관리] 컬럼 정렬 검증",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const R={phase:'SORT'};const headers=Array.from(document.querySelectorAll('table thead th,table thead td,[role=\"columnheader\"]'));R.headerCount=headers.length;R.headerTexts=headers.map(h=>h.innerText?.trim()).filter(t=>t).slice(0,10);const sortableHeaders=headers.filter(h=>{ const t=h.innerText?.trim()||''; return t.length>0&&!h.querySelector('input[type=\"checkbox\"]')&&h.offsetParent!==null;});R.sortableCount=sortableHeaders.length;if(sortableHeaders.length===0){R.warn='정렬 가능한 헤더 없음';R.ok=true;return JSON.stringify(R);}const getFirstColValues=()=>Array.from(document.querySelectorAll('table tbody tr')).slice(0,5).map(r=>{const cells=r.querySelectorAll('td');return(cells[1]||cells[0])?.innerText?.trim().substring(0,30)||'';});R.beforeSort=getFirstColValues();const targetHeader=sortableHeaders.find(h=>h.innerText?.trim().length>1)||sortableHeaders[0];R.sortColumn=targetHeader.innerText?.trim();targetHeader.click();await w(1500);R.afterSort1=getFirstColValues();R.sortChanged1=JSON.stringify(R.beforeSort)!==JSON.stringify(R.afterSort1);targetHeader.click();await w(1500);R.afterSort2=getFirstColValues();R.sortChanged2=JSON.stringify(R.afterSort1)!==JSON.stringify(R.afterSort2);if(!R.sortChanged1&&!R.sortChanged2)R.warn='⚠️ 컬럼 클릭 후 정렬 변화 없음 (정렬 미구현 의심)';else if(R.sortChanged1&&!R.sortChanged2)R.warn='⚠️ 역순 정렬 미동작 (한방향만 정렬)';R.ok=true;return JSON.stringify(R);})()",
"timeout": 15000,
"phase": "SORT"
},
{
"id": 5,
"name": "[인사관리 > 사원관리] 페이지네이션 검증",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const R={phase:'PAGINATION'};const rows1=Array.from(document.querySelectorAll('table tbody tr'));R.page1RowCount=rows1.length;R.page1FirstRow=rows1[0]?.innerText?.substring(0,60)||'';R.page1LastRow=rows1[rows1.length-1]?.innerText?.substring(0,60)||'';const paginationBtns=Array.from(document.querySelectorAll('button,a,[role=\"button\"]')).filter(b=>{ const t=b.innerText?.trim()||'';const al=b.getAttribute('aria-label')||''; return(/^[2-9]$|^\\d{2,}$/.test(t)||/next|다음|chevron.?right||»|>/.test(t+al+b.className))&&b.offsetParent!==null;});R.paginationBtnCount=paginationBtns.length;const navPagination=document.querySelector('nav[aria-label*=\"pagination\"],nav[aria-label*=\"page\"]');if(navPagination){ const navBtns=Array.from(navPagination.querySelectorAll('button,a')).filter(b=>b.offsetParent!==null); R.navPaginationBtns=navBtns.length;}let nextBtn=paginationBtns.find(b=>{const t=(b.innerText?.trim()||'')+(b.getAttribute('aria-label')||'');return/next|다음||»|chevron.?right/i.test(t+b.className);});if(!nextBtn)nextBtn=paginationBtns.find(b=>b.innerText?.trim()==='2');if(!nextBtn&&navPagination){nextBtn=Array.from(navPagination.querySelectorAll('button,a')).find(b=>/next|다음||»/i.test((b.innerText||'')+(b.getAttribute('aria-label')||'')+b.className)&&b.offsetParent!==null);}R.hasNextBtn=!!nextBtn;if(!nextBtn){R.warn='페이지네이션 버튼 없음 (데이터 부족 또는 미구현)';R.ok=true;return JSON.stringify(R);}nextBtn.click();await w(2000);const rows2=Array.from(document.querySelectorAll('table tbody tr'));R.page2RowCount=rows2.length;R.page2FirstRow=rows2[0]?.innerText?.substring(0,60)||'';R.dataChanged=R.page1FirstRow!==R.page2FirstRow;R.hasRows=R.page2RowCount>0;if(!R.dataChanged&&R.hasRows)R.warn='⚠️ 페이지 변경 후 동일 데이터 표시 (페이지네이션 미동작 의심)';if(!R.hasRows)R.warn='⚠️ 2페이지에 데이터 없음';const prevBtn=Array.from(document.querySelectorAll('button,a,[role=\"button\"]')).find(b=>{const t=(b.innerText?.trim()||'')+(b.getAttribute('aria-label')||'');return(/prev|이전||«|chevron.?left/i.test(t+b.className)||b.innerText?.trim()==='1')&&b.offsetParent!==null;});if(!prevBtn&&navPagination){const pb=Array.from(navPagination.querySelectorAll('button,a')).find(b=>/prev|이전||«/i.test((b.innerText||'')+(b.getAttribute('aria-label')||'')+b.className)&&b.offsetParent!==null);if(pb)pb.click();}else if(prevBtn){prevBtn.click();}await w(1500);const rows3=Array.from(document.querySelectorAll('table tbody tr'));R.backToPage1=rows3[0]?.innerText?.substring(0,60)===R.page1FirstRow;if(!R.backToPage1)R.warn=(R.warn||'')+' ⚠️ 1페이지 복귀 후 데이터 불일치';R.ok=true;return JSON.stringify(R);})()",
"timeout": 20000,
"phase": "PAGINATION"
},
{
"id": 6,
"name": "[게시판 > 자유게시판] 메뉴 이동",
"action": "menu_navigate",
"level1": "게시판",
"level2": "자유게시판",
"timeout": 10000
},
{
"id": 7,
"name": "[게시판 > 자유게시판] 페이지 로드 대기",
"action": "wait",
"timeout": 3000
},
{
"id": 8,
"name": "[게시판 > 자유게시판] 테이블 로드 대기",
"action": "wait_for_table",
"timeout": 5000
},
{
"id": 9,
"name": "[게시판 > 자유게시판] 행 수/중복 검증",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const R={phase:'ROW_COUNT'};const rows=document.querySelectorAll('table tbody tr');R.rowCount=rows.length;const pageInfo=document.body.innerText.match(new RegExp('(\\\\d+)\\\\s*[-~]\\\\s*(\\\\d+)\\\\s*(of|중|개|건|/|총)\\\\s*(\\\\d+)','i'));if(pageInfo){R.pageInfoText=pageInfo[0];R.totalItems=parseInt(pageInfo[4]);}const totalBadge=Array.from(document.querySelectorAll('[class*=\"badge\"],[class*=\"count\"],[class*=\"total\"]')).find(e=>/\\d+/.test(e.innerText));if(totalBadge)R.totalBadgeText=totalBadge.innerText?.trim();const emptyRows=Array.from(rows).filter(r=>r.innerText?.trim().length===0);R.emptyRowCount=emptyRows.length;if(emptyRows.length>0)R.warn='⚠️ 빈 행 '+emptyRows.length+'개 발견 (렌더링 버그 의심)';const rowTexts=Array.from(rows).map(r=>r.innerText?.trim().substring(0,80));const duplicates=rowTexts.filter((t,i)=>rowTexts.indexOf(t)!==i);R.duplicateCount=duplicates.length;if(duplicates.length>0)R.warn=(R.warn||'')+' ⚠️ 중복 행 '+duplicates.length+'개 발견';R.ok=true;return JSON.stringify(R);})()",
"timeout": 10000,
"phase": "VERIFY"
},
{
"id": 10,
"name": "[게시판 > 자유게시판] 컬럼 정렬 검증",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const R={phase:'SORT'};const headers=Array.from(document.querySelectorAll('table thead th,table thead td,[role=\"columnheader\"]'));R.headerCount=headers.length;R.headerTexts=headers.map(h=>h.innerText?.trim()).filter(t=>t).slice(0,10);const sortableHeaders=headers.filter(h=>{ const t=h.innerText?.trim()||''; return t.length>0&&!h.querySelector('input[type=\"checkbox\"]')&&h.offsetParent!==null;});R.sortableCount=sortableHeaders.length;if(sortableHeaders.length===0){R.warn='정렬 가능한 헤더 없음';R.ok=true;return JSON.stringify(R);}const getFirstColValues=()=>Array.from(document.querySelectorAll('table tbody tr')).slice(0,5).map(r=>{const cells=r.querySelectorAll('td');return(cells[1]||cells[0])?.innerText?.trim().substring(0,30)||'';});R.beforeSort=getFirstColValues();const targetHeader=sortableHeaders.find(h=>h.innerText?.trim().length>1)||sortableHeaders[0];R.sortColumn=targetHeader.innerText?.trim();targetHeader.click();await w(1500);R.afterSort1=getFirstColValues();R.sortChanged1=JSON.stringify(R.beforeSort)!==JSON.stringify(R.afterSort1);targetHeader.click();await w(1500);R.afterSort2=getFirstColValues();R.sortChanged2=JSON.stringify(R.afterSort1)!==JSON.stringify(R.afterSort2);if(!R.sortChanged1&&!R.sortChanged2)R.warn='⚠️ 컬럼 클릭 후 정렬 변화 없음 (정렬 미구현 의심)';else if(R.sortChanged1&&!R.sortChanged2)R.warn='⚠️ 역순 정렬 미동작 (한방향만 정렬)';R.ok=true;return JSON.stringify(R);})()",
"timeout": 15000,
"phase": "SORT"
},
{
"id": 11,
"name": "[게시판 > 자유게시판] 페이지네이션 검증",
"action": "evaluate",
"script": "(async()=>{const w=ms=>new Promise(r=>setTimeout(r,ms));const R={phase:'PAGINATION'};const rows1=Array.from(document.querySelectorAll('table tbody tr'));R.page1RowCount=rows1.length;R.page1FirstRow=rows1[0]?.innerText?.substring(0,60)||'';R.page1LastRow=rows1[rows1.length-1]?.innerText?.substring(0,60)||'';const paginationBtns=Array.from(document.querySelectorAll('button,a,[role=\"button\"]')).filter(b=>{ const t=b.innerText?.trim()||'';const al=b.getAttribute('aria-label')||''; return(/^[2-9]$|^\\d{2,}$/.test(t)||/next|다음|chevron.?right||»|>/.test(t+al+b.className))&&b.offsetParent!==null;});R.paginationBtnCount=paginationBtns.length;const navPagination=document.querySelector('nav[aria-label*=\"pagination\"],nav[aria-label*=\"page\"]');if(navPagination){ const navBtns=Array.from(navPagination.querySelectorAll('button,a')).filter(b=>b.offsetParent!==null); R.navPaginationBtns=navBtns.length;}let nextBtn=paginationBtns.find(b=>{const t=(b.innerText?.trim()||'')+(b.getAttribute('aria-label')||'');return/next|다음||»|chevron.?right/i.test(t+b.className);});if(!nextBtn)nextBtn=paginationBtns.find(b=>b.innerText?.trim()==='2');if(!nextBtn&&navPagination){nextBtn=Array.from(navPagination.querySelectorAll('button,a')).find(b=>/next|다음||»/i.test((b.innerText||'')+(b.getAttribute('aria-label')||'')+b.className)&&b.offsetParent!==null);}R.hasNextBtn=!!nextBtn;if(!nextBtn){R.warn='페이지네이션 버튼 없음 (데이터 부족 또는 미구현)';R.ok=true;return JSON.stringify(R);}nextBtn.click();await w(2000);const rows2=Array.from(document.querySelectorAll('table tbody tr'));R.page2RowCount=rows2.length;R.page2FirstRow=rows2[0]?.innerText?.substring(0,60)||'';R.dataChanged=R.page1FirstRow!==R.page2FirstRow;R.hasRows=R.page2RowCount>0;if(!R.dataChanged&&R.hasRows)R.warn='⚠️ 페이지 변경 후 동일 데이터 표시 (페이지네이션 미동작 의심)';if(!R.hasRows)R.warn='⚠️ 2페이지에 데이터 없음';const prevBtn=Array.from(document.querySelectorAll('button,a,[role=\"button\"]')).find(b=>{const t=(b.innerText?.trim()||'')+(b.getAttribute('aria-label')||'');return(/prev|이전||«|chevron.?left/i.test(t+b.className)||b.innerText?.trim()==='1')&&b.offsetParent!==null;});if(!prevBtn&&navPagination){const pb=Array.from(navPagination.querySelectorAll('button,a')).find(b=>/prev|이전||«/i.test((b.innerText||'')+(b.getAttribute('aria-label')||'')+b.className)&&b.offsetParent!==null);if(pb)pb.click();}else if(prevBtn){prevBtn.click();}await w(1500);const rows3=Array.from(document.querySelectorAll('table tbody tr'));R.backToPage1=rows3[0]?.innerText?.substring(0,60)===R.page1FirstRow;if(!R.backToPage1)R.warn=(R.warn||'')+' ⚠️ 1페이지 복귀 후 데이터 불일치';R.ok=true;return JSON.stringify(R);})()",
"timeout": 20000,
"phase": "PAGINATION"
}
]
}