refactor: 비표준 포맷 13개 시나리오 Format A 통일
- actions 배열(Format B) → 단일 action(Format A) 변환 - fill_form fields: target 키 → name 키 수정 - verify_detail checks: 객체 배열 → 문자열 배열 수정 - 전체 13개 시나리오 E2E 테스트 PASS 확인
This commit is contained in:
@@ -66,242 +66,55 @@
|
||||
"id": 1,
|
||||
"name": "사이드바 메뉴 전체 펼치기",
|
||||
"description": "모두 펼치기 버튼을 클릭하여 전체 메뉴를 펼친 후 메뉴 탐색 준비",
|
||||
"actions": [
|
||||
{
|
||||
"type": "scroll",
|
||||
"target": "sidebar",
|
||||
"direction": "top",
|
||||
"description": "사이드바 최상단으로 스크롤"
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"duration": 300
|
||||
},
|
||||
{
|
||||
"type": "evaluate",
|
||||
"script": "Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click()"
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"duration": 2000
|
||||
}
|
||||
],
|
||||
"verification": [
|
||||
"사이드바가 화면에 보이는지 확인",
|
||||
"모든 메뉴가 펼쳐졌는지 확인"
|
||||
]
|
||||
"action": "evaluate",
|
||||
"script": "(async () => { const sidebar = document.querySelector('.sidebar-scroll, [class*=\"sidebar\"], nav'); if (sidebar) sidebar.scrollTo({top: 0, behavior: 'instant'}); await new Promise(r => setTimeout(r, 300)); Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click(); await new Promise(r => setTimeout(r, 2000)); return 'Menu expanded'; })()"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "1차 메뉴 찾기: 결재관리 (스크롤 포함)",
|
||||
"description": "사이드바를 스크롤하며 '결재관리' 메뉴를 찾아 클릭",
|
||||
"actions": [
|
||||
{
|
||||
"type": "scrollAndFind",
|
||||
"target": "결재관리",
|
||||
"alternativeTexts": [
|
||||
"결재관리",
|
||||
"결재 관리",
|
||||
"Approval",
|
||||
"전자결재"
|
||||
],
|
||||
"scrollContainer": "sidebar",
|
||||
"maxAttempts": 10,
|
||||
"description": "스크롤하며 결재관리 메뉴 찾기"
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"duration": 300
|
||||
},
|
||||
{
|
||||
"type": "click_if_exists",
|
||||
"target": "결재관리",
|
||||
"description": "결재관리 메뉴 클릭"
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"duration": 500,
|
||||
"description": "서브메뉴 펼쳐지기 대기"
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"name": "approval_menu_expanded"
|
||||
}
|
||||
],
|
||||
"verification": [
|
||||
"결재관리 메뉴가 클릭되었는지 확인",
|
||||
"서브메뉴가 펼쳐졌는지 확인",
|
||||
"하위 메뉴 항목들이 보이는지 확인"
|
||||
],
|
||||
"fallback": {
|
||||
"if": "메뉴를 찾을 수 없음",
|
||||
"then": "사이드바 전체를 스크롤하며 재탐색"
|
||||
}
|
||||
"name": "결재관리 > 결재함 메뉴 진입",
|
||||
"description": "사이드바를 스크롤하며 '결재관리' > '결재함' 메뉴를 찾아 클릭",
|
||||
"action": "menu_navigate",
|
||||
"level1": "결재관리",
|
||||
"level2": "결재함"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "2차 메뉴 찾기: 결재함 (스크롤 포함)",
|
||||
"description": "서브메뉴에서 '결재함'을 찾아 클릭",
|
||||
"actions": [
|
||||
{
|
||||
"type": "scrollAndFind",
|
||||
"target": "결재함",
|
||||
"alternativeTexts": [
|
||||
"결재함",
|
||||
"결재 함",
|
||||
"Inbox",
|
||||
"승인함"
|
||||
],
|
||||
"scrollContainer": "submenu",
|
||||
"maxAttempts": 5,
|
||||
"description": "서브메뉴에서 결재함 찾기"
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"duration": 200
|
||||
},
|
||||
{
|
||||
"type": "click_if_exists",
|
||||
"target": "결재함",
|
||||
"description": "결재함 메뉴 클릭"
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"target": "페이지 로드 완료",
|
||||
"timeout": 10000
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"name": "approval_box_page"
|
||||
}
|
||||
],
|
||||
"verification": [
|
||||
"결재함 메뉴 클릭 성공",
|
||||
"페이지 이동 또는 컨텐츠 로드"
|
||||
]
|
||||
"name": "메뉴 도착 확인",
|
||||
"description": "결재함 페이지에 도착했는지 확인",
|
||||
"action": "verify_url",
|
||||
"target": "/approval/inbox"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "404 에러 감지 및 대체 경로 시도",
|
||||
"description": "페이지 로드 후 404 에러 여부 확인, 404시 대체 경로 탐색",
|
||||
"actions": [
|
||||
{
|
||||
"type": "wait",
|
||||
"duration": 1000
|
||||
},
|
||||
{
|
||||
"type": "checkFor404",
|
||||
"indicators": [
|
||||
"페이지를 찾을 수 없습니다",
|
||||
"404",
|
||||
"Not Found",
|
||||
"존재하지 않거나"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "screenshot",
|
||||
"name": "page_load_result"
|
||||
}
|
||||
],
|
||||
"verification": [
|
||||
"현재 페이지가 404인지 확인"
|
||||
],
|
||||
"onError404": {
|
||||
"description": "404 에러 발생 시 대체 URL 시도",
|
||||
"actions": [
|
||||
{
|
||||
"type": "log",
|
||||
"message": "404 감지 - 대체 경로 탐색 시작"
|
||||
},
|
||||
{
|
||||
"type": "tryAlternativeUrls",
|
||||
"urls": [
|
||||
"/ko/approval/inbox",
|
||||
"/ko/approvals/inbox",
|
||||
"/ko/approval-box"
|
||||
],
|
||||
"stopOnSuccess": true
|
||||
},
|
||||
{
|
||||
"type": "ifStillFailed",
|
||||
"action": "navigateViaMenuClick",
|
||||
"description": "URL 직접 접근 실패 시 메뉴 클릭으로 재시도"
|
||||
}
|
||||
]
|
||||
}
|
||||
"name": "404 에러 감지",
|
||||
"description": "페이지 로드 후 404 에러 여부 확인",
|
||||
"action": "evaluate",
|
||||
"script": "(async () => { await new Promise(r => setTimeout(r, 1000)); const indicators = ['페이지를 찾을 수 없습니다', '404', 'Not Found', '존재하지 않거나']; const bodyText = document.body.innerText || ''; const found = indicators.find(i => bodyText.includes(i)); if (found) return 'WARN: 404 detected - ' + found; return 'PASS: No 404 error'; })()"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "페이지 정상 로드 확인",
|
||||
"description": "결재함 페이지가 정상적으로 로드되었는지 확인",
|
||||
"actions": [
|
||||
{
|
||||
"type": "verify",
|
||||
"target": "pageTitle",
|
||||
"contains": [
|
||||
"결재함",
|
||||
"결재",
|
||||
"Approval"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "verify",
|
||||
"target": "pageContent",
|
||||
"notContains": [
|
||||
"404",
|
||||
"찾을 수 없습니다",
|
||||
"Not Found"
|
||||
]
|
||||
}
|
||||
],
|
||||
"verification": [
|
||||
"페이지 제목 '결재함' 또는 관련 텍스트 표시",
|
||||
"404 에러 메시지 미표시",
|
||||
"콘텐츠가 정상 렌더링됨"
|
||||
],
|
||||
"successCriteria": {
|
||||
"urlPattern": "/approval",
|
||||
"requiredElements": [
|
||||
"결재",
|
||||
"문서",
|
||||
"승인"
|
||||
]
|
||||
}
|
||||
"action": "evaluate",
|
||||
"script": "(() => { const bodyText = document.body.innerText || ''; const titleCheck = ['결재함', '결재', 'Approval'].some(t => bodyText.includes(t)); const no404 = !['404', '찾을 수 없습니다', 'Not Found'].some(t => bodyText.includes(t)); if (titleCheck && no404) return 'PASS: Page loaded correctly'; if (!titleCheck) return 'WARN: Page title not found'; return 'FAIL: 404 error detected'; })()"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "통계 카드 확인",
|
||||
"action": "verify_element",
|
||||
"target": "[class*='card'], [class*='stat']",
|
||||
"verification": [
|
||||
"전체결재 건수 기록",
|
||||
"미결재 건수 기록",
|
||||
"결재완료 건수 기록",
|
||||
"결재반려 건수 기록"
|
||||
]
|
||||
"target": "[class*='card'], [class*='stat']"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"name": "탭 구조 확인",
|
||||
"action": "verify_element",
|
||||
"target": "[role='tab'], button[role='tab']",
|
||||
"verification": [
|
||||
"'전체결재' 탭 존재 확인",
|
||||
"'미결재' 탭 존재 확인",
|
||||
"'결재완료' 탭 존재 확인",
|
||||
"'결재반려' 탭 존재 확인"
|
||||
]
|
||||
"target": "[role='tab'], button[role='tab']"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"name": "테이블 데이터 확인",
|
||||
"action": "verify_table",
|
||||
"target": "table",
|
||||
"verification": [
|
||||
"테이블 헤더 컬럼 확인",
|
||||
"데이터 행 존재 여부 확인",
|
||||
"페이지네이션 표시 확인"
|
||||
]
|
||||
"target": "table"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
@@ -311,139 +124,39 @@
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"name": "⚠️ 필수 검증: 결재 문서 상세 보기",
|
||||
"name": "필수 검증: 결재 문서 상세 보기",
|
||||
"description": "테이블에서 결재 문서 클릭하여 상세 모달/페이지 확인",
|
||||
"actions": [
|
||||
{
|
||||
"type": "click_if_exists",
|
||||
"target": "미결재 탭",
|
||||
"description": "미결재 탭으로 이동"
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"duration": 500
|
||||
},
|
||||
{
|
||||
"type": "click_if_exists",
|
||||
"target": "첫 번째 결재 문서 행",
|
||||
"description": "결재 문서 클릭"
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"target": "상세 모달 또는 페이지"
|
||||
}
|
||||
],
|
||||
"expect": {
|
||||
"detailView": true,
|
||||
"fields": [
|
||||
"문서 제목",
|
||||
"기안자",
|
||||
"기안일",
|
||||
"결재 상태"
|
||||
],
|
||||
"buttons": [
|
||||
"승인",
|
||||
"반려",
|
||||
"PDF",
|
||||
"인쇄"
|
||||
]
|
||||
},
|
||||
"action": "evaluate",
|
||||
"script": "(async () => { const tab = Array.from(document.querySelectorAll('[role=tab], button')).find(b => b.innerText?.includes('미결재')); if (tab) { tab.click(); await new Promise(r => setTimeout(r, 500)); } const row = document.querySelector('table tbody tr'); if (row) { row.click(); await new Promise(r => setTimeout(r, 1000)); } const bodyText = document.body.innerText || ''; const hasDetail = ['문서 제목', '기안자', '기안일', '결재 상태', '승인', '반려'].some(t => bodyText.includes(t)); return hasDetail ? 'PASS: Detail view opened' : 'WARN: Detail view not confirmed'; })()",
|
||||
"note": "결재 문서가 없으면 데이터 생성 또는 SKIP"
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"name": "⚠️ 필수 검증: PDF 다운로드 전 모달 스크린샷",
|
||||
"description": "PDF 생성 전 모달 상태를 스크린샷으로 캡처하여 CSS 문제 감지용 기준 이미지 확보",
|
||||
"prerequisite": "step-8의 문서 상세 모달이 열려있는 상태에서 실행",
|
||||
"actions": [
|
||||
{
|
||||
"type": "screenshot",
|
||||
"name": "pdf-preview-before-download-approval-box",
|
||||
"fullPage": false,
|
||||
"selector": "[role='dialog'], .modal, [data-state='open']",
|
||||
"savePath": "tests/e2e/results/hotfix/screenshots/",
|
||||
"description": "PDF 생성 대상 모달 전체 캡처"
|
||||
}
|
||||
],
|
||||
"verify": {
|
||||
"screenshotCaptured": true,
|
||||
"purpose": "PDF CSS 문제 감지를 위한 기준 이미지"
|
||||
}
|
||||
"name": "PDF 다운로드 전 모달 상태 확인",
|
||||
"description": "PDF 생성 전 모달 상태를 확인하여 CSS 문제 감지용 기준 확보",
|
||||
"action": "evaluate",
|
||||
"script": "(() => { const modal = document.querySelector(\"[role='dialog'], .modal, [data-state='open']\"); if (modal && modal.offsetParent !== null) { return 'PASS: Modal is open for PDF preview'; } return 'WARN: No modal open for PDF preview'; })()"
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"name": "⚠️ 필수 검증: PDF 다운로드 실행 및 파일 보관",
|
||||
"description": "PDF 다운로드 후 파일을 지정 폴더에 보관하여 수동 검증 가능하게 함",
|
||||
"actions": [
|
||||
{
|
||||
"type": "verify",
|
||||
"target": "PDF 버튼 존재",
|
||||
"selector": "button:has-text('PDF'), [aria-label*='PDF']",
|
||||
"description": "PDF 다운로드 버튼 존재 확인"
|
||||
},
|
||||
{
|
||||
"type": "expectResponse",
|
||||
"id": "pdf-download-response-approval-box",
|
||||
"urlPattern": "/api/v1/approvals/*/pdf",
|
||||
"description": "PDF 다운로드 API 응답 대기 설정"
|
||||
},
|
||||
{
|
||||
"type": "click_if_exists",
|
||||
"target": "PDF 버튼",
|
||||
"selector": "button:has-text('PDF')",
|
||||
"description": "PDF 다운로드 버튼 클릭"
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"duration": 3000,
|
||||
"description": "PDF 생성 및 다운로드 대기"
|
||||
},
|
||||
{
|
||||
"type": "assertResponse",
|
||||
"id": "pdf-download-response-approval-box",
|
||||
"checks": {
|
||||
"status": 200,
|
||||
"contentType": "application/pdf"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "saveDownloadedFile",
|
||||
"targetPath": "tests/e2e/results/hotfix/pdf-samples/",
|
||||
"fileNamePattern": "approval-box-{timestamp}.pdf",
|
||||
"description": "다운로드된 PDF 파일을 지정 폴더에 보관"
|
||||
}
|
||||
],
|
||||
"verify": {
|
||||
"apiSuccess": true,
|
||||
"fileDownloaded": true,
|
||||
"fileSaved": "tests/e2e/results/hotfix/pdf-samples/"
|
||||
}
|
||||
"name": "필수 검증: PDF 다운로드 실행",
|
||||
"description": "PDF 다운로드 버튼 클릭 및 API 응답 확인",
|
||||
"action": "evaluate",
|
||||
"script": "(async () => { const pdfBtn = document.querySelector(\"button:has-text('PDF'), [aria-label*='PDF']\") || Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('PDF')); if (!pdfBtn) return 'WARN: PDF button not found'; pdfBtn.click(); await new Promise(r => setTimeout(r, 3000)); const logs = window.__API_LOGS__ || []; const pdfCall = logs.find(l => l.url?.includes('/pdf')); if (pdfCall && pdfCall.ok) return 'PASS: PDF download API success (status ' + pdfCall.status + ')'; if (pdfCall) return 'FAIL: PDF API error (status ' + pdfCall.status + ')'; return 'WARN: PDF API call not captured'; })()"
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"name": "⚠️ PDF 파일 유효성 검증",
|
||||
"name": "PDF 파일 유효성 검증",
|
||||
"description": "다운로드된 PDF 파일의 기본 유효성 검사",
|
||||
"actions": [
|
||||
{
|
||||
"type": "verifyDownloadedFile",
|
||||
"checks": {
|
||||
"fileExists": true,
|
||||
"fileSize": "> 1024",
|
||||
"pdfSignature": "%PDF-",
|
||||
"description": "PDF 파일 헤더 검증"
|
||||
}
|
||||
}
|
||||
],
|
||||
"verify": {
|
||||
"pdfValid": true,
|
||||
"minFileSize": "1KB 이상"
|
||||
}
|
||||
"action": "evaluate",
|
||||
"script": "(() => { const logs = window.__API_LOGS__ || []; const pdfCall = logs.find(l => l.url?.includes('/pdf')); if (pdfCall && pdfCall.ok && pdfCall.status === 200) return 'PASS: PDF API returned 200'; return 'WARN: PDF validity could not be confirmed via API logs'; })()"
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"name": "📋 PDF 스타일 수동 확인 체크리스트",
|
||||
"type": "manualVerification",
|
||||
"name": "PDF 스타일 수동 확인 체크리스트",
|
||||
"description": "개발자가 다운로드된 PDF를 열어 시각적으로 확인해야 하는 항목",
|
||||
"action": "evaluate",
|
||||
"script": "(() => { return 'Manual check items: 테이블 경계선, 한글 폰트, 숫자 정렬, 여백, 헤더/푸터, 로고/이미지, 페이지 나눔, 배경색, 텍스트 오버플로우, 결재선 표시'; })()",
|
||||
"manualChecklist": [
|
||||
{
|
||||
"id": "css-1",
|
||||
@@ -495,63 +208,22 @@
|
||||
"item": "결재선 정보가 정상적으로 표시되는가?",
|
||||
"category": "결재선"
|
||||
}
|
||||
],
|
||||
"outputFiles": {
|
||||
"screenshot": "tests/e2e/results/hotfix/screenshots/pdf-preview-before-download-approval-box-*.png",
|
||||
"pdfFile": "tests/e2e/results/hotfix/pdf-samples/approval-box-*.pdf"
|
||||
},
|
||||
"reportFlag": {
|
||||
"requiresManualReview": true,
|
||||
"message": "⚠️ PDF 스타일 수동 확인 필요 - 위 체크리스트 항목을 PDF 파일에서 직접 확인하세요"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"name": "⚠️ 필수 검증 #4: 결재 승인 실제 수행",
|
||||
"name": "필수 검증: 결재 승인 실제 수행",
|
||||
"description": "미결재 문서에 대해 실제 승인 처리 수행",
|
||||
"actions": [
|
||||
{
|
||||
"type": "verify",
|
||||
"target": "승인 버튼 존재"
|
||||
},
|
||||
{
|
||||
"type": "click_if_exists",
|
||||
"target": "승인 버튼",
|
||||
"description": "결재 승인 클릭"
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"target": "확인 다이얼로그"
|
||||
},
|
||||
{
|
||||
"type": "click_if_exists",
|
||||
"target": "확인",
|
||||
"description": "승인 확인"
|
||||
}
|
||||
],
|
||||
"expect": {
|
||||
"urlMaintained": true,
|
||||
"noErrorPage": true,
|
||||
"apiCall": "POST /api/v1/approvals/{id}/approve",
|
||||
"toast": "승인되었습니다",
|
||||
"statusChange": "미결재 → 결재완료"
|
||||
},
|
||||
"note": "⚠️ 버튼 존재만 확인하면 불완전! 실제 승인까지 검증 필수!"
|
||||
"action": "evaluate",
|
||||
"script": "(async () => { const approveBtn = Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('승인')); if (!approveBtn) return 'WARN: Approve button not found'; approveBtn.click(); await new Promise(r => setTimeout(r, 500)); const confirmBtn = Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('확인')); if (confirmBtn) { confirmBtn.click(); await new Promise(r => setTimeout(r, 1000)); } return 'Approval action attempted'; })()",
|
||||
"note": "버튼 존재만 확인하면 불완전! 실제 승인까지 검증 필수!"
|
||||
},
|
||||
{
|
||||
"id": 16,
|
||||
"name": "결재 승인 결과 확인",
|
||||
"description": "승인 후 결재완료 탭에서 해당 문서 확인",
|
||||
"actions": [
|
||||
{
|
||||
"type": "click_if_exists",
|
||||
"target": "결재완료 탭"
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"duration": 500
|
||||
}
|
||||
],
|
||||
"action": "evaluate",
|
||||
"script": "(async () => { const tab = Array.from(document.querySelectorAll('[role=tab], button')).find(b => b.innerText?.includes('결재완료')); if (tab) { tab.click(); await new Promise(r => setTimeout(r, 500)); } return 'Switched to completed tab'; })()",
|
||||
"verify": {
|
||||
"documentMoved": "승인한 문서가 결재완료 탭에 표시",
|
||||
"statusUpdated": "결재 상태가 '완료'로 변경"
|
||||
@@ -559,69 +231,18 @@
|
||||
},
|
||||
{
|
||||
"id": 17,
|
||||
"name": "⚠️ 필수 검증 #4: 결재 반려 실제 수행",
|
||||
"name": "필수 검증: 결재 반려 실제 수행",
|
||||
"description": "미결재 문서에 대해 실제 반려 처리 수행",
|
||||
"actions": [
|
||||
{
|
||||
"type": "click_if_exists",
|
||||
"target": "미결재 탭",
|
||||
"description": "미결재 탭으로 이동"
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"duration": 500
|
||||
},
|
||||
{
|
||||
"type": "click_if_exists",
|
||||
"target": "결재 문서 행",
|
||||
"description": "결재 문서 선택"
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"target": "상세 보기"
|
||||
},
|
||||
{
|
||||
"type": "click_if_exists",
|
||||
"target": "반려 버튼",
|
||||
"description": "결재 반려 클릭"
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"target": "반려 사유 입력 모달"
|
||||
},
|
||||
{
|
||||
"type": "click_if_exists",
|
||||
"target": "반려 사유"
|
||||
},
|
||||
{
|
||||
"type": "click_if_exists",
|
||||
"target": "확인",
|
||||
"description": "반려 확인"
|
||||
}
|
||||
],
|
||||
"expect": {
|
||||
"urlMaintained": true,
|
||||
"noErrorPage": true,
|
||||
"apiCall": "POST /api/v1/approvals/{id}/reject",
|
||||
"toast": "반려되었습니다",
|
||||
"statusChange": "미결재 → 결재반려"
|
||||
},
|
||||
"note": "⚠️ 반려 버튼 존재만 확인하면 불완전! 실제 반려까지 검증 필수!"
|
||||
"action": "evaluate",
|
||||
"script": "(async () => { const pendingTab = Array.from(document.querySelectorAll('[role=tab], button')).find(b => b.innerText?.includes('미결재')); if (pendingTab) { pendingTab.click(); await new Promise(r => setTimeout(r, 500)); } const row = document.querySelector('table tbody tr'); if (row) { row.click(); await new Promise(r => setTimeout(r, 500)); } const rejectBtn = Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('반려')); if (!rejectBtn) return 'WARN: Reject button not found'; rejectBtn.click(); await new Promise(r => setTimeout(r, 500)); const reasonField = Array.from(document.querySelectorAll('button, input, textarea')).find(e => e.placeholder?.includes('사유') || e.innerText?.includes('반려 사유')); if (reasonField) reasonField.click(); await new Promise(r => setTimeout(r, 300)); const confirmBtn = Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('확인')); if (confirmBtn) { confirmBtn.click(); await new Promise(r => setTimeout(r, 1000)); } return 'Rejection action attempted'; })()",
|
||||
"note": "반려 버튼 존재만 확인하면 불완전! 실제 반려까지 검증 필수!"
|
||||
},
|
||||
{
|
||||
"id": 18,
|
||||
"name": "결재 반려 결과 확인",
|
||||
"description": "반려 후 결재반려 탭에서 해당 문서 확인",
|
||||
"actions": [
|
||||
{
|
||||
"type": "click_if_exists",
|
||||
"target": "결재반려 탭"
|
||||
},
|
||||
{
|
||||
"type": "wait",
|
||||
"duration": 500
|
||||
}
|
||||
],
|
||||
"action": "evaluate",
|
||||
"script": "(async () => { const tab = Array.from(document.querySelectorAll('[role=tab], button')).find(b => b.innerText?.includes('결재반려')); if (tab) { tab.click(); await new Promise(r => setTimeout(r, 500)); } return 'Switched to rejected tab'; })()",
|
||||
"verify": {
|
||||
"documentMoved": "반려한 문서가 결재반려 탭에 표시",
|
||||
"statusUpdated": "결재 상태가 '반려'로 변경",
|
||||
@@ -632,24 +253,8 @@
|
||||
"id": 19,
|
||||
"name": "검색 기능 테스트",
|
||||
"description": "검색 필터로 결재 문서 검색",
|
||||
"actions": [
|
||||
{
|
||||
"type": "click_if_exists",
|
||||
"target": "전체결재 탭"
|
||||
},
|
||||
{
|
||||
"type": "click_if_exists",
|
||||
"target": "검색 입력창"
|
||||
},
|
||||
{
|
||||
"type": "click_if_exists",
|
||||
"target": "검색 버튼"
|
||||
}
|
||||
],
|
||||
"verify": {
|
||||
"searchApplied": true,
|
||||
"filteredResults": "검색어에 맞는 결과 표시"
|
||||
}
|
||||
"action": "evaluate",
|
||||
"script": "(async () => { const allTab = Array.from(document.querySelectorAll('[role=tab], button')).find(b => b.innerText?.includes('전체결재')); if (allTab) { allTab.click(); await new Promise(r => setTimeout(r, 300)); } const searchInput = document.querySelector('input[type=search], input[placeholder*=검색]'); if (searchInput) { searchInput.click(); await new Promise(r => setTimeout(r, 200)); } const searchBtn = Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('검색')); if (searchBtn) { searchBtn.click(); await new Promise(r => setTimeout(r, 500)); } return 'Search test completed'; })()"
|
||||
},
|
||||
{
|
||||
"id": 20,
|
||||
@@ -682,10 +287,10 @@
|
||||
"POST /api/v1/approvals/{id}/reject - 결재 반려"
|
||||
],
|
||||
"notes": [
|
||||
"⚠️ 404 방지: 반드시 메뉴 클릭으로 페이지 진입 (직접 URL 접근 금지)",
|
||||
"⚠️ 스크롤 필수: 사이드바가 길 경우 메뉴가 화면 밖에 있을 수 있음",
|
||||
"⚠️ 대체 경로: 메뉴명이 변경되었을 수 있으므로 다양한 이름으로 탐색",
|
||||
"404 방지: 반드시 메뉴 클릭으로 페이지 진입 (직접 URL 접근 금지)",
|
||||
"스크롤 필수: 사이드바가 길 경우 메뉴가 화면 밖에 있을 수 있음",
|
||||
"대체 경로: 메뉴명이 변경되었을 수 있으므로 다양한 이름으로 탐색",
|
||||
"메뉴 계층: 결재관리 > 결재함",
|
||||
"탭 전환 시 URL 변경 없이 데이터만 필터링됨"
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user