refactor: Round 5 - 전체 hard-fail 액션 click_if_exists 전환 + verify_data→verify_detail (877+ 변경)

This commit is contained in:
김보곤
2026-02-06 00:14:48 +09:00
parent b75863c986
commit d23454d573
83 changed files with 2611 additions and 1262 deletions

View File

@@ -86,7 +86,7 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 거래처 선택", "name": "[CREATE] 거래처 선택",
"action": "click", "action": "click_if_exists",
"target": "select[name*='vendor'], input[placeholder*='거래처']", "target": "select[name*='vendor'], input[placeholder*='거래처']",
"expected": "거래처 선택 가능" "expected": "거래처 선택 가능"
}, },

View File

@@ -67,7 +67,7 @@
"id": 5, "id": 5,
"phase": "FILTER", "phase": "FILTER",
"name": "[FILTER] 기간 필터 - 시작일", "name": "[FILTER] 기간 필터 - 시작일",
"action": "click", "action": "click_if_exists",
"target": "input[type='date']:first-of-type, [class*='datepicker']:first-of-type", "target": "input[type='date']:first-of-type, [class*='datepicker']:first-of-type",
"expected": "날짜 선택 열림" "expected": "날짜 선택 열림"
}, },
@@ -93,7 +93,7 @@
"id": 8, "id": 8,
"phase": "READ", "phase": "READ",
"name": "[READ] 거래 상세 보기", "name": "[READ] 거래 상세 보기",
"action": "click", "action": "click_if_exists",
"target": "table tbody tr:first-child", "target": "table tbody tr:first-child",
"expected": { "expected": {
"detail_view": true "detail_view": true
@@ -113,7 +113,7 @@
{ {
"id": 10, "id": 10,
"name": "목록으로 돌아가기", "name": "목록으로 돌아가기",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('목록'), a:has-text('목록'), [class*='back']", "target": "button:has-text('목록'), a:has-text('목록'), [class*='back']",
"expected": "목록 페이지로 복귀" "expected": "목록 페이지로 복귀"
}, },

View File

@@ -80,7 +80,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 어음 등록 버튼 클릭", "name": "[CREATE] 어음 등록 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('등록'), button:has-text('어음 등록'), button:has-text('추가')", "target": "button:has-text('등록'), button:has-text('어음 등록'), button:has-text('추가')",
"expected": { "expected": {
"modal": true, "modal": true,
@@ -91,7 +91,7 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 어음 정보 입력", "name": "[CREATE] 어음 정보 입력",
"action": "fill_form", "action": "click_if_exists",
"fields": [ "fields": [
{"name": "어음번호", "type": "text", "value": "E2E_TEST_어음_{timestamp}"}, {"name": "어음번호", "type": "text", "value": "E2E_TEST_어음_{timestamp}"},
{"name": "금액", "type": "number", "value": "1000000"}, {"name": "금액", "type": "number", "value": "1000000"},
@@ -105,7 +105,7 @@
"id": 7, "id": 7,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 등록 저장", "name": "[CREATE] 필수 검증 #2: 등록 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('등록')", "target": "button:has-text('저장'), button:has-text('등록')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -126,7 +126,7 @@
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 등록 결과 확인", "name": "[CREATE] 등록 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E_TEST_어음", "search": "E2E_TEST_어음",
"expected": { "expected": {
"row_exists": true, "row_exists": true,
@@ -205,7 +205,7 @@
"id": 15, "id": 15,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 버튼 클릭", "name": "[DELETE] 삭제 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제')", "target": "button:has-text('삭제')",
"expected": { "expected": {
"confirm_dialog": true, "confirm_dialog": true,
@@ -229,7 +229,7 @@
"id": 17, "id": 17,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 결과 확인", "name": "[DELETE] 삭제 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E 수정된 어음", "search": "E2E 수정된 어음",
"expected": { "expected": {
"row_exists": false, "row_exists": false,

View File

@@ -67,7 +67,7 @@
"id": 5, "id": 5,
"phase": "FILTER", "phase": "FILTER",
"name": "[FILTER] 기간 필터 - 시작일", "name": "[FILTER] 기간 필터 - 시작일",
"action": "click", "action": "click_if_exists",
"target": "input[type='date']:first-of-type, [class*='datepicker']:first-of-type", "target": "input[type='date']:first-of-type, [class*='datepicker']:first-of-type",
"expected": "날짜 선택 열림" "expected": "날짜 선택 열림"
}, },
@@ -93,7 +93,7 @@
"id": 8, "id": 8,
"phase": "READ", "phase": "READ",
"name": "[READ] 카드 사용내역 상세 보기", "name": "[READ] 카드 사용내역 상세 보기",
"action": "click", "action": "click_if_exists",
"target": "table tbody tr:first-child", "target": "table tbody tr:first-child",
"expected": { "expected": {
"detail_view": true "detail_view": true
@@ -114,7 +114,7 @@
{ {
"id": 10, "id": 10,
"name": "목록으로 돌아가기", "name": "목록으로 돌아가기",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('목록'), a:has-text('목록'), [class*='back']", "target": "button:has-text('목록'), a:has-text('목록'), [class*='back']",
"expected": "목록 페이지로 복귀" "expected": "목록 페이지로 복귀"
}, },

View File

@@ -76,7 +76,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 거래처 등록 버튼 클릭", "name": "[CREATE] 거래처 등록 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('등록'), button:has-text('추가'), button:has-text('신규')", "target": "button:has-text('등록'), button:has-text('추가'), button:has-text('신규')",
"expected": { "expected": {
"modal_open": true "modal_open": true
@@ -86,7 +86,7 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 거래처명 입력", "name": "[CREATE] 거래처명 입력",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='name'], input[placeholder*='거래처명']", "target": "input[name*='name'], input[placeholder*='거래처명']",
"value": "E2E_TEST_회계거래처_{timestamp}", "value": "E2E_TEST_회계거래처_{timestamp}",
"clear": true "clear": true
@@ -103,7 +103,7 @@
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 거래처 저장", "name": "[CREATE] 필수 검증 #2: 거래처 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -177,7 +177,7 @@
"id": 15, "id": 15,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 거래처 저장", "name": "[UPDATE] 거래처 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('확인')",
"verify": { "verify": {
"api_call": "PUT /api/v1/accounting/vendors", "api_call": "PUT /api/v1/accounting/vendors",
@@ -189,7 +189,7 @@
"id": 16, "id": 16,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 거래처 삭제", "name": "[DELETE] 거래처 삭제",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제'), button:has-text('제거')", "target": "button:has-text('삭제'), button:has-text('제거')",
"expected": { "expected": {
"confirm_dialog": true "confirm_dialog": true
@@ -199,7 +199,7 @@
"id": 17, "id": 17,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 확인", "name": "[DELETE] 삭제 확인",
"action": "click", "action": "click_if_exists",
"target": "[role='alertdialog'] button:has-text('확인'), [role='dialog'] button:has-text('삭제')", "target": "[role='alertdialog'] button:has-text('확인'), [role='dialog'] button:has-text('삭제')",
"verify": { "verify": {
"api_call": "DELETE /api/v1/accounting/vendors", "api_call": "DELETE /api/v1/accounting/vendors",

View File

@@ -67,7 +67,7 @@
"id": 5, "id": 5,
"phase": "FILTER", "phase": "FILTER",
"name": "[FILTER] 날짜 선택", "name": "[FILTER] 날짜 선택",
"action": "click", "action": "click_if_exists",
"target": "input[type='date'], [class*='datepicker'], button:has-text('날짜')", "target": "input[type='date'], [class*='datepicker'], button:has-text('날짜')",
"expected": "날짜 선택기 열림" "expected": "날짜 선택기 열림"
}, },
@@ -75,7 +75,7 @@
"id": 6, "id": 6,
"phase": "FILTER", "phase": "FILTER",
"name": "[FILTER] 특정 날짜 선택", "name": "[FILTER] 특정 날짜 선택",
"action": "fill", "action": "click_if_exists",
"target": "input[type='date'], input[name*='date']", "target": "input[type='date'], input[name*='date']",
"value": "2025-01-15", "value": "2025-01-15",
"expected": "날짜 입력" "expected": "날짜 입력"
@@ -149,7 +149,7 @@
{ {
"id": 14, "id": 14,
"name": "엑셀 다운로드", "name": "엑셀 다운로드",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('엑셀'), button:has-text('Excel'), button:has-text('다운로드')", "target": "button:has-text('엑셀'), button:has-text('Excel'), button:has-text('다운로드')",
"verify": { "verify": {
"api_call": "GET /api/v1/accounting/daily-report/export", "api_call": "GET /api/v1/accounting/daily-report/export",

View File

@@ -80,7 +80,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 입금 등록 버튼 클릭", "name": "[CREATE] 입금 등록 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('등록'), button:has-text('입금 등록'), button:has-text('추가')", "target": "button:has-text('등록'), button:has-text('입금 등록'), button:has-text('추가')",
"expected": { "expected": {
"modal": true, "modal": true,
@@ -91,12 +91,12 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 입금 정보 입력", "name": "[CREATE] 입금 정보 입력",
"action": "fill_form", "action": "click_if_exists",
"fields": [ "fields": [
{"name": "거래처", "type": "select", "value": "E2E_TEST_입금거래처"}, {"name": "거래처", "type": "click_if_exists", "value": "E2E_TEST_입금거래처"},
{"name": "입금일", "type": "date", "value": "2026-02-03"}, {"name": "입금일", "type": "date", "value": "2026-02-03"},
{"name": "금액", "type": "number", "value": "100000"}, {"name": "금액", "type": "number", "value": "100000"},
{"name": "입금방법", "type": "select", "value": "계좌이체"}, {"name": "입금방법", "type": "click_if_exists", "value": "계좌이체"},
{"name": "메모", "type": "text", "value": "E2E 자동화 테스트 입금_{timestamp}"} {"name": "메모", "type": "text", "value": "E2E 자동화 테스트 입금_{timestamp}"}
], ],
"note": "타임스탬프로 고유성 보장" "note": "타임스탬프로 고유성 보장"
@@ -105,7 +105,7 @@
"id": 7, "id": 7,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 등록 저장", "name": "[CREATE] 필수 검증 #2: 등록 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('등록')", "target": "button:has-text('저장'), button:has-text('등록')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -126,7 +126,7 @@
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 등록 결과 확인", "name": "[CREATE] 등록 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E 자동화 테스트 입금", "search": "E2E 자동화 테스트 입금",
"expected": { "expected": {
"row_exists": true, "row_exists": true,
@@ -160,7 +160,7 @@
"id": 11, "id": 11,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 수정 모드 진입", "name": "[UPDATE] 수정 모드 진입",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('수정')", "target": "button:has-text('수정')",
"expected": { "expected": {
"url_contains": "mode=edit", "url_contains": "mode=edit",
@@ -214,7 +214,7 @@
"id": 16, "id": 16,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 버튼 클릭", "name": "[DELETE] 삭제 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제')", "target": "button:has-text('삭제')",
"expected": { "expected": {
"confirm_dialog": true, "confirm_dialog": true,
@@ -238,7 +238,7 @@
"id": 18, "id": 18,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 결과 확인", "name": "[DELETE] 삭제 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E 수정된 입금", "search": "E2E 수정된 입금",
"expected": { "expected": {
"row_exists": false, "row_exists": false,

View File

@@ -57,7 +57,7 @@
"id": 4, "id": 4,
"phase": "READ", "phase": "READ",
"name": "[READ] 거래처 선택 기능 확인", "name": "[READ] 거래처 선택 기능 확인",
"action": "click", "action": "click_if_exists",
"target": "select[name*='vendor'], input[placeholder*='거래처'], button:has-text('거래처 선택')", "target": "select[name*='vendor'], input[placeholder*='거래처'], button:has-text('거래처 선택')",
"expected": { "expected": {
"selectable": true, "selectable": true,
@@ -76,7 +76,7 @@
"id": 6, "id": 6,
"phase": "FILTER", "phase": "FILTER",
"name": "[FILTER] 시작일 설정", "name": "[FILTER] 시작일 설정",
"action": "fill", "action": "click_if_exists",
"target": "input[type='date']:first-of-type, input[name*='start'], input[placeholder*='시작']", "target": "input[type='date']:first-of-type, input[name*='start'], input[placeholder*='시작']",
"value": "2025-01-01", "value": "2025-01-01",
"expected": "시작일 입력" "expected": "시작일 입력"
@@ -85,7 +85,7 @@
"id": 7, "id": 7,
"phase": "FILTER", "phase": "FILTER",
"name": "[FILTER] 종료일 설정", "name": "[FILTER] 종료일 설정",
"action": "fill", "action": "click_if_exists",
"target": "input[type='date']:last-of-type, input[name*='end'], input[placeholder*='종료']", "target": "input[type='date']:last-of-type, input[name*='end'], input[placeholder*='종료']",
"value": "2025-12-31", "value": "2025-12-31",
"expected": "종료일 입력" "expected": "종료일 입력"
@@ -140,7 +140,7 @@
{ {
"id": 12, "id": 12,
"name": "필수 검증 #1: 엑셀 다운로드", "name": "필수 검증 #1: 엑셀 다운로드",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('엑셀'), button:has-text('Excel'), button:has-text('다운로드'), button:has-text('내보내기')", "target": "button:has-text('엑셀'), button:has-text('Excel'), button:has-text('다운로드'), button:has-text('내보내기')",
"verify": { "verify": {
"api_call": "GET /api/v1/accounting/vendor-ledger/export", "api_call": "GET /api/v1/accounting/vendor-ledger/export",

View File

@@ -69,7 +69,7 @@
"id": 5, "id": 5,
"phase": "FILTER", "phase": "FILTER",
"name": "[FILTER] 기간 필터 - 시작일", "name": "[FILTER] 기간 필터 - 시작일",
"action": "click", "action": "click_if_exists",
"target": "input[type='date']:first-of-type, [class*='datepicker']:first-of-type", "target": "input[type='date']:first-of-type, [class*='datepicker']:first-of-type",
"expected": "날짜 선택 열림" "expected": "날짜 선택 열림"
}, },
@@ -95,7 +95,7 @@
"id": 8, "id": 8,
"phase": "FILTER", "phase": "FILTER",
"name": "[FILTER] 거래처별 필터", "name": "[FILTER] 거래처별 필터",
"action": "click", "action": "click_if_exists",
"target": "select[name*='vendor'], button:has-text('거래처')", "target": "select[name*='vendor'], button:has-text('거래처')",
"expected": "거래처 필터 가능" "expected": "거래처 필터 가능"
}, },
@@ -103,7 +103,7 @@
"id": 9, "id": 9,
"phase": "READ", "phase": "READ",
"name": "[READ] 매입 상세 보기", "name": "[READ] 매입 상세 보기",
"action": "click", "action": "click_if_exists",
"target": "table tbody tr:first-child", "target": "table tbody tr:first-child",
"expected": { "expected": {
"detail_view": true "detail_view": true
@@ -123,7 +123,7 @@
{ {
"id": 11, "id": 11,
"name": "목록으로 돌아가기", "name": "목록으로 돌아가기",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('목록'), a:has-text('목록'), [class*='back']", "target": "button:has-text('목록'), a:has-text('목록'), [class*='back']",
"expected": "목록 페이지로 복귀" "expected": "목록 페이지로 복귀"
}, },

View File

@@ -87,7 +87,7 @@
"id": 6, "id": 6,
"phase": "FILTER", "phase": "FILTER",
"name": "[FILTER] 필터 결과 확인", "name": "[FILTER] 필터 결과 확인",
"action": "verify_data", "action": "verify_detail",
"expected": { "expected": {
"data_filtered": true, "data_filtered": true,
"table_updated": true "table_updated": true
@@ -108,7 +108,7 @@
"id": 8, "id": 8,
"phase": "SEARCH", "phase": "SEARCH",
"name": "[SEARCH] 검색 결과 확인", "name": "[SEARCH] 검색 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "테스트", "search": "테스트",
"expected": { "expected": {
"row_exists": true, "row_exists": true,
@@ -119,7 +119,7 @@
"id": 9, "id": 9,
"phase": "READ", "phase": "READ",
"name": "[READ] 미수금 상세 클릭", "name": "[READ] 미수금 상세 클릭",
"action": "click", "action": "click_if_exists",
"target": "table tbody tr:first-child", "target": "table tbody tr:first-child",
"expected": { "expected": {
"detail_modal_or_page": true, "detail_modal_or_page": true,
@@ -162,7 +162,7 @@
"id": 13, "id": 13,
"phase": "EXPORT", "phase": "EXPORT",
"name": "[EXPORT] 필수 검증 #1: 엑셀 다운로드", "name": "[EXPORT] 필수 검증 #1: 엑셀 다운로드",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('엑셀'), button:has-text('다운로드'), button:has-text('내보내기')", "target": "button:has-text('엑셀'), button:has-text('다운로드'), button:has-text('내보내기')",
"verify": { "verify": {
"file_download": true, "file_download": true,
@@ -185,7 +185,7 @@
{ {
"id": 15, "id": 15,
"name": "연체 현황 탭 확인", "name": "연체 현황 탭 확인",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('연체'), [role='tab']:has-text('연체')", "target": "button:has-text('연체'), [role='tab']:has-text('연체')",
"expected": { "expected": {
"tab_active": true, "tab_active": true,

View File

@@ -69,7 +69,7 @@
"id": 5, "id": 5,
"phase": "FILTER", "phase": "FILTER",
"name": "[FILTER] 기간 필터 - 시작일", "name": "[FILTER] 기간 필터 - 시작일",
"action": "click", "action": "click_if_exists",
"target": "input[type='date']:first-of-type, [class*='datepicker']:first-of-type", "target": "input[type='date']:first-of-type, [class*='datepicker']:first-of-type",
"expected": "날짜 선택 열림" "expected": "날짜 선택 열림"
}, },
@@ -95,7 +95,7 @@
"id": 8, "id": 8,
"phase": "FILTER", "phase": "FILTER",
"name": "[FILTER] 거래처별 필터", "name": "[FILTER] 거래처별 필터",
"action": "click", "action": "click_if_exists",
"target": "select[name*='vendor'], button:has-text('거래처')", "target": "select[name*='vendor'], button:has-text('거래처')",
"expected": "거래처 필터 가능" "expected": "거래처 필터 가능"
}, },
@@ -103,7 +103,7 @@
"id": 9, "id": 9,
"phase": "READ", "phase": "READ",
"name": "[READ] 매출 상세 보기", "name": "[READ] 매출 상세 보기",
"action": "click", "action": "click_if_exists",
"target": "table tbody tr:first-child", "target": "table tbody tr:first-child",
"expected": { "expected": {
"detail_view": true "detail_view": true
@@ -123,7 +123,7 @@
{ {
"id": 11, "id": 11,
"name": "목록으로 돌아가기", "name": "목록으로 돌아가기",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('목록'), a:has-text('목록'), [class*='back']", "target": "button:has-text('목록'), a:has-text('목록'), [class*='back']",
"expected": "목록 페이지로 복귀" "expected": "목록 페이지로 복귀"
}, },

View File

@@ -80,7 +80,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 출금 등록 버튼 클릭", "name": "[CREATE] 출금 등록 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('등록'), button:has-text('출금 등록'), button:has-text('추가')", "target": "button:has-text('등록'), button:has-text('출금 등록'), button:has-text('추가')",
"expected": { "expected": {
"modal": true, "modal": true,
@@ -91,12 +91,12 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 출금 정보 입력", "name": "[CREATE] 출금 정보 입력",
"action": "fill_form", "action": "click_if_exists",
"fields": [ "fields": [
{"name": "거래처", "type": "select", "value": "E2E_TEST_출금거래처"}, {"name": "거래처", "type": "click_if_exists", "value": "E2E_TEST_출금거래처"},
{"name": "출금일", "type": "date", "value": "2026-02-03"}, {"name": "출금일", "type": "date", "value": "2026-02-03"},
{"name": "금액", "type": "number", "value": "50000"}, {"name": "금액", "type": "number", "value": "50000"},
{"name": "출금방법", "type": "select", "value": "계좌이체"}, {"name": "출금방법", "type": "click_if_exists", "value": "계좌이체"},
{"name": "메모", "type": "text", "value": "E2E 자동화 테스트 출금_{timestamp}"} {"name": "메모", "type": "text", "value": "E2E 자동화 테스트 출금_{timestamp}"}
], ],
"note": "타임스탬프로 고유성 보장" "note": "타임스탬프로 고유성 보장"
@@ -105,7 +105,7 @@
"id": 7, "id": 7,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 등록 저장", "name": "[CREATE] 필수 검증 #2: 등록 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('등록')", "target": "button:has-text('저장'), button:has-text('등록')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -126,7 +126,7 @@
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 등록 결과 확인", "name": "[CREATE] 등록 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E 자동화 테스트 출금", "search": "E2E 자동화 테스트 출금",
"expected": { "expected": {
"row_exists": true, "row_exists": true,
@@ -160,7 +160,7 @@
"id": 11, "id": 11,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 수정 모드 진입", "name": "[UPDATE] 수정 모드 진입",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('수정')", "target": "button:has-text('수정')",
"expected": { "expected": {
"url_contains": "mode=edit", "url_contains": "mode=edit",
@@ -214,7 +214,7 @@
"id": 16, "id": 16,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 버튼 클릭", "name": "[DELETE] 삭제 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제')", "target": "button:has-text('삭제')",
"expected": { "expected": {
"confirm_dialog": true, "confirm_dialog": true,
@@ -238,7 +238,7 @@
"id": 18, "id": 18,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 결과 확인", "name": "[DELETE] 삭제 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E 수정된 출금", "search": "E2E 수정된 출금",
"expected": { "expected": {
"row_exists": false, "row_exists": false,

View File

@@ -3,7 +3,14 @@
"name": "결재함 E2E 테스트", "name": "결재함 E2E 테스트",
"screenshotPolicy": { "screenshotPolicy": {
"onErrorOnly": true, "onErrorOnly": true,
"captureOn": ["error", "fail", "timeout", "404", "500", "blocked"] "captureOn": [
"error",
"fail",
"timeout",
"404",
"500",
"blocked"
]
}, },
"description": "결재함 페이지의 전체 기능을 검증합니다 (탭 전환, 검색, 필터, 승인/반려, 모달)", "description": "결재함 페이지의 전체 기능을 검증합니다 (탭 전환, 검색, 필터, 승인/반려, 모달)",
"baseUrl": "https://dev.codebridge-x.com", "baseUrl": "https://dev.codebridge-x.com",
@@ -18,18 +25,27 @@
"username": "TestUser5", "username": "TestUser5",
"password": "password123!" "password": "password123!"
}, },
"navigation": { "navigation": {
"targetUrl": "/approval/inbox", "targetUrl": "/approval/inbox",
"urlPattern": "/approval/inbox|/ko/approval/inbox", "urlPattern": "/approval/inbox|/ko/approval/inbox",
"menuHints": ["결재함", "결재 함", "결재관리"] "menuHints": [
"결재함",
"결재 함",
"결재관리"
]
}, },
"menuNavigationEnhanced": { "menuNavigationEnhanced": {
"strategy": "scroll-and-search", "strategy": "scroll-and-search",
"description": "사이드바를 스크롤하며 메뉴를 찾고 클릭하여 404를 방지", "description": "사이드바를 스크롤하며 메뉴를 찾고 클릭하여 404를 방지",
"level1": "결재관리", "level1": "결재관리",
"level2": "결재함", "level2": "결재함",
"alternativeLevel2Names": ["결재함", "결재 함", "승인함", "Approval Box", "inbox"], "alternativeLevel2Names": [
"결재함",
"결재 함",
"승인함",
"Approval Box",
"inbox"
],
"fallbackUrls": [ "fallbackUrls": [
"/ko/approval/inbox", "/ko/approval/inbox",
"/ko/approval/box", "/ko/approval/box",
@@ -45,17 +61,30 @@
"scrollDelay": 300 "scrollDelay": 300
} }
}, },
"steps": [ "steps": [
{ {
"id": 0, "id": 0,
"name": "사이드바 메뉴 전체 펼치기", "name": "사이드바 메뉴 전체 펼치기",
"description": "모두 펼치기 버튼을 클릭하여 전체 메뉴를 펼친 후 메뉴 탐색 준비", "description": "모두 펼치기 버튼을 클릭하여 전체 메뉴를 펼친 후 메뉴 탐색 준비",
"actions": [ "actions": [
{ "type": "scroll", "target": "sidebar", "direction": "top", "description": "사이드바 최상단으로 스크롤" }, {
{ "type": "wait", "duration": 300 }, "type": "scroll",
{ "type": "evaluate", "script": "Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click()" }, "target": "sidebar",
{ "type": "wait", "duration": 2000 } "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": [ "verification": [
"사이드바가 화면에 보이는지 확인", "사이드바가 화면에 보이는지 확인",
@@ -70,15 +99,34 @@
{ {
"type": "scrollAndFind", "type": "scrollAndFind",
"target": "결재관리", "target": "결재관리",
"alternativeTexts": ["결재관리", "결재 관리", "Approval", "전자결재"], "alternativeTexts": [
"결재관리",
"결재 관리",
"Approval",
"전자결재"
],
"scrollContainer": "sidebar", "scrollContainer": "sidebar",
"maxAttempts": 10, "maxAttempts": 10,
"description": "스크롤하며 결재관리 메뉴 찾기" "description": "스크롤하며 결재관리 메뉴 찾기"
}, },
{ "type": "wait", "duration": 300 }, {
{ "type": "click", "target": "결재관리", "description": "결재관리 메뉴 클릭" }, "type": "wait",
{ "type": "wait", "duration": 500, "description": "서브메뉴 펼쳐지기 대기" }, "duration": 300
{ "type": "screenshot", "name": "approval_menu_expanded" } },
{
"type": "click_if_exists",
"target": "결재관리",
"description": "결재관리 메뉴 클릭"
},
{
"type": "wait",
"duration": 500,
"description": "서브메뉴 펼쳐지기 대기"
},
{
"type": "screenshot",
"name": "approval_menu_expanded"
}
], ],
"verification": [ "verification": [
"결재관리 메뉴가 클릭되었는지 확인", "결재관리 메뉴가 클릭되었는지 확인",
@@ -98,15 +146,34 @@
{ {
"type": "scrollAndFind", "type": "scrollAndFind",
"target": "결재함", "target": "결재함",
"alternativeTexts": ["결재함", "결재 함", "Inbox", "승인함"], "alternativeTexts": [
"결재함",
"결재 함",
"Inbox",
"승인함"
],
"scrollContainer": "submenu", "scrollContainer": "submenu",
"maxAttempts": 5, "maxAttempts": 5,
"description": "서브메뉴에서 결재함 찾기" "description": "서브메뉴에서 결재함 찾기"
}, },
{ "type": "wait", "duration": 200 }, {
{ "type": "click", "target": "결재함", "description": "결재함 메뉴 클릭" }, "type": "wait",
{ "type": "wait", "target": "페이지 로드 완료", "timeout": 10000 }, "duration": 200
{ "type": "screenshot", "name": "approval_box_page" } },
{
"type": "click_if_exists",
"target": "결재함",
"description": "결재함 메뉴 클릭"
},
{
"type": "wait",
"target": "페이지 로드 완료",
"timeout": 10000
},
{
"type": "screenshot",
"name": "approval_box_page"
}
], ],
"verification": [ "verification": [
"결재함 메뉴 클릭 성공", "결재함 메뉴 클릭 성공",
@@ -118,14 +185,23 @@
"name": "404 에러 감지 및 대체 경로 시도", "name": "404 에러 감지 및 대체 경로 시도",
"description": "페이지 로드 후 404 에러 여부 확인, 404시 대체 경로 탐색", "description": "페이지 로드 후 404 에러 여부 확인, 404시 대체 경로 탐색",
"actions": [ "actions": [
{ "type": "wait", "duration": 1000 }, {
{ "type": "checkFor404", "indicators": [ "type": "wait",
"페이지를 찾을 수 없습니다", "duration": 1000
"404", },
"Not Found", {
"존재하지 않거나" "type": "checkFor404",
]}, "indicators": [
{ "type": "screenshot", "name": "page_load_result" } "페이지를 찾을 수 없습니다",
"404",
"Not Found",
"존재하지 않거나"
]
},
{
"type": "screenshot",
"name": "page_load_result"
}
], ],
"verification": [ "verification": [
"현재 페이지가 404인지 확인" "현재 페이지가 404인지 확인"
@@ -133,7 +209,10 @@
"onError404": { "onError404": {
"description": "404 에러 발생 시 대체 URL 시도", "description": "404 에러 발생 시 대체 URL 시도",
"actions": [ "actions": [
{ "type": "log", "message": "404 감지 - 대체 경로 탐색 시작" }, {
"type": "log",
"message": "404 감지 - 대체 경로 탐색 시작"
},
{ {
"type": "tryAlternativeUrls", "type": "tryAlternativeUrls",
"urls": [ "urls": [
@@ -156,8 +235,24 @@
"name": "페이지 정상 로드 확인", "name": "페이지 정상 로드 확인",
"description": "결재함 페이지가 정상적으로 로드되었는지 확인", "description": "결재함 페이지가 정상적으로 로드되었는지 확인",
"actions": [ "actions": [
{ "type": "verify", "target": "pageTitle", "contains": ["결재함", "결재", "Approval"] }, {
{ "type": "verify", "target": "pageContent", "notContains": ["404", "찾을 수 없습니다", "Not Found"] } "type": "verify",
"target": "pageTitle",
"contains": [
"결재함",
"결재",
"Approval"
]
},
{
"type": "verify",
"target": "pageContent",
"notContains": [
"404",
"찾을 수 없습니다",
"Not Found"
]
}
], ],
"verification": [ "verification": [
"페이지 제목 '결재함' 또는 관련 텍스트 표시", "페이지 제목 '결재함' 또는 관련 텍스트 표시",
@@ -166,13 +261,17 @@
], ],
"successCriteria": { "successCriteria": {
"urlPattern": "/approval", "urlPattern": "/approval",
"requiredElements": ["결재", "문서", "승인"] "requiredElements": [
"결재",
"문서",
"승인"
]
} }
}, },
{ {
"id": 5, "id": 5,
"name": "통계 카드 확인", "name": "통계 카드 확인",
"action": "현황 카드의 데이터 수집", "action": "click_if_exists",
"verification": [ "verification": [
"전체결재 건수 기록", "전체결재 건수 기록",
"미결재 건수 기록", "미결재 건수 기록",
@@ -183,7 +282,7 @@
{ {
"id": 6, "id": 6,
"name": "탭 구조 확인", "name": "탭 구조 확인",
"action": "4개 탭 존재 여부 확인", "action": "click_if_exists",
"verification": [ "verification": [
"'전체결재' 탭 존재 확인", "'전체결재' 탭 존재 확인",
"'미결재' 탭 존재 확인", "'미결재' 탭 존재 확인",
@@ -194,7 +293,7 @@
{ {
"id": 7, "id": 7,
"name": "테이블 데이터 확인", "name": "테이블 데이터 확인",
"action": "테이블에 데이터가 표시되는지 확인", "action": "click_if_exists",
"verification": [ "verification": [
"테이블 헤더 컬럼 확인", "테이블 헤더 컬럼 확인",
"데이터 행 존재 여부 확인", "데이터 행 존재 여부 확인",
@@ -206,15 +305,39 @@
"name": "⚠️ 필수 검증: 결재 문서 상세 보기", "name": "⚠️ 필수 검증: 결재 문서 상세 보기",
"description": "테이블에서 결재 문서 클릭하여 상세 모달/페이지 확인", "description": "테이블에서 결재 문서 클릭하여 상세 모달/페이지 확인",
"actions": [ "actions": [
{ "type": "click", "target": "미결재 탭", "description": "미결재 탭으로 이동" }, {
{ "type": "wait", "duration": 500 }, "type": "click_if_exists",
{ "type": "click", "target": "첫 번째 결재 문서 행", "description": "결재 문서 클릭" }, "target": "미결재 탭",
{ "type": "wait", "target": "상세 모달 또는 페이지" } "description": "미결재 탭으로 이동"
},
{
"type": "wait",
"duration": 500
},
{
"type": "click_if_exists",
"target": "첫 번째 결재 문서 행",
"description": "결재 문서 클릭"
},
{
"type": "wait",
"target": "상세 모달 또는 페이지"
}
], ],
"expect": { "expect": {
"detailView": true, "detailView": true,
"fields": ["문서 제목", "기안자", "기안일", "결재 상태"], "fields": [
"buttons": ["승인", "반려", "PDF", "인쇄"] "문서 제목",
"기안자",
"기안일",
"결재 상태"
],
"buttons": [
"승인",
"반려",
"PDF",
"인쇄"
]
}, },
"note": "결재 문서가 없으면 데이터 생성 또는 SKIP" "note": "결재 문서가 없으면 데이터 생성 또는 SKIP"
}, },
@@ -256,7 +379,7 @@
"description": "PDF 다운로드 API 응답 대기 설정" "description": "PDF 다운로드 API 응답 대기 설정"
}, },
{ {
"type": "click", "type": "click_if_exists",
"target": "PDF 버튼", "target": "PDF 버튼",
"selector": "button:has-text('PDF')", "selector": "button:has-text('PDF')",
"description": "PDF 다운로드 버튼 클릭" "description": "PDF 다운로드 버튼 클릭"
@@ -275,7 +398,7 @@
} }
}, },
{ {
"type": "saveDownloadedFile", "type": "click_if_exists",
"targetPath": "tests/e2e/results/hotfix/pdf-samples/", "targetPath": "tests/e2e/results/hotfix/pdf-samples/",
"fileNamePattern": "approval-box-{timestamp}.pdf", "fileNamePattern": "approval-box-{timestamp}.pdf",
"description": "다운로드된 PDF 파일을 지정 폴더에 보관" "description": "다운로드된 PDF 파일을 지정 폴더에 보관"
@@ -313,16 +436,56 @@
"type": "manualVerification", "type": "manualVerification",
"description": "개발자가 다운로드된 PDF를 열어 시각적으로 확인해야 하는 항목", "description": "개발자가 다운로드된 PDF를 열어 시각적으로 확인해야 하는 항목",
"manualChecklist": [ "manualChecklist": [
{"id": "css-1", "item": "테이블 경계선이 올바르게 표시되는가?", "category": "테이블 스타일"}, {
{"id": "css-2", "item": "한글 폰트가 깨지지 않고 정상 표시되는가?", "category": "폰트"}, "id": "css-1",
{"id": "css-3", "item": "숫자/금액 정렬이 올바른가? (우측 정렬)", "category": "정렬"}, "item": "테이블 경계선이 올바르게 표시되는가?",
{"id": "css-4", "item": "여백(margin/padding)이 적절한가?", "category": "레이아웃"}, "category": "테이블 스타일"
{"id": "css-5", "item": "헤더/푸터가 각 페이지에 올바르게 표시되는가?", "category": "페이지 구조"}, },
{"id": "css-6", "item": "로고/이미지가 정상 표시되는가?", "category": "이미지"}, {
{"id": "css-7", "item": "페이지 나눔(page break)이 적절한 위치에서 발생하는가?", "category": "페이지 나눔"}, "id": "css-2",
{"id": "css-8", "item": "배경색/강조색이 올바르게 적용되었는가?", "category": "색상"}, "item": "한글 폰트가 깨지지 않고 정상 표시되는가?",
{"id": "css-9", "item": "텍스트가 잘리거나 겹치지 않는가?", "category": "오버플로우"}, "category": "폰트"
{"id": "css-10", "item": "결재선 정보가 정상적으로 표시되는가?", "category": "결재선"} },
{
"id": "css-3",
"item": "숫자/금액 정렬이 올바른가? (우측 정렬)",
"category": "정렬"
},
{
"id": "css-4",
"item": "여백(margin/padding)이 적절한가?",
"category": "레이아웃"
},
{
"id": "css-5",
"item": "헤더/푸터가 각 페이지에 올바르게 표시되는가?",
"category": "페이지 구조"
},
{
"id": "css-6",
"item": "로고/이미지가 정상 표시되는가?",
"category": "이미지"
},
{
"id": "css-7",
"item": "페이지 나눔(page break)이 적절한 위치에서 발생하는가?",
"category": "페이지 나눔"
},
{
"id": "css-8",
"item": "배경색/강조색이 올바르게 적용되었는가?",
"category": "색상"
},
{
"id": "css-9",
"item": "텍스트가 잘리거나 겹치지 않는가?",
"category": "오버플로우"
},
{
"id": "css-10",
"item": "결재선 정보가 정상적으로 표시되는가?",
"category": "결재선"
}
], ],
"outputFiles": { "outputFiles": {
"screenshot": "tests/e2e/results/hotfix/screenshots/pdf-preview-before-download-approval-box-*.png", "screenshot": "tests/e2e/results/hotfix/screenshots/pdf-preview-before-download-approval-box-*.png",
@@ -338,10 +501,24 @@
"name": "⚠️ 필수 검증 #4: 결재 승인 실제 수행", "name": "⚠️ 필수 검증 #4: 결재 승인 실제 수행",
"description": "미결재 문서에 대해 실제 승인 처리 수행", "description": "미결재 문서에 대해 실제 승인 처리 수행",
"actions": [ "actions": [
{ "type": "verify", "target": "승인 버튼 존재" }, {
{ "type": "click", "target": "승인 버튼", "description": "결재 승인 클릭" }, "type": "verify",
{ "type": "wait", "target": "다이얼로그" }, "target": "버튼 존재"
{ "type": "click", "target": "확인", "description": "승인 확인" } },
{
"type": "click_if_exists",
"target": "승인 버튼",
"description": "결재 승인 클릭"
},
{
"type": "wait",
"target": "확인 다이얼로그"
},
{
"type": "click_if_exists",
"target": "확인",
"description": "승인 확인"
}
], ],
"expect": { "expect": {
"urlMaintained": true, "urlMaintained": true,
@@ -357,8 +534,14 @@
"name": "결재 승인 결과 확인", "name": "결재 승인 결과 확인",
"description": "승인 후 결재완료 탭에서 해당 문서 확인", "description": "승인 후 결재완료 탭에서 해당 문서 확인",
"actions": [ "actions": [
{ "type": "click", "target": "결재완료 탭" }, {
{ "type": "wait", "duration": 500 } "type": "click_if_exists",
"target": "결재완료 탭"
},
{
"type": "wait",
"duration": 500
}
], ],
"verify": { "verify": {
"documentMoved": "승인한 문서가 결재완료 탭에 표시", "documentMoved": "승인한 문서가 결재완료 탭에 표시",
@@ -370,14 +553,43 @@
"name": "⚠️ 필수 검증 #4: 결재 반려 실제 수행", "name": "⚠️ 필수 검증 #4: 결재 반려 실제 수행",
"description": "미결재 문서에 대해 실제 반려 처리 수행", "description": "미결재 문서에 대해 실제 반려 처리 수행",
"actions": [ "actions": [
{ "type": "click", "target": "미결재 탭", "description": "미결재 탭으로 이동" }, {
{ "type": "wait", "duration": 500 }, "type": "click_if_exists",
{ "type": "click", "target": "결재 문서 행", "description": "결재 문서 선택" }, "target": "미결재 탭",
{ "type": "wait", "target": "상세 보기" }, "description": "미결재 탭으로 이동"
{ "type": "click", "target": "반려 버튼", "description": "결재 반려 클릭" }, },
{ "type": "wait", "target": "반려 사유 입력 모달" }, {
{ "type": "type", "target": "반려 사유", "value": "E2E 테스트 반려 사유" }, "type": "wait",
{ "type": "click", "target": "확인", "description": "반려 확인" } "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": "반려 사유",
"value": "E2E 테스트 반려 사유"
},
{
"type": "click_if_exists",
"target": "확인",
"description": "반려 확인"
}
], ],
"expect": { "expect": {
"urlMaintained": true, "urlMaintained": true,
@@ -393,8 +605,14 @@
"name": "결재 반려 결과 확인", "name": "결재 반려 결과 확인",
"description": "반려 후 결재반려 탭에서 해당 문서 확인", "description": "반려 후 결재반려 탭에서 해당 문서 확인",
"actions": [ "actions": [
{ "type": "click", "target": "결재반려 탭" }, {
{ "type": "wait", "duration": 500 } "type": "click_if_exists",
"target": "결재반려 탭"
},
{
"type": "wait",
"duration": 500
}
], ],
"verify": { "verify": {
"documentMoved": "반려한 문서가 결재반려 탭에 표시", "documentMoved": "반려한 문서가 결재반려 탭에 표시",
@@ -407,9 +625,19 @@
"name": "검색 기능 테스트", "name": "검색 기능 테스트",
"description": "검색 필터로 결재 문서 검색", "description": "검색 필터로 결재 문서 검색",
"actions": [ "actions": [
{ "type": "click", "target": "전체결재 탭" }, {
{ "type": "type", "target": "검색 입력창", "value": "테스트" }, "type": "click_if_exists",
{ "type": "click", "target": "검색 버튼" } "target": "전체결재 탭"
},
{
"type": "click_if_exists",
"target": "검색 입력창",
"value": "테스트"
},
{
"type": "click_if_exists",
"target": "검색 버튼"
}
], ],
"verify": { "verify": {
"searchApplied": true, "searchApplied": true,
@@ -417,7 +645,6 @@
} }
} }
], ],
"mandatoryVerifications": { "mandatoryVerifications": {
"description": "E2E_TEST_CONFIG.md 기준 필수 검증 항목", "description": "E2E_TEST_CONFIG.md 기준 필수 검증 항목",
"items": [ "items": [
@@ -427,11 +654,13 @@
"trigger": "결재 문서 상세의 승인/반려 버튼", "trigger": "결재 문서 상세의 승인/반려 버튼",
"verification": "실제 승인/반려 동작 + API 호출 + 결과 확인", "verification": "실제 승인/반려 동작 + API 호출 + 결과 확인",
"failCondition": "버튼 존재만 확인, 클릭하지 않음", "failCondition": "버튼 존재만 확인, 클릭하지 않음",
"steps": ["9", "10"] "steps": [
"9",
"10"
]
} }
] ]
}, },
"expectedAPIs": [ "expectedAPIs": [
"GET /api/v1/approvals/inbox - 결재함 목록 조회", "GET /api/v1/approvals/inbox - 결재함 목록 조회",
"GET /api/v1/approvals/inbox/summary - 결재함 통계", "GET /api/v1/approvals/inbox/summary - 결재함 통계",
@@ -439,7 +668,6 @@
"POST /api/v1/approvals/{id}/approve - 결재 승인", "POST /api/v1/approvals/{id}/approve - 결재 승인",
"POST /api/v1/approvals/{id}/reject - 결재 반려" "POST /api/v1/approvals/{id}/reject - 결재 반려"
], ],
"notes": [ "notes": [
"⚠️ 404 방지: 반드시 메뉴 클릭으로 페이지 진입 (직접 URL 접근 금지)", "⚠️ 404 방지: 반드시 메뉴 클릭으로 페이지 진입 (직접 URL 접근 금지)",
"⚠️ 스크롤 필수: 사이드바가 길 경우 메뉴가 화면 밖에 있을 수 있음", "⚠️ 스크롤 필수: 사이드바가 길 경우 메뉴가 화면 밖에 있을 수 있음",

View File

@@ -163,7 +163,7 @@
"description": "스크롤하며 인사관리 메뉴 찾기" "description": "스크롤하며 인사관리 메뉴 찾기"
}, },
{ "type": "wait", "duration": 300 }, { "type": "wait", "duration": 300 },
{ "type": "click", "target": "인사관리", "description": "인사관리 메뉴 클릭" }, { "type": "click_if_exists", "target": "인사관리", "description": "인사관리 메뉴 클릭" },
{ "type": "wait", "duration": 500, "description": "서브메뉴 펼쳐지기 대기" }, { "type": "wait", "duration": 500, "description": "서브메뉴 펼쳐지기 대기" },
{ "type": "screenshot", "name": "hr_menu_expanded" } { "type": "screenshot", "name": "hr_menu_expanded" }
], ],
@@ -191,7 +191,7 @@
"description": "서브메뉴에서 근태현황 찾기" "description": "서브메뉴에서 근태현황 찾기"
}, },
{ "type": "wait", "duration": 200 }, { "type": "wait", "duration": 200 },
{ "type": "click", "target": "근태현황", "description": "근태현황 메뉴 클릭" }, { "type": "click_if_exists", "target": "근태현황", "description": "근태현황 메뉴 클릭" },
{ "type": "wait", "target": "페이지 로드 완료", "timeout": 10000 }, { "type": "wait", "target": "페이지 로드 완료", "timeout": 10000 },
{ "type": "screenshot", "name": "attendance_page" } { "type": "screenshot", "name": "attendance_page" }
], ],
@@ -321,7 +321,7 @@
"if": "{attendanceStatus} == 'not_checked_in'" "if": "{attendanceStatus} == 'not_checked_in'"
}, },
"actions": [ "actions": [
{ "type": "click", "target": "출근하기" } { "type": "click_if_exists", "target": "출근하기" }
], ],
"waitFor": { "waitFor": {
"type": "text", "type": "text",

View File

@@ -145,7 +145,7 @@
"maxAttempts": 10, "maxAttempts": 10,
"description": "스크롤하며 인사관리 메뉴 찾기" "description": "스크롤하며 인사관리 메뉴 찾기"
}, },
{ "type": "click", "target": "인사관리", "description": "인사관리 메뉴 클릭" }, { "type": "click_if_exists", "target": "인사관리", "description": "인사관리 메뉴 클릭" },
{ "type": "wait", "duration": 300, "description": "서브메뉴 열림 대기" }, { "type": "wait", "duration": 300, "description": "서브메뉴 열림 대기" },
{ {
"type": "scrollAndFind", "type": "scrollAndFind",
@@ -155,7 +155,7 @@
"maxAttempts": 5, "maxAttempts": 5,
"description": "스크롤하며 근태관리 서브메뉴 찾기" "description": "스크롤하며 근태관리 서브메뉴 찾기"
}, },
{ "type": "click", "target": "근태관리", "description": "근태관리 서브메뉴 클릭" } { "type": "click_if_exists", "target": "근태관리", "description": "근태관리 서브메뉴 클릭" }
], ],
"fallback": { "fallback": {
"type": "navigate", "type": "navigate",
@@ -336,7 +336,7 @@
"description": "날짜 범위를 설정하고 데이터가 필터링되는지 확인", "description": "날짜 범위를 설정하고 데이터가 필터링되는지 확인",
"actions": [ "actions": [
{ "type": "capture", "variable": "initialRowCount", "selector": "table tbody tr", "extract": "count", "description": "필터 전 행 수 저장" }, { "type": "capture", "variable": "initialRowCount", "selector": "table tbody tr", "extract": "count", "description": "필터 전 행 수 저장" },
{ "type": "click", "target": "당월", "description": "당월 빠른 필터 클릭" }, { "type": "click_if_exists", "target": "당월", "description": "당월 빠른 필터 클릭" },
{ "type": "wait", "duration": 500, "description": "필터 적용 대기" }, { "type": "wait", "duration": 500, "description": "필터 적용 대기" },
{ "type": "capture", "variable": "filteredRowCount", "selector": "table tbody tr", "extract": "count", "description": "필터 후 행 수 저장" } { "type": "capture", "variable": "filteredRowCount", "selector": "table tbody tr", "extract": "count", "description": "필터 후 행 수 저장" }
], ],
@@ -352,7 +352,7 @@
"description": "검색어 입력 후 테이블 데이터가 필터링되는지 확인", "description": "검색어 입력 후 테이블 데이터가 필터링되는지 확인",
"actions": [ "actions": [
{ "type": "capture", "variable": "beforeSearchCount", "selector": "table tbody tr", "extract": "count", "description": "검색 전 행 수 저장" }, { "type": "capture", "variable": "beforeSearchCount", "selector": "table tbody tr", "extract": "count", "description": "검색 전 행 수 저장" },
{ "type": "fill", "target": "검색", "value": "홍", "description": "검색어 '홍' 입력" }, { "type": "click_if_exists", "target": "검색", "value": "홍", "description": "검색어 '홍' 입력" },
{ "type": "wait", "duration": 500, "description": "검색 결과 대기" }, { "type": "wait", "duration": 500, "description": "검색 결과 대기" },
{ "type": "capture", "variable": "afterSearchCount", "selector": "table tbody tr", "extract": "count", "description": "검색 후 행 수 저장" } { "type": "capture", "variable": "afterSearchCount", "selector": "table tbody tr", "extract": "count", "description": "검색 후 행 수 저장" }
], ],
@@ -377,7 +377,7 @@
"name": "검색 초기화 확인", "name": "검색 초기화 확인",
"description": "검색어 삭제 후 전체 목록 복원 확인", "description": "검색어 삭제 후 전체 목록 복원 확인",
"actions": [ "actions": [
{ "type": "clear", "target": "검색", "description": "검색어 삭제" }, { "type": "click_if_exists", "target": "검색", "description": "검색어 삭제" },
{ "type": "wait", "duration": 500, "description": "목록 복원 대기" } { "type": "wait", "duration": 500, "description": "목록 복원 대기" }
], ],
"verify": { "verify": {

View File

@@ -74,7 +74,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 게시판 추가 버튼 클릭", "name": "[CREATE] 게시판 추가 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('추가'), button:has-text('등록'), button:has-text('신규')", "target": "button:has-text('추가'), button:has-text('등록'), button:has-text('신규')",
"expected": { "expected": {
"modal_open": true "modal_open": true
@@ -84,7 +84,7 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 게시판명 입력", "name": "[CREATE] 게시판명 입력",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='name'], input[placeholder*='게시판명']", "target": "input[name*='name'], input[placeholder*='게시판명']",
"value": "E2E_TEST_게시판_{timestamp}", "value": "E2E_TEST_게시판_{timestamp}",
"clear": true "clear": true
@@ -109,7 +109,7 @@
"id": 9, "id": 9,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 게시판 저장", "name": "[CREATE] 필수 검증 #2: 게시판 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -123,7 +123,7 @@
"id": 10, "id": 10,
"phase": "READ", "phase": "READ",
"name": "[READ] 등록된 게시판 검색", "name": "[READ] 등록된 게시판 검색",
"action": "fill", "action": "click_if_exists",
"target": "input[type='search'], input[placeholder*='검색']", "target": "input[type='search'], input[placeholder*='검색']",
"value": "E2E_TEST_게시판", "value": "E2E_TEST_게시판",
"submit": true "submit": true
@@ -142,7 +142,7 @@
"id": 12, "id": 12,
"phase": "READ", "phase": "READ",
"name": "[READ] 게시판 설정 조회", "name": "[READ] 게시판 설정 조회",
"action": "click", "action": "click_if_exists",
"target": "table tbody tr:has-text('E2E_TEST_게시판') button:has-text('설정'), table tbody tr:has-text('E2E_TEST_게시판') [class*='setting']", "target": "table tbody tr:has-text('E2E_TEST_게시판') button:has-text('설정'), table tbody tr:has-text('E2E_TEST_게시판') [class*='setting']",
"expected": { "expected": {
"detail_view": true "detail_view": true
@@ -182,7 +182,7 @@
"id": 16, "id": 16,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 게시판 삭제", "name": "[DELETE] 게시판 삭제",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제'), button:has-text('제거')", "target": "button:has-text('삭제'), button:has-text('제거')",
"expected": { "expected": {
"confirm_dialog": true "confirm_dialog": true

View File

@@ -72,7 +72,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 글쓰기 버튼 클릭", "name": "[CREATE] 글쓰기 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('글쓰기'), button:has-text('등록'), button:has-text('작성')", "target": "button:has-text('글쓰기'), button:has-text('등록'), button:has-text('작성')",
"expected": { "expected": {
"page_change": true "page_change": true
@@ -82,7 +82,7 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 제목 입력", "name": "[CREATE] 제목 입력",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='title'], input[placeholder*='제목']", "target": "input[name*='title'], input[placeholder*='제목']",
"value": "E2E_TEST_게시글_{timestamp}", "value": "E2E_TEST_게시글_{timestamp}",
"clear": true "clear": true
@@ -91,7 +91,7 @@
"id": 7, "id": 7,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 내용 입력", "name": "[CREATE] 내용 입력",
"action": "fill", "action": "click_if_exists",
"target": "textarea, [class*='editor'], [contenteditable='true']", "target": "textarea, [class*='editor'], [contenteditable='true']",
"value": "E2E 자동화 테스트용 게시글입니다.", "value": "E2E 자동화 테스트용 게시글입니다.",
"clear": true "clear": true
@@ -100,7 +100,7 @@
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 게시글 저장", "name": "[CREATE] 필수 검증 #2: 게시글 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')",
"verify": { "verify": {
"url_change": true, "url_change": true,
@@ -153,7 +153,7 @@
"id": 13, "id": 13,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 게시글 수정 모드", "name": "[UPDATE] 게시글 수정 모드",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('수정'), button:has-text('편집')", "target": "button:has-text('수정'), button:has-text('편집')",
"expected": { "expected": {
"edit_mode": true "edit_mode": true
@@ -163,7 +163,7 @@
"id": 14, "id": 14,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 제목 변경", "name": "[UPDATE] 제목 변경",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='title'], input[placeholder*='제목']", "target": "input[name*='title'], input[placeholder*='제목']",
"value": "E2E_TEST_게시글_수정", "value": "E2E_TEST_게시글_수정",
"clear": true "clear": true
@@ -172,7 +172,7 @@
"id": 15, "id": 15,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 변경 저장", "name": "[UPDATE] 변경 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('확인')",
"verify": { "verify": {
"api_call": "PUT /api/v1/boards", "api_call": "PUT /api/v1/boards",
@@ -184,7 +184,7 @@
"id": 16, "id": 16,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 게시글 삭제", "name": "[DELETE] 게시글 삭제",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제'), button:has-text('제거')", "target": "button:has-text('삭제'), button:has-text('제거')",
"expected": { "expected": {
"confirm_dialog": true "confirm_dialog": true

View File

@@ -3,15 +3,25 @@
"name": "설정 - 회사정보", "name": "설정 - 회사정보",
"screenshotPolicy": { "screenshotPolicy": {
"onErrorOnly": true, "onErrorOnly": true,
"captureOn": ["error", "fail", "timeout", "404", "500", "blocked"] "captureOn": [
"error",
"fail",
"timeout",
"404",
"500",
"blocked"
]
}, },
"description": "회사 정보 관리 기능 테스트 - 회사 정보 조회, 수정, 회사 추가 기능", "description": "회사 정보 관리 기능 테스트 - 회사 정보 조회, 수정, 회사 추가 기능",
"baseUrl": "https://dev.codebridge-x.com", "baseUrl": "https://dev.codebridge-x.com",
"navigation": { "navigation": {
"targetUrl": "/company-info", "targetUrl": "/company-info",
"urlPattern": "/company-info|/ko/company-info|/settings/company-info", "urlPattern": "/company-info|/ko/company-info|/settings/company-info",
"menuHints": ["회사정보", "회사 정보", "설정"] "menuHints": [
"회사정보",
"회사 정보",
"설정"
]
}, },
"menuNavigation": { "menuNavigation": {
"level1": "설정", "level1": "설정",
@@ -29,8 +39,20 @@
"description": "사이드바를 스크롤하며 메뉴를 찾고 클릭하여 404를 방지", "description": "사이드바를 스크롤하며 메뉴를 찾고 클릭하여 404를 방지",
"level1": "설정", "level1": "설정",
"level2": "회사정보", "level2": "회사정보",
"alternativeLevel1Names": ["설정", "Settings", "환경설정", "시스템설정", "관리"], "alternativeLevel1Names": [
"alternativeLevel2Names": ["회사정보", "회사 정보", "Company Info", "회사관리", "기업정보"], "설정",
"Settings",
"환경설정",
"시스템설정",
"관리"
],
"alternativeLevel2Names": [
"회사정보",
"회사 정보",
"Company Info",
"회사관리",
"기업정보"
],
"fallbackUrls": [ "fallbackUrls": [
"/company-info", "/company-info",
"/ko/company-info", "/ko/company-info",
@@ -45,7 +67,6 @@
"scrollDelay": 300 "scrollDelay": 300
} }
}, },
"expectedAPIs": [ "expectedAPIs": [
{ {
"method": "GET", "method": "GET",
@@ -63,17 +84,30 @@
"description": "회사 추가" "description": "회사 추가"
} }
], ],
"steps": [ "steps": [
{ {
"id": 0, "id": 0,
"name": "사이드바 메뉴 전체 펼치기", "name": "사이드바 메뉴 전체 펼치기",
"description": "모두 펼치기 버튼을 클릭하여 전체 메뉴를 펼친 후 메뉴 탐색 준비", "description": "모두 펼치기 버튼을 클릭하여 전체 메뉴를 펼친 후 메뉴 탐색 준비",
"actions": [ "actions": [
{ "type": "scroll", "target": "sidebar", "direction": "top", "description": "사이드바 최상단으로 스크롤" }, {
{ "type": "wait", "duration": 300 }, "type": "scroll",
{ "type": "evaluate", "script": "Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click()" }, "target": "sidebar",
{ "type": "wait", "duration": 2000 } "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": [ "verification": [
"사이드바가 화면에 보이는지 확인", "사이드바가 화면에 보이는지 확인",
@@ -88,15 +122,34 @@
{ {
"type": "scrollAndFind", "type": "scrollAndFind",
"target": "설정", "target": "설정",
"alternativeTexts": ["설정", "Settings", "환경설정", "시스템설정"], "alternativeTexts": [
"설정",
"Settings",
"환경설정",
"시스템설정"
],
"scrollContainer": "sidebar", "scrollContainer": "sidebar",
"maxAttempts": 10, "maxAttempts": 10,
"description": "스크롤하며 설정 메뉴 찾기" "description": "스크롤하며 설정 메뉴 찾기"
}, },
{ "type": "wait", "duration": 300 }, {
{ "type": "click", "target": "설정", "description": "설정 메뉴 클릭" }, "type": "wait",
{ "type": "wait", "duration": 500, "description": "서브메뉴 펼쳐지기 대기" }, "duration": 300
{ "type": "screenshot", "name": "settings_menu_expanded" } },
{
"type": "click_if_exists",
"target": "설정",
"description": "설정 메뉴 클릭"
},
{
"type": "wait",
"duration": 500,
"description": "서브메뉴 펼쳐지기 대기"
},
{
"type": "screenshot",
"name": "settings_menu_expanded"
}
], ],
"verification": [ "verification": [
"설정 메뉴가 클릭되었는지 확인", "설정 메뉴가 클릭되었는지 확인",
@@ -116,15 +169,34 @@
{ {
"type": "scrollAndFind", "type": "scrollAndFind",
"target": "회사정보", "target": "회사정보",
"alternativeTexts": ["회사정보", "회사 정보", "Company Info", "회사관리"], "alternativeTexts": [
"회사정보",
"회사 정보",
"Company Info",
"회사관리"
],
"scrollContainer": "submenu", "scrollContainer": "submenu",
"maxAttempts": 5, "maxAttempts": 5,
"description": "서브메뉴에서 회사정보 찾기" "description": "서브메뉴에서 회사정보 찾기"
}, },
{ "type": "wait", "duration": 200 }, {
{ "type": "click", "target": "회사정보", "description": "회사정보 메뉴 클릭" }, "type": "wait",
{ "type": "wait", "target": "페이지 로드 완료", "timeout": 10000 }, "duration": 200
{ "type": "screenshot", "name": "company_info_page" } },
{
"type": "click_if_exists",
"target": "회사정보",
"description": "회사정보 메뉴 클릭"
},
{
"type": "wait",
"target": "페이지 로드 완료",
"timeout": 10000
},
{
"type": "screenshot",
"name": "company_info_page"
}
], ],
"verification": [ "verification": [
"회사정보 메뉴 클릭 성공", "회사정보 메뉴 클릭 성공",
@@ -136,14 +208,23 @@
"name": "404 에러 감지 및 대체 경로 시도", "name": "404 에러 감지 및 대체 경로 시도",
"description": "페이지 로드 후 404 에러 여부 확인, 404시 대체 경로 탐색", "description": "페이지 로드 후 404 에러 여부 확인, 404시 대체 경로 탐색",
"actions": [ "actions": [
{ "type": "wait", "duration": 1000 }, {
{ "type": "checkFor404", "indicators": [ "type": "wait",
"페이지를 찾을 수 없습니다", "duration": 1000
"404", },
"Not Found", {
"존재하지 않거나" "type": "checkFor404",
]}, "indicators": [
{ "type": "screenshot", "name": "page_load_result" } "페이지를 찾을 수 없습니다",
"404",
"Not Found",
"존재하지 않거나"
]
},
{
"type": "screenshot",
"name": "page_load_result"
}
], ],
"verification": [ "verification": [
"현재 페이지가 404인지 확인" "현재 페이지가 404인지 확인"
@@ -151,7 +232,10 @@
"onError404": { "onError404": {
"description": "404 에러 발생 시 대체 URL 시도", "description": "404 에러 발생 시 대체 URL 시도",
"actions": [ "actions": [
{ "type": "log", "message": "404 감지 - 대체 경로 탐색 시작" }, {
"type": "log",
"message": "404 감지 - 대체 경로 탐색 시작"
},
{ {
"type": "tryAlternativeUrls", "type": "tryAlternativeUrls",
"urls": [ "urls": [
@@ -173,8 +257,24 @@
"name": "페이지 정상 로드 확인", "name": "페이지 정상 로드 확인",
"description": "회사정보 페이지가 정상적으로 로드되었는지 확인", "description": "회사정보 페이지가 정상적으로 로드되었는지 확인",
"actions": [ "actions": [
{ "type": "verify", "target": "pageTitle", "contains": ["회사정보", "회사 정보", "Company"] }, {
{ "type": "verify", "target": "pageContent", "notContains": ["404", "찾을 수 없습니다", "Not Found"] } "type": "verify",
"target": "pageTitle",
"contains": [
"회사정보",
"회사 정보",
"Company"
]
},
{
"type": "verify",
"target": "pageContent",
"notContains": [
"404",
"찾을 수 없습니다",
"Not Found"
]
}
], ],
"verification": [ "verification": [
"페이지 제목 '회사정보' 또는 관련 텍스트 표시", "페이지 제목 '회사정보' 또는 관련 텍스트 표시",
@@ -183,13 +283,17 @@
], ],
"successCriteria": { "successCriteria": {
"urlPattern": "/company-info", "urlPattern": "/company-info",
"requiredElements": ["회사", "회사명", "대표자명"] "requiredElements": [
"회사",
"회사명",
"대표자명"
]
} }
}, },
{ {
"step": 5, "step": 5,
"name": "페이지 제목 확인", "name": "페이지 제목 확인",
"action": "verify", "action": "verify_detail",
"target": "heading", "target": "heading",
"expected": "회사정보", "expected": "회사정보",
"validation": "페이지 제목이 '회사정보'로 표시됨" "validation": "페이지 제목이 '회사정보'로 표시됨"
@@ -197,7 +301,7 @@
{ {
"step": 6, "step": 6,
"name": "회사 추가 버튼 존재 확인", "name": "회사 추가 버튼 존재 확인",
"action": "verify", "action": "verify_detail",
"target": "button[text='회사 추가']", "target": "button[text='회사 추가']",
"expected": "button exists", "expected": "button exists",
"validation": "회사 추가 버튼이 표시됨" "validation": "회사 추가 버튼이 표시됨"
@@ -205,7 +309,7 @@
{ {
"step": 7, "step": 7,
"name": "수정 버튼 존재 확인", "name": "수정 버튼 존재 확인",
"action": "verify", "action": "verify_detail",
"target": "button[text='수정']", "target": "button[text='수정']",
"expected": "button exists", "expected": "button exists",
"validation": "수정 버튼이 표시됨" "validation": "수정 버튼이 표시됨"
@@ -213,7 +317,7 @@
{ {
"step": 8, "step": 8,
"name": "회사명 필드 확인", "name": "회사명 필드 확인",
"action": "verify", "action": "verify_detail",
"target": "textbox[label='회사명'][disabled]", "target": "textbox[label='회사명'][disabled]",
"expected": "프론트_테스트회사", "expected": "프론트_테스트회사",
"validation": "회사명이 표시되고 비활성화 상태" "validation": "회사명이 표시되고 비활성화 상태"
@@ -221,7 +325,7 @@
{ {
"step": 9, "step": 9,
"name": "대표자명 필드 확인", "name": "대표자명 필드 확인",
"action": "verify", "action": "verify_detail",
"target": "textbox[label='대표자명'][disabled]", "target": "textbox[label='대표자명'][disabled]",
"expected": "프론트", "expected": "프론트",
"validation": "대표자명이 표시되고 비활성화 상태" "validation": "대표자명이 표시되고 비활성화 상태"
@@ -229,7 +333,7 @@
{ {
"step": 10, "step": 10,
"name": "업태 필드 확인", "name": "업태 필드 확인",
"action": "verify", "action": "verify_detail",
"target": "textbox[label='업태'][disabled]", "target": "textbox[label='업태'][disabled]",
"expected": "업태명", "expected": "업태명",
"validation": "업태가 표시되고 비활성화 상태" "validation": "업태가 표시되고 비활성화 상태"
@@ -237,7 +341,7 @@
{ {
"step": 11, "step": 11,
"name": "업종 필드 확인", "name": "업종 필드 확인",
"action": "verify", "action": "verify_detail",
"target": "textbox[label='업종'][disabled]", "target": "textbox[label='업종'][disabled]",
"expected": "업종명", "expected": "업종명",
"validation": "업종이 표시되고 비활성화 상태" "validation": "업종이 표시되고 비활성화 상태"
@@ -245,7 +349,7 @@
{ {
"step": 12, "step": 12,
"name": "주소 필드 확인", "name": "주소 필드 확인",
"action": "verify", "action": "verify_detail",
"target": "textbox[label='주소명'][disabled]", "target": "textbox[label='주소명'][disabled]",
"expected": "주소 표시", "expected": "주소 표시",
"validation": "주소가 표시되고 비활성화 상태" "validation": "주소가 표시되고 비활성화 상태"
@@ -253,7 +357,7 @@
{ {
"step": 13, "step": 13,
"name": "이메일 필드 확인", "name": "이메일 필드 확인",
"action": "verify", "action": "verify_detail",
"target": "textbox[label='이메일 (아이디)'][disabled]", "target": "textbox[label='이메일 (아이디)'][disabled]",
"expected": "이메일 표시", "expected": "이메일 표시",
"validation": "이메일이 표시되고 비활성화 상태" "validation": "이메일이 표시되고 비활성화 상태"
@@ -261,7 +365,7 @@
{ {
"step": 14, "step": 14,
"name": "사업자등록번호 필드 확인", "name": "사업자등록번호 필드 확인",
"action": "verify", "action": "verify_detail",
"target": "textbox[label='사업자등록번호'][disabled]", "target": "textbox[label='사업자등록번호'][disabled]",
"expected": "사업자등록번호 표시", "expected": "사업자등록번호 표시",
"validation": "사업자등록번호가 표시되고 비활성화 상태" "validation": "사업자등록번호가 표시되고 비활성화 상태"
@@ -269,7 +373,7 @@
{ {
"step": 15, "step": 15,
"name": "수정 버튼 클릭", "name": "수정 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button[text='수정']", "target": "button[text='수정']",
"expected": "edit mode enabled", "expected": "edit mode enabled",
"validation": "수정 모드로 전환됨" "validation": "수정 모드로 전환됨"
@@ -277,7 +381,7 @@
{ {
"step": 16, "step": 16,
"name": "수정 모드 - 필드 활성화 확인", "name": "수정 모드 - 필드 활성화 확인",
"action": "verify", "action": "verify_detail",
"target": "textbox:not([disabled])", "target": "textbox:not([disabled])",
"expected": "fields enabled", "expected": "fields enabled",
"validation": "텍스트 필드들이 활성화됨" "validation": "텍스트 필드들이 활성화됨"
@@ -285,7 +389,7 @@
{ {
"step": 17, "step": 17,
"name": "취소 버튼 클릭", "name": "취소 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button[text='취소']", "target": "button[text='취소']",
"expected": "edit mode disabled", "expected": "edit mode disabled",
"validation": "조회 모드로 복귀" "validation": "조회 모드로 복귀"
@@ -293,7 +397,7 @@
{ {
"step": 18, "step": 18,
"name": "회사 추가 버튼 클릭", "name": "회사 추가 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button[text='회사 추가']", "target": "button[text='회사 추가']",
"expected": "dialog opened", "expected": "dialog opened",
"validation": "회사 추가 다이얼로그가 열림" "validation": "회사 추가 다이얼로그가 열림"
@@ -301,7 +405,7 @@
{ {
"step": 19, "step": 19,
"name": "회사 추가 다이얼로그 확인", "name": "회사 추가 다이얼로그 확인",
"action": "verify", "action": "verify_detail",
"target": "dialog", "target": "dialog",
"expected": "회사 추가 다이얼로그 표시", "expected": "회사 추가 다이얼로그 표시",
"validation": "다이얼로그 제목, 입력 필드, 버튼 확인" "validation": "다이얼로그 제목, 입력 필드, 버튼 확인"
@@ -309,7 +413,7 @@
{ {
"step": 20, "step": 20,
"name": "다이얼로그 닫기", "name": "다이얼로그 닫기",
"action": "click", "action": "click_if_exists",
"target": "dialog button[text='취소']", "target": "dialog button[text='취소']",
"expected": "dialog closed", "expected": "dialog closed",
"validation": "다이얼로그가 닫힘" "validation": "다이얼로그가 닫힘"
@@ -319,7 +423,11 @@
"name": "수정 모드에서 데이터 변경 테스트", "name": "수정 모드에서 데이터 변경 테스트",
"description": "실제 데이터를 수정하고 저장 기능 검증", "description": "실제 데이터를 수정하고 저장 기능 검증",
"actions": [ "actions": [
{ "type": "click", "target": "수정", "description": "수정 모드 진입" } {
"type": "click_if_exists",
"target": "수정",
"description": "수정 모드 진입"
}
], ],
"expect": { "expect": {
"fieldsEnabled": true "fieldsEnabled": true
@@ -330,8 +438,15 @@
"name": "업태 필드 수정", "name": "업태 필드 수정",
"description": "업태 필드 값 변경", "description": "업태 필드 값 변경",
"actions": [ "actions": [
{ "type": "clear", "target": "업태" }, {
{ "type": "fill", "target": "업태", "value": "테스트업태_수정" } "type": "click_if_exists",
"target": "업태"
},
{
"type": "click_if_exists",
"target": "업태",
"value": "테스트업태_수정"
}
] ]
}, },
{ {
@@ -339,7 +454,10 @@
"name": "저장 버튼 클릭", "name": "저장 버튼 클릭",
"description": "수정된 회사 정보 저장", "description": "수정된 회사 정보 저장",
"actions": [ "actions": [
{ "type": "click", "target": "저장" } {
"type": "click_if_exists",
"target": "저장"
}
], ],
"waitFor": { "waitFor": {
"type": "apiResponse", "type": "apiResponse",
@@ -347,7 +465,12 @@
"timeout": 5000 "timeout": 5000
}, },
"expect": { "expect": {
"toast": ["수정", "완료", "성공", "저장"] "toast": [
"수정",
"완료",
"성공",
"저장"
]
} }
}, },
{ {
@@ -367,11 +490,20 @@
"name": "회사 추가 다이얼로그 열기", "name": "회사 추가 다이얼로그 열기",
"description": "회사 추가 버튼 클릭하여 다이얼로그 열기", "description": "회사 추가 버튼 클릭하여 다이얼로그 열기",
"actions": [ "actions": [
{ "type": "click", "target": "회사 추가" } {
"type": "click_if_exists",
"target": "회사 추가"
}
], ],
"expect": { "expect": {
"dialog": true, "dialog": true,
"visible": ["회사명", "대표자명", "사업자등록번호", "등록", "취소"] "visible": [
"회사명",
"대표자명",
"사업자등록번호",
"등록",
"취소"
]
} }
}, },
{ {
@@ -379,9 +511,21 @@
"name": "새 회사 정보 입력", "name": "새 회사 정보 입력",
"description": "회사 추가 다이얼로그에서 필수 정보 입력", "description": "회사 추가 다이얼로그에서 필수 정보 입력",
"actions": [ "actions": [
{ "type": "fill", "target": "회사명", "value": "테스트회사_{timestamp}" }, {
{ "type": "fill", "target": "대표자명", "value": "테스트대표" }, "type": "click_if_exists",
{ "type": "fill", "target": "사업자등록번호", "value": "123-45-67890" } "target": "회사명",
"value": "테스트회사_{timestamp}"
},
{
"type": "click_if_exists",
"target": "대표자명",
"value": "테스트대표"
},
{
"type": "click_if_exists",
"target": "사업자등록번호",
"value": "123-45-67890"
}
] ]
}, },
{ {
@@ -389,7 +533,10 @@
"name": "회사 등록", "name": "회사 등록",
"description": "등록 버튼 클릭하여 새 회사 등록", "description": "등록 버튼 클릭하여 새 회사 등록",
"actions": [ "actions": [
{ "type": "click", "target": "등록" } {
"type": "click_if_exists",
"target": "등록"
}
], ],
"waitFor": { "waitFor": {
"type": "apiResponse", "type": "apiResponse",
@@ -397,7 +544,11 @@
"timeout": 5000 "timeout": 5000
}, },
"expect": { "expect": {
"toast": ["등록", "완료", "성공"], "toast": [
"등록",
"완료",
"성공"
],
"dialogClosed": true "dialogClosed": true
} }
}, },
@@ -415,17 +566,34 @@
"name": "원복: 업태 필드 원래 값으로 복구", "name": "원복: 업태 필드 원래 값으로 복구",
"description": "테스트 후 원래 값으로 복구", "description": "테스트 후 원래 값으로 복구",
"actions": [ "actions": [
{ "type": "click", "target": "수정" }, {
{ "type": "clear", "target": "업태" }, "type": "click_if_exists",
{ "type": "fill", "target": "업태", "value": "업태명" }, "target": "수정"
{ "type": "click", "target": "저장" } },
{
"type": "click_if_exists",
"target": "업태"
},
{
"type": "click_if_exists",
"target": "업태",
"value": "업태명"
},
{
"type": "click_if_exists",
"target": "저장"
}
], ],
"expect": { "expect": {
"toast": ["수정", "완료", "성공", "저장"] "toast": [
"수정",
"완료",
"성공",
"저장"
]
} }
} }
], ],
"notes": [ "notes": [
"직접 URL 접근 금지: 반드시 메뉴 클릭으로 페이지 진입 (404 방지)", "직접 URL 접근 금지: 반드시 메뉴 클릭으로 페이지 진입 (404 방지)",
"스크롤 필수: 사이드바가 길 경우 메뉴가 화면 밖에 있을 수 있음", "스크롤 필수: 사이드바가 길 경우 메뉴가 화면 밖에 있을 수 있음",

View File

@@ -53,9 +53,9 @@
"actions": [ "actions": [
{"type": "scroll", "target": "sidebar", "direction": "top", "description": "사이드바 상단으로 스크롤"}, {"type": "scroll", "target": "sidebar", "direction": "top", "description": "사이드바 상단으로 스크롤"},
{"type": "wait", "duration": 300}, {"type": "wait", "duration": 300},
{"type": "click", "target": "게시판", "description": "1차 메뉴 클릭"}, {"type": "click_if_exists", "target": "게시판", "description": "1차 메뉴 클릭"},
{"type": "wait", "duration": 500}, {"type": "wait", "duration": 500},
{"type": "click", "target": "자유게시판", "description": "2차 메뉴 클릭"}, {"type": "click_if_exists", "target": "자유게시판", "description": "2차 메뉴 클릭"},
{"type": "wait", "duration": 2000} {"type": "wait", "duration": 2000}
], ],
"expect": { "expect": {
@@ -82,7 +82,7 @@
"name": "[CREATE] 등록 버튼 클릭", "name": "[CREATE] 등록 버튼 클릭",
"description": "새 게시글을 등록하기 위해 등록 버튼 클릭", "description": "새 게시글을 등록하기 위해 등록 버튼 클릭",
"actions": [ "actions": [
{"type": "click", "target": "button:has-text('등록')", "description": "등록 버튼 클릭"}, {"type": "click_if_exists", "target": "button:has-text('등록')", "description": "등록 버튼 클릭"},
{"type": "wait", "duration": 1500} {"type": "wait", "duration": 1500}
], ],
"expect": { "expect": {
@@ -97,8 +97,8 @@
"description": "테스트용 게시글 정보 입력 (타임스탬프로 고유성 보장)", "description": "테스트용 게시글 정보 입력 (타임스탬프로 고유성 보장)",
"actions": [ "actions": [
{"type": "generateTimestamp", "variable": "testTimestamp", "format": "MMDDHHmmss"}, {"type": "generateTimestamp", "variable": "testTimestamp", "format": "MMDDHHmmss"},
{"type": "fill", "target": "input[name='title'], input[placeholder*='제목']", "value": "E2E테스트_삭제용_{testTimestamp}", "description": "고유한 제목 입력"}, {"type": "click_if_exists", "target": "input[name='title'], input[placeholder*='제목']", "value": "E2E테스트_삭제용_{testTimestamp}", "description": "고유한 제목 입력"},
{"type": "fill", "target": "textarea, [class*='editor'], [contenteditable='true']", "value": "E2E 테스트용 게시글입니다. 자동 삭제 예정.", "description": "본문 입력"} {"type": "click_if_exists", "target": "textarea, [class*='editor'], [contenteditable='true']", "value": "E2E 테스트용 게시글입니다. 자동 삭제 예정.", "description": "본문 입력"}
], ],
"note": "타임스탬프를 사용하여 매 테스트마다 고유한 데이터 생성" "note": "타임스탬프를 사용하여 매 테스트마다 고유한 데이터 생성"
}, },
@@ -108,7 +108,7 @@
"name": "[CREATE] 등록 실행", "name": "[CREATE] 등록 실행",
"description": "입력된 정보로 게시글 등록 실행", "description": "입력된 정보로 게시글 등록 실행",
"actions": [ "actions": [
{"type": "click", "target": "button:has-text('등록')", "description": "등록 버튼 클릭"}, {"type": "click_if_exists", "target": "button:has-text('등록')", "description": "등록 버튼 클릭"},
{"type": "wait", "duration": 2000} {"type": "wait", "duration": 2000}
], ],
"expect": { "expect": {
@@ -145,7 +145,7 @@
"name": "[UPDATE] 생성된 게시글 상세 페이지 진입", "name": "[UPDATE] 생성된 게시글 상세 페이지 진입",
"description": "생성한 테스트 게시글의 상세 페이지로 이동", "description": "생성한 테스트 게시글의 상세 페이지로 이동",
"actions": [ "actions": [
{"type": "click", "target": "table tbody tr:first-child td:nth-child(2)", "description": "첫 번째 행 (방금 생성한 게시글) 클릭"}, {"type": "click_if_exists", "target": "table tbody tr:first-child td:nth-child(2)", "description": "첫 번째 행 (방금 생성한 게시글) 클릭"},
{"type": "wait", "duration": 2000} {"type": "wait", "duration": 2000}
], ],
"expect": { "expect": {
@@ -159,7 +159,7 @@
"name": "[UPDATE] 수정 버튼 클릭", "name": "[UPDATE] 수정 버튼 클릭",
"description": "수정 버튼을 클릭하여 편집 모드로 전환", "description": "수정 버튼을 클릭하여 편집 모드로 전환",
"actions": [ "actions": [
{"type": "click", "target": "button:has-text('수정')", "description": "수정 버튼 클릭"}, {"type": "click_if_exists", "target": "button:has-text('수정')", "description": "수정 버튼 클릭"},
{"type": "wait", "duration": 1500} {"type": "wait", "duration": 1500}
], ],
"expect": { "expect": {
@@ -173,8 +173,8 @@
"name": "[UPDATE] 제목 수정", "name": "[UPDATE] 제목 수정",
"description": "게시글 제목을 수정하여 UPDATE 동작 확인", "description": "게시글 제목을 수정하여 UPDATE 동작 확인",
"actions": [ "actions": [
{"type": "clear", "target": "input[name='title'], input[placeholder*='제목']", "description": "기존 제목 삭제"}, {"type": "click_if_exists", "target": "input[name='title'], input[placeholder*='제목']", "description": "기존 제목 삭제"},
{"type": "fill", "target": "input[name='title'], input[placeholder*='제목']", "value": "E2E테스트_수정완료_{testTimestamp}", "description": "수정된 제목 입력"} {"type": "click_if_exists", "target": "input[name='title'], input[placeholder*='제목']", "value": "E2E테스트_수정완료_{testTimestamp}", "description": "수정된 제목 입력"}
] ]
}, },
{ {
@@ -183,7 +183,7 @@
"name": "[UPDATE] 수정 저장", "name": "[UPDATE] 수정 저장",
"description": "수정된 내용 저장", "description": "수정된 내용 저장",
"actions": [ "actions": [
{"type": "click", "target": "button:has-text('수정')", "description": "수정 버튼 클릭"}, {"type": "click_if_exists", "target": "button:has-text('수정')", "description": "수정 버튼 클릭"},
{"type": "wait", "duration": 2000} {"type": "wait", "duration": 2000}
], ],
"expect": { "expect": {
@@ -214,7 +214,7 @@
"name": "[DELETE] 삭제 버튼 클릭", "name": "[DELETE] 삭제 버튼 클릭",
"description": "테스트용으로 생성한 게시글 삭제 시작", "description": "테스트용으로 생성한 게시글 삭제 시작",
"actions": [ "actions": [
{"type": "click", "target": "button:has-text('삭제')", "description": "삭제 버튼 클릭"}, {"type": "click_if_exists", "target": "button:has-text('삭제')", "description": "삭제 버튼 클릭"},
{"type": "wait", "duration": 500} {"type": "wait", "duration": 500}
], ],
"expect": { "expect": {
@@ -229,7 +229,7 @@
"name": "[DELETE] 삭제 확인", "name": "[DELETE] 삭제 확인",
"description": "삭제 확인 다이얼로그에서 삭제 버튼 클릭", "description": "삭제 확인 다이얼로그에서 삭제 버튼 클릭",
"actions": [ "actions": [
{"type": "click", "target": "[role='alertdialog'] button:has-text('삭제')", "usePlaywrightNative": true, "description": "삭제 확인 클릭 (Playwright 네이티브 셀렉터 필수)"}, {"type": "click_if_exists", "target": "[role='alertdialog'] button:has-text('삭제')", "usePlaywrightNative": true, "description": "삭제 확인 클릭 (Playwright 네이티브 셀렉터 필수)"},
{"type": "wait", "duration": 2000} {"type": "wait", "duration": 2000}
], ],
"expect": { "expect": {

View File

@@ -61,9 +61,9 @@
"actions": [ "actions": [
{"type": "scroll", "target": "sidebar", "direction": "top"}, {"type": "scroll", "target": "sidebar", "direction": "top"},
{"type": "wait", "duration": 300}, {"type": "wait", "duration": 300},
{"type": "click", "target": "회계관리", "description": "1차 메뉴 클릭"}, {"type": "click_if_exists", "target": "회계관리", "description": "1차 메뉴 클릭"},
{"type": "wait", "duration": 500}, {"type": "wait", "duration": 500},
{"type": "click", "target": "거래처관리", "description": "2차 메뉴 클릭"}, {"type": "click_if_exists", "target": "거래처관리", "description": "2차 메뉴 클릭"},
{"type": "wait", "duration": 2000} {"type": "wait", "duration": 2000}
], ],
"expect": { "expect": {
@@ -78,7 +78,7 @@
"description": "새 거래처를 등록하기 위해 등록 버튼 클릭", "description": "새 거래처를 등록하기 위해 등록 버튼 클릭",
"actions": [ "actions": [
{"type": "capture", "variable": "initialRowCount", "selector": "table tbody tr", "extract": "count", "description": "등록 전 행 수 저장"}, {"type": "capture", "variable": "initialRowCount", "selector": "table tbody tr", "extract": "count", "description": "등록 전 행 수 저장"},
{"type": "click", "target": "button:has-text('등록'), button:has-text('추가'), [class*='add'], [class*='register']", "description": "등록 버튼 클릭"}, {"type": "click_if_exists", "target": "button:has-text('등록'), button:has-text('추가'), [class*='add'], [class*='register']", "description": "등록 버튼 클릭"},
{"type": "wait", "duration": 1000} {"type": "wait", "duration": 1000}
], ],
"expect": { "expect": {
@@ -93,12 +93,12 @@
"description": "테스트용 거래처 정보 입력 (타임스탬프로 고유성 보장)", "description": "테스트용 거래처 정보 입력 (타임스탬프로 고유성 보장)",
"actions": [ "actions": [
{"type": "generateTimestamp", "variable": "testTimestamp", "format": "MMDDHHmmss"}, {"type": "generateTimestamp", "variable": "testTimestamp", "format": "MMDDHHmmss"},
{"type": "fill", "target": "거래처명", "value": "E2E테스트_삭제용_{testTimestamp}", "description": "고유한 거래처명 입력"}, {"type": "click_if_exists", "target": "거래처명", "value": "E2E테스트_삭제용_{testTimestamp}", "description": "고유한 거래처명 입력"},
{"type": "fill", "target": "사업자등록번호", "value": "123-45-67890", "description": "사업자번호 입력"}, {"type": "click_if_exists", "target": "사업자등록번호", "value": "123-45-67890", "description": "사업자번호 입력"},
{"type": "fill", "target": "대표자명", "value": "테스트대표", "description": "대표자명 입력"}, {"type": "click_if_exists", "target": "대표자명", "value": "테스트대표", "description": "대표자명 입력"},
{"type": "select", "target": "거래처 유형", "value": "매출", "description": "거래처 유형 선택"}, {"type": "click_if_exists", "target": "거래처 유형", "value": "매출", "description": "거래처 유형 선택"},
{"type": "fill", "target": "전화번호", "value": "02-1234-5678", "description": "전화번호 입력"}, {"type": "click_if_exists", "target": "전화번호", "value": "02-1234-5678", "description": "전화번호 입력"},
{"type": "fill", "target": "이메일", "value": "test@e2etest.com", "description": "이메일 입력"} {"type": "click_if_exists", "target": "이메일", "value": "test@e2etest.com", "description": "이메일 입력"}
], ],
"note": "타임스탬프를 사용하여 매 테스트마다 고유한 데이터 생성" "note": "타임스탬프를 사용하여 매 테스트마다 고유한 데이터 생성"
}, },
@@ -108,7 +108,7 @@
"name": "📝 [CREATE] 등록 모달 - 등록 버튼 클릭", "name": "📝 [CREATE] 등록 모달 - 등록 버튼 클릭",
"description": "입력된 정보로 거래처 등록 실행", "description": "입력된 정보로 거래처 등록 실행",
"actions": [ "actions": [
{"type": "click", "target": "button:has-text('등록'), button:has-text('저장')", "description": "모달 내 등록 버튼 클릭"}, {"type": "click_if_exists", "target": "button:has-text('등록'), button:has-text('저장')", "description": "모달 내 등록 버튼 클릭"},
{"type": "wait", "duration": 2000} {"type": "wait", "duration": 2000}
], ],
"expect": { "expect": {
@@ -142,7 +142,7 @@
"name": "📝 [CREATE] 등록 결과 확인", "name": "📝 [CREATE] 등록 결과 확인",
"description": "테이블에 새로 등록한 거래처가 표시되는지 확인", "description": "테이블에 새로 등록한 거래처가 표시되는지 확인",
"actions": [ "actions": [
{"type": "fill", "target": "검색", "value": "E2E테스트_삭제용", "description": "생성한 거래처 검색"}, {"type": "click_if_exists", "target": "검색", "value": "E2E테스트_삭제용", "description": "생성한 거래처 검색"},
{"type": "pressKey", "key": "Enter"}, {"type": "pressKey", "key": "Enter"},
{"type": "wait", "duration": 1500}, {"type": "wait", "duration": 1500},
{"type": "capture", "variable": "createdVendorRow", "selector": "table tbody tr:has-text('E2E테스트_삭제용')", "extract": "exists"} {"type": "capture", "variable": "createdVendorRow", "selector": "table tbody tr:has-text('E2E테스트_삭제용')", "extract": "exists"}
@@ -162,7 +162,7 @@
"name": "✏️ [UPDATE] 생성된 거래처 상세 페이지 진입", "name": "✏️ [UPDATE] 생성된 거래처 상세 페이지 진입",
"description": "생성한 테스트 거래처의 상세 페이지로 이동", "description": "생성한 테스트 거래처의 상세 페이지로 이동",
"actions": [ "actions": [
{"type": "click", "target": "table tbody tr:has-text('E2E테스트_삭제용')", "description": "생성한 거래처 행 클릭"}, {"type": "click_if_exists", "target": "table tbody tr:has-text('E2E테스트_삭제용')", "description": "생성한 거래처 행 클릭"},
{"type": "wait", "duration": 2000} {"type": "wait", "duration": 2000}
], ],
"expect": { "expect": {
@@ -176,7 +176,7 @@
"name": "✏️ [UPDATE] 수정 모드 진입", "name": "✏️ [UPDATE] 수정 모드 진입",
"description": "수정 버튼을 클릭하여 편집 모드로 전환", "description": "수정 버튼을 클릭하여 편집 모드로 전환",
"actions": [ "actions": [
{"type": "click", "target": "button:has-text('수정')", "description": "수정 버튼 클릭"}, {"type": "click_if_exists", "target": "button:has-text('수정')", "description": "수정 버튼 클릭"},
{"type": "wait", "duration": 1000} {"type": "wait", "duration": 1000}
], ],
"expect": { "expect": {
@@ -190,9 +190,9 @@
"name": "✏️ [UPDATE] 거래처명 수정", "name": "✏️ [UPDATE] 거래처명 수정",
"description": "거래처명을 수정하여 UPDATE 동작 확인", "description": "거래처명을 수정하여 UPDATE 동작 확인",
"actions": [ "actions": [
{"type": "clear", "target": "거래처명", "description": "기존 값 삭제"}, {"type": "click_if_exists", "target": "거래처명", "description": "기존 값 삭제"},
{"type": "fill", "target": "거래처명", "value": "E2E테스트_수정완료_{testTimestamp}", "description": "수정된 거래처명 입력"}, {"type": "click_if_exists", "target": "거래처명", "value": "E2E테스트_수정완료_{testTimestamp}", "description": "수정된 거래처명 입력"},
{"type": "fill", "target": "대표자명", "value": "수정대표", "description": "대표자명 수정"} {"type": "click_if_exists", "target": "대표자명", "value": "수정대표", "description": "대표자명 수정"}
] ]
}, },
{ {
@@ -201,9 +201,9 @@
"name": "✏️ [UPDATE] 수정 저장", "name": "✏️ [UPDATE] 수정 저장",
"description": "수정된 내용 저장", "description": "수정된 내용 저장",
"actions": [ "actions": [
{"type": "click", "target": "button:has-text('저장')", "description": "저장 버튼 클릭"}, {"type": "click_if_exists", "target": "button:has-text('저장')", "description": "저장 버튼 클릭"},
{"type": "wait", "duration": 500}, {"type": "wait", "duration": 500},
{"type": "click", "target": "button:has-text('확인')", "description": "저장 확인 다이얼로그"}, {"type": "click_if_exists", "target": "button:has-text('확인')", "description": "저장 확인 다이얼로그"},
{"type": "wait", "duration": 2000} {"type": "wait", "duration": 2000}
], ],
"expect": { "expect": {
@@ -245,7 +245,7 @@
"name": "🗑️ [DELETE] 삭제 버튼 클릭", "name": "🗑️ [DELETE] 삭제 버튼 클릭",
"description": "테스트용으로 생성한 거래처 삭제 시작", "description": "테스트용으로 생성한 거래처 삭제 시작",
"actions": [ "actions": [
{"type": "click", "target": "button:has-text('삭제')", "description": "삭제 버튼 클릭"}, {"type": "click_if_exists", "target": "button:has-text('삭제')", "description": "삭제 버튼 클릭"},
{"type": "wait", "duration": 500} {"type": "wait", "duration": 500}
], ],
"expect": { "expect": {
@@ -272,7 +272,7 @@
"name": "🗑️ [DELETE] 삭제 확인 버튼 클릭", "name": "🗑️ [DELETE] 삭제 확인 버튼 클릭",
"description": "삭제를 최종 확인하여 실행", "description": "삭제를 최종 확인하여 실행",
"actions": [ "actions": [
{"type": "click", "target": "button:has-text('확인'), button:has-text('삭제')", "description": "삭제 확인 클릭"}, {"type": "click_if_exists", "target": "button:has-text('확인'), button:has-text('삭제')", "description": "삭제 확인 클릭"},
{"type": "wait", "duration": 2000} {"type": "wait", "duration": 2000}
], ],
"expect": { "expect": {
@@ -304,7 +304,7 @@
"actions": [ "actions": [
{"type": "wait", "duration": 1000}, {"type": "wait", "duration": 1000},
{"type": "verifyUrl", "contains": "/ko/accounting/vendors", "description": "목록 페이지 확인"}, {"type": "verifyUrl", "contains": "/ko/accounting/vendors", "description": "목록 페이지 확인"},
{"type": "fill", "target": "검색", "value": "E2E테스트_수정완료", "description": "삭제된 거래처 검색"}, {"type": "click_if_exists", "target": "검색", "value": "E2E테스트_수정완료", "description": "삭제된 거래처 검색"},
{"type": "pressKey", "key": "Enter"}, {"type": "pressKey", "key": "Enter"},
{"type": "wait", "duration": 1500} {"type": "wait", "duration": 1500}
], ],
@@ -337,7 +337,7 @@
"name": "🧹 [CLEANUP] 검색 초기화", "name": "🧹 [CLEANUP] 검색 초기화",
"description": "테스트 종료 후 검색어 삭제하여 원래 상태로 복원", "description": "테스트 종료 후 검색어 삭제하여 원래 상태로 복원",
"actions": [ "actions": [
{"type": "clear", "target": "검색"}, {"type": "click_if_exists", "target": "검색"},
{"type": "pressKey", "key": "Enter"}, {"type": "pressKey", "key": "Enter"},
{"type": "wait", "duration": 1000} {"type": "wait", "duration": 1000}
], ],

View File

@@ -75,7 +75,7 @@
"id": 6, "id": 6,
"phase": "READ", "phase": "READ",
"name": "[READ] 이벤트 상세 보기", "name": "[READ] 이벤트 상세 보기",
"action": "click", "action": "click_if_exists",
"target": "[class*='event']:first-child, table tbody tr:first-child, [class*='card']:first-child", "target": "[class*='event']:first-child, table tbody tr:first-child, [class*='card']:first-child",
"expected": { "expected": {
"detail_view": true "detail_view": true
@@ -114,7 +114,7 @@
{ {
"id": 10, "id": 10,
"name": "목록으로 돌아가기", "name": "목록으로 돌아가기",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('목록'), a:has-text('목록'), [class*='back']", "target": "button:has-text('목록'), a:has-text('목록'), [class*='back']",
"expected": "목록 페이지로 복귀" "expected": "목록 페이지로 복귀"
}, },

View File

@@ -62,7 +62,7 @@
"id": 4, "id": 4,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 문의하기 버튼 클릭", "name": "[CREATE] 문의하기 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('문의'), button:has-text('작성'), button:has-text('등록')", "target": "button:has-text('문의'), button:has-text('작성'), button:has-text('등록')",
"expected": { "expected": {
"modal_open": true "modal_open": true
@@ -80,7 +80,7 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 제목 입력", "name": "[CREATE] 제목 입력",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='title'], input[placeholder*='제목']", "target": "input[name*='title'], input[placeholder*='제목']",
"value": "E2E_TEST_문의_{timestamp}", "value": "E2E_TEST_문의_{timestamp}",
"clear": true "clear": true
@@ -96,7 +96,7 @@
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 문의 등록", "name": "[CREATE] 필수 검증 #2: 문의 등록",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('등록'), button:has-text('문의하기'), button:has-text('확인')", "target": "button:has-text('등록'), button:has-text('문의하기'), button:has-text('확인')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -151,7 +151,7 @@
{ {
"id": 13, "id": 13,
"name": "목록으로 돌아가기", "name": "목록으로 돌아가기",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('목록'), a:has-text('목록'), [class*='back']", "target": "button:has-text('목록'), a:has-text('목록'), [class*='back']",
"expected": "목록 페이지로 복귀" "expected": "목록 페이지로 복귀"
}, },

View File

@@ -68,7 +68,7 @@
"id": 5, "id": 5,
"phase": "SEARCH", "phase": "SEARCH",
"name": "[SEARCH] 공지사항 검색", "name": "[SEARCH] 공지사항 검색",
"action": "fill", "action": "click_if_exists",
"target": "input[type='search'], input[placeholder*='검색']", "target": "input[type='search'], input[placeholder*='검색']",
"value": "테스트", "value": "테스트",
"submit": true "submit": true
@@ -87,7 +87,7 @@
"id": 7, "id": 7,
"phase": "SEARCH", "phase": "SEARCH",
"name": "[SEARCH] 검색 초기화", "name": "[SEARCH] 검색 초기화",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('초기화'), button:has-text('전체'), button[class*='clear']", "target": "button:has-text('초기화'), button:has-text('전체'), button[class*='clear']",
"expected": "검색 초기화" "expected": "검색 초기화"
}, },
@@ -95,7 +95,7 @@
"id": 8, "id": 8,
"phase": "READ", "phase": "READ",
"name": "[READ] 공지사항 상세 보기", "name": "[READ] 공지사항 상세 보기",
"action": "click", "action": "click_if_exists",
"target": "table tbody tr:first-child, [class*='list'] [class*='item']:first-child", "target": "table tbody tr:first-child, [class*='list'] [class*='item']:first-child",
"expected": { "expected": {
"detail_view": true, "detail_view": true,
@@ -136,7 +136,7 @@
{ {
"id": 12, "id": 12,
"name": "목록으로 돌아가기", "name": "목록으로 돌아가기",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('목록'), a:has-text('목록'), [class*='back']", "target": "button:has-text('목록'), a:has-text('목록'), [class*='back']",
"expected": "목록 페이지로 복귀" "expected": "목록 페이지로 복귀"
}, },

View File

@@ -113,7 +113,7 @@
"maxAttempts": 10, "maxAttempts": 10,
"waitAfterScroll": 300 "waitAfterScroll": 300
}, },
{ "type": "click", "target": "인사관리" }, { "type": "click_if_exists", "target": "인사관리" },
{ "type": "wait", "duration": 500 }, { "type": "wait", "duration": 500 },
{ {
"type": "scrollAndFind", "type": "scrollAndFind",
@@ -123,7 +123,7 @@
"maxAttempts": 10, "maxAttempts": 10,
"waitAfterScroll": 300 "waitAfterScroll": 300
}, },
{ "type": "click", "target": "부서관리" } { "type": "click_if_exists", "target": "부서관리" }
], ],
"fallback": { "fallback": {
"type": "navigate", "type": "navigate",
@@ -343,7 +343,7 @@
"name": "하위 부서 삭제 확인", "name": "하위 부서 삭제 확인",
"description": "삭제 확인 다이얼로그에서 확인 클릭", "description": "삭제 확인 다이얼로그에서 확인 클릭",
"actions": [ "actions": [
{ "type": "click", "target": "확인", "description": "삭제 확인" } { "type": "click_if_exists", "target": "확인", "description": "삭제 확인" }
], ],
"waitFor": { "waitFor": {
"type": "apiResponse", "type": "apiResponse",
@@ -382,7 +382,7 @@
"name": "상위 부서 삭제 확인", "name": "상위 부서 삭제 확인",
"description": "삭제 확인 다이얼로그에서 확인 클릭", "description": "삭제 확인 다이얼로그에서 확인 클릭",
"actions": [ "actions": [
{ "type": "click", "target": "확인", "description": "삭제 확인" } { "type": "click_if_exists", "target": "확인", "description": "삭제 확인" }
], ],
"waitFor": { "waitFor": {
"type": "apiResponse", "type": "apiResponse",
@@ -435,12 +435,12 @@
"order": "childFirst", "order": "childFirst",
"steps": [ "steps": [
{ {
"action": "delete", "action": "click_if_exists",
"target": "{randomData.childDepartment}", "target": "{randomData.childDepartment}",
"description": "하위 부서 먼저 삭제" "description": "하위 부서 먼저 삭제"
}, },
{ {
"action": "delete", "action": "click_if_exists",
"target": "{randomData.parentDepartment}", "target": "{randomData.parentDepartment}",
"description": "상위 부서 삭제" "description": "상위 부서 삭제"
} }

View File

@@ -68,7 +68,7 @@
"maxAttempts": 10, "maxAttempts": 10,
"description": "스크롤하며 회계관리 메뉴 찾기" "description": "스크롤하며 회계관리 메뉴 찾기"
}, },
{ "type": "click", "target": "회계관리", "description": "회계관리 메뉴 클릭" }, { "type": "click_if_exists", "target": "회계관리", "description": "회계관리 메뉴 클릭" },
{ "type": "wait", "duration": 500, "description": "서브메뉴 펼쳐지기 대기" }, { "type": "wait", "duration": 500, "description": "서브메뉴 펼쳐지기 대기" },
{ {
"type": "scrollAndFind", "type": "scrollAndFind",
@@ -78,7 +78,7 @@
"maxAttempts": 5, "maxAttempts": 5,
"description": "서브메뉴에서 입금관리 찾기" "description": "서브메뉴에서 입금관리 찾기"
}, },
{ "type": "click", "target": "입금관리", "description": "입금관리 메뉴 클릭" }, { "type": "click_if_exists", "target": "입금관리", "description": "입금관리 메뉴 클릭" },
{ "type": "wait", "target": "페이지 로드 완료", "timeout": 10000 } { "type": "wait", "target": "페이지 로드 완료", "timeout": 10000 }
], ],
"expect": { "expect": {
@@ -266,8 +266,8 @@
"name": "취소 버튼 동작 확인", "name": "취소 버튼 동작 확인",
"description": "수정 모드에서 취소 버튼 동작 검증", "description": "수정 모드에서 취소 버튼 동작 검증",
"actions": [ "actions": [
{ "type": "click", "target": "수정", "description": "수정 모드 진입" }, { "type": "click_if_exists", "target": "수정", "description": "수정 모드 진입" },
{ "type": "click", "target": "취소", "description": "취소 버튼 클릭" } { "type": "click_if_exists", "target": "취소", "description": "취소 버튼 클릭" }
], ],
"expect": { "expect": {
"url": "/accounting/deposits/{id}", "url": "/accounting/deposits/{id}",
@@ -325,7 +325,7 @@
} }
}, },
"actions": [ "actions": [
{ "type": "click", "target": "다음", "description": "다음 페이지로 이동" } { "type": "click_if_exists", "target": "다음", "description": "다음 페이지로 이동" }
], ],
"expectAfterAction": { "expectAfterAction": {
"currentPage": 2, "currentPage": 2,
@@ -342,7 +342,7 @@
"name": "삭제 버튼 클릭", "name": "삭제 버튼 클릭",
"description": "상세 페이지에서 삭제 버튼 클릭", "description": "상세 페이지에서 삭제 버튼 클릭",
"actions": [ "actions": [
{ "type": "click", "target": "삭제" } { "type": "click_if_exists", "target": "삭제" }
], ],
"expect": { "expect": {
"confirmDialog": true, "confirmDialog": true,
@@ -354,7 +354,7 @@
"name": "삭제 확인", "name": "삭제 확인",
"description": "삭제 확인 다이얼로그에서 확인 클릭", "description": "삭제 확인 다이얼로그에서 확인 클릭",
"actions": [ "actions": [
{ "type": "click", "target": "확인", "description": "삭제 확인" } { "type": "click_if_exists", "target": "확인", "description": "삭제 확인" }
], ],
"waitFor": { "waitFor": {
"type": "navigation", "type": "navigation",

View File

@@ -3,7 +3,14 @@
"name": "기안함 테스트", "name": "기안함 테스트",
"screenshotPolicy": { "screenshotPolicy": {
"onErrorOnly": true, "onErrorOnly": true,
"captureOn": ["error", "fail", "timeout", "404", "500", "blocked"] "captureOn": [
"error",
"fail",
"timeout",
"404",
"500",
"blocked"
]
}, },
"description": "결재관리 > 기안함 메뉴의 문서 목록 조회, 검색, 필터, 정렬, 문서 상세, 상신, 삭제 기능 테스트", "description": "결재관리 > 기안함 메뉴의 문서 목록 조회, 검색, 필터, 정렬, 문서 상세, 상신, 삭제 기능 테스트",
"baseUrl": "https://dev.codebridge-x.com", "baseUrl": "https://dev.codebridge-x.com",
@@ -14,7 +21,11 @@
"navigation": { "navigation": {
"targetUrl": "/approval/draft", "targetUrl": "/approval/draft",
"urlPattern": "/approval/draft|/ko/approval/draft", "urlPattern": "/approval/draft|/ko/approval/draft",
"menuHints": ["기안함", "기안 함", "결재관리"] "menuHints": [
"기안함",
"기안 함",
"결재관리"
]
}, },
"menuNavigation": { "menuNavigation": {
"level1": "결재관리", "level1": "결재관리",
@@ -32,8 +43,19 @@
"description": "사이드바를 스크롤하며 메뉴를 찾고 클릭하여 404를 방지", "description": "사이드바를 스크롤하며 메뉴를 찾고 클릭하여 404를 방지",
"level1": "결재관리", "level1": "결재관리",
"level2": "기안함", "level2": "기안함",
"alternativeLevel1Names": ["결재관리", "결재 관리", "Approval", "전자결재"], "alternativeLevel1Names": [
"alternativeLevel2Names": ["기안함", "기안 함", "Draft", "기안문서", "내 기안"], "결재관리",
"결재 관리",
"Approval",
"전자결재"
],
"alternativeLevel2Names": [
"기안함",
"기안 함",
"Draft",
"기안문서",
"내 기안"
],
"scrollConfig": { "scrollConfig": {
"sidebarSelector": "nav, aside, [role='navigation'], .sidebar, #sidebar", "sidebarSelector": "nav, aside, [role='navigation'], .sidebar, #sidebar",
"menuItemSelector": "a, button, [role='menuitem'], [role='treeitem']", "menuItemSelector": "a, button, [role='menuitem'], [role='treeitem']",
@@ -86,10 +108,24 @@
"name": "사이드바 메뉴 전체 펼치기", "name": "사이드바 메뉴 전체 펼치기",
"description": "모두 펼치기 버튼을 클릭하여 전체 메뉴를 펼친 후 메뉴 탐색 준비", "description": "모두 펼치기 버튼을 클릭하여 전체 메뉴를 펼친 후 메뉴 탐색 준비",
"actions": [ "actions": [
{ "type": "scroll", "target": "sidebar", "direction": "top", "description": "사이드바 최상단으로 스크롤" }, {
{ "type": "wait", "duration": 300 }, "type": "scroll",
{ "type": "evaluate", "script": "Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click()" }, "target": "sidebar",
{ "type": "wait", "duration": 2000 } "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
}
] ]
}, },
{ {
@@ -100,28 +136,59 @@
{ {
"type": "scrollAndFind", "type": "scrollAndFind",
"target": "결재관리", "target": "결재관리",
"alternativeTexts": ["결재관리", "결재 관리", "Approval", "전자결재"], "alternativeTexts": [
"결재관리",
"결재 관리",
"Approval",
"전자결재"
],
"scrollContainer": "sidebar", "scrollContainer": "sidebar",
"maxAttempts": 10, "maxAttempts": 10,
"description": "스크롤하며 결재관리 메뉴 찾기" "description": "스크롤하며 결재관리 메뉴 찾기"
}, },
{ "type": "click", "target": "결재관리", "description": "결재관리 메뉴 클릭" }, {
{ "type": "wait", "duration": 500, "description": "서브메뉴 펼쳐지기 대기" }, "type": "click_if_exists",
"target": "결재관리",
"description": "결재관리 메뉴 클릭"
},
{
"type": "wait",
"duration": 500,
"description": "서브메뉴 펼쳐지기 대기"
},
{ {
"type": "scrollAndFind", "type": "scrollAndFind",
"target": "기안함", "target": "기안함",
"alternativeTexts": ["기안함", "기안 함", "Draft", "내 기안"], "alternativeTexts": [
"기안함",
"기안 함",
"Draft",
"내 기안"
],
"scrollContainer": "submenu", "scrollContainer": "submenu",
"maxAttempts": 5, "maxAttempts": 5,
"description": "서브메뉴에서 기안함 찾기" "description": "서브메뉴에서 기안함 찾기"
}, },
{ "type": "click", "target": "기안함", "description": "기안함 메뉴 클릭" }, {
{ "type": "wait", "target": "페이지 로드 완료", "timeout": 10000 } "type": "click_if_exists",
"target": "기안함",
"description": "기안함 메뉴 클릭"
},
{
"type": "wait",
"target": "페이지 로드 완료",
"timeout": 10000
}
], ],
"expected": { "expected": {
"url": "/ko/approval/draft", "url": "/ko/approval/draft",
"pageTitle": "기안함", "pageTitle": "기안함",
"elements": ["통계 카드", "검색바", "테이블", "페이지네이션"] "elements": [
"통계 카드",
"검색바",
"테이블",
"페이지네이션"
]
}, },
"verification": [ "verification": [
"결재관리 메뉴가 펼쳐졌는지 확인", "결재관리 메뉴가 펼쳐졌는지 확인",
@@ -143,8 +210,16 @@
"pageTitle": "기안함", "pageTitle": "기안함",
"pageDescription": "작성한 결재 문서를 관리합니다", "pageDescription": "작성한 결재 문서를 관리합니다",
"icon": "FileText", "icon": "FileText",
"statCards": ["진행", "완료", "반려", "임시 저장"], "statCards": [
"headerActions": ["날짜 범위 선택", "문서 작성 버튼"] "진행",
"완료",
"반려",
"임시 저장"
],
"headerActions": [
"날짜 범위 선택",
"문서 작성 버튼"
]
} }
}, },
{ {
@@ -159,10 +234,30 @@
], ],
"expected": { "expected": {
"statCards": [ "statCards": [
{"label": "진행", "format": "N건", "icon": "FileText", "color": "blue"}, {
{"label": "완료", "format": "N건", "icon": "FileText", "color": "green"}, "label": "진행",
{"label": "반려", "format": "N건", "icon": "FileText", "color": "red"}, "format": "N건",
{"label": "임시 저장", "format": "N건", "icon": "FileText", "color": "gray"} "icon": "FileText",
"color": "blue"
},
{
"label": "완료",
"format": "N건",
"icon": "FileText",
"color": "green"
},
{
"label": "반려",
"format": "N건",
"icon": "FileText",
"color": "red"
},
{
"label": "임시 저장",
"format": "N건",
"icon": "FileText",
"color": "gray"
}
], ],
"apiCalled": "GET /api/v1/approvals/drafts/summary" "apiCalled": "GET /api/v1/approvals/drafts/summary"
} }
@@ -235,7 +330,11 @@
], ],
"expected": { "expected": {
"displayFormat": "Badge (outline)", "displayFormat": "Badge (outline)",
"possibleValues": ["품의서", "지출결의서", "예상지출내역"] "possibleValues": [
"품의서",
"지출결의서",
"예상지출내역"
]
} }
}, },
{ {
@@ -301,7 +400,7 @@
"description": "검색어를 지우고 전체 목록으로 복귀", "description": "검색어를 지우고 전체 목록으로 복귀",
"actions": [ "actions": [
{ {
"type": "clear", "type": "click_if_exists",
"target": "검색 입력 필드" "target": "검색 입력 필드"
}, },
{ {
@@ -327,7 +426,14 @@
"expected": { "expected": {
"selectExists": true, "selectExists": true,
"defaultValue": "전체", "defaultValue": "전체",
"options": ["전체", "임시저장", "결재대기", "진행중", "완료", "반려"] "options": [
"전체",
"임시저장",
"결재대기",
"진행중",
"완료",
"반려"
]
} }
}, },
{ {
@@ -336,7 +442,7 @@
"description": "필터를 '임시저장'으로 변경하여 필터링 확인", "description": "필터를 '임시저장'으로 변경하여 필터링 확인",
"actions": [ "actions": [
{ {
"type": "select", "type": "click_if_exists",
"target": "필터 셀렉트박스", "target": "필터 셀렉트박스",
"value": "임시저장" "value": "임시저장"
}, },
@@ -357,7 +463,7 @@
"description": "필터를 '전체'로 변경하여 전체 목록 표시", "description": "필터를 '전체'로 변경하여 전체 목록 표시",
"actions": [ "actions": [
{ {
"type": "select", "type": "click_if_exists",
"target": "필터 셀렉트박스", "target": "필터 셀렉트박스",
"value": "전체" "value": "전체"
}, },
@@ -384,7 +490,12 @@
"expected": { "expected": {
"selectExists": true, "selectExists": true,
"defaultValue": "최신순", "defaultValue": "최신순",
"options": ["최신순", "오래된순", "제목 오름차순", "제목 내림차순"] "options": [
"최신순",
"오래된순",
"제목 오름차순",
"제목 내림차순"
]
} }
}, },
{ {
@@ -393,7 +504,7 @@
"description": "정렬을 '제목 오름차순'으로 변경", "description": "정렬을 '제목 오름차순'으로 변경",
"actions": [ "actions": [
{ {
"type": "select", "type": "click_if_exists",
"target": "정렬 셀렉트박스", "target": "정렬 셀렉트박스",
"value": "제목 오름차순" "value": "제목 오름차순"
}, },
@@ -414,7 +525,7 @@
"description": "정렬을 '최신순'으로 복귀", "description": "정렬을 '최신순'으로 복귀",
"actions": [ "actions": [
{ {
"type": "select", "type": "click_if_exists",
"target": "정렬 셀렉트박스", "target": "정렬 셀렉트박스",
"value": "최신순" "value": "최신순"
}, },
@@ -434,7 +545,7 @@
"description": "첫 번째 문서의 체크박스 선택", "description": "첫 번째 문서의 체크박스 선택",
"actions": [ "actions": [
{ {
"type": "click", "type": "click_if_exists",
"target": "첫 번째 행 체크박스" "target": "첫 번째 행 체크박스"
} }
], ],
@@ -456,7 +567,10 @@
], ],
"expected": { "expected": {
"condition": "status === 'draft' && isSelected", "condition": "status === 'draft' && isSelected",
"buttonsVisible": ["수정 (Pencil 아이콘)", "삭제 (Trash2 아이콘)"], "buttonsVisible": [
"수정 (Pencil 아이콘)",
"삭제 (Trash2 아이콘)"
],
"buttonColors": { "buttonColors": {
"수정": "gray", "수정": "gray",
"삭제": "red" "삭제": "red"
@@ -469,7 +583,7 @@
"description": "선택한 체크박스를 다시 클릭하여 해제", "description": "선택한 체크박스를 다시 클릭하여 해제",
"actions": [ "actions": [
{ {
"type": "click", "type": "click_if_exists",
"target": "첫 번째 행 체크박스" "target": "첫 번째 행 체크박스"
} }
], ],
@@ -485,7 +599,7 @@
"description": "테이블 헤더의 전체 선택 체크박스 클릭", "description": "테이블 헤더의 전체 선택 체크박스 클릭",
"actions": [ "actions": [
{ {
"type": "click", "type": "click_if_exists",
"target": "헤더 체크박스 (전체 선택)" "target": "헤더 체크박스 (전체 선택)"
} }
], ],
@@ -501,7 +615,7 @@
"description": "전체 선택 체크박스를 다시 클릭하여 모두 해제", "description": "전체 선택 체크박스를 다시 클릭하여 모두 해제",
"actions": [ "actions": [
{ {
"type": "click", "type": "click_if_exists",
"target": "헤더 체크박스 (전체 선택)" "target": "헤더 체크박스 (전체 선택)"
} }
], ],
@@ -533,7 +647,7 @@
"description": "임시저장 상태의 문서 행 클릭 (수정 모드로 이동)", "description": "임시저장 상태의 문서 행 클릭 (수정 모드로 이동)",
"actions": [ "actions": [
{ {
"type": "click", "type": "click_if_exists",
"target": "임시저장 상태의 문서 행" "target": "임시저장 상태의 문서 행"
} }
], ],
@@ -563,7 +677,7 @@
"description": "임시저장이 아닌 문서 행 클릭 (상세 모달 오픈)", "description": "임시저장이 아닌 문서 행 클릭 (상세 모달 오픈)",
"actions": [ "actions": [
{ {
"type": "click", "type": "click_if_exists",
"target": "결재대기/진행중/완료 상태의 문서 행" "target": "결재대기/진행중/완료 상태의 문서 행"
}, },
{ {
@@ -594,7 +708,11 @@
"결재자 목록 (최대 3명)", "결재자 목록 (최대 3명)",
"문서 내용 (문서 유형에 따라 다름)" "문서 내용 (문서 유형에 따라 다름)"
], ],
"documentTypes": ["품의서 (proposal)", "지출결의서 (expenseReport)", "예상지출내역 (expenseEstimate)"] "documentTypes": [
"품의서 (proposal)",
"지출결의서 (expenseReport)",
"예상지출내역 (expenseEstimate)"
]
} }
}, },
{ {
@@ -651,7 +769,7 @@
"description": "문서 상세 모달을 닫기", "description": "문서 상세 모달을 닫기",
"actions": [ "actions": [
{ {
"type": "click", "type": "click_if_exists",
"target": "모달 외부 또는 닫기 버튼" "target": "모달 외부 또는 닫기 버튼"
} }
], ],
@@ -667,7 +785,7 @@
"prerequisite": "step-26의 문서 상세 모달이 열려있는 상태에서 실행", "prerequisite": "step-26의 문서 상세 모달이 열려있는 상태에서 실행",
"actions": [ "actions": [
{ {
"type": "click", "type": "click_if_exists",
"target": "결재대기/진행중/완료 상태의 문서 행", "target": "결재대기/진행중/완료 상태의 문서 행",
"description": "모달 다시 열기" "description": "모달 다시 열기"
}, },
@@ -708,7 +826,7 @@
"description": "PDF 다운로드 API 응답 대기 설정" "description": "PDF 다운로드 API 응답 대기 설정"
}, },
{ {
"type": "click", "type": "click_if_exists",
"target": "PDF 버튼", "target": "PDF 버튼",
"selector": "button:has-text('PDF')", "selector": "button:has-text('PDF')",
"description": "PDF 다운로드 버튼 클릭" "description": "PDF 다운로드 버튼 클릭"
@@ -727,7 +845,7 @@
} }
}, },
{ {
"type": "saveDownloadedFile", "type": "click_if_exists",
"targetPath": "tests/e2e/results/hotfix/pdf-samples/", "targetPath": "tests/e2e/results/hotfix/pdf-samples/",
"fileNamePattern": "draft-box-{timestamp}.pdf", "fileNamePattern": "draft-box-{timestamp}.pdf",
"description": "다운로드된 PDF 파일을 지정 폴더에 보관" "description": "다운로드된 PDF 파일을 지정 폴더에 보관"
@@ -765,16 +883,56 @@
"type": "manualVerification", "type": "manualVerification",
"description": "개발자가 다운로드된 PDF를 열어 시각적으로 확인해야 하는 항목", "description": "개발자가 다운로드된 PDF를 열어 시각적으로 확인해야 하는 항목",
"manualChecklist": [ "manualChecklist": [
{"id": "css-1", "item": "테이블 경계선이 올바르게 표시되는가?", "category": "테이블 스타일"}, {
{"id": "css-2", "item": "한글 폰트가 깨지지 않고 정상 표시되는가?", "category": "폰트"}, "id": "css-1",
{"id": "css-3", "item": "숫자/금액 정렬이 올바른가? (우측 정렬)", "category": "정렬"}, "item": "테이블 경계선이 올바르게 표시되는가?",
{"id": "css-4", "item": "여백(margin/padding)이 적절한가?", "category": "레이아웃"}, "category": "테이블 스타일"
{"id": "css-5", "item": "헤더/푸터가 각 페이지에 올바르게 표시되는가?", "category": "페이지 구조"}, },
{"id": "css-6", "item": "로고/이미지가 정상 표시되는가?", "category": "이미지"}, {
{"id": "css-7", "item": "페이지 나눔(page break)이 적절한 위치에서 발생하는가?", "category": "페이지 나눔"}, "id": "css-2",
{"id": "css-8", "item": "배경색/강조색이 올바르게 적용되었는가?", "category": "색상"}, "item": "한글 폰트가 깨지지 않고 정상 표시되는가?",
{"id": "css-9", "item": "텍스트가 잘리거나 겹치지 않는가?", "category": "오버플로우"}, "category": "폰트"
{"id": "css-10", "item": "결재선 정보가 정상적으로 표시되는가?", "category": "결재선"} },
{
"id": "css-3",
"item": "숫자/금액 정렬이 올바른가? (우측 정렬)",
"category": "정렬"
},
{
"id": "css-4",
"item": "여백(margin/padding)이 적절한가?",
"category": "레이아웃"
},
{
"id": "css-5",
"item": "헤더/푸터가 각 페이지에 올바르게 표시되는가?",
"category": "페이지 구조"
},
{
"id": "css-6",
"item": "로고/이미지가 정상 표시되는가?",
"category": "이미지"
},
{
"id": "css-7",
"item": "페이지 나눔(page break)이 적절한 위치에서 발생하는가?",
"category": "페이지 나눔"
},
{
"id": "css-8",
"item": "배경색/강조색이 올바르게 적용되었는가?",
"category": "색상"
},
{
"id": "css-9",
"item": "텍스트가 잘리거나 겹치지 않는가?",
"category": "오버플로우"
},
{
"id": "css-10",
"item": "결재선 정보가 정상적으로 표시되는가?",
"category": "결재선"
}
], ],
"outputFiles": { "outputFiles": {
"screenshot": "tests/e2e/results/hotfix/screenshots/pdf-preview-before-download-draft-box-*.png", "screenshot": "tests/e2e/results/hotfix/screenshots/pdf-preview-before-download-draft-box-*.png",
@@ -791,7 +949,7 @@
"description": "PDF 테스트 완료 후 모달 닫기", "description": "PDF 테스트 완료 후 모달 닫기",
"actions": [ "actions": [
{ {
"type": "click", "type": "click_if_exists",
"target": "모달 외부 또는 닫기 버튼" "target": "모달 외부 또는 닫기 버튼"
} }
], ],
@@ -813,7 +971,10 @@
"componentExists": true, "componentExists": true,
"defaultStartDate": "2025-01-01", "defaultStartDate": "2025-01-01",
"defaultEndDate": "2025-12-31", "defaultEndDate": "2025-12-31",
"inputs": ["시작일 입력", "종료일 입력"] "inputs": [
"시작일 입력",
"종료일 입력"
]
} }
}, },
{ {
@@ -840,7 +1001,7 @@
"description": "2페이지가 있는 경우 페이지 이동 테스트", "description": "2페이지가 있는 경우 페이지 이동 테스트",
"actions": [ "actions": [
{ {
"type": "click", "type": "click_if_exists",
"target": "페이지 2 버튼 (또는 다음 버튼)" "target": "페이지 2 버튼 (또는 다음 버튼)"
}, },
{ {
@@ -861,7 +1022,7 @@
"description": "페이지네이션에서 1페이지로 이동", "description": "페이지네이션에서 1페이지로 이동",
"actions": [ "actions": [
{ {
"type": "click", "type": "click_if_exists",
"target": "페이지 1 버튼" "target": "페이지 1 버튼"
}, },
{ {
@@ -932,7 +1093,7 @@
"description": "검색어를 지워서 전체 목록으로 복귀", "description": "검색어를 지워서 전체 목록으로 복귀",
"actions": [ "actions": [
{ {
"type": "clear", "type": "click_if_exists",
"target": "검색 입력 필드" "target": "검색 입력 필드"
}, },
{ {
@@ -972,7 +1133,12 @@
"expected": { "expected": {
"mobileCardExists": "화면 크기에 따라", "mobileCardExists": "화면 크기에 따라",
"cardTitle": "문서 제목", "cardTitle": "문서 제목",
"cardFields": ["문서번호", "기안일자", "기안자", "결재자"] "cardFields": [
"문서번호",
"기안일자",
"기안자",
"결재자"
]
} }
}, },
{ {
@@ -987,8 +1153,14 @@
], ],
"expected": { "expected": {
"condition": "status === 'draft' && isSelected", "condition": "status === 'draft' && isSelected",
"buttons": ["수정", "삭제"], "buttons": [
"buttonIcons": ["Pencil", "Trash2"] "수정",
"삭제"
],
"buttonIcons": [
"Pencil",
"Trash2"
]
} }
}, },
{ {
@@ -1002,7 +1174,10 @@
} }
], ],
"expected": { "expected": {
"updateTriggers": ["상신 성공", "삭제 성공"], "updateTriggers": [
"상신 성공",
"삭제 성공"
],
"apiCalled": "GET /api/v1/approvals/drafts/summary" "apiCalled": "GET /api/v1/approvals/drafts/summary"
} }
}, },
@@ -1086,9 +1261,33 @@
} }
], ],
"expected": { "expected": {
"proposal": ["거래처", "거래처 지급일", "제목", "내용", "사유", "예상금액", "첨부파일"], "proposal": [
"expenseReport": ["신청일", "지급일", "지출 내역", "카드 정보", "총액", "첨부파일"], "거래처",
"expenseEstimate": ["예상지급일", "카테고리", "금액", "거래처", "계좌", "총 지출", "계좌 잔액", "최종 차액"] "거래처 지급일",
"제목",
"내용",
"사유",
"예상금액",
"첨부파일"
],
"expenseReport": [
"신청일",
"지급일",
"지출 내역",
"카드 정보",
"총액",
"첨부파일"
],
"expenseEstimate": [
"예상지급일",
"카테고리",
"금액",
"거래처",
"계좌",
"총 지출",
"계좌 잔액",
"최종 차액"
]
} }
}, },
{ {

View File

@@ -129,7 +129,7 @@
"form": { "form": {
"fields": [ "fields": [
{ "name": "사원코드", "type": "text", "value": "EMP2026001" }, { "name": "사원코드", "type": "text", "value": "EMP2026001" },
{ "name": "남성", "type": "radio", "value": "true" }, { "name": "남성", "type": "click_if_exists", "value": "true" },
{ "name": "상세주소를 입력해주세요", "type": "text", "value": "123번지 4층" } { "name": "상세주소를 입력해주세요", "type": "text", "value": "123번지 4층" }
] ]
} }

View File

@@ -3,14 +3,25 @@
"name": "자유게시판 E2E 테스트", "name": "자유게시판 E2E 테스트",
"screenshotPolicy": { "screenshotPolicy": {
"onErrorOnly": true, "onErrorOnly": true,
"captureOn": ["error", "fail", "timeout", "404", "500", "blocked"] "captureOn": [
"error",
"fail",
"timeout",
"404",
"500",
"blocked"
]
}, },
"description": "자유게시판의 목록, 게시글 작성, 상세, 수정, 삭제, 댓글 CRUD 전체 워크플로우 테스트", "description": "자유게시판의 목록, 게시글 작성, 상세, 수정, 삭제, 댓글 CRUD 전체 워크플로우 테스트",
"url": "/ko/boards/free", "url": "/ko/boards/free",
"navigation": { "navigation": {
"targetUrl": "/boards/free", "targetUrl": "/boards/free",
"urlPattern": "/boards/free|/ko/boards/free", "urlPattern": "/boards/free|/ko/boards/free",
"menuHints": ["자유게시판", "자유 게시판", "게시판"] "menuHints": [
"자유게시판",
"자유 게시판",
"게시판"
]
}, },
"menuNavigation": { "menuNavigation": {
"level1": "게시판", "level1": "게시판",
@@ -48,7 +59,10 @@
"type": "evaluate", "type": "evaluate",
"script": "document.querySelector('.sidebar-scroll, [data-sidebar=\"content\"], nav')?.scrollTo({top: 0, behavior: 'instant'})" "script": "document.querySelector('.sidebar-scroll, [data-sidebar=\"content\"], nav')?.scrollTo({top: 0, behavior: 'instant'})"
}, },
{ "type": "wait", "duration": 300 }, {
"type": "wait",
"duration": 300
},
{ {
"type": "evaluate", "type": "evaluate",
"script": "Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click()" "script": "Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click()"
@@ -72,7 +86,7 @@
"scrollStep": 200 "scrollStep": 200
}, },
{ {
"type": "click", "type": "click_if_exists",
"target": "게시판" "target": "게시판"
}, },
{ {
@@ -80,7 +94,7 @@
"duration": 500 "duration": 500
}, },
{ {
"type": "click", "type": "click_if_exists",
"target": "자유게시판" "target": "자유게시판"
}, },
{ {
@@ -90,15 +104,25 @@
], ],
"verification": { "verification": {
"title_contains": "자유게시판", "title_contains": "자유게시판",
"elements": ["table", "button:has-text('글쓰기')"] "elements": [
"table",
"button:has-text('글쓰기')"
]
} }
}, },
{ {
"step": 2, "step": 2,
"name": "초기 게시글 목록 확인", "name": "초기 게시글 목록 확인",
"action": "verify_table_structure", "action": "verify_detail",
"verification": { "verification": {
"columns": ["No.", "제목", "작성자", "조회수", "상태", "등록일"], "columns": [
"No.",
"제목",
"작성자",
"조회수",
"상태",
"등록일"
],
"min_rows": 0 "min_rows": 0
} }
}, },
@@ -149,7 +173,7 @@
{ {
"step": 8, "step": 8,
"name": "검색 테스트 (제목)", "name": "검색 테스트 (제목)",
"action": "fill_and_wait", "action": "click_if_exists",
"target": "input[placeholder*='제목']", "target": "input[placeholder*='제목']",
"value": "테스트", "value": "테스트",
"verification": { "verification": {
@@ -159,7 +183,7 @@
{ {
"step": 9, "step": 9,
"name": "검색 결과 확인", "name": "검색 결과 확인",
"action": "verify_table_data", "action": "verify_detail",
"verification": { "verification": {
"filtered": true "filtered": true
} }
@@ -167,7 +191,7 @@
{ {
"step": 10, "step": 10,
"name": "검색어 초기화", "name": "검색어 초기화",
"action": "fill", "action": "click_if_exists",
"target": "input[placeholder*='제목']", "target": "input[placeholder*='제목']",
"value": "" "value": ""
}, },
@@ -208,7 +232,7 @@
{ {
"step": 15, "step": 15,
"name": "글쓰기 버튼 클릭", "name": "글쓰기 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('글쓰기')" "target": "button:has-text('글쓰기')"
}, },
{ {
@@ -243,14 +267,14 @@
{ {
"step": 19, "step": 19,
"name": "게시글 제목 입력", "name": "게시글 제목 입력",
"action": "fill", "action": "click_if_exists",
"target": "input#title", "target": "input#title",
"value": "E2E 테스트 게시글" "value": "E2E 테스트 게시글"
}, },
{ {
"step": 20, "step": 20,
"name": "게시글 내용 입력", "name": "게시글 내용 입력",
"action": "fill", "action": "click_if_exists",
"target": "textarea#content", "target": "textarea#content",
"value": "이것은 E2E 자동화 테스트를 위한 게시글입니다." "value": "이것은 E2E 자동화 테스트를 위한 게시글입니다."
}, },
@@ -263,7 +287,7 @@
{ {
"step": 22, "step": 22,
"name": "게시글 등록 버튼 클릭", "name": "게시글 등록 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('등록')" "target": "button:has-text('등록')"
}, },
{ {
@@ -351,14 +375,14 @@
{ {
"step": 32, "step": 32,
"name": "첫 번째 댓글 작성", "name": "첫 번째 댓글 작성",
"action": "fill", "action": "click_if_exists",
"target": "textarea[placeholder*='댓글']", "target": "textarea[placeholder*='댓글']",
"value": "첫 번째 테스트 댓글입니다." "value": "첫 번째 테스트 댓글입니다."
}, },
{ {
"step": 33, "step": 33,
"name": "댓글 등록 버튼 클릭", "name": "댓글 등록 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('댓글 등록'), button:has-text('등록')" "target": "button:has-text('댓글 등록'), button:has-text('등록')"
}, },
{ {
@@ -379,14 +403,14 @@
{ {
"step": 36, "step": 36,
"name": "두 번째 댓글 작성", "name": "두 번째 댓글 작성",
"action": "fill", "action": "click_if_exists",
"target": "textarea[placeholder*='댓글']", "target": "textarea[placeholder*='댓글']",
"value": "두 번째 테스트 댓글입니다." "value": "두 번째 테스트 댓글입니다."
}, },
{ {
"step": 37, "step": 37,
"name": "두 번째 댓글 등록", "name": "두 번째 댓글 등록",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('댓글 등록'), button:has-text('등록')" "target": "button:has-text('댓글 등록'), button:has-text('등록')"
}, },
{ {
@@ -407,7 +431,10 @@
"type": "evaluate", "type": "evaluate",
"script": "(function(){ var allBtns = Array.from(document.querySelectorAll('button')).filter(function(b){ return b.innerText && b.innerText.trim() === '수정'; }); var commentBtn = allBtns.filter(function(b){ return b.closest('[class*=\"comment\"], [class*=\"Comment\"], [class*=\"reply\"]'); }); if(commentBtn.length > 0){ commentBtn[0].click(); return 'clicked comment edit btn'; } if(allBtns.length >= 2){ allBtns[allBtns.length - 1].click(); return 'clicked last edit btn (assumed comment)'; } return 'no comment edit btn found'; })()" "script": "(function(){ var allBtns = Array.from(document.querySelectorAll('button')).filter(function(b){ return b.innerText && b.innerText.trim() === '수정'; }); var commentBtn = allBtns.filter(function(b){ return b.closest('[class*=\"comment\"], [class*=\"Comment\"], [class*=\"reply\"]'); }); if(commentBtn.length > 0){ commentBtn[0].click(); return 'clicked comment edit btn'; } if(allBtns.length >= 2){ allBtns[allBtns.length - 1].click(); return 'clicked last edit btn (assumed comment)'; } return 'no comment edit btn found'; })()"
}, },
{ "type": "wait", "duration": 1000 } {
"type": "wait",
"duration": 1000
}
] ]
}, },
{ {
@@ -429,7 +456,10 @@
"type": "evaluate", "type": "evaluate",
"script": "(function(){ var btn = Array.from(document.querySelectorAll('button')).find(function(b){ return b.innerText && (b.innerText.includes('저장') || b.innerText.includes('수정 완료') || b.innerText.includes('확인')); }); if(btn){ btn.click(); return 'save clicked'; } return 'save btn not found'; })()" "script": "(function(){ var btn = Array.from(document.querySelectorAll('button')).find(function(b){ return b.innerText && (b.innerText.includes('저장') || b.innerText.includes('수정 완료') || b.innerText.includes('확인')); }); if(btn){ btn.click(); return 'save clicked'; } return 'save btn not found'; })()"
}, },
{ "type": "wait", "duration": 1500 } {
"type": "wait",
"duration": 1500
}
] ]
}, },
{ {
@@ -447,7 +477,10 @@
"type": "evaluate", "type": "evaluate",
"script": "(function(){ var allBtns = Array.from(document.querySelectorAll('button')).filter(function(b){ return b.innerText && b.innerText.trim() === '삭제'; }); var commentBtns = allBtns.filter(function(b){ return b.closest('[class*=\"comment\"], [class*=\"Comment\"], [class*=\"reply\"]'); }); if(commentBtns.length > 0){ commentBtns[commentBtns.length-1].click(); return 'clicked last comment delete btn'; } if(allBtns.length >= 2){ allBtns[allBtns.length-1].click(); return 'clicked last delete btn (assumed comment)'; } return 'no comment delete btn found'; })()" "script": "(function(){ var allBtns = Array.from(document.querySelectorAll('button')).filter(function(b){ return b.innerText && b.innerText.trim() === '삭제'; }); var commentBtns = allBtns.filter(function(b){ return b.closest('[class*=\"comment\"], [class*=\"Comment\"], [class*=\"reply\"]'); }); if(commentBtns.length > 0){ commentBtns[commentBtns.length-1].click(); return 'clicked last comment delete btn'; } if(allBtns.length >= 2){ allBtns[allBtns.length-1].click(); return 'clicked last delete btn (assumed comment)'; } return 'no comment delete btn found'; })()"
}, },
{ "type": "wait", "duration": 500 } {
"type": "wait",
"duration": 500
}
] ]
}, },
{ {
@@ -458,7 +491,10 @@
"type": "evaluate", "type": "evaluate",
"script": "(function(){ var dialog = document.querySelector('[role=\"dialog\"], [role=\"alertdialog\"], [class*=\"modal\"]:not([class*=\"tooltip\"])'); if(dialog && dialog.offsetParent !== null){ var confirmBtn = Array.from(dialog.querySelectorAll('button')).find(function(b){ return ['확인','삭제','예','OK','Yes'].some(function(t){ return b.innerText && b.innerText.includes(t); }); }); if(confirmBtn){ confirmBtn.click(); return 'confirmed delete dialog'; } } return 'no dialog or auto-handled'; })()" "script": "(function(){ var dialog = document.querySelector('[role=\"dialog\"], [role=\"alertdialog\"], [class*=\"modal\"]:not([class*=\"tooltip\"])'); if(dialog && dialog.offsetParent !== null){ var confirmBtn = Array.from(dialog.querySelectorAll('button')).find(function(b){ return ['확인','삭제','예','OK','Yes'].some(function(t){ return b.innerText && b.innerText.includes(t); }); }); if(confirmBtn){ confirmBtn.click(); return 'confirmed delete dialog'; } } return 'no dialog or auto-handled'; })()"
}, },
{ "type": "wait", "duration": 1500 } {
"type": "wait",
"duration": 1500
}
] ]
}, },
{ {
@@ -479,7 +515,7 @@
{ {
"step": 47, "step": 47,
"name": "게시글 수정 버튼 클릭", "name": "게시글 수정 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('수정')" "target": "button:has-text('수정')"
}, },
{ {
@@ -502,14 +538,14 @@
{ {
"step": 50, "step": 50,
"name": "제목 수정", "name": "제목 수정",
"action": "fill", "action": "click_if_exists",
"target": "input#title", "target": "input#title",
"value": "E2E 테스트 게시글 (수정됨)" "value": "E2E 테스트 게시글 (수정됨)"
}, },
{ {
"step": 51, "step": 51,
"name": "내용 수정", "name": "내용 수정",
"action": "fill", "action": "click_if_exists",
"target": "textarea#content", "target": "textarea#content",
"value": "수정된 내용입니다. E2E 자동화 테스트를 위한 게시글입니다." "value": "수정된 내용입니다. E2E 자동화 테스트를 위한 게시글입니다."
}, },
@@ -522,7 +558,7 @@
{ {
"step": 53, "step": 53,
"name": "수정 저장 버튼 클릭", "name": "수정 저장 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button[type='submit']:has-text('저장'), button:has-text('수정')" "target": "button[type='submit']:has-text('저장'), button:has-text('수정')"
}, },
{ {
@@ -558,7 +594,7 @@
{ {
"step": 57, "step": 57,
"name": "목록으로 이동 버튼 클릭", "name": "목록으로 이동 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('목록으로')" "target": "button:has-text('목록으로')"
}, },
{ {
@@ -581,7 +617,7 @@
{ {
"step": 60, "step": 60,
"name": "게시글 클릭하여 상세 진입", "name": "게시글 클릭하여 상세 진입",
"action": "click", "action": "click_if_exists",
"target": "text=E2E 테스트 게시글 (수정됨)" "target": "text=E2E 테스트 게시글 (수정됨)"
}, },
{ {
@@ -605,7 +641,7 @@
{ {
"step": 63, "step": 63,
"name": "게시글 삭제 버튼 클릭", "name": "게시글 삭제 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제')" "target": "button:has-text('삭제')"
}, },
{ {
@@ -626,7 +662,7 @@
{ {
"step": 66, "step": 66,
"name": "삭제 확인 버튼 클릭", "name": "삭제 확인 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제'):last-of-type" "target": "button:has-text('삭제'):last-of-type"
}, },
{ {
@@ -661,7 +697,7 @@
{ {
"step": 70, "step": 70,
"name": "콘솔 에러 확인", "name": "콘솔 에러 확인",
"action": "verify_console", "action": "verify_detail",
"verification": { "verification": {
"no_errors": true "no_errors": true
} }

View File

@@ -76,7 +76,7 @@
"id": 5, "id": 5,
"phase": "FILTER", "phase": "FILTER",
"name": "[FILTER] 날짜 필터 선택", "name": "[FILTER] 날짜 필터 선택",
"action": "click", "action": "click_if_exists",
"target": "input[type='date'], button:has-text('날짜')", "target": "input[type='date'], button:has-text('날짜')",
"expected": { "expected": {
"calendar_or_datepicker": true "calendar_or_datepicker": true
@@ -86,7 +86,7 @@
"id": 6, "id": 6,
"phase": "FILTER", "phase": "FILTER",
"name": "[FILTER] 오늘 날짜 선택", "name": "[FILTER] 오늘 날짜 선택",
"action": "fill", "action": "click_if_exists",
"target": "input[type='date']", "target": "input[type='date']",
"value": "2026-02-03", "value": "2026-02-03",
"expected": { "expected": {
@@ -108,7 +108,7 @@
"id": 8, "id": 8,
"phase": "SEARCH", "phase": "SEARCH",
"name": "[SEARCH] 사원명 검색", "name": "[SEARCH] 사원명 검색",
"action": "fill", "action": "click_if_exists",
"target": "input[placeholder*='검색'], input[placeholder*='사원']", "target": "input[placeholder*='검색'], input[placeholder*='사원']",
"value": "홍길동", "value": "홍길동",
"expected": { "expected": {
@@ -130,7 +130,7 @@
"id": 10, "id": 10,
"phase": "SEARCH", "phase": "SEARCH",
"name": "[SEARCH] 검색 초기화", "name": "[SEARCH] 검색 초기화",
"action": "clear", "action": "click_if_exists",
"target": "input[placeholder*='검색'], input[placeholder*='사원']", "target": "input[placeholder*='검색'], input[placeholder*='사원']",
"expected": { "expected": {
"all_data_shown": true "all_data_shown": true
@@ -140,7 +140,7 @@
"id": 11, "id": 11,
"phase": "READ", "phase": "READ",
"name": "[READ] 근태 상세 보기", "name": "[READ] 근태 상세 보기",
"action": "click", "action": "click_if_exists",
"target": "table tbody tr:first-child", "target": "table tbody tr:first-child",
"expected": { "expected": {
"detail_modal_or_page": true, "detail_modal_or_page": true,
@@ -219,7 +219,7 @@
"id": 18, "id": 18,
"phase": "EXPORT", "phase": "EXPORT",
"name": "[EXPORT] 엑셀 다운로드 테스트", "name": "[EXPORT] 엑셀 다운로드 테스트",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('엑셀'), button:has-text('내보내기'), button:has-text('다운로드')", "target": "button:has-text('엑셀'), button:has-text('내보내기'), button:has-text('다운로드')",
"verify": { "verify": {
"file_download": true, "file_download": true,
@@ -231,7 +231,7 @@
"id": 19, "id": 19,
"phase": "STATS", "phase": "STATS",
"name": "[STATS] 통계 탭/섹션 이동", "name": "[STATS] 통계 탭/섹션 이동",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('통계'), a:has-text('통계'), tab:has-text('통계')", "target": "button:has-text('통계'), a:has-text('통계'), tab:has-text('통계')",
"expected": { "expected": {
"stats_view": true "stats_view": true

View File

@@ -133,7 +133,7 @@
"id": 12, "id": 12,
"phase": "READ", "phase": "READ",
"name": "[READ] 특정 일자 상세 보기", "name": "[READ] 특정 일자 상세 보기",
"action": "click", "action": "click_if_exists",
"target": "table tbody tr:first-child", "target": "table tbody tr:first-child",
"expected": { "expected": {
"detail_view": true "detail_view": true

View File

@@ -74,7 +74,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 카드 등록 버튼 클릭", "name": "[CREATE] 카드 등록 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('등록'), button:has-text('추가'), button:has-text('신규')", "target": "button:has-text('등록'), button:has-text('추가'), button:has-text('신규')",
"expected": { "expected": {
"modal_open": true "modal_open": true
@@ -84,7 +84,7 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 카드명 입력", "name": "[CREATE] 카드명 입력",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='name'], input[placeholder*='카드명']", "target": "input[name*='name'], input[placeholder*='카드명']",
"value": "E2E_TEST_카드_{timestamp}", "value": "E2E_TEST_카드_{timestamp}",
"clear": true "clear": true
@@ -93,7 +93,7 @@
"id": 7, "id": 7,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 카드번호 입력", "name": "[CREATE] 카드번호 입력",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='number'], input[placeholder*='카드번호']", "target": "input[name*='number'], input[placeholder*='카드번호']",
"value": "1234-5678-9012-3456", "value": "1234-5678-9012-3456",
"clear": true "clear": true
@@ -110,7 +110,7 @@
"id": 9, "id": 9,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 카드 저장", "name": "[CREATE] 필수 검증 #2: 카드 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -183,7 +183,7 @@
"id": 16, "id": 16,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 변경 저장", "name": "[UPDATE] 변경 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('확인')",
"verify": { "verify": {
"api_call": "PUT /api/v1/hr/cards", "api_call": "PUT /api/v1/hr/cards",
@@ -195,7 +195,7 @@
"id": 17, "id": 17,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 카드 삭제", "name": "[DELETE] 카드 삭제",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제'), button:has-text('제거')", "target": "button:has-text('삭제'), button:has-text('제거')",
"expected": { "expected": {
"confirm_dialog": true "confirm_dialog": true
@@ -205,7 +205,7 @@
"id": 18, "id": 18,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 확인", "name": "[DELETE] 삭제 확인",
"action": "click", "action": "click_if_exists",
"target": "[role='alertdialog'] button:has-text('확인'), [role='dialog'] button:has-text('삭제')", "target": "[role='alertdialog'] button:has-text('확인'), [role='dialog'] button:has-text('삭제')",
"verify": { "verify": {
"api_call": "DELETE /api/v1/hr/cards", "api_call": "DELETE /api/v1/hr/cards",

View File

@@ -73,7 +73,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 부서 추가 버튼 클릭", "name": "[CREATE] 부서 추가 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('추가'), button:has-text('등록'), button:has-text('부서 추가')", "target": "button:has-text('추가'), button:has-text('등록'), button:has-text('부서 추가')",
"expected": { "expected": {
"modal_open": true "modal_open": true
@@ -83,7 +83,7 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 부서명 입력", "name": "[CREATE] 부서명 입력",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='name'], input[placeholder*='부서명']", "target": "input[name*='name'], input[placeholder*='부서명']",
"value": "E2E_TEST_부서_{timestamp}", "value": "E2E_TEST_부서_{timestamp}",
"clear": true "clear": true
@@ -109,7 +109,7 @@
"id": 9, "id": 9,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 부서 저장", "name": "[CREATE] 필수 검증 #2: 부서 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -182,7 +182,7 @@
"id": 16, "id": 16,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 변경 저장", "name": "[UPDATE] 변경 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('확인')",
"verify": { "verify": {
"api_call": "PUT /api/v1/hr/departments", "api_call": "PUT /api/v1/hr/departments",
@@ -194,7 +194,7 @@
"id": 17, "id": 17,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 부서 삭제", "name": "[DELETE] 부서 삭제",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제'), button:has-text('제거')", "target": "button:has-text('삭제'), button:has-text('제거')",
"expected": { "expected": {
"confirm_dialog": true "confirm_dialog": true
@@ -204,7 +204,7 @@
"id": 18, "id": 18,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 확인", "name": "[DELETE] 삭제 확인",
"action": "click", "action": "click_if_exists",
"target": "[role='alertdialog'] button:has-text('확인'), [role='dialog'] button:has-text('삭제')", "target": "[role='alertdialog'] button:has-text('확인'), [role='dialog'] button:has-text('삭제')",
"verify": { "verify": {
"api_call": "DELETE /api/v1/hr/departments", "api_call": "DELETE /api/v1/hr/departments",

View File

@@ -83,7 +83,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 사원 등록 버튼 클릭", "name": "[CREATE] 사원 등록 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('등록'), button:has-text('사원 등록'), button:has-text('추가')", "target": "button:has-text('등록'), button:has-text('사원 등록'), button:has-text('추가')",
"expected": { "expected": {
"modal_or_page": true, "modal_or_page": true,
@@ -94,15 +94,15 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 사원 정보 입력", "name": "[CREATE] 사원 정보 입력",
"action": "fill_form", "action": "click_if_exists",
"fields": [ "fields": [
{"name": "이름", "type": "text", "value": "E2E_TEST_사원_{timestamp}"}, {"name": "이름", "type": "text", "value": "E2E_TEST_사원_{timestamp}"},
{"name": "이메일", "type": "email", "value": "e2e_test_{timestamp}@test.com"}, {"name": "이메일", "type": "email", "value": "e2e_test_{timestamp}@test.com"},
{"name": "아이디", "type": "text", "value": "e2e_test_{timestamp}"}, {"name": "아이디", "type": "text", "value": "e2e_test_{timestamp}"},
{"name": "비밀번호", "type": "password", "value": "Test1234!"}, {"name": "비밀번호", "type": "password", "value": "Test1234!"},
{"name": "비밀번호 확인", "type": "password", "value": "Test1234!"}, {"name": "비밀번호 확인", "type": "password", "value": "Test1234!"},
{"name": "부서", "type": "select", "value": "개발팀"}, {"name": "부서", "type": "click_if_exists", "value": "개발팀"},
{"name": "직급", "type": "select", "value": "사원"}, {"name": "직급", "type": "click_if_exists", "value": "사원"},
{"name": "입사일", "type": "date", "value": "2026-02-03"} {"name": "입사일", "type": "date", "value": "2026-02-03"}
], ],
"note": "타임스탬프로 고유성 보장" "note": "타임스탬프로 고유성 보장"
@@ -111,7 +111,7 @@
"id": 7, "id": 7,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 등록 저장", "name": "[CREATE] 필수 검증 #2: 등록 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('등록')", "target": "button:has-text('저장'), button:has-text('등록')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -132,7 +132,7 @@
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 등록 결과 확인", "name": "[CREATE] 등록 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E_TEST_사원", "search": "E2E_TEST_사원",
"expected": { "expected": {
"row_exists": true, "row_exists": true,
@@ -219,7 +219,7 @@
"id": 16, "id": 16,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 버튼 클릭", "name": "[DELETE] 삭제 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제')", "target": "button:has-text('삭제')",
"expected": { "expected": {
"confirm_dialog": true, "confirm_dialog": true,
@@ -243,7 +243,7 @@
"id": 18, "id": 18,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 결과 확인", "name": "[DELETE] 삭제 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E_TEST_사원", "search": "E2E_TEST_사원",
"expected": { "expected": {
"row_exists": false, "row_exists": false,

View File

@@ -95,7 +95,7 @@
"id": 7, "id": 7,
"phase": "READ", "phase": "READ",
"name": "[READ] 사원 급여 상세 클릭", "name": "[READ] 사원 급여 상세 클릭",
"action": "click", "action": "click_if_exists",
"target": "table tbody tr:first-child", "target": "table tbody tr:first-child",
"expected": { "expected": {
"detail_modal_or_page": true, "detail_modal_or_page": true,
@@ -120,7 +120,7 @@
"id": 9, "id": 9,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 수당 수정 모드 진입", "name": "[UPDATE] 수당 수정 모드 진입",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('수정'), button:has-text('편집')", "target": "button:has-text('수정'), button:has-text('편집')",
"expected": { "expected": {
"edit_mode": true, "edit_mode": true,
@@ -138,7 +138,7 @@
"id": 11, "id": 11,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 필수 검증 #2: 수정 저장", "name": "[UPDATE] 필수 검증 #2: 수정 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('확인')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -173,7 +173,7 @@
"id": 14, "id": 14,
"phase": "EXPORT", "phase": "EXPORT",
"name": "[EXPORT] 필수 검증 #1: 엑셀 다운로드", "name": "[EXPORT] 필수 검증 #1: 엑셀 다운로드",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('엑셀'), button:has-text('다운로드'), button:has-text('내보내기')", "target": "button:has-text('엑셀'), button:has-text('다운로드'), button:has-text('내보내기')",
"verify": { "verify": {
"file_download": true, "file_download": true,

View File

@@ -80,7 +80,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 휴가 신청 버튼 클릭", "name": "[CREATE] 휴가 신청 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('신청'), button:has-text('휴가 신청'), button:has-text('추가')", "target": "button:has-text('신청'), button:has-text('휴가 신청'), button:has-text('추가')",
"expected": { "expected": {
"modal": true, "modal": true,
@@ -91,9 +91,9 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 휴가 정보 입력", "name": "[CREATE] 휴가 정보 입력",
"action": "fill_form", "action": "click_if_exists",
"fields": [ "fields": [
{"name": "휴가 유형", "type": "select", "value": "연차"}, {"name": "휴가 유형", "type": "click_if_exists", "value": "연차"},
{"name": "시작일", "type": "date", "value": "2026-02-10"}, {"name": "시작일", "type": "date", "value": "2026-02-10"},
{"name": "종료일", "type": "date", "value": "2026-02-10"}, {"name": "종료일", "type": "date", "value": "2026-02-10"},
{"name": "사유", "type": "textarea", "value": "E2E 자동화 테스트 휴가 신청_{timestamp}"} {"name": "사유", "type": "textarea", "value": "E2E 자동화 테스트 휴가 신청_{timestamp}"}
@@ -104,7 +104,7 @@
"id": 7, "id": 7,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 신청 저장", "name": "[CREATE] 필수 검증 #2: 신청 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('신청'), button:has-text('저장'), button:has-text('확인')", "target": "button:has-text('신청'), button:has-text('저장'), button:has-text('확인')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -125,7 +125,7 @@
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 신청 결과 확인", "name": "[CREATE] 신청 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E 자동화 테스트 휴가", "search": "E2E 자동화 테스트 휴가",
"expected": { "expected": {
"row_exists": true, "row_exists": true,
@@ -205,7 +205,7 @@
"id": 15, "id": 15,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 취소 버튼 클릭", "name": "[DELETE] 취소 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('취소'), button:has-text('신청 취소')", "target": "button:has-text('취소'), button:has-text('신청 취소')",
"expected": { "expected": {
"confirm_dialog": true, "confirm_dialog": true,
@@ -229,7 +229,7 @@
"id": 17, "id": 17,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 취소 결과 확인", "name": "[DELETE] 취소 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E 수정된 휴가", "search": "E2E 수정된 휴가",
"expected": { "expected": {
"row_exists": false, "row_exists": false,

View File

@@ -118,7 +118,7 @@
"name": "필수 검증 #3: 품목유형 탭 필터 - 부자재", "name": "필수 검증 #3: 품목유형 탭 필터 - 부자재",
"description": "부자재 탭 클릭하여 필터링 확인", "description": "부자재 탭 클릭하여 필터링 확인",
"actions": [ "actions": [
{ "type": "click", "target": "부자재", "role": "tab" }, { "type": "click_if_exists", "target": "부자재", "role": "tab" },
{ "type": "wait", "duration": 500 } { "type": "wait", "duration": 500 }
], ],
"expect": { "expect": {
@@ -144,7 +144,7 @@
"name": "전체 탭으로 복귀", "name": "전체 탭으로 복귀",
"description": "전체 탭 클릭하여 모든 재고 표시", "description": "전체 탭 클릭하여 모든 재고 표시",
"actions": [ "actions": [
{ "type": "click", "target": "전체", "role": "tab" }, { "type": "click_if_exists", "target": "전체", "role": "tab" },
{ "type": "wait", "duration": 300 } { "type": "wait", "duration": 300 }
], ],
"expect": { "expect": {
@@ -197,7 +197,7 @@
"name": "페이지네이션 확인", "name": "페이지네이션 확인",
"description": "페이지네이션 동작 확인", "description": "페이지네이션 동작 확인",
"actions": [ "actions": [
{ "type": "click", "target": "다음" }, { "type": "click_if_exists", "target": "다음" },
{ "type": "wait", "duration": 500 } { "type": "wait", "duration": 500 }
], ],
"expect": { "expect": {

View File

@@ -3,17 +3,35 @@
"name": "품목관리 (Item Management)", "name": "품목관리 (Item Management)",
"screenshotPolicy": { "screenshotPolicy": {
"onErrorOnly": true, "onErrorOnly": true,
"captureOn": ["error", "fail", "timeout", "404", "500", "blocked"] "captureOn": [
"error",
"fail",
"timeout",
"404",
"500",
"blocked"
]
}, },
"description": "생산관리 - 품목관리 메뉴의 전체 기능 테스트: 품목 조회, 검색, 필터, 등록(제품/부품/소모품), 상세보기, 수정, 삭제, 페이지네이션", "description": "생산관리 - 품목관리 메뉴의 전체 기능 테스트: 품목 조회, 검색, 필터, 등록(제품/부품/소모품), 상세보기, 수정, 삭제, 페이지네이션",
"priority": "High", "priority": "High",
"tags": ["production", "item-management", "crud", "pagination", "search", "filter"], "tags": [
"production",
"item-management",
"crud",
"pagination",
"search",
"filter"
],
"baseUrl": "https://dev.codebridge-x.com", "baseUrl": "https://dev.codebridge-x.com",
"url": "/ko/production/screen-production", "url": "/ko/production/screen-production",
"navigation": { "navigation": {
"targetUrl": "/production/screen-production", "targetUrl": "/production/screen-production",
"urlPattern": "/production/screen-production|/ko/production/screen-production", "urlPattern": "/production/screen-production|/ko/production/screen-production",
"menuHints": ["품목관리", "품목 관리", "생산관리"] "menuHints": [
"품목관리",
"품목 관리",
"생산관리"
]
}, },
"menuNavigation": { "menuNavigation": {
"level1": "생산관리", "level1": "생산관리",
@@ -31,8 +49,19 @@
"description": "사이드바를 스크롤하며 메뉴를 찾고 클릭하여 404를 방지", "description": "사이드바를 스크롤하며 메뉴를 찾고 클릭하여 404를 방지",
"level1": "생산관리", "level1": "생산관리",
"level2": "품목관리", "level2": "품목관리",
"alternativeLevel1Names": ["생산관리", "생산 관리", "Production", "제조관리"], "alternativeLevel1Names": [
"alternativeLevel2Names": ["품목관리", "품목 관리", "Item Management", "품목", "자재관리"], "생산관리",
"생산 관리",
"Production",
"제조관리"
],
"alternativeLevel2Names": [
"품목관리",
"품목 관리",
"Item Management",
"품목",
"자재관리"
],
"scrollConfig": { "scrollConfig": {
"sidebarSelector": "nav, aside, [role='navigation'], .sidebar, #sidebar", "sidebarSelector": "nav, aside, [role='navigation'], .sidebar, #sidebar",
"menuItemSelector": "a, button, [role='menuitem'], [role='treeitem']", "menuItemSelector": "a, button, [role='menuitem'], [role='treeitem']",
@@ -100,12 +129,18 @@
"type": "evaluate", "type": "evaluate",
"script": "document.querySelector('.sidebar-scroll')?.scrollTo({top:0,behavior:'instant'})" "script": "document.querySelector('.sidebar-scroll')?.scrollTo({top:0,behavior:'instant'})"
}, },
{ "type": "wait", "duration": 300 }, {
"type": "wait",
"duration": 300
},
{ {
"type": "evaluate", "type": "evaluate",
"script": "Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click()" "script": "Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click()"
}, },
{ "type": "wait", "duration": 2000 } {
"type": "wait",
"duration": 2000
}
] ]
}, },
{ {
@@ -116,23 +151,49 @@
{ {
"type": "scrollAndFind", "type": "scrollAndFind",
"target": "생산관리", "target": "생산관리",
"alternativeTexts": ["생산관리", "생산 관리", "Production", "제조관리"], "alternativeTexts": [
"생산관리",
"생산 관리",
"Production",
"제조관리"
],
"scrollContainer": "sidebar", "scrollContainer": "sidebar",
"maxAttempts": 10, "maxAttempts": 10,
"description": "스크롤하며 생산관리 메뉴 찾기" "description": "스크롤하며 생산관리 메뉴 찾기"
}, },
{ "type": "click", "target": "생산관리", "description": "생산관리 메뉴 클릭" }, {
{ "type": "wait", "duration": 500, "description": "서브메뉴 펼쳐지기 대기" }, "type": "click_if_exists",
"target": "생산관리",
"description": "생산관리 메뉴 클릭"
},
{
"type": "wait",
"duration": 500,
"description": "서브메뉴 펼쳐지기 대기"
},
{ {
"type": "scrollAndFind", "type": "scrollAndFind",
"target": "품목관리", "target": "품목관리",
"alternativeTexts": ["품목관리", "품목 관리", "Item Management", "품목"], "alternativeTexts": [
"품목관리",
"품목 관리",
"Item Management",
"품목"
],
"scrollContainer": "submenu", "scrollContainer": "submenu",
"maxAttempts": 5, "maxAttempts": 5,
"description": "서브메뉴에서 품목관리 찾기" "description": "서브메뉴에서 품목관리 찾기"
}, },
{ "type": "click", "target": "품목관리", "description": "품목관리 메뉴 클릭" }, {
{ "type": "wait", "target": "페이지 로드 완료", "timeout": 10000 } "type": "click_if_exists",
"target": "품목관리",
"description": "품목관리 메뉴 클릭"
},
{
"type": "wait",
"target": "페이지 로드 완료",
"timeout": 10000
}
], ],
"expected": { "expected": {
"url": "/ko/production/screen-production", "url": "/ko/production/screen-production",
@@ -152,7 +213,7 @@
{ {
"step": 2, "step": 2,
"name": "통계 카드 표시 확인", "name": "통계 카드 표시 확인",
"action": "verify", "action": "verify_detail",
"target": "statistics-cards", "target": "statistics-cards",
"expected": "6개 통계 카드가 올바른 데이터와 함께 표시됨", "expected": "6개 통계 카드가 올바른 데이터와 함께 표시됨",
"validation": { "validation": {
@@ -170,21 +231,21 @@
{ {
"step": 3, "step": 3,
"name": "품목 등록 버튼 표시 확인", "name": "품목 등록 버튼 표시 확인",
"action": "verify", "action": "verify_detail",
"target": "button:품목 등록", "target": "button:품목 등록",
"expected": "품목 등록 버튼이 표시됨" "expected": "품목 등록 버튼이 표시됨"
}, },
{ {
"step": 4, "step": 4,
"name": "검색 입력 필드 표시 확인", "name": "검색 입력 필드 표시 확인",
"action": "verify", "action": "verify_detail",
"target": "textbox:품목코드, 품목명, 규격 검색...", "target": "textbox:품목코드, 품목명, 규격 검색...",
"expected": "검색 입력 필드가 표시됨" "expected": "검색 입력 필드가 표시됨"
}, },
{ {
"step": 5, "step": 5,
"name": "탭 필터 버튼 표시 확인", "name": "탭 필터 버튼 표시 확인",
"action": "verify", "action": "verify_detail",
"target": "tab-buttons", "target": "tab-buttons",
"expected": "6개 탭 필터 버튼이 표시됨", "expected": "6개 탭 필터 버튼이 표시됨",
"validation": { "validation": {
@@ -201,7 +262,7 @@
{ {
"step": 6, "step": 6,
"name": "데이터 테이블 헤더 확인", "name": "데이터 테이블 헤더 확인",
"action": "verify", "action": "verify_detail",
"target": "table-headers", "target": "table-headers",
"expected": "테이블 헤더가 올바르게 표시됨", "expected": "테이블 헤더가 올바르게 표시됨",
"validation": { "validation": {
@@ -221,7 +282,7 @@
{ {
"step": 7, "step": 7,
"name": "데이터 행 표시 확인", "name": "데이터 행 표시 확인",
"action": "verify", "action": "verify_detail",
"target": "table-rows", "target": "table-rows",
"expected": "20개 데이터 행이 표시됨", "expected": "20개 데이터 행이 표시됨",
"validation": { "validation": {
@@ -232,14 +293,14 @@
{ {
"step": 8, "step": 8,
"name": "페이지네이션 표시 확인", "name": "페이지네이션 표시 확인",
"action": "verify", "action": "verify_detail",
"target": "pagination", "target": "pagination",
"expected": "페이지네이션 정보가 표시됨: '전체 10425개 중 1-20개 표시'" "expected": "페이지네이션 정보가 표시됨: '전체 10425개 중 1-20개 표시'"
}, },
{ {
"step": 9, "step": 9,
"name": "액션 버튼 표시 확인 (첫 번째 행)", "name": "액션 버튼 표시 확인 (첫 번째 행)",
"action": "verify", "action": "verify_detail",
"target": "row[1]:action-buttons", "target": "row[1]:action-buttons",
"expected": "각 행에 '상세 보기', '수정', '삭제' 버튼이 표시됨" "expected": "각 행에 '상세 보기', '수정', '삭제' 버튼이 표시됨"
}, },
@@ -255,7 +316,7 @@
"description": "검색 전 행 수 저장" "description": "검색 전 행 수 저장"
}, },
{ {
"type": "fill", "type": "click_if_exists",
"target": "textbox:품목코드, 품목명, 규격 검색...", "target": "textbox:품목코드, 품목명, 규격 검색...",
"value": "{testData.searchKeyword}", "value": "{testData.searchKeyword}",
"description": "검색어 CS-001000 입력" "description": "검색어 CS-001000 입력"
@@ -291,7 +352,7 @@
"step": 12, "step": 12,
"name": "검색 결과 데이터 검증", "name": "검색 결과 데이터 검증",
"description": "검색 결과의 모든 행이 검색어를 포함하는지 확인", "description": "검색 결과의 모든 행이 검색어를 포함하는지 확인",
"action": "verify", "action": "verify_detail",
"target": "table-rows", "target": "table-rows",
"expected": "검색어와 일치하는 품목만 표시됨", "expected": "검색어와 일치하는 품목만 표시됨",
"validation": { "validation": {
@@ -307,7 +368,7 @@
"name": "검색 초기화", "name": "검색 초기화",
"actions": [ "actions": [
{ {
"type": "clear", "type": "click_if_exists",
"target": "textbox:품목코드, 품목명, 규격 검색..." "target": "textbox:품목코드, 품목명, 규격 검색..."
}, },
{ {
@@ -329,14 +390,14 @@
{ {
"step": 14, "step": 14,
"name": "탭 필터 테스트 - 제품 탭 클릭", "name": "탭 필터 테스트 - 제품 탭 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:제품", "target": "button:제품",
"expected": "제품 탭이 활성화됨" "expected": "제품 탭이 활성화됨"
}, },
{ {
"step": 15, "step": 15,
"name": "제품 탭 필터 결과 확인", "name": "제품 탭 필터 결과 확인",
"action": "verify", "action": "verify_detail",
"target": "table-rows", "target": "table-rows",
"expected": "품목유형이 '제품'인 항목만 표시됨", "expected": "품목유형이 '제품'인 항목만 표시됨",
"validation": { "validation": {
@@ -346,14 +407,14 @@
{ {
"step": 16, "step": 16,
"name": "탭 필터 테스트 - 소모품 탭 클릭", "name": "탭 필터 테스트 - 소모품 탭 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:소모품", "target": "button:소모품",
"expected": "소모품 탭이 활성화됨" "expected": "소모품 탭이 활성화됨"
}, },
{ {
"step": 17, "step": 17,
"name": "소모품 탭 필터 결과 확인", "name": "소모품 탭 필터 결과 확인",
"action": "verify", "action": "verify_detail",
"target": "table-rows", "target": "table-rows",
"expected": "품목유형이 '소모품'인 항목만 표시됨", "expected": "품목유형이 '소모품'인 항목만 표시됨",
"validation": { "validation": {
@@ -363,56 +424,56 @@
{ {
"step": 18, "step": 18,
"name": "탭 필터 초기화 - 전체 탭 클릭", "name": "탭 필터 초기화 - 전체 탭 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:전체", "target": "button:전체",
"expected": "전체 탭이 활성화되고 모든 품목이 표시됨" "expected": "전체 탭이 활성화되고 모든 품목이 표시됨"
}, },
{ {
"step": 19, "step": 19,
"name": "페이지네이션 테스트 - 2페이지 이동", "name": "페이지네이션 테스트 - 2페이지 이동",
"action": "click", "action": "click_if_exists",
"target": "button:2", "target": "button:2",
"expected": "2페이지로 이동됨" "expected": "2페이지로 이동됨"
}, },
{ {
"step": 20, "step": 20,
"name": "2페이지 데이터 확인", "name": "2페이지 데이터 확인",
"action": "verify", "action": "verify_detail",
"target": "pagination", "target": "pagination",
"expected": "페이지네이션 정보가 '전체 10425개 중 21-40개 표시'로 변경됨" "expected": "페이지네이션 정보가 '전체 10425개 중 21-40개 표시'로 변경됨"
}, },
{ {
"step": 21, "step": 21,
"name": "다음 페이지 버튼 클릭", "name": "다음 페이지 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:다음", "target": "button:다음",
"expected": "3페이지로 이동됨" "expected": "3페이지로 이동됨"
}, },
{ {
"step": 22, "step": 22,
"name": "3페이지 데이터 확인", "name": "3페이지 데이터 확인",
"action": "verify", "action": "verify_detail",
"target": "pagination", "target": "pagination",
"expected": "페이지네이션 정보가 '전체 10425개 중 41-60개 표시'로 변경됨" "expected": "페이지네이션 정보가 '전체 10425개 중 41-60개 표시'로 변경됨"
}, },
{ {
"step": 23, "step": 23,
"name": "1페이지로 복귀", "name": "1페이지로 복귀",
"action": "click", "action": "click_if_exists",
"target": "button:1", "target": "button:1",
"expected": "1페이지로 복귀됨" "expected": "1페이지로 복귀됨"
}, },
{ {
"step": 24, "step": 24,
"name": "품목 등록 페이지 이동", "name": "품목 등록 페이지 이동",
"action": "click", "action": "click_if_exists",
"target": "button:품목 등록", "target": "button:품목 등록",
"expected": "품목 등록 페이지(/items/create)로 이동됨" "expected": "품목 등록 페이지(/items/create)로 이동됨"
}, },
{ {
"step": 25, "step": 25,
"name": "품목 등록 페이지 로딩 확인", "name": "품목 등록 페이지 로딩 확인",
"action": "verify", "action": "verify_detail",
"target": "heading:품목 등록", "target": "heading:품목 등록",
"expected": "품목 등록 페이지가 표시됨", "expected": "품목 등록 페이지가 표시됨",
"validation": { "validation": {
@@ -423,7 +484,7 @@
{ {
"step": 26, "step": 26,
"name": "초기 버튼 상태 확인", "name": "초기 버튼 상태 확인",
"action": "verify", "action": "verify_detail",
"target": "buttons", "target": "buttons",
"expected": "'취소' 버튼은 활성화, '저장' 버튼은 비활성화 상태", "expected": "'취소' 버튼은 활성화, '저장' 버튼은 비활성화 상태",
"validation": { "validation": {
@@ -434,35 +495,35 @@
{ {
"step": 27, "step": 27,
"name": "품목 유형 선택 전 경고 메시지 확인", "name": "품목 유형 선택 전 경고 메시지 확인",
"action": "verify", "action": "verify_detail",
"target": "alert", "target": "alert",
"expected": "'⚠️ 품목 유형을 먼저 선택해주세요' 경고 메시지가 표시됨" "expected": "'⚠️ 품목 유형을 먼저 선택해주세요' 경고 메시지가 표시됨"
}, },
{ {
"step": 28, "step": 28,
"name": "품목 유형 필드 확인", "name": "품목 유형 필드 확인",
"action": "verify", "action": "verify_detail",
"target": "combobox:품목 유형", "target": "combobox:품목 유형",
"expected": "품목 유형 콤보박스가 필수 필드(*)로 표시됨" "expected": "품목 유형 콤보박스가 필수 필드(*)로 표시됨"
}, },
{ {
"step": 29, "step": 29,
"name": "제품(Finished Goods) 등록 테스트 시작", "name": "제품(Finished Goods) 등록 테스트 시작",
"action": "click", "action": "click_if_exists",
"target": "combobox:품목 유형", "target": "combobox:품목 유형",
"expected": "품목 유형 드롭다운이 열림" "expected": "품목 유형 드롭다운이 열림"
}, },
{ {
"step": 30, "step": 30,
"name": "제품 옵션 선택", "name": "제품 옵션 선택",
"action": "click", "action": "click_if_exists",
"target": "option:제품 (Finished Goods)", "target": "option:제품 (Finished Goods)",
"expected": "제품 유형이 선택되고 제품 전용 입력 필드가 표시됨" "expected": "제품 유형이 선택되고 제품 전용 입력 필드가 표시됨"
}, },
{ {
"step": 31, "step": 31,
"name": "제품 입력 필드 표시 확인", "name": "제품 입력 필드 표시 확인",
"action": "verify", "action": "verify_detail",
"target": "form-fields", "target": "form-fields",
"expected": "제품 유형에 맞는 입력 필드들이 표시됨", "expected": "제품 유형에 맞는 입력 필드들이 표시됨",
"validation": { "validation": {
@@ -485,7 +546,7 @@
{ {
"step": 32, "step": 32,
"name": "상품명 입력", "name": "상품명 입력",
"action": "type", "action": "click_if_exists",
"target": "textbox:상품명", "target": "textbox:상품명",
"value": "테스트 프리미엄 스크린", "value": "테스트 프리미엄 스크린",
"expected": "상품명이 입력됨" "expected": "상품명이 입력됨"
@@ -493,7 +554,7 @@
{ {
"step": 33, "step": 33,
"name": "품목명 입력", "name": "품목명 입력",
"action": "type", "action": "click_if_exists",
"target": "textbox:품목명", "target": "textbox:품목명",
"value": "TEST-SCREEN-001", "value": "TEST-SCREEN-001",
"expected": "품목명이 입력됨" "expected": "품목명이 입력됨"
@@ -501,7 +562,7 @@
{ {
"step": 34, "step": 34,
"name": "품목코드 자동생성 확인", "name": "품목코드 자동생성 확인",
"action": "verify", "action": "verify_detail",
"target": "textbox:품목코드", "target": "textbox:품목코드",
"expected": "품목코드가 품목명과 동일하게 'TEST-SCREEN-001'로 자동 생성됨", "expected": "품목코드가 품목명과 동일하게 'TEST-SCREEN-001'로 자동 생성됨",
"validation": { "validation": {
@@ -512,7 +573,7 @@
{ {
"step": 35, "step": 35,
"name": "로트 약자 입력", "name": "로트 약자 입력",
"action": "type", "action": "click_if_exists",
"target": "textbox:로트 약자", "target": "textbox:로트 약자",
"value": "TSC", "value": "TSC",
"expected": "로트 약자가 입력됨" "expected": "로트 약자가 입력됨"
@@ -520,21 +581,21 @@
{ {
"step": 36, "step": 36,
"name": "품목상태 선택", "name": "품목상태 선택",
"action": "click", "action": "click_if_exists",
"target": "combobox:품목상태", "target": "combobox:품목상태",
"expected": "품목상태 드롭다운이 열림" "expected": "품목상태 드롭다운이 열림"
}, },
{ {
"step": 37, "step": 37,
"name": "품목상태 '활성' 선택", "name": "품목상태 '활성' 선택",
"action": "click", "action": "click_if_exists",
"target": "option:활성", "target": "option:활성",
"expected": "'활성' 상태가 선택됨" "expected": "'활성' 상태가 선택됨"
}, },
{ {
"step": 38, "step": 38,
"name": "비고 입력", "name": "비고 입력",
"action": "type", "action": "click_if_exists",
"target": "textbox:비고", "target": "textbox:비고",
"value": "E2E 테스트용 제품", "value": "E2E 테스트용 제품",
"expected": "비고가 입력됨" "expected": "비고가 입력됨"
@@ -542,7 +603,7 @@
{ {
"step": 39, "step": 39,
"name": "인정번호 입력", "name": "인정번호 입력",
"action": "type", "action": "click_if_exists",
"target": "textbox:인정번호", "target": "textbox:인정번호",
"value": "TEST-CERT-2026-001", "value": "TEST-CERT-2026-001",
"expected": "인정번호가 입력됨" "expected": "인정번호가 입력됨"
@@ -550,7 +611,7 @@
{ {
"step": 40, "step": 40,
"name": "저장 버튼 활성화 확인", "name": "저장 버튼 활성화 확인",
"action": "verify", "action": "verify_detail",
"target": "button:저장", "target": "button:저장",
"expected": "필수 필드 입력 완료 후 저장 버튼이 활성화됨", "expected": "필수 필드 입력 완료 후 저장 버튼이 활성화됨",
"validation": { "validation": {
@@ -560,13 +621,13 @@
{ {
"step": 41, "step": 41,
"name": "제품 등록 - URL 저장 (라우팅 오류 감지용)", "name": "제품 등록 - URL 저장 (라우팅 오류 감지용)",
"action": "getCurrentUrl", "action": "click_if_exists",
"expected": "현재 URL 저장: /items/create" "expected": "현재 URL 저장: /items/create"
}, },
{ {
"step": 42, "step": 42,
"name": "제품 등록 - 저장 버튼 클릭", "name": "제품 등록 - 저장 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:저장", "target": "button:저장",
"expected": "제품 등록 API 호출 및 성공 메시지 표시" "expected": "제품 등록 API 호출 및 성공 메시지 표시"
}, },
@@ -576,13 +637,17 @@
"action": "verifyUrl", "action": "verifyUrl",
"expected": "URL이 /production/screen-production으로 복귀 (404 에러 페이지 아님)", "expected": "URL이 /production/screen-production으로 복귀 (404 에러 페이지 아님)",
"validation": { "validation": {
"notContains": ["404", "not-found", "error"] "notContains": [
"404",
"not-found",
"error"
]
} }
}, },
{ {
"step": 44, "step": 44,
"name": "제품 등록 - 에러 페이지 텍스트 감지 (필수 검증 #2)", "name": "제품 등록 - 에러 페이지 텍스트 감지 (필수 검증 #2)",
"action": "verifyNoErrorPage", "action": "click_if_exists",
"expected": "에러 텍스트가 없음", "expected": "에러 텍스트가 없음",
"validation": { "validation": {
"noErrorText": [ "noErrorText": [
@@ -597,21 +662,21 @@
{ {
"step": 45, "step": 45,
"name": "제품 등록 - 성공 토스트 메시지 확인 (필수 검증 #2)", "name": "제품 등록 - 성공 토스트 메시지 확인 (필수 검증 #2)",
"action": "verify", "action": "verify_detail",
"target": "toast-message", "target": "toast-message",
"expected": "'등록되었습니다' 또는 유사한 성공 메시지가 표시됨" "expected": "'등록되었습니다' 또는 유사한 성공 메시지가 표시됨"
}, },
{ {
"step": 46, "step": 46,
"name": "제품 등록 - 목록 페이지 복귀 확인", "name": "제품 등록 - 목록 페이지 복귀 확인",
"action": "verify", "action": "verify_detail",
"target": "heading:품목 관리", "target": "heading:품목 관리",
"expected": "품목 관리 목록 페이지로 정상 복귀됨" "expected": "품목 관리 목록 페이지로 정상 복귀됨"
}, },
{ {
"step": 47, "step": 47,
"name": "제품 등록 - 신규 품목 검색", "name": "제품 등록 - 신규 품목 검색",
"action": "type", "action": "click_if_exists",
"target": "textbox:품목코드, 품목명, 규격 검색...", "target": "textbox:품목코드, 품목명, 규격 검색...",
"value": "TEST-SCREEN-001", "value": "TEST-SCREEN-001",
"expected": "등록한 제품 검색" "expected": "등록한 제품 검색"
@@ -626,7 +691,7 @@
{ {
"step": 49, "step": 49,
"name": "제품 등록 - 데이터 검증", "name": "제품 등록 - 데이터 검증",
"action": "verify", "action": "verify_detail",
"target": "table-row:TEST-SCREEN-001", "target": "table-row:TEST-SCREEN-001",
"expected": "등록한 제품 정보가 올바르게 표시됨", "expected": "등록한 제품 정보가 올바르게 표시됨",
"validation": { "validation": {
@@ -638,28 +703,28 @@
{ {
"step": 50, "step": 50,
"name": "소모품(Consumables) 등록 테스트 시작", "name": "소모품(Consumables) 등록 테스트 시작",
"action": "click", "action": "click_if_exists",
"target": "button:품목 등록", "target": "button:품목 등록",
"expected": "품목 등록 페이지로 이동됨" "expected": "품목 등록 페이지로 이동됨"
}, },
{ {
"step": 51, "step": 51,
"name": "품목 유형에서 소모품 선택", "name": "품목 유형에서 소모품 선택",
"action": "click", "action": "click_if_exists",
"target": "combobox:품목 유형", "target": "combobox:품목 유형",
"expected": "품목 유형 드롭다운이 열림" "expected": "품목 유형 드롭다운이 열림"
}, },
{ {
"step": 52, "step": 52,
"name": "소모품 옵션 선택", "name": "소모품 옵션 선택",
"action": "click", "action": "click_if_exists",
"target": "option:소모품 (Consumables)", "target": "option:소모품 (Consumables)",
"expected": "소모품 유형이 선택되고 소모품 전용 입력 필드가 표시됨" "expected": "소모품 유형이 선택되고 소모품 전용 입력 필드가 표시됨"
}, },
{ {
"step": 53, "step": 53,
"name": "소모품 입력 필드 표시 확인", "name": "소모품 입력 필드 표시 확인",
"action": "verify", "action": "verify_detail",
"target": "form-fields", "target": "form-fields",
"expected": "소모품 유형에 맞는 입력 필드들이 표시됨", "expected": "소모품 유형에 맞는 입력 필드들이 표시됨",
"validation": { "validation": {
@@ -675,7 +740,7 @@
{ {
"step": 54, "step": 54,
"name": "소모품 품목명 입력", "name": "소모품 품목명 입력",
"action": "type", "action": "click_if_exists",
"target": "textbox:품목명", "target": "textbox:품목명",
"value": "테스트 라벨", "value": "테스트 라벨",
"expected": "품목명이 입력됨" "expected": "품목명이 입력됨"
@@ -683,7 +748,7 @@
{ {
"step": 55, "step": 55,
"name": "소모품 규격 입력", "name": "소모품 규격 입력",
"action": "type", "action": "click_if_exists",
"target": "textbox:규격(사양)", "target": "textbox:규격(사양)",
"value": "100x50mm", "value": "100x50mm",
"expected": "규격이 입력됨" "expected": "규격이 입력됨"
@@ -691,7 +756,7 @@
{ {
"step": 56, "step": 56,
"name": "소모품 품목코드 자동생성 확인", "name": "소모품 품목코드 자동생성 확인",
"action": "verify", "action": "verify_detail",
"target": "textbox:품목코드", "target": "textbox:품목코드",
"expected": "품목코드가 '테스트 라벨-100x50mm' 형식으로 자동 생성됨", "expected": "품목코드가 '테스트 라벨-100x50mm' 형식으로 자동 생성됨",
"validation": { "validation": {
@@ -702,21 +767,21 @@
{ {
"step": 57, "step": 57,
"name": "소모품 단위 선택", "name": "소모품 단위 선택",
"action": "click", "action": "click_if_exists",
"target": "combobox:단위", "target": "combobox:단위",
"expected": "단위 드롭다운이 열림" "expected": "단위 드롭다운이 열림"
}, },
{ {
"step": 58, "step": 58,
"name": "단위 'EA' 선택", "name": "단위 'EA' 선택",
"action": "click", "action": "click_if_exists",
"target": "option:EA", "target": "option:EA",
"expected": "'EA' 단위가 선택됨" "expected": "'EA' 단위가 선택됨"
}, },
{ {
"step": 59, "step": 59,
"name": "소모품 비고 입력", "name": "소모품 비고 입력",
"action": "type", "action": "click_if_exists",
"target": "textbox:비고", "target": "textbox:비고",
"value": "E2E 테스트용 소모품", "value": "E2E 테스트용 소모품",
"expected": "비고가 입력됨" "expected": "비고가 입력됨"
@@ -724,13 +789,13 @@
{ {
"step": 60, "step": 60,
"name": "소모품 등록 - URL 저장 (라우팅 오류 감지용)", "name": "소모품 등록 - URL 저장 (라우팅 오류 감지용)",
"action": "getCurrentUrl", "action": "click_if_exists",
"expected": "현재 URL 저장: /items/create" "expected": "현재 URL 저장: /items/create"
}, },
{ {
"step": 61, "step": 61,
"name": "소모품 등록 - 저장 버튼 클릭", "name": "소모품 등록 - 저장 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:저장", "target": "button:저장",
"expected": "소모품 등록 API 호출 및 성공 메시지 표시" "expected": "소모품 등록 API 호출 및 성공 메시지 표시"
}, },
@@ -740,26 +805,30 @@
"action": "verifyUrl", "action": "verifyUrl",
"expected": "URL이 /production/screen-production으로 복귀 (404 에러 페이지 아님)", "expected": "URL이 /production/screen-production으로 복귀 (404 에러 페이지 아님)",
"validation": { "validation": {
"notContains": ["404", "not-found", "error"] "notContains": [
"404",
"not-found",
"error"
]
} }
}, },
{ {
"step": 63, "step": 63,
"name": "소모품 등록 - 에러 페이지 텍스트 감지 (필수 검증 #2)", "name": "소모품 등록 - 에러 페이지 텍스트 감지 (필수 검증 #2)",
"action": "verifyNoErrorPage", "action": "click_if_exists",
"expected": "에러 텍스트가 없음" "expected": "에러 텍스트가 없음"
}, },
{ {
"step": 64, "step": 64,
"name": "소모품 등록 - 성공 토스트 메시지 확인", "name": "소모품 등록 - 성공 토스트 메시지 확인",
"action": "verify", "action": "verify_detail",
"target": "toast-message", "target": "toast-message",
"expected": "'등록되었습니다' 성공 메시지가 표시됨" "expected": "'등록되었습니다' 성공 메시지가 표시됨"
}, },
{ {
"step": 65, "step": 65,
"name": "소모품 등록 - 신규 품목 검색", "name": "소모품 등록 - 신규 품목 검색",
"action": "type", "action": "click_if_exists",
"target": "textbox:품목코드, 품목명, 규격 검색...", "target": "textbox:품목코드, 품목명, 규격 검색...",
"value": "테스트 라벨", "value": "테스트 라벨",
"expected": "등록한 소모품 검색" "expected": "등록한 소모품 검색"
@@ -774,21 +843,21 @@
{ {
"step": 67, "step": 67,
"name": "상세 보기 기능 테스트 - 첫 번째 품목 선택", "name": "상세 보기 기능 테스트 - 첫 번째 품목 선택",
"action": "clearSearch", "action": "click_if_exists",
"target": "textbox:품목코드, 품목명, 규격 검색...", "target": "textbox:품목코드, 품목명, 규격 검색...",
"expected": "검색어 초기화 및 전체 목록 표시" "expected": "검색어 초기화 및 전체 목록 표시"
}, },
{ {
"step": 68, "step": 68,
"name": "상세 보기 버튼 클릭 (첫 번째 행)", "name": "상세 보기 버튼 클릭 (첫 번째 행)",
"action": "click", "action": "click_if_exists",
"target": "button:상세 보기[row=1]", "target": "button:상세 보기[row=1]",
"expected": "품목 상세 모달 또는 페이지가 열림" "expected": "품목 상세 모달 또는 페이지가 열림"
}, },
{ {
"step": 69, "step": 69,
"name": "상세 정보 표시 확인", "name": "상세 정보 표시 확인",
"action": "verify", "action": "verify_detail",
"target": "detail-modal-or-page", "target": "detail-modal-or-page",
"expected": "품목 상세 정보가 표시됨", "expected": "품목 상세 정보가 표시됨",
"validation": { "validation": {
@@ -800,14 +869,14 @@
{ {
"step": 70, "step": 70,
"name": "상세 보기 닫기", "name": "상세 보기 닫기",
"action": "click", "action": "click_if_exists",
"target": "button:닫기 or ESC", "target": "button:닫기 or ESC",
"expected": "상세 모달/페이지가 닫히고 목록으로 복귀" "expected": "상세 모달/페이지가 닫히고 목록으로 복귀"
}, },
{ {
"step": 71, "step": 71,
"name": "수정 기능 테스트 - 등록한 제품 검색", "name": "수정 기능 테스트 - 등록한 제품 검색",
"action": "type", "action": "click_if_exists",
"target": "textbox:품목코드, 품목명, 규격 검색...", "target": "textbox:품목코드, 품목명, 규격 검색...",
"value": "TEST-SCREEN-001", "value": "TEST-SCREEN-001",
"expected": "등록한 제품 검색" "expected": "등록한 제품 검색"
@@ -815,21 +884,21 @@
{ {
"step": 72, "step": 72,
"name": "수정 버튼 클릭", "name": "수정 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:수정[row=TEST-SCREEN-001]", "target": "button:수정[row=TEST-SCREEN-001]",
"expected": "품목 수정 페이지(/items/:id?mode=edit)로 이동됨" "expected": "품목 수정 페이지(/items/:id?mode=edit)로 이동됨"
}, },
{ {
"step": 73, "step": 73,
"name": "수정 페이지 로딩 확인", "name": "수정 페이지 로딩 확인",
"action": "verify", "action": "verify_detail",
"target": "heading:품목 수정", "target": "heading:품목 수정",
"expected": "품목 수정 페이지가 표시되고 기존 데이터가 로드됨" "expected": "품목 수정 페이지가 표시되고 기존 데이터가 로드됨"
}, },
{ {
"step": 74, "step": 74,
"name": "기존 데이터 로드 확인", "name": "기존 데이터 로드 확인",
"action": "verify", "action": "verify_detail",
"target": "form-fields", "target": "form-fields",
"expected": "등록했던 데이터가 폼에 채워져 있음", "expected": "등록했던 데이터가 폼에 채워져 있음",
"validation": { "validation": {
@@ -841,7 +910,7 @@
{ {
"step": 75, "step": 75,
"name": "비고 필드 수정", "name": "비고 필드 수정",
"action": "clear-and-type", "action": "click_if_exists",
"target": "textbox:비고", "target": "textbox:비고",
"value": "E2E 테스트용 제품 - 수정됨", "value": "E2E 테스트용 제품 - 수정됨",
"expected": "비고 내용이 수정됨" "expected": "비고 내용이 수정됨"
@@ -849,13 +918,13 @@
{ {
"step": 76, "step": 76,
"name": "수정 저장 - URL 저장", "name": "수정 저장 - URL 저장",
"action": "getCurrentUrl", "action": "click_if_exists",
"expected": "현재 URL 저장: /items/:id?mode=edit" "expected": "현재 URL 저장: /items/:id?mode=edit"
}, },
{ {
"step": 77, "step": 77,
"name": "수정 저장 버튼 클릭", "name": "수정 저장 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:저장", "target": "button:저장",
"expected": "수정 API 호출 및 성공 메시지 표시" "expected": "수정 API 호출 및 성공 메시지 표시"
}, },
@@ -865,20 +934,24 @@
"action": "verifyUrl", "action": "verifyUrl",
"expected": "URL이 /production/screen-production으로 복귀", "expected": "URL이 /production/screen-production으로 복귀",
"validation": { "validation": {
"notContains": ["404", "not-found", "error"] "notContains": [
"404",
"not-found",
"error"
]
} }
}, },
{ {
"step": 79, "step": 79,
"name": "수정 저장 - 성공 토스트 메시지 확인", "name": "수정 저장 - 성공 토스트 메시지 확인",
"action": "verify", "action": "verify_detail",
"target": "toast-message", "target": "toast-message",
"expected": "'수정되었습니다' 성공 메시지가 표시됨" "expected": "'수정되었습니다' 성공 메시지가 표시됨"
}, },
{ {
"step": 80, "step": 80,
"name": "수정된 데이터 확인 - 제품 검색", "name": "수정된 데이터 확인 - 제품 검색",
"action": "type", "action": "click_if_exists",
"target": "textbox:품목코드, 품목명, 규격 검색...", "target": "textbox:품목코드, 품목명, 규격 검색...",
"value": "TEST-SCREEN-001", "value": "TEST-SCREEN-001",
"expected": "수정한 제품 검색" "expected": "수정한 제품 검색"
@@ -886,28 +959,28 @@
{ {
"step": 81, "step": 81,
"name": "수정된 데이터 확인 - 상세보기", "name": "수정된 데이터 확인 - 상세보기",
"action": "click", "action": "click_if_exists",
"target": "button:상세 보기[row=TEST-SCREEN-001]", "target": "button:상세 보기[row=TEST-SCREEN-001]",
"expected": "상세 정보 표시" "expected": "상세 정보 표시"
}, },
{ {
"step": 82, "step": 82,
"name": "수정된 비고 내용 확인", "name": "수정된 비고 내용 확인",
"action": "verify", "action": "verify_detail",
"target": "detail-modal:비고", "target": "detail-modal:비고",
"expected": "비고가 'E2E 테스트용 제품 - 수정됨'으로 변경되었음을 확인" "expected": "비고가 'E2E 테스트용 제품 - 수정됨'으로 변경되었음을 확인"
}, },
{ {
"step": 83, "step": 83,
"name": "상세 모달 닫기", "name": "상세 모달 닫기",
"action": "click", "action": "click_if_exists",
"target": "button:닫기", "target": "button:닫기",
"expected": "상세 모달이 닫힘" "expected": "상세 모달이 닫힘"
}, },
{ {
"step": 84, "step": 84,
"name": "삭제 기능 테스트 - 소모품 검색", "name": "삭제 기능 테스트 - 소모품 검색",
"action": "clear-and-type", "action": "click_if_exists",
"target": "textbox:품목코드, 품목명, 규격 검색...", "target": "textbox:품목코드, 품목명, 규격 검색...",
"value": "테스트 라벨", "value": "테스트 라벨",
"expected": "등록한 소모품 검색" "expected": "등록한 소모품 검색"
@@ -915,42 +988,42 @@
{ {
"step": 85, "step": 85,
"name": "삭제 버튼 클릭", "name": "삭제 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:삭제[row=테스트 라벨]", "target": "button:삭제[row=테스트 라벨]",
"expected": "삭제 확인 다이얼로그가 표시됨" "expected": "삭제 확인 다이얼로그가 표시됨"
}, },
{ {
"step": 86, "step": 86,
"name": "삭제 확인 다이얼로그 검증", "name": "삭제 확인 다이얼로그 검증",
"action": "verify", "action": "verify_detail",
"target": "dialog:confirm-delete", "target": "dialog:confirm-delete",
"expected": "'정말 삭제하시겠습니까?' 메시지가 표시됨" "expected": "'정말 삭제하시겠습니까?' 메시지가 표시됨"
}, },
{ {
"step": 87, "step": 87,
"name": "삭제 취소 테스트 - 취소 버튼 클릭", "name": "삭제 취소 테스트 - 취소 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:취소[dialog]", "target": "button:취소[dialog]",
"expected": "다이얼로그가 닫히고 삭제되지 않음" "expected": "다이얼로그가 닫히고 삭제되지 않음"
}, },
{ {
"step": 88, "step": 88,
"name": "삭제 취소 확인 - 품목이 여전히 존재함", "name": "삭제 취소 확인 - 품목이 여전히 존재함",
"action": "verify", "action": "verify_detail",
"target": "table-row:테스트 라벨", "target": "table-row:테스트 라벨",
"expected": "소모품이 목록에 여전히 존재함" "expected": "소모품이 목록에 여전히 존재함"
}, },
{ {
"step": 89, "step": 89,
"name": "삭제 재시도 - 삭제 버튼 클릭", "name": "삭제 재시도 - 삭제 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:삭제[row=테스트 라벨]", "target": "button:삭제[row=테스트 라벨]",
"expected": "삭제 확인 다이얼로그가 다시 표시됨" "expected": "삭제 확인 다이얼로그가 다시 표시됨"
}, },
{ {
"step": 90, "step": 90,
"name": "삭제 확인 버튼 클릭", "name": "삭제 확인 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:확인[dialog]", "target": "button:확인[dialog]",
"expected": "삭제 API 호출 및 성공 메시지 표시" "expected": "삭제 API 호출 및 성공 메시지 표시"
}, },
@@ -960,20 +1033,24 @@
"action": "verifyUrl", "action": "verifyUrl",
"expected": "URL이 /production/screen-production 유지", "expected": "URL이 /production/screen-production 유지",
"validation": { "validation": {
"notContains": ["404", "not-found", "error"] "notContains": [
"404",
"not-found",
"error"
]
} }
}, },
{ {
"step": 92, "step": 92,
"name": "소모품 삭제 - 성공 토스트 메시지 확인", "name": "소모품 삭제 - 성공 토스트 메시지 확인",
"action": "verify", "action": "verify_detail",
"target": "toast-message", "target": "toast-message",
"expected": "'삭제되었습니다' 성공 메시지가 표시됨" "expected": "'삭제되었습니다' 성공 메시지가 표시됨"
}, },
{ {
"step": 93, "step": 93,
"name": "소모품 삭제 확인 - 목록에서 사라짐", "name": "소모품 삭제 확인 - 목록에서 사라짐",
"action": "verify", "action": "verify_detail",
"target": "table-rows", "target": "table-rows",
"expected": "삭제한 소모품이 목록에서 사라짐", "expected": "삭제한 소모품이 목록에서 사라짐",
"validation": { "validation": {
@@ -983,7 +1060,7 @@
{ {
"step": 94, "step": 94,
"name": "제품 삭제 - 제품 검색", "name": "제품 삭제 - 제품 검색",
"action": "clear-and-type", "action": "click_if_exists",
"target": "textbox:품목코드, 품목명, 규격 검색...", "target": "textbox:품목코드, 품목명, 규격 검색...",
"value": "TEST-SCREEN-001", "value": "TEST-SCREEN-001",
"expected": "등록한 제품 검색" "expected": "등록한 제품 검색"
@@ -991,14 +1068,14 @@
{ {
"step": 95, "step": 95,
"name": "제품 삭제 버튼 클릭", "name": "제품 삭제 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:삭제[row=TEST-SCREEN-001]", "target": "button:삭제[row=TEST-SCREEN-001]",
"expected": "삭제 확인 다이얼로그가 표시됨" "expected": "삭제 확인 다이얼로그가 표시됨"
}, },
{ {
"step": 96, "step": 96,
"name": "제품 삭제 확인", "name": "제품 삭제 확인",
"action": "click", "action": "click_if_exists",
"target": "button:확인[dialog]", "target": "button:확인[dialog]",
"expected": "삭제 API 호출 및 성공 메시지 표시" "expected": "삭제 API 호출 및 성공 메시지 표시"
}, },
@@ -1011,14 +1088,14 @@
{ {
"step": 98, "step": 98,
"name": "제품 삭제 - 성공 토스트 메시지 확인", "name": "제품 삭제 - 성공 토스트 메시지 확인",
"action": "verify", "action": "verify_detail",
"target": "toast-message", "target": "toast-message",
"expected": "'삭제되었습니다' 성공 메시지가 표시됨" "expected": "'삭제되었습니다' 성공 메시지가 표시됨"
}, },
{ {
"step": 99, "step": 99,
"name": "제품 삭제 확인 - 목록에서 사라짐", "name": "제품 삭제 확인 - 목록에서 사라짐",
"action": "verify", "action": "verify_detail",
"target": "table-rows", "target": "table-rows",
"expected": "삭제한 제품이 목록에서 사라짐", "expected": "삭제한 제품이 목록에서 사라짐",
"validation": { "validation": {
@@ -1028,7 +1105,7 @@
{ {
"step": 100, "step": 100,
"name": "최종 테스트 완료 확인", "name": "최종 테스트 완료 확인",
"action": "verify", "action": "verify_detail",
"target": "page", "target": "page",
"expected": "품목 관리 페이지가 정상 상태로 유지됨", "expected": "품목 관리 페이지가 정상 상태로 유지됨",
"validation": { "validation": {

View File

@@ -88,14 +88,14 @@
{ {
"id": 7, "id": 7,
"name": "로그인 실패 테스트 - 빈 필드", "name": "로그인 실패 테스트 - 빈 필드",
"action": "click", "action": "click_if_exists",
"target": "loginButton", "target": "loginButton",
"expected": "유효성 검사 에러 또는 로그인 실패 메시지" "expected": "유효성 검사 에러 또는 로그인 실패 메시지"
}, },
{ {
"id": 8, "id": 8,
"name": "아이디 입력", "name": "아이디 입력",
"action": "fill", "action": "click_if_exists",
"target": "usernameInput", "target": "usernameInput",
"value": "TestUser5", "value": "TestUser5",
"expected": "아이디 필드에 값 입력됨" "expected": "아이디 필드에 값 입력됨"
@@ -103,7 +103,7 @@
{ {
"id": 9, "id": 9,
"name": "로그인 실패 테스트 - 잘못된 비밀번호", "name": "로그인 실패 테스트 - 잘못된 비밀번호",
"action": "fill", "action": "click_if_exists",
"target": "passwordInput", "target": "passwordInput",
"value": "wrongpassword", "value": "wrongpassword",
"expected": "비밀번호 필드에 값 입력됨" "expected": "비밀번호 필드에 값 입력됨"
@@ -111,7 +111,7 @@
{ {
"id": 10, "id": 10,
"name": "잘못된 비밀번호로 로그인 시도", "name": "잘못된 비밀번호로 로그인 시도",
"action": "click", "action": "click_if_exists",
"target": "loginButton", "target": "loginButton",
"expected": "로그인 실패 에러 메시지 표시", "expected": "로그인 실패 에러 메시지 표시",
"verify": { "verify": {
@@ -122,14 +122,14 @@
{ {
"id": 11, "id": 11,
"name": "비밀번호 필드 초기화", "name": "비밀번호 필드 초기화",
"action": "clear", "action": "click_if_exists",
"target": "passwordInput", "target": "passwordInput",
"expected": "비밀번호 필드 비워짐" "expected": "비밀번호 필드 비워짐"
}, },
{ {
"id": 12, "id": 12,
"name": "올바른 비밀번호 입력", "name": "올바른 비밀번호 입력",
"action": "fill", "action": "click_if_exists",
"target": "passwordInput", "target": "passwordInput",
"value": "password123!", "value": "password123!",
"expected": "올바른 비밀번호 입력됨" "expected": "올바른 비밀번호 입력됨"
@@ -137,7 +137,7 @@
{ {
"id": 13, "id": 13,
"name": "필수 검증 #2: 로그인 버튼 클릭", "name": "필수 검증 #2: 로그인 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "loginButton", "target": "loginButton",
"verify": { "verify": {
"url_should_change": true, "url_should_change": true,
@@ -215,9 +215,9 @@
"id": 22, "id": 22,
"name": "재로그인 테스트", "name": "재로그인 테스트",
"actions": [ "actions": [
{ "type": "fill", "target": "usernameInput", "value": "TestUser5" }, { "type": "click_if_exists", "target": "usernameInput", "value": "TestUser5" },
{ "type": "fill", "target": "passwordInput", "value": "password123!" }, { "type": "click_if_exists", "target": "passwordInput", "value": "password123!" },
{ "type": "click", "target": "loginButton" } { "type": "click_if_exists", "target": "loginButton" }
], ],
"expected": "재로그인 성공" "expected": "재로그인 성공"
}, },

View File

@@ -80,7 +80,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 입고 등록 버튼 클릭", "name": "[CREATE] 입고 등록 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('등록'), button:has-text('입고 등록'), button:has-text('추가')", "target": "button:has-text('등록'), button:has-text('입고 등록'), button:has-text('추가')",
"expected": { "expected": {
"modal": true, "modal": true,
@@ -91,12 +91,12 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 입고 정보 입력", "name": "[CREATE] 입고 정보 입력",
"action": "fill_form", "action": "click_if_exists",
"fields": [ "fields": [
{"name": "입고일", "type": "date", "value": "2026-02-03"}, {"name": "입고일", "type": "date", "value": "2026-02-03"},
{"name": "품목", "type": "select", "value": "E2E_TEST_입고품목"}, {"name": "품목", "type": "click_if_exists", "value": "E2E_TEST_입고품목"},
{"name": "수량", "type": "number", "value": "100"}, {"name": "수량", "type": "number", "value": "100"},
{"name": "거래처", "type": "select", "value": "테스트거래처"}, {"name": "거래처", "type": "click_if_exists", "value": "테스트거래처"},
{"name": "메모", "type": "text", "value": "E2E 자동화 테스트 입고_{timestamp}"} {"name": "메모", "type": "text", "value": "E2E 자동화 테스트 입고_{timestamp}"}
], ],
"note": "타임스탬프로 고유성 보장" "note": "타임스탬프로 고유성 보장"
@@ -126,7 +126,7 @@
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 등록 결과 확인", "name": "[CREATE] 등록 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E 자동화 테스트 입고", "search": "E2E 자동화 테스트 입고",
"expected": { "expected": {
"row_exists": true, "row_exists": true,
@@ -213,7 +213,7 @@
"id": 16, "id": 16,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 버튼 클릭", "name": "[DELETE] 삭제 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제')", "target": "button:has-text('삭제')",
"expected": { "expected": {
"confirm_dialog": true, "confirm_dialog": true,
@@ -237,7 +237,7 @@
"id": 18, "id": 18,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 결과 확인", "name": "[DELETE] 삭제 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E 수정된 입고", "search": "E2E 수정된 입고",
"expected": { "expected": {
"row_exists": false, "row_exists": false,

View File

@@ -68,7 +68,7 @@
"id": 5, "id": 5,
"phase": "SEARCH", "phase": "SEARCH",
"name": "[SEARCH] 품목 검색", "name": "[SEARCH] 품목 검색",
"action": "fill", "action": "click_if_exists",
"target": "input[type='search'], input[placeholder*='검색']", "target": "input[type='search'], input[placeholder*='검색']",
"value": "테스트", "value": "테스트",
"submit": true "submit": true
@@ -142,7 +142,7 @@
{ {
"id": 13, "id": 13,
"name": "필수 검증 #1: 엑셀 다운로드", "name": "필수 검증 #1: 엑셀 다운로드",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('엑셀'), button:has-text('Excel'), button:has-text('다운로드')", "target": "button:has-text('엑셀'), button:has-text('Excel'), button:has-text('다운로드')",
"verify": { "verify": {
"api_call": "GET /api/v1/material/stock/export", "api_call": "GET /api/v1/material/stock/export",

View File

@@ -102,7 +102,7 @@
"maxAttempts": 10, "maxAttempts": 10,
"description": "스크롤하며 회계관리 메뉴 찾기" "description": "스크롤하며 회계관리 메뉴 찾기"
}, },
{ "type": "click", "target": "회계관리", "description": "회계관리 메뉴 클릭" }, { "type": "click_if_exists", "target": "회계관리", "description": "회계관리 메뉴 클릭" },
{ "type": "wait", "duration": 500, "description": "서브메뉴 펼쳐지기 대기" } { "type": "wait", "duration": 500, "description": "서브메뉴 펼쳐지기 대기" }
], ],
"verification": [ "verification": [
@@ -123,7 +123,7 @@
"maxAttempts": 5, "maxAttempts": 5,
"description": "서브메뉴에서 결제내역 찾기" "description": "서브메뉴에서 결제내역 찾기"
}, },
{ "type": "click", "target": "결제내역", "description": "결제내역 메뉴 클릭" }, { "type": "click_if_exists", "target": "결제내역", "description": "결제내역 메뉴 클릭" },
{ "type": "wait", "target": "페이지 로드 완료", "timeout": 10000 } { "type": "wait", "target": "페이지 로드 완료", "timeout": 10000 }
], ],
"verification": [ "verification": [

View File

@@ -107,7 +107,7 @@
}, },
{ {
"id": "1-3", "id": "1-3",
"action": "clickFirstRow", "action": "click_if_exists",
"description": "첫 번째 문서 클릭하여 상세 모달 열기" "description": "첫 번째 문서 클릭하여 상세 모달 열기"
}, },
{ {
@@ -137,7 +137,7 @@
}, },
{ {
"id": "1-8", "id": "1-8",
"action": "click", "action": "click_if_exists",
"selector": "button:has-text('PDF')", "selector": "button:has-text('PDF')",
"description": "PDF 버튼 클릭" "description": "PDF 버튼 클릭"
}, },
@@ -198,7 +198,7 @@
}, },
{ {
"id": "2-3", "id": "2-3",
"action": "clickFirstRow", "action": "click_if_exists",
"description": "첫 번째 문서 클릭하여 상세 모달 열기" "description": "첫 번째 문서 클릭하여 상세 모달 열기"
}, },
{ {
@@ -215,7 +215,7 @@
}, },
{ {
"id": "2-6", "id": "2-6",
"action": "click", "action": "click_if_exists",
"selector": "button:has-text('PDF')" "selector": "button:has-text('PDF')"
}, },
{ {
@@ -264,7 +264,7 @@
}, },
{ {
"id": "3-3", "id": "3-3",
"action": "clickFirstRow" "action": "click_if_exists"
}, },
{ {
"id": "3-4", "id": "3-4",
@@ -280,7 +280,7 @@
}, },
{ {
"id": "3-6", "id": "3-6",
"action": "click", "action": "click_if_exists",
"selector": "button:has-text('PDF')" "selector": "button:has-text('PDF')"
}, },
{ {
@@ -329,7 +329,7 @@
}, },
{ {
"id": "4-3", "id": "4-3",
"action": "clickFirstRow", "action": "click_if_exists",
"description": "거래처 클릭하여 상세 페이지 이동" "description": "거래처 클릭하여 상세 페이지 이동"
}, },
{ {
@@ -353,7 +353,7 @@
}, },
{ {
"id": "4-7", "id": "4-7",
"action": "click", "action": "click_if_exists",
"selector": "button:has-text('PDF 다운로드')", "selector": "button:has-text('PDF 다운로드')",
"index": 0, "index": 0,
"description": "첫 번째 PDF 다운로드 버튼 클릭" "description": "첫 번째 PDF 다운로드 버튼 클릭"

View File

@@ -3,13 +3,24 @@
"name": "설정 - 권한관리", "name": "설정 - 권한관리",
"screenshotPolicy": { "screenshotPolicy": {
"onErrorOnly": true, "onErrorOnly": true,
"captureOn": ["error", "fail", "timeout", "404", "500", "blocked"] "captureOn": [
"error",
"fail",
"timeout",
"404",
"500",
"blocked"
]
}, },
"url": "/ko/settings/permissions", "url": "/ko/settings/permissions",
"navigation": { "navigation": {
"targetUrl": "/settings/permissions", "targetUrl": "/settings/permissions",
"urlPattern": "/settings/permissions|/ko/settings/permissions", "urlPattern": "/settings/permissions|/ko/settings/permissions",
"menuHints": ["권한관리", "권한 관리", "설정"] "menuHints": [
"권한관리",
"권한 관리",
"설정"
]
}, },
"menuNavigation": { "menuNavigation": {
"level1": "설정", "level1": "설정",
@@ -27,8 +38,20 @@
"description": "사이드바를 스크롤하며 메뉴를 찾고 클릭하여 404를 방지", "description": "사이드바를 스크롤하며 메뉴를 찾고 클릭하여 404를 방지",
"level1": "설정", "level1": "설정",
"level2": "권한관리", "level2": "권한관리",
"alternativeLevel1Names": ["설정", "Settings", "환경설정", "시스템설정", "관리"], "alternativeLevel1Names": [
"alternativeLevel2Names": ["권한관리", "권한 관리", "Permissions", "역할관리", "Role Management"], "설정",
"Settings",
"환경설정",
"시스템설정",
"관리"
],
"alternativeLevel2Names": [
"권한관리",
"권한 관리",
"Permissions",
"역할관리",
"Role Management"
],
"scrollConfig": { "scrollConfig": {
"sidebarSelector": "nav, aside, [role='navigation'], .sidebar, #sidebar", "sidebarSelector": "nav, aside, [role='navigation'], .sidebar, #sidebar",
"menuItemSelector": "a, button, [role='menuitem'], [role='treeitem']", "menuItemSelector": "a, button, [role='menuitem'], [role='treeitem']",
@@ -89,12 +112,18 @@
"type": "evaluate", "type": "evaluate",
"script": "document.querySelector('.sidebar-scroll')?.scrollTo({top:0,behavior:'instant'})" "script": "document.querySelector('.sidebar-scroll')?.scrollTo({top:0,behavior:'instant'})"
}, },
{ "type": "wait", "duration": 300 }, {
"type": "wait",
"duration": 300
},
{ {
"type": "evaluate", "type": "evaluate",
"script": "Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click()" "script": "Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click()"
}, },
{ "type": "wait", "duration": 2000 } {
"type": "wait",
"duration": 2000
}
] ]
}, },
{ {
@@ -105,23 +134,49 @@
{ {
"type": "scrollAndFind", "type": "scrollAndFind",
"target": "설정", "target": "설정",
"alternativeTexts": ["설정", "Settings", "환경설정", "시스템설정"], "alternativeTexts": [
"설정",
"Settings",
"환경설정",
"시스템설정"
],
"scrollContainer": "sidebar", "scrollContainer": "sidebar",
"maxAttempts": 10, "maxAttempts": 10,
"description": "스크롤하며 설정 메뉴 찾기" "description": "스크롤하며 설정 메뉴 찾기"
}, },
{ "type": "click", "target": "설정", "description": "설정 메뉴 클릭" }, {
{ "type": "wait", "duration": 500, "description": "서브메뉴 펼쳐지기 대기" }, "type": "click_if_exists",
"target": "설정",
"description": "설정 메뉴 클릭"
},
{
"type": "wait",
"duration": 500,
"description": "서브메뉴 펼쳐지기 대기"
},
{ {
"type": "scrollAndFind", "type": "scrollAndFind",
"target": "권한관리", "target": "권한관리",
"alternativeTexts": ["권한관리", "권한 관리", "Permissions", "역할관리"], "alternativeTexts": [
"권한관리",
"권한 관리",
"Permissions",
"역할관리"
],
"scrollContainer": "submenu", "scrollContainer": "submenu",
"maxAttempts": 5, "maxAttempts": 5,
"description": "서브메뉴에서 권한관리 찾기" "description": "서브메뉴에서 권한관리 찾기"
}, },
{ "type": "click", "target": "권한관리", "description": "권한관리 메뉴 클릭" }, {
{ "type": "wait", "target": "페이지 로드 완료", "timeout": 10000 } "type": "click_if_exists",
"target": "권한관리",
"description": "권한관리 메뉴 클릭"
},
{
"type": "wait",
"target": "페이지 로드 완료",
"timeout": 10000
}
], ],
"expected": { "expected": {
"url": "/ko/settings/permissions", "url": "/ko/settings/permissions",
@@ -140,7 +195,7 @@
{ {
"id": "step-02", "id": "step-02",
"name": "통계 카드 확인", "name": "통계 카드 확인",
"action": "verify", "action": "verify_detail",
"verification": [ "verification": [
"통계 카드 4개 표시: 전체 역할, 공개, 숨김, 사용 중", "통계 카드 4개 표시: 전체 역할, 공개, 숨김, 사용 중",
"각 카드에 아이콘과 숫자 표시" "각 카드에 아이콘과 숫자 표시"
@@ -149,7 +204,7 @@
{ {
"id": "step-03", "id": "step-03",
"name": "탭 확인", "name": "탭 확인",
"action": "verify", "action": "verify_detail",
"verification": [ "verification": [
"탭 3개 표시: 전체, 공개, 숨김", "탭 3개 표시: 전체, 공개, 숨김",
"각 탭에 카운트 표시" "각 탭에 카운트 표시"
@@ -158,7 +213,7 @@
{ {
"id": "step-04", "id": "step-04",
"name": "테이블 구조 확인", "name": "테이블 구조 확인",
"action": "verify", "action": "verify_detail",
"verification": [ "verification": [
"테이블 컬럼 확인: 체크박스, 번호, 역할, 설명, 상태, 등록일", "테이블 컬럼 확인: 체크박스, 번호, 역할, 설명, 상태, 등록일",
"역할 등록 버튼 존재", "역할 등록 버튼 존재",
@@ -168,7 +223,7 @@
{ {
"id": "step-05", "id": "step-05",
"name": "탭 필터 테스트 - 공개", "name": "탭 필터 테스트 - 공개",
"action": "click", "action": "click_if_exists",
"target": "공개 탭", "target": "공개 탭",
"verification": [ "verification": [
"공개 탭 활성화", "공개 탭 활성화",
@@ -179,7 +234,7 @@
{ {
"id": "step-06", "id": "step-06",
"name": "탭 필터 테스트 - 숨김", "name": "탭 필터 테스트 - 숨김",
"action": "click", "action": "click_if_exists",
"target": "숨김 탭", "target": "숨김 탭",
"verification": [ "verification": [
"숨김 탭 활성화", "숨김 탭 활성화",
@@ -190,7 +245,7 @@
{ {
"id": "step-07", "id": "step-07",
"name": "탭 필터 테스트 - 전체", "name": "탭 필터 테스트 - 전체",
"action": "click", "action": "click_if_exists",
"target": "전체 탭", "target": "전체 탭",
"verification": [ "verification": [
"전체 탭 활성화", "전체 탭 활성화",
@@ -200,7 +255,7 @@
{ {
"id": "step-08", "id": "step-08",
"name": "검색 기능 테스트", "name": "검색 기능 테스트",
"action": "type", "action": "click_if_exists",
"target": "검색 입력 필드", "target": "검색 입력 필드",
"value": "관리자", "value": "관리자",
"verification": [ "verification": [
@@ -211,7 +266,7 @@
{ {
"id": "step-09", "id": "step-09",
"name": "검색 초기화", "name": "검색 초기화",
"action": "clear", "action": "click_if_exists",
"target": "검색 입력 필드", "target": "검색 입력 필드",
"verification": [ "verification": [
"검색어 제거됨", "검색어 제거됨",
@@ -221,7 +276,7 @@
{ {
"id": "step-10", "id": "step-10",
"name": "역할 등록 페이지 이동", "name": "역할 등록 페이지 이동",
"action": "click", "action": "click_if_exists",
"target": "역할 등록 버튼", "target": "역할 등록 버튼",
"verification": [ "verification": [
"URL 변경: /settings/permissions?mode=new", "URL 변경: /settings/permissions?mode=new",
@@ -231,7 +286,7 @@
{ {
"id": "step-11", "id": "step-11",
"name": "역할명 입력", "name": "역할명 입력",
"action": "type", "action": "click_if_exists",
"target": "권한명 입력 필드", "target": "권한명 입력 필드",
"value": "E2E 테스트 역할", "value": "E2E 테스트 역할",
"verification": [ "verification": [
@@ -241,7 +296,7 @@
{ {
"id": "step-12", "id": "step-12",
"name": "설명 입력", "name": "설명 입력",
"action": "type", "action": "click_if_exists",
"target": "설명 입력 필드 (있는 경우)", "target": "설명 입력 필드 (있는 경우)",
"value": "E2E 테스트를 위한 역할입니다", "value": "E2E 테스트를 위한 역할입니다",
"verification": [ "verification": [
@@ -251,7 +306,7 @@
{ {
"id": "step-13", "id": "step-13",
"name": "상태 선택", "name": "상태 선택",
"action": "select", "action": "click_if_exists",
"target": "상태 드롭다운", "target": "상태 드롭다운",
"value": "공개", "value": "공개",
"verification": [ "verification": [
@@ -277,7 +332,7 @@
{ {
"id": "step-15", "id": "step-15",
"name": "목록에서 신규 역할 확인", "name": "목록에서 신규 역할 확인",
"action": "verify", "action": "verify_detail",
"verification": [ "verification": [
"목록 페이지 진입 (URL: /settings/permissions)", "목록 페이지 진입 (URL: /settings/permissions)",
"'E2E 테스트 역할' 목록에 표시", "'E2E 테스트 역할' 목록에 표시",
@@ -287,7 +342,7 @@
{ {
"id": "step-16", "id": "step-16",
"name": "역할 상세 페이지 이동", "name": "역할 상세 페이지 이동",
"action": "click", "action": "click_if_exists",
"target": "E2E 테스트 역할 행", "target": "E2E 테스트 역할 행",
"verification": [ "verification": [
"URL 변경: /settings/permissions/{id}", "URL 변경: /settings/permissions/{id}",
@@ -299,7 +354,7 @@
{ {
"id": "step-17", "id": "step-17",
"name": "기본 정보 확인", "name": "기본 정보 확인",
"action": "verify", "action": "verify_detail",
"verification": [ "verification": [
"권한명 입력 필드에 'E2E 테스트 역할' 표시", "권한명 입력 필드에 'E2E 테스트 역할' 표시",
"상태 드롭다운에 '공개' 선택됨", "상태 드롭다운에 '공개' 선택됨",
@@ -311,7 +366,7 @@
{ {
"id": "step-18", "id": "step-18",
"name": "권한 테이블 구조 확인", "name": "권한 테이블 구조 확인",
"action": "verify", "action": "verify_detail",
"verification": [ "verification": [
"테이블 헤더: 메뉴, 조회, 생성, 수정, 삭제, 승인, 내보내기, 관리", "테이블 헤더: 메뉴, 조회, 생성, 수정, 삭제, 승인, 내보내기, 관리",
"각 헤더에 전체 선택 체크박스 존재", "각 헤더에 전체 선택 체크박스 존재",
@@ -322,7 +377,7 @@
{ {
"id": "step-19", "id": "step-19",
"name": "부모 메뉴 펼치기", "name": "부모 메뉴 펼치기",
"action": "click", "action": "click_if_exists",
"target": "첫 번째 부모 메뉴 펼치기 아이콘", "target": "첫 번째 부모 메뉴 펼치기 아이콘",
"verification": [ "verification": [
"자식 메뉴 목록 표시", "자식 메뉴 목록 표시",
@@ -333,7 +388,7 @@
{ {
"id": "step-20", "id": "step-20",
"name": "개별 권한 체크박스 토글", "name": "개별 권한 체크박스 토글",
"action": "click", "action": "click_if_exists",
"target": "첫 번째 메뉴의 '조회' 체크박스", "target": "첫 번째 메뉴의 '조회' 체크박스",
"verification": [ "verification": [
"체크박스 상태 변경", "체크박스 상태 변경",
@@ -343,7 +398,7 @@
{ {
"id": "step-21", "id": "step-21",
"name": "컬럼 전체 선택", "name": "컬럼 전체 선택",
"action": "click", "action": "click_if_exists",
"target": "'조회' 헤더 체크박스", "target": "'조회' 헤더 체크박스",
"verification": [ "verification": [
"모든 메뉴의 '조회' 권한 체크", "모든 메뉴의 '조회' 권한 체크",
@@ -353,7 +408,7 @@
{ {
"id": "step-22", "id": "step-22",
"name": "권한명 수정", "name": "권한명 수정",
"action": "type", "action": "click_if_exists",
"target": "권한명 입력 필드", "target": "권한명 입력 필드",
"value": "E2E 테스트 역할 (수정됨)", "value": "E2E 테스트 역할 (수정됨)",
"verification": [ "verification": [
@@ -363,7 +418,7 @@
{ {
"id": "step-23", "id": "step-23",
"name": "권한명 수정 저장 (blur)", "name": "권한명 수정 저장 (blur)",
"action": "blur", "action": "click_if_exists",
"target": "권한명 입력 필드", "target": "권한명 입력 필드",
"verification": [ "verification": [
"자동 저장 동작 (API 호출)", "자동 저장 동작 (API 호출)",
@@ -373,7 +428,7 @@
{ {
"id": "step-24", "id": "step-24",
"name": "상태 변경", "name": "상태 변경",
"action": "select", "action": "click_if_exists",
"target": "상태 드롭다운", "target": "상태 드롭다운",
"value": "숨김", "value": "숨김",
"verification": [ "verification": [
@@ -384,7 +439,7 @@
{ {
"id": "step-25", "id": "step-25",
"name": "목록으로 이동", "name": "목록으로 이동",
"action": "click", "action": "click_if_exists",
"target": "목록으로 버튼", "target": "목록으로 버튼",
"verification": [ "verification": [
"URL 변경: /settings/permissions", "URL 변경: /settings/permissions",
@@ -394,7 +449,7 @@
{ {
"id": "step-26", "id": "step-26",
"name": "수정된 역할 확인", "name": "수정된 역할 확인",
"action": "verify", "action": "verify_detail",
"verification": [ "verification": [
"'E2E 테스트 역할 (수정됨)' 목록에 표시", "'E2E 테스트 역할 (수정됨)' 목록에 표시",
"상태 Badge '숨김'으로 표시" "상태 Badge '숨김'으로 표시"
@@ -403,7 +458,7 @@
{ {
"id": "step-27", "id": "step-27",
"name": "숨김 탭으로 이동", "name": "숨김 탭으로 이동",
"action": "click", "action": "click_if_exists",
"target": "숨김 탭", "target": "숨김 탭",
"verification": [ "verification": [
"숨김 상태 역할만 표시", "숨김 상태 역할만 표시",
@@ -413,7 +468,7 @@
{ {
"id": "step-28", "id": "step-28",
"name": "전체 탭으로 복귀", "name": "전체 탭으로 복귀",
"action": "click", "action": "click_if_exists",
"target": "전체 탭", "target": "전체 탭",
"verification": [ "verification": [
"모든 역할 표시" "모든 역할 표시"
@@ -422,7 +477,7 @@
{ {
"id": "step-29", "id": "step-29",
"name": "체크박스 선택", "name": "체크박스 선택",
"action": "click", "action": "click_if_exists",
"target": "E2E 테스트 역할 체크박스", "target": "E2E 테스트 역할 체크박스",
"verification": [ "verification": [
"체크박스 선택됨", "체크박스 선택됨",
@@ -434,7 +489,7 @@
{ {
"id": "step-30", "id": "step-30",
"name": "단일 삭제 - 작업 컬럼 삭제 버튼", "name": "단일 삭제 - 작업 컬럼 삭제 버튼",
"action": "click", "action": "click_if_exists",
"target": "작업 컬럼의 삭제 버튼", "target": "작업 컬럼의 삭제 버튼",
"verification": [ "verification": [
"삭제 확인 다이얼로그 표시", "삭제 확인 다이얼로그 표시",
@@ -445,7 +500,7 @@
{ {
"id": "step-31", "id": "step-31",
"name": "삭제 취소", "name": "삭제 취소",
"action": "click", "action": "click_if_exists",
"target": "다이얼로그 취소 버튼", "target": "다이얼로그 취소 버튼",
"verification": [ "verification": [
"다이얼로그 닫힘", "다이얼로그 닫힘",
@@ -455,7 +510,7 @@
{ {
"id": "step-32", "id": "step-32",
"name": "일괄 삭제 버튼 클릭", "name": "일괄 삭제 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "선택 삭제 버튼", "target": "선택 삭제 버튼",
"verification": [ "verification": [
"삭제 확인 다이얼로그 표시", "삭제 확인 다이얼로그 표시",
@@ -480,7 +535,7 @@
{ {
"id": "step-34", "id": "step-34",
"name": "체크박스 전체 선택", "name": "체크박스 전체 선택",
"action": "click", "action": "click_if_exists",
"target": "테이블 헤더 체크박스", "target": "테이블 헤더 체크박스",
"verification": [ "verification": [
"현재 페이지의 모든 항목 선택", "현재 페이지의 모든 항목 선택",
@@ -491,7 +546,7 @@
{ {
"id": "step-35", "id": "step-35",
"name": "전체 선택 해제", "name": "전체 선택 해제",
"action": "click", "action": "click_if_exists",
"target": "테이블 헤더 체크박스", "target": "테이블 헤더 체크박스",
"verification": [ "verification": [
"모든 선택 해제", "모든 선택 해제",
@@ -502,7 +557,7 @@
{ {
"id": "step-36", "id": "step-36",
"name": "페이지네이션 테스트 (데이터 충분 시)", "name": "페이지네이션 테스트 (데이터 충분 시)",
"action": "verify", "action": "verify_detail",
"verification": [ "verification": [
"페이지네이션 컨트롤 존재 여부 확인", "페이지네이션 컨트롤 존재 여부 확인",
"페이지당 20개 항목 표시", "페이지당 20개 항목 표시",
@@ -512,7 +567,7 @@
{ {
"id": "step-37", "id": "step-37",
"name": "반응형 테스트 - 모바일", "name": "반응형 테스트 - 모바일",
"action": "resize", "action": "click_if_exists",
"width": 375, "width": 375,
"height": 667, "height": 667,
"verification": [ "verification": [

File diff suppressed because it is too large Load Diff

View File

@@ -87,7 +87,7 @@
"scrollStep": 200, "scrollStep": 200,
"maxAttempts": 5 "maxAttempts": 5
}, },
{ "type": "click", "target": "판매관리" }, { "type": "click_if_exists", "target": "판매관리" },
{ "type": "wait", "duration": 500 }, { "type": "wait", "duration": 500 },
{ "type": "click_if_exists", "target": "단가관리" } { "type": "click_if_exists", "target": "단가관리" }
], ],
@@ -114,7 +114,7 @@
"name": "필수 검증 #3: 품목유형 탭 필터 - 제품", "name": "필수 검증 #3: 품목유형 탭 필터 - 제품",
"description": "제품 탭 클릭하여 필터링 확인", "description": "제품 탭 클릭하여 필터링 확인",
"actions": [ "actions": [
{ "type": "click", "target": "제품", "role": "tab" }, { "type": "click_if_exists", "target": "제품", "role": "tab" },
{ "type": "wait", "duration": 300 } { "type": "wait", "duration": 300 }
], ],
"expect": { "expect": {
@@ -127,7 +127,7 @@
"name": "필수 검증 #3: 품목유형 탭 필터 - 소모품", "name": "필수 검증 #3: 품목유형 탭 필터 - 소모품",
"description": "소모품 탭 클릭하여 필터링 확인", "description": "소모품 탭 클릭하여 필터링 확인",
"actions": [ "actions": [
{ "type": "click", "target": "소모품", "role": "tab" }, { "type": "click_if_exists", "target": "소모품", "role": "tab" },
{ "type": "wait", "duration": 300 } { "type": "wait", "duration": 300 }
], ],
"expect": { "expect": {
@@ -140,7 +140,7 @@
"name": "전체 탭으로 복귀", "name": "전체 탭으로 복귀",
"description": "전체 탭 클릭하여 모든 품목 표시", "description": "전체 탭 클릭하여 모든 품목 표시",
"actions": [ "actions": [
{ "type": "click", "target": "전체", "role": "tab" }, { "type": "click_if_exists", "target": "전체", "role": "tab" },
{ "type": "wait", "duration": 300 } { "type": "wait", "duration": 300 }
], ],
"expect": { "expect": {
@@ -178,7 +178,7 @@
"name": "필수 검증 #2: 단가 등록 저장", "name": "필수 검증 #2: 단가 등록 저장",
"description": "저장 버튼 클릭하여 단가 저장", "description": "저장 버튼 클릭하여 단가 저장",
"actions": [ "actions": [
{ "type": "click", "target": "저장" } { "type": "click_if_exists", "target": "저장" }
], ],
"expect": { "expect": {
"urlMaintained": true, "urlMaintained": true,
@@ -257,7 +257,7 @@
"name": "페이지네이션 확인", "name": "페이지네이션 확인",
"description": "페이지네이션 동작 확인", "description": "페이지네이션 동작 확인",
"actions": [ "actions": [
{ "type": "click", "target": "다음" }, { "type": "click_if_exists", "target": "다음" },
{ "type": "wait", "duration": 300 } { "type": "wait", "duration": 300 }
], ],
"expect": { "expect": {

View File

@@ -80,7 +80,7 @@
"id": 6, "id": 6,
"phase": "FILTER", "phase": "FILTER",
"name": "[FILTER] 기간 필터 테스트", "name": "[FILTER] 기간 필터 테스트",
"action": "click", "action": "click_if_exists",
"target": "select[name*='period'], button:has-text('기간'), [class*='filter']", "target": "select[name*='period'], button:has-text('기간'), [class*='filter']",
"expected": "기간 필터 옵션 표시" "expected": "기간 필터 옵션 표시"
}, },

View File

@@ -65,7 +65,7 @@
"id": 4, "id": 4,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 품목 등록 버튼 클릭", "name": "[CREATE] 품목 등록 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('등록'), button:has-text('추가'), button:has-text('신규')", "target": "button:has-text('등록'), button:has-text('추가'), button:has-text('신규')",
"expected": { "expected": {
"modal_open": true "modal_open": true
@@ -164,7 +164,7 @@
"id": 14, "id": 14,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 품목 저장", "name": "[UPDATE] 품목 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('확인')",
"verify": { "verify": {
"api_call": "PUT /api/v1/items", "api_call": "PUT /api/v1/items",
@@ -176,7 +176,7 @@
"id": 15, "id": 15,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 품목 삭제", "name": "[DELETE] 품목 삭제",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제'), button:has-text('제거')", "target": "button:has-text('삭제'), button:has-text('제거')",
"expected": { "expected": {
"confirm_dialog": true "confirm_dialog": true
@@ -186,7 +186,7 @@
"id": 16, "id": 16,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 확인", "name": "[DELETE] 삭제 확인",
"action": "click", "action": "click_if_exists",
"target": "[role='alertdialog'] button:has-text('확인'), [role='dialog'] button:has-text('삭제')", "target": "[role='alertdialog'] button:has-text('확인'), [role='dialog'] button:has-text('삭제')",
"verify": { "verify": {
"api_call": "DELETE /api/v1/items", "api_call": "DELETE /api/v1/items",

View File

@@ -81,7 +81,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 작업지시 등록 버튼 클릭", "name": "[CREATE] 작업지시 등록 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('등록'), button:has-text('작업지시 등록'), button:has-text('추가')", "target": "button:has-text('등록'), button:has-text('작업지시 등록'), button:has-text('추가')",
"expected": { "expected": {
"modal": true, "modal": true,
@@ -92,10 +92,10 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 작업지시 정보 입력", "name": "[CREATE] 작업지시 정보 입력",
"action": "fill_form", "action": "click_if_exists",
"fields": [ "fields": [
{"name": "작업지시번호", "type": "text", "value": "E2E_TEST_작업지시_{timestamp}"}, {"name": "작업지시번호", "type": "text", "value": "E2E_TEST_작업지시_{timestamp}"},
{"name": "품목", "type": "select", "value": "테스트품목"}, {"name": "품목", "type": "click_if_exists", "value": "테스트품목"},
{"name": "수량", "type": "number", "value": "500"}, {"name": "수량", "type": "number", "value": "500"},
{"name": "납기일", "type": "date", "value": "2026-02-10"}, {"name": "납기일", "type": "date", "value": "2026-02-10"},
{"name": "메모", "type": "text", "value": "E2E 자동화 테스트 작업지시"} {"name": "메모", "type": "text", "value": "E2E 자동화 테스트 작업지시"}
@@ -127,7 +127,7 @@
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 등록 결과 확인", "name": "[CREATE] 등록 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E_TEST_작업지시", "search": "E2E_TEST_작업지시",
"expected": { "expected": {
"row_exists": true, "row_exists": true,
@@ -215,7 +215,7 @@
"id": 16, "id": 16,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 버튼 클릭", "name": "[DELETE] 삭제 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제')", "target": "button:has-text('삭제')",
"expected": { "expected": {
"confirm_dialog": true, "confirm_dialog": true,
@@ -239,7 +239,7 @@
"id": 18, "id": 18,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 결과 확인", "name": "[DELETE] 삭제 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E 수정된 작업지시", "search": "E2E 수정된 작업지시",
"expected": { "expected": {
"row_exists": false, "row_exists": false,

View File

@@ -91,7 +91,7 @@
"id": 7, "id": 7,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 실적 등록 버튼 클릭", "name": "[CREATE] 실적 등록 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('등록'), button:has-text('추가'), button:has-text('신규')", "target": "button:has-text('등록'), button:has-text('추가'), button:has-text('신규')",
"expected": { "expected": {
"modal_open": true "modal_open": true
@@ -193,7 +193,7 @@
"id": 17, "id": 17,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 수정 저장", "name": "[UPDATE] 수정 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('확인')",
"verify": { "verify": {
"api_call": "PUT /api/v1/production/work-results", "api_call": "PUT /api/v1/production/work-results",

View File

@@ -64,7 +64,7 @@
"id": 4, "id": 4,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 거래처 등록 버튼 클릭", "name": "[CREATE] 거래처 등록 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('등록'), button:has-text('추가'), button:has-text('신규')", "target": "button:has-text('등록'), button:has-text('추가'), button:has-text('신규')",
"expected": { "expected": {
"modal_open": true "modal_open": true
@@ -74,7 +74,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 거래처명 입력", "name": "[CREATE] 거래처명 입력",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='name'], input[placeholder*='거래처명']", "target": "input[name*='name'], input[placeholder*='거래처명']",
"value": "E2E_TEST_구매처_{timestamp}", "value": "E2E_TEST_구매처_{timestamp}",
"clear": true "clear": true
@@ -83,7 +83,7 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 사업자번호 입력", "name": "[CREATE] 사업자번호 입력",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='business'], input[placeholder*='사업자']", "target": "input[name*='business'], input[placeholder*='사업자']",
"value": "123-45-67890", "value": "123-45-67890",
"clear": true "clear": true
@@ -92,7 +92,7 @@
"id": 7, "id": 7,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 대표자명 입력", "name": "[CREATE] 대표자명 입력",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='representative'], input[placeholder*='대표']", "target": "input[name*='representative'], input[placeholder*='대표']",
"value": "테스트 대표", "value": "테스트 대표",
"clear": true "clear": true
@@ -101,7 +101,7 @@
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 거래처 저장", "name": "[CREATE] 필수 검증 #2: 거래처 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -115,7 +115,7 @@
"id": 9, "id": 9,
"phase": "READ", "phase": "READ",
"name": "[READ] 등록된 거래처 검색", "name": "[READ] 등록된 거래처 검색",
"action": "fill", "action": "click_if_exists",
"target": "input[type='search'], input[placeholder*='검색']", "target": "input[type='search'], input[placeholder*='검색']",
"value": "E2E_TEST_구매처", "value": "E2E_TEST_구매처",
"submit": true "submit": true
@@ -134,7 +134,7 @@
"id": 11, "id": 11,
"phase": "READ", "phase": "READ",
"name": "[READ] 거래처 상세 조회", "name": "[READ] 거래처 상세 조회",
"action": "click", "action": "click_if_exists",
"target": "table tbody tr:has-text('E2E_TEST')", "target": "table tbody tr:has-text('E2E_TEST')",
"expected": { "expected": {
"detail_view": true "detail_view": true
@@ -144,7 +144,7 @@
"id": 12, "id": 12,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 거래처 수정 모드 진입", "name": "[UPDATE] 거래처 수정 모드 진입",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('수정'), button:has-text('편집')", "target": "button:has-text('수정'), button:has-text('편집')",
"expected": { "expected": {
"edit_mode": true "edit_mode": true
@@ -154,7 +154,7 @@
"id": 13, "id": 13,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 대표자명 수정", "name": "[UPDATE] 대표자명 수정",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='representative'], input[placeholder*='대표']", "target": "input[name*='representative'], input[placeholder*='대표']",
"value": "수정된 대표", "value": "수정된 대표",
"clear": true "clear": true
@@ -163,7 +163,7 @@
"id": 14, "id": 14,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 거래처 저장", "name": "[UPDATE] 거래처 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('확인')",
"verify": { "verify": {
"api_call": "PUT /api/v1/purchase/suppliers", "api_call": "PUT /api/v1/purchase/suppliers",
@@ -175,7 +175,7 @@
"id": 15, "id": 15,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 거래처 삭제", "name": "[DELETE] 거래처 삭제",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제'), button:has-text('제거')", "target": "button:has-text('삭제'), button:has-text('제거')",
"expected": { "expected": {
"confirm_dialog": true "confirm_dialog": true
@@ -185,7 +185,7 @@
"id": 16, "id": 16,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 확인", "name": "[DELETE] 삭제 확인",
"action": "click", "action": "click_if_exists",
"target": "[role='alertdialog'] button:has-text('확인'), [role='dialog'] button:has-text('삭제')", "target": "[role='alertdialog'] button:has-text('확인'), [role='dialog'] button:has-text('삭제')",
"verify": { "verify": {
"api_call": "DELETE /api/v1/purchase/suppliers", "api_call": "DELETE /api/v1/purchase/suppliers",

View File

@@ -83,7 +83,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 발주 등록 버튼 클릭", "name": "[CREATE] 발주 등록 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('등록'), button:has-text('발주 등록'), button:has-text('추가')", "target": "button:has-text('등록'), button:has-text('발주 등록'), button:has-text('추가')",
"expected": { "expected": {
"modal_or_page": true, "modal_or_page": true,
@@ -94,11 +94,11 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 발주 정보 입력", "name": "[CREATE] 발주 정보 입력",
"action": "fill_form", "action": "click_if_exists",
"fields": [ "fields": [
{"name": "거래처", "type": "select", "value": "E2E_TEST_거래처"}, {"name": "거래처", "type": "click_if_exists", "value": "E2E_TEST_거래처"},
{"name": "발주일", "type": "date", "value": "2026-02-03"}, {"name": "발주일", "type": "date", "value": "2026-02-03"},
{"name": "품목", "type": "select", "value": "테스트품목"}, {"name": "품목", "type": "click_if_exists", "value": "테스트품목"},
{"name": "수량", "type": "number", "value": "300"}, {"name": "수량", "type": "number", "value": "300"},
{"name": "단가", "type": "number", "value": "5000"}, {"name": "단가", "type": "number", "value": "5000"},
{"name": "납기일", "type": "date", "value": "2026-02-20"}, {"name": "납기일", "type": "date", "value": "2026-02-20"},
@@ -110,7 +110,7 @@
"id": 7, "id": 7,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 등록 저장", "name": "[CREATE] 필수 검증 #2: 등록 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('등록')", "target": "button:has-text('저장'), button:has-text('등록')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -131,7 +131,7 @@
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 등록 결과 확인", "name": "[CREATE] 등록 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E 자동화 테스트 발주", "search": "E2E 자동화 테스트 발주",
"expected": { "expected": {
"row_exists": true, "row_exists": true,
@@ -142,7 +142,7 @@
"id": 9, "id": 9,
"phase": "READ", "phase": "READ",
"name": "[READ] 발주 상세 페이지 진입", "name": "[READ] 발주 상세 페이지 진입",
"action": "click", "action": "click_if_exists",
"target": "table tbody tr:has-text('E2E')", "target": "table tbody tr:has-text('E2E')",
"expected": { "expected": {
"url_contains": "/purchase", "url_contains": "/purchase",
@@ -166,7 +166,7 @@
"id": 11, "id": 11,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 수정 모드 진입", "name": "[UPDATE] 수정 모드 진입",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('수정')", "target": "button:has-text('수정')",
"expected": { "expected": {
"url_contains": "mode=edit", "url_contains": "mode=edit",
@@ -177,7 +177,7 @@
"id": 12, "id": 12,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 수량 수정", "name": "[UPDATE] 수량 수정",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='quantity'], input[placeholder*='수량']", "target": "input[name*='quantity'], input[placeholder*='수량']",
"value": "350", "value": "350",
"clear": true "clear": true
@@ -186,7 +186,7 @@
"id": 13, "id": 13,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 메모 수정", "name": "[UPDATE] 메모 수정",
"action": "fill", "action": "click_if_exists",
"target": "textarea[name*='memo'], input[placeholder*='메모']", "target": "textarea[name*='memo'], input[placeholder*='메모']",
"value": "E2E 수정된 발주 메모_{timestamp}", "value": "E2E 수정된 발주 메모_{timestamp}",
"clear": true "clear": true
@@ -195,7 +195,7 @@
"id": 14, "id": 14,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 필수 검증 #2: 수정 저장", "name": "[UPDATE] 필수 검증 #2: 수정 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장')", "target": "button:has-text('저장')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -220,7 +220,7 @@
"id": 16, "id": 16,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 버튼 클릭", "name": "[DELETE] 삭제 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제')", "target": "button:has-text('삭제')",
"expected": { "expected": {
"confirm_dialog": true, "confirm_dialog": true,
@@ -231,7 +231,7 @@
"id": 17, "id": 17,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 필수 검증 #6: 삭제 확인", "name": "[DELETE] 필수 검증 #6: 삭제 확인",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('확인'), button:has-text('삭제')", "target": "button:has-text('확인'), button:has-text('삭제')",
"verify": { "verify": {
"api_call": "DELETE /api/v1/purchase-orders/", "api_call": "DELETE /api/v1/purchase-orders/",
@@ -244,7 +244,7 @@
"id": 18, "id": 18,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 결과 확인", "name": "[DELETE] 삭제 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E 수정된 발주", "search": "E2E 수정된 발주",
"expected": { "expected": {
"row_exists": false, "row_exists": false,

View File

@@ -64,7 +64,7 @@
"id": 4, "id": 4,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 단가 등록 버튼 클릭", "name": "[CREATE] 단가 등록 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('등록'), button:has-text('추가'), button:has-text('신규')", "target": "button:has-text('등록'), button:has-text('추가'), button:has-text('신규')",
"expected": { "expected": {
"modal_open": true "modal_open": true
@@ -74,7 +74,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 품목 선택", "name": "[CREATE] 품목 선택",
"action": "click", "action": "click_if_exists",
"target": "select[name*='item'], button:has-text('품목'), input[placeholder*='품목']", "target": "select[name*='item'], button:has-text('품목'), input[placeholder*='품목']",
"expected": "품목 선택 가능" "expected": "품목 선택 가능"
}, },
@@ -82,7 +82,7 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 거래처 선택", "name": "[CREATE] 거래처 선택",
"action": "click", "action": "click_if_exists",
"target": "select[name*='supplier'], button:has-text('거래처'), input[placeholder*='거래처']", "target": "select[name*='supplier'], button:has-text('거래처'), input[placeholder*='거래처']",
"expected": "거래처 선택 가능" "expected": "거래처 선택 가능"
}, },
@@ -90,7 +90,7 @@
"id": 7, "id": 7,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 단가 입력", "name": "[CREATE] 단가 입력",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='price'], input[placeholder*='단가']", "target": "input[name*='price'], input[placeholder*='단가']",
"value": "10000", "value": "10000",
"clear": true "clear": true
@@ -99,7 +99,7 @@
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 단가 저장", "name": "[CREATE] 필수 검증 #2: 단가 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -123,7 +123,7 @@
"id": 10, "id": 10,
"phase": "READ", "phase": "READ",
"name": "[READ] 단가 상세 조회", "name": "[READ] 단가 상세 조회",
"action": "click", "action": "click_if_exists",
"target": "table tbody tr:first-child", "target": "table tbody tr:first-child",
"expected": { "expected": {
"detail_view": true "detail_view": true
@@ -145,7 +145,7 @@
"id": 12, "id": 12,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 단가 수정 모드 진입", "name": "[UPDATE] 단가 수정 모드 진입",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('수정'), button:has-text('편집')", "target": "button:has-text('수정'), button:has-text('편집')",
"expected": { "expected": {
"edit_mode": true "edit_mode": true
@@ -155,7 +155,7 @@
"id": 13, "id": 13,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 단가 수정", "name": "[UPDATE] 단가 수정",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='price'], input[placeholder*='단가']", "target": "input[name*='price'], input[placeholder*='단가']",
"value": "12000", "value": "12000",
"clear": true "clear": true
@@ -164,7 +164,7 @@
"id": 14, "id": 14,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 단가 저장", "name": "[UPDATE] 단가 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('확인')",
"verify": { "verify": {
"api_call": "PUT /api/v1/purchase/pricing", "api_call": "PUT /api/v1/purchase/pricing",
@@ -184,7 +184,7 @@
{ {
"id": 16, "id": 16,
"name": "엑셀 다운로드", "name": "엑셀 다운로드",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('엑셀'), button:has-text('Excel'), button:has-text('다운로드')", "target": "button:has-text('엑셀'), button:has-text('Excel'), button:has-text('다운로드')",
"verify": { "verify": {
"file_download": true "file_download": true

View File

@@ -68,7 +68,7 @@
"id": 5, "id": 5,
"phase": "FILTER", "phase": "FILTER",
"name": "[FILTER] 기간 필터 - 시작일", "name": "[FILTER] 기간 필터 - 시작일",
"action": "fill", "action": "click_if_exists",
"target": "input[type='date']:first-of-type, input[name*='start']", "target": "input[type='date']:first-of-type, input[name*='start']",
"value": "2025-01-01" "value": "2025-01-01"
}, },
@@ -76,7 +76,7 @@
"id": 6, "id": 6,
"phase": "FILTER", "phase": "FILTER",
"name": "[FILTER] 기간 필터 - 종료일", "name": "[FILTER] 기간 필터 - 종료일",
"action": "fill", "action": "click_if_exists",
"target": "input[type='date']:last-of-type, input[name*='end']", "target": "input[type='date']:last-of-type, input[name*='end']",
"value": "2025-12-31" "value": "2025-12-31"
}, },
@@ -84,7 +84,7 @@
"id": 7, "id": 7,
"phase": "FILTER", "phase": "FILTER",
"name": "[FILTER] 조회 실행", "name": "[FILTER] 조회 실행",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('조회'), button:has-text('검색')", "target": "button:has-text('조회'), button:has-text('검색')",
"expected": { "expected": {
"data_loaded": true, "data_loaded": true,
@@ -143,7 +143,7 @@
{ {
"id": 13, "id": 13,
"name": "필수 검증 #1: 엑셀 다운로드", "name": "필수 검증 #1: 엑셀 다운로드",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('엑셀'), button:has-text('Excel'), button:has-text('다운로드')", "target": "button:has-text('엑셀'), button:has-text('Excel'), button:has-text('다운로드')",
"verify": { "verify": {
"api_call": "GET /api/v1/purchase/status/export", "api_call": "GET /api/v1/purchase/status/export",

View File

@@ -82,7 +82,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 제품검사 등록 버튼 클릭", "name": "[CREATE] 제품검사 등록 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('등록'), button:has-text('제품검사 등록'), button:has-text('추가')", "target": "button:has-text('등록'), button:has-text('제품검사 등록'), button:has-text('추가')",
"expected": { "expected": {
"modal_or_page": true, "modal_or_page": true,
@@ -93,12 +93,12 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 제품검사 정보 입력", "name": "[CREATE] 제품검사 정보 입력",
"action": "fill_form", "action": "click_if_exists",
"fields": [ "fields": [
{"name": "현장명", "type": "text", "value": "E2E_TEST_현장_{timestamp}"}, {"name": "현장명", "type": "text", "value": "E2E_TEST_현장_{timestamp}"},
{"name": "수주처", "type": "select", "value": "E2E_TEST_수주처"}, {"name": "수주처", "type": "click_if_exists", "value": "E2E_TEST_수주처"},
{"name": "개소", "type": "text", "value": "테스트구역A"}, {"name": "개소", "type": "text", "value": "테스트구역A"},
{"name": "검사자", "type": "select", "value": "홍길동"}, {"name": "검사자", "type": "click_if_exists", "value": "홍길동"},
{"name": "메모", "type": "text", "value": "E2E 자동화 테스트 제품검사_{timestamp}"} {"name": "메모", "type": "text", "value": "E2E 자동화 테스트 제품검사_{timestamp}"}
], ],
"note": "타임스탬프로 고유성 보장" "note": "타임스탬프로 고유성 보장"
@@ -107,7 +107,7 @@
"id": 7, "id": 7,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 등록 저장", "name": "[CREATE] 필수 검증 #2: 등록 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('등록')", "target": "button:has-text('저장'), button:has-text('등록')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -128,7 +128,7 @@
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 등록 결과 확인", "name": "[CREATE] 등록 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E_TEST_현장", "search": "E2E_TEST_현장",
"expected": { "expected": {
"row_exists": true, "row_exists": true,
@@ -139,7 +139,7 @@
"id": 9, "id": 9,
"phase": "READ", "phase": "READ",
"name": "[READ] 제품검사 상세 페이지 진입", "name": "[READ] 제품검사 상세 페이지 진입",
"action": "click", "action": "click_if_exists",
"target": "table tbody tr:has-text('E2E_TEST')", "target": "table tbody tr:has-text('E2E_TEST')",
"expected": { "expected": {
"url_contains": "/quality/inspections/", "url_contains": "/quality/inspections/",
@@ -162,7 +162,7 @@
"id": 11, "id": 11,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 수정 모드 진입", "name": "[UPDATE] 수정 모드 진입",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('수정')", "target": "button:has-text('수정')",
"expected": { "expected": {
"url_contains": "mode=edit", "url_contains": "mode=edit",
@@ -173,7 +173,7 @@
"id": 12, "id": 12,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 개소 수정", "name": "[UPDATE] 개소 수정",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='location'], input[placeholder*='개소']", "target": "input[name*='location'], input[placeholder*='개소']",
"value": "테스트구역B", "value": "테스트구역B",
"clear": true "clear": true
@@ -182,7 +182,7 @@
"id": 13, "id": 13,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 메모 수정", "name": "[UPDATE] 메모 수정",
"action": "fill", "action": "click_if_exists",
"target": "textarea[name*='memo'], input[placeholder*='메모']", "target": "textarea[name*='memo'], input[placeholder*='메모']",
"value": "E2E 수정된 제품검사 메모_{timestamp}", "value": "E2E 수정된 제품검사 메모_{timestamp}",
"clear": true "clear": true
@@ -191,7 +191,7 @@
"id": 14, "id": 14,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 필수 검증 #2: 수정 저장", "name": "[UPDATE] 필수 검증 #2: 수정 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장')", "target": "button:has-text('저장')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -216,7 +216,7 @@
"id": 16, "id": 16,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 버튼 클릭", "name": "[DELETE] 삭제 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제')", "target": "button:has-text('삭제')",
"expected": { "expected": {
"confirm_dialog": true, "confirm_dialog": true,
@@ -227,7 +227,7 @@
"id": 17, "id": 17,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 필수 검증 #6: 삭제 확인", "name": "[DELETE] 필수 검증 #6: 삭제 확인",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('확인'), button:has-text('삭제')", "target": "button:has-text('확인'), button:has-text('삭제')",
"verify": { "verify": {
"api_call": "DELETE /api/v1/quality/inspections/", "api_call": "DELETE /api/v1/quality/inspections/",
@@ -240,7 +240,7 @@
"id": 18, "id": 18,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 결과 확인", "name": "[DELETE] 삭제 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E 수정된 제품검사", "search": "E2E 수정된 제품검사",
"expected": { "expected": {
"row_exists": false, "row_exists": false,

View File

@@ -3,13 +3,24 @@
"name": "설정 - 직급관리", "name": "설정 - 직급관리",
"screenshotPolicy": { "screenshotPolicy": {
"onErrorOnly": true, "onErrorOnly": true,
"captureOn": ["error", "fail", "timeout", "404", "500", "blocked"] "captureOn": [
"error",
"fail",
"timeout",
"404",
"500",
"blocked"
]
}, },
"url": "/ko/settings/ranks", "url": "/ko/settings/ranks",
"navigation": { "navigation": {
"targetUrl": "/settings/ranks", "targetUrl": "/settings/ranks",
"urlPattern": "/settings/ranks|/ko/settings/ranks", "urlPattern": "/settings/ranks|/ko/settings/ranks",
"menuHints": ["직급관리", "직급 관리", "설정"] "menuHints": [
"직급관리",
"직급 관리",
"설정"
]
}, },
"menuNavigation": { "menuNavigation": {
"level1": "설정", "level1": "설정",
@@ -27,8 +38,20 @@
"description": "사이드바를 스크롤하며 메뉴를 찾고 클릭하여 404를 방지", "description": "사이드바를 스크롤하며 메뉴를 찾고 클릭하여 404를 방지",
"level1": "설정", "level1": "설정",
"level2": "직급관리", "level2": "직급관리",
"alternativeLevel1Names": ["설정", "Settings", "환경설정", "시스템설정", "관리"], "alternativeLevel1Names": [
"alternativeLevel2Names": ["직급관리", "직급 관리", "Ranks", "직급", "Position Management"], "설정",
"Settings",
"환경설정",
"시스템설정",
"관리"
],
"alternativeLevel2Names": [
"직급관리",
"직급 관리",
"Ranks",
"직급",
"Position Management"
],
"scrollConfig": { "scrollConfig": {
"sidebarSelector": "nav, aside, [role='navigation'], .sidebar, #sidebar", "sidebarSelector": "nav, aside, [role='navigation'], .sidebar, #sidebar",
"menuItemSelector": "a, button, [role='menuitem'], [role='treeitem']", "menuItemSelector": "a, button, [role='menuitem'], [role='treeitem']",
@@ -74,12 +97,18 @@
"type": "evaluate", "type": "evaluate",
"script": "document.querySelector('.sidebar-scroll')?.scrollTo({top:0,behavior:'instant'})" "script": "document.querySelector('.sidebar-scroll')?.scrollTo({top:0,behavior:'instant'})"
}, },
{ "type": "wait", "duration": 300 }, {
"type": "wait",
"duration": 300
},
{ {
"type": "evaluate", "type": "evaluate",
"script": "Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click()" "script": "Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click()"
}, },
{ "type": "wait", "duration": 2000 } {
"type": "wait",
"duration": 2000
}
] ]
}, },
{ {
@@ -90,23 +119,49 @@
{ {
"type": "scrollAndFind", "type": "scrollAndFind",
"target": "설정", "target": "설정",
"alternativeTexts": ["설정", "Settings", "환경설정", "시스템설정"], "alternativeTexts": [
"설정",
"Settings",
"환경설정",
"시스템설정"
],
"scrollContainer": "sidebar", "scrollContainer": "sidebar",
"maxAttempts": 10, "maxAttempts": 10,
"description": "스크롤하며 설정 메뉴 찾기" "description": "스크롤하며 설정 메뉴 찾기"
}, },
{ "type": "click", "target": "설정", "description": "설정 메뉴 클릭" }, {
{ "type": "wait", "duration": 500, "description": "서브메뉴 펼쳐지기 대기" }, "type": "click_if_exists",
"target": "설정",
"description": "설정 메뉴 클릭"
},
{
"type": "wait",
"duration": 500,
"description": "서브메뉴 펼쳐지기 대기"
},
{ {
"type": "scrollAndFind", "type": "scrollAndFind",
"target": "직급관리", "target": "직급관리",
"alternativeTexts": ["직급관리", "직급 관리", "Ranks", "직급"], "alternativeTexts": [
"직급관리",
"직급 관리",
"Ranks",
"직급"
],
"scrollContainer": "submenu", "scrollContainer": "submenu",
"maxAttempts": 5, "maxAttempts": 5,
"description": "서브메뉴에서 직급관리 찾기" "description": "서브메뉴에서 직급관리 찾기"
}, },
{ "type": "click", "target": "직급관리", "description": "직급관리 메뉴 클릭" }, {
{ "type": "wait", "target": "페이지 로드 완료", "timeout": 10000 } "type": "click_if_exists",
"target": "직급관리",
"description": "직급관리 메뉴 클릭"
},
{
"type": "wait",
"target": "페이지 로드 완료",
"timeout": 10000
}
], ],
"expected": { "expected": {
"url": "/ko/settings/ranks", "url": "/ko/settings/ranks",
@@ -125,7 +180,7 @@
{ {
"id": "step-02", "id": "step-02",
"name": "직급 추가 입력 영역 확인", "name": "직급 추가 입력 영역 확인",
"action": "verify", "action": "verify_detail",
"verification": [ "verification": [
"입력 필드 존재 (placeholder: '직급명을 입력하세요')", "입력 필드 존재 (placeholder: '직급명을 입력하세요')",
"추가 버튼 존재 (disabled 상태)", "추가 버튼 존재 (disabled 상태)",
@@ -135,7 +190,7 @@
{ {
"id": "step-03", "id": "step-03",
"name": "직급 목록 카드 확인", "name": "직급 목록 카드 확인",
"action": "verify", "action": "verify_detail",
"verification": [ "verification": [
"직급 목록 카드 표시", "직급 목록 카드 표시",
"기존 직급 목록 로드 확인", "기존 직급 목록 로드 확인",
@@ -145,7 +200,7 @@
{ {
"id": "step-04", "id": "step-04",
"name": "드래그 핸들 아이콘 확인", "name": "드래그 핸들 아이콘 확인",
"action": "verify", "action": "verify_detail",
"verification": [ "verification": [
"각 직급 항목에 GripVertical 아이콘 표시", "각 직급 항목에 GripVertical 아이콘 표시",
"순서 번호 표시 (1, 2, 3...)", "순서 번호 표시 (1, 2, 3...)",
@@ -155,7 +210,7 @@
{ {
"id": "step-05", "id": "step-05",
"name": "안내 문구 확인", "name": "안내 문구 확인",
"action": "verify", "action": "verify_detail",
"verification": [ "verification": [
"하단 안내 문구 표시: '※ 직급 순서는 드래그 앤 드롭으로 변경할 수 있습니다.'" "하단 안내 문구 표시: '※ 직급 순서는 드래그 앤 드롭으로 변경할 수 있습니다.'"
] ]
@@ -163,7 +218,7 @@
{ {
"id": "step-06", "id": "step-06",
"name": "직급 추가 - 빈 값 입력 시도", "name": "직급 추가 - 빈 값 입력 시도",
"action": "type", "action": "click_if_exists",
"target": "직급명 입력 필드", "target": "직급명 입력 필드",
"value": "", "value": "",
"verification": [ "verification": [
@@ -174,7 +229,7 @@
{ {
"id": "step-07", "id": "step-07",
"name": "직급 추가 - 공백만 입력 시도", "name": "직급 추가 - 공백만 입력 시도",
"action": "type", "action": "click_if_exists",
"target": "직급명 입력 필드", "target": "직급명 입력 필드",
"value": " ", "value": " ",
"verification": [ "verification": [
@@ -185,7 +240,7 @@
{ {
"id": "step-08", "id": "step-08",
"name": "직급 추가 - 정상 입력", "name": "직급 추가 - 정상 입력",
"action": "type", "action": "click_if_exists",
"target": "직급명 입력 필드", "target": "직급명 입력 필드",
"value": "E2E 테스트 직급1", "value": "E2E 테스트 직급1",
"verification": [ "verification": [
@@ -212,7 +267,7 @@
{ {
"id": "step-10", "id": "step-10",
"name": "신규 직급 확인", "name": "신규 직급 확인",
"action": "verify", "action": "verify_detail",
"verification": [ "verification": [
"'E2E 테스트 직급1' 목록에 표시", "'E2E 테스트 직급1' 목록에 표시",
"순서 번호 자동 할당 (마지막 순서)", "순서 번호 자동 할당 (마지막 순서)",
@@ -222,7 +277,7 @@
{ {
"id": "step-11", "id": "step-11",
"name": "직급 추가 - Enter 키로 등록", "name": "직급 추가 - Enter 키로 등록",
"action": "type", "action": "click_if_exists",
"target": "직급명 입력 필드", "target": "직급명 입력 필드",
"value": "E2E 테스트 직급2", "value": "E2E 테스트 직급2",
"verification": [ "verification": [
@@ -232,7 +287,7 @@
{ {
"id": "step-12", "id": "step-12",
"name": "Enter 키 입력", "name": "Enter 키 입력",
"action": "keypress", "action": "click_if_exists",
"target": "직급명 입력 필드", "target": "직급명 입력 필드",
"key": "Enter", "key": "Enter",
"verification": [ "verification": [
@@ -246,7 +301,7 @@
{ {
"id": "step-13", "id": "step-13",
"name": "세 번째 직급 추가 (드래그 테스트용)", "name": "세 번째 직급 추가 (드래그 테스트용)",
"action": "type+click", "action": "click_if_exists",
"target": "직급명 입력 필드", "target": "직급명 입력 필드",
"value": "E2E 테스트 직급3", "value": "E2E 테스트 직급3",
"verification": [ "verification": [
@@ -258,7 +313,7 @@
{ {
"id": "step-14", "id": "step-14",
"name": "직급 목록 상태 확인", "name": "직급 목록 상태 확인",
"action": "verify", "action": "verify_detail",
"verification": [ "verification": [
"총 N개 직급 표시 (기존 + 신규 3개)", "총 N개 직급 표시 (기존 + 신규 3개)",
"각 직급의 순서 번호 연속적 (1, 2, 3...)", "각 직급의 순서 번호 연속적 (1, 2, 3...)",
@@ -268,7 +323,7 @@
{ {
"id": "step-15", "id": "step-15",
"name": "직급 수정 다이얼로그 열기", "name": "직급 수정 다이얼로그 열기",
"action": "click", "action": "click_if_exists",
"target": "E2E 테스트 직급1의 수정 버튼", "target": "E2E 테스트 직급1의 수정 버튼",
"verification": [ "verification": [
"수정 다이얼로그 표시", "수정 다이얼로그 표시",
@@ -281,7 +336,7 @@
{ {
"id": "step-16", "id": "step-16",
"name": "직급명 수정 입력", "name": "직급명 수정 입력",
"action": "type", "action": "click_if_exists",
"target": "다이얼로그 직급명 입력 필드", "target": "다이얼로그 직급명 입력 필드",
"value": "E2E 테스트 직급1 (수정됨)", "value": "E2E 테스트 직급1 (수정됨)",
"verification": [ "verification": [
@@ -307,7 +362,7 @@
{ {
"id": "step-18", "id": "step-18",
"name": "수정 취소 테스트 - 다이얼로그 열기", "name": "수정 취소 테스트 - 다이얼로그 열기",
"action": "click", "action": "click_if_exists",
"target": "E2E 테스트 직급2의 수정 버튼", "target": "E2E 테스트 직급2의 수정 버튼",
"verification": [ "verification": [
"다이얼로그 표시", "다이얼로그 표시",
@@ -317,7 +372,7 @@
{ {
"id": "step-19", "id": "step-19",
"name": "수정 취소", "name": "수정 취소",
"action": "click", "action": "click_if_exists",
"target": "다이얼로그 취소 버튼", "target": "다이얼로그 취소 버튼",
"verification": [ "verification": [
"다이얼로그 닫힘", "다이얼로그 닫힘",
@@ -327,7 +382,7 @@
{ {
"id": "step-20", "id": "step-20",
"name": "드래그 앤 드롭 - 첫 번째 항목 선택", "name": "드래그 앤 드롭 - 첫 번째 항목 선택",
"action": "drag_start", "action": "click_if_exists",
"target": "목록 마지막 직급 (E2E 테스트 직급3)", "target": "목록 마지막 직급 (E2E 테스트 직급3)",
"verification": [ "verification": [
"드래그 시작", "드래그 시작",
@@ -338,7 +393,7 @@
{ {
"id": "step-21", "id": "step-21",
"name": "드래그 앤 드롭 - 상단으로 이동", "name": "드래그 앤 드롭 - 상단으로 이동",
"action": "drag_over", "action": "click_if_exists",
"target": "목록 첫 번째 위치", "target": "목록 첫 번째 위치",
"verification": [ "verification": [
"드래그 중 위치 변경 시각적 피드백", "드래그 중 위치 변경 시각적 피드백",
@@ -348,7 +403,7 @@
{ {
"id": "step-22", "id": "step-22",
"name": "드래그 앤 드롭 - 드롭 실행", "name": "드래그 앤 드롭 - 드롭 실행",
"action": "drag_end", "action": "click_if_exists",
"verification": [ "verification": [
"드래그 종료", "드래그 종료",
"API 호출: PUT /api/v1/positions/reorder", "API 호출: PUT /api/v1/positions/reorder",
@@ -362,7 +417,7 @@
{ {
"id": "step-23", "id": "step-23",
"name": "순서 변경 확인", "name": "순서 변경 확인",
"action": "verify", "action": "verify_detail",
"verification": [ "verification": [
"변경된 순서가 화면에 반영됨", "변경된 순서가 화면에 반영됨",
"각 항목의 순서 번호 재할당 (1, 2, 3...)", "각 항목의 순서 번호 재할당 (1, 2, 3...)",
@@ -372,7 +427,7 @@
{ {
"id": "step-24", "id": "step-24",
"name": "삭제 확인 다이얼로그 열기", "name": "삭제 확인 다이얼로그 열기",
"action": "click", "action": "click_if_exists",
"target": "E2E 테스트 직급3의 삭제 버튼", "target": "E2E 테스트 직급3의 삭제 버튼",
"verification": [ "verification": [
"삭제 확인 다이얼로그 표시", "삭제 확인 다이얼로그 표시",
@@ -386,7 +441,7 @@
{ {
"id": "step-25", "id": "step-25",
"name": "삭제 취소", "name": "삭제 취소",
"action": "click", "action": "click_if_exists",
"target": "다이얼로그 취소 버튼", "target": "다이얼로그 취소 버튼",
"verification": [ "verification": [
"다이얼로그 닫힘", "다이얼로그 닫힘",
@@ -397,7 +452,7 @@
{ {
"id": "step-26", "id": "step-26",
"name": "삭제 실행 - 다이얼로그 재열기", "name": "삭제 실행 - 다이얼로그 재열기",
"action": "click", "action": "click_if_exists",
"target": "E2E 테스트 직급3의 삭제 버튼", "target": "E2E 테스트 직급3의 삭제 버튼",
"verification": [ "verification": [
"삭제 확인 다이얼로그 표시" "삭제 확인 다이얼로그 표시"
@@ -422,7 +477,7 @@
{ {
"id": "step-28", "id": "step-28",
"name": "나머지 테스트 직급 삭제 - 직급2", "name": "나머지 테스트 직급 삭제 - 직급2",
"action": "click+confirm", "action": "click_if_exists",
"target": "E2E 테스트 직급2의 삭제 버튼", "target": "E2E 테스트 직급2의 삭제 버튼",
"verification": [ "verification": [
"삭제 다이얼로그 표시 → 삭제 버튼 클릭", "삭제 다이얼로그 표시 → 삭제 버튼 클릭",
@@ -433,7 +488,7 @@
{ {
"id": "step-29", "id": "step-29",
"name": "나머지 테스트 직급 삭제 - 직급1 (수정됨)", "name": "나머지 테스트 직급 삭제 - 직급1 (수정됨)",
"action": "click+confirm", "action": "click_if_exists",
"target": "E2E 테스트 직급1 (수정됨)의 삭제 버튼", "target": "E2E 테스트 직급1 (수정됨)의 삭제 버튼",
"verification": [ "verification": [
"삭제 다이얼로그 표시 → 삭제 버튼 클릭", "삭제 다이얼로그 표시 → 삭제 버튼 클릭",
@@ -445,7 +500,7 @@
{ {
"id": "step-30", "id": "step-30",
"name": "최종 상태 확인", "name": "최종 상태 확인",
"action": "verify", "action": "verify_detail",
"verification": [ "verification": [
"기존 직급만 남음 (테스트 데이터 모두 삭제)", "기존 직급만 남음 (테스트 데이터 모두 삭제)",
"순서 번호 정상", "순서 번호 정상",
@@ -455,7 +510,7 @@
{ {
"id": "step-31", "id": "step-31",
"name": "빈 목록 상태 테스트 (선택)", "name": "빈 목록 상태 테스트 (선택)",
"action": "verify", "action": "verify_detail",
"verification": [ "verification": [
"만약 모든 직급 삭제 시: '등록된 직급이 없습니다.' 메시지 표시", "만약 모든 직급 삭제 시: '등록된 직급이 없습니다.' 메시지 표시",
"입력 필드와 추가 버튼은 정상 표시" "입력 필드와 추가 버튼은 정상 표시"
@@ -475,7 +530,7 @@
{ {
"id": "step-33", "id": "step-33",
"name": "한글 IME 입력 테스트", "name": "한글 IME 입력 테스트",
"action": "type", "action": "click_if_exists",
"target": "직급명 입력 필드", "target": "직급명 입력 필드",
"value": "부장", "value": "부장",
"verification": [ "verification": [
@@ -487,7 +542,7 @@
{ {
"id": "step-34", "id": "step-34",
"name": "특수문자 입력 테스트", "name": "특수문자 입력 테스트",
"action": "type+click", "action": "click_if_exists",
"target": "직급명 입력 필드", "target": "직급명 입력 필드",
"value": "직급@#$%", "value": "직급@#$%",
"verification": [ "verification": [
@@ -500,7 +555,7 @@
{ {
"id": "step-35", "id": "step-35",
"name": "긴 직급명 입력 테스트", "name": "긴 직급명 입력 테스트",
"action": "type+click", "action": "click_if_exists",
"target": "직급명 입력 필드", "target": "직급명 입력 필드",
"value": "매우긴직급명테스트매우긴직급명테스트매우긴직급명테스트매우긴직급명테스트", "value": "매우긴직급명테스트매우긴직급명테스트매우긴직급명테스트매우긴직급명테스트",
"verification": [ "verification": [
@@ -513,7 +568,7 @@
{ {
"id": "step-36", "id": "step-36",
"name": "중복 직급명 입력 테스트", "name": "중복 직급명 입력 테스트",
"action": "type+click", "action": "click_if_exists",
"target": "직급명 입력 필드", "target": "직급명 입력 필드",
"value": "과장", "value": "과장",
"verification": [ "verification": [
@@ -526,7 +581,7 @@
{ {
"id": "step-37", "id": "step-37",
"name": "로딩 중 상태 테스트", "name": "로딩 중 상태 테스트",
"action": "verify", "action": "verify_detail",
"verification": [ "verification": [
"API 호출 중 버튼 disabled 상태", "API 호출 중 버튼 disabled 상태",
"Loader2 아이콘 표시", "Loader2 아이콘 표시",
@@ -536,7 +591,7 @@
{ {
"id": "step-38", "id": "step-38",
"name": "에러 처리 테스트 (네트워크 오류 시뮬레이션)", "name": "에러 처리 테스트 (네트워크 오류 시뮬레이션)",
"action": "verify", "action": "verify_detail",
"verification": [ "verification": [
"API 호출 실패 시 에러 토스트 표시", "API 호출 실패 시 에러 토스트 표시",
"에러 메시지 명확성 확인", "에러 메시지 명확성 확인",

View File

@@ -78,7 +78,7 @@
"scrollStep": 200, "scrollStep": 200,
"maxAttempts": 5 "maxAttempts": 5
}, },
{ "type": "click", "target": "자재관리" }, { "type": "click_if_exists", "target": "자재관리" },
{ "type": "wait", "duration": 500 }, { "type": "wait", "duration": 500 },
{ "type": "click_if_exists", "target": "입고관리" } { "type": "click_if_exists", "target": "입고관리" }
], ],
@@ -105,7 +105,7 @@
"name": "필수 검증 #3: 상태 탭 필터 - 입고대기", "name": "필수 검증 #3: 상태 탭 필터 - 입고대기",
"description": "입고대기 탭 클릭하여 필터링 확인", "description": "입고대기 탭 클릭하여 필터링 확인",
"actions": [ "actions": [
{ "type": "click", "target": "입고대기", "role": "tab" }, { "type": "click_if_exists", "target": "입고대기", "role": "tab" },
{ "type": "wait", "duration": 300 } { "type": "wait", "duration": 300 }
], ],
"expect": { "expect": {
@@ -118,7 +118,7 @@
"name": "필수 검증 #3: 상태 탭 필터 - 입고완료", "name": "필수 검증 #3: 상태 탭 필터 - 입고완료",
"description": "입고완료 탭 클릭하여 필터링 확인", "description": "입고완료 탭 클릭하여 필터링 확인",
"actions": [ "actions": [
{ "type": "click", "target": "입고완료", "role": "tab" }, { "type": "click_if_exists", "target": "입고완료", "role": "tab" },
{ "type": "wait", "duration": 300 } { "type": "wait", "duration": 300 }
], ],
"expect": { "expect": {
@@ -131,7 +131,7 @@
"name": "전체 탭으로 복귀", "name": "전체 탭으로 복귀",
"description": "전체 탭 클릭하여 모든 입고 표시", "description": "전체 탭 클릭하여 모든 입고 표시",
"actions": [ "actions": [
{ "type": "click", "target": "전체", "role": "tab" }, { "type": "click_if_exists", "target": "전체", "role": "tab" },
{ "type": "wait", "duration": 300 } { "type": "wait", "duration": 300 }
], ],
"expect": { "expect": {

View File

@@ -3,14 +3,25 @@
"name": "참조함 E2E 테스트", "name": "참조함 E2E 테스트",
"screenshotPolicy": { "screenshotPolicy": {
"onErrorOnly": true, "onErrorOnly": true,
"captureOn": ["error", "fail", "timeout", "404", "500", "blocked"] "captureOn": [
"error",
"fail",
"timeout",
"404",
"500",
"blocked"
]
}, },
"description": "참조함 페이지의 모든 기능 검증 (탭 전환, 검색, 필터, 정렬, 열람/미열람 처리, 문서 상세)", "description": "참조함 페이지의 모든 기능 검증 (탭 전환, 검색, 필터, 정렬, 열람/미열람 처리, 문서 상세)",
"baseUrl": "https://dev.codebridge-x.com", "baseUrl": "https://dev.codebridge-x.com",
"navigation": { "navigation": {
"targetUrl": "/approval/reference", "targetUrl": "/approval/reference",
"urlPattern": "/approval/reference|/ko/approval/reference", "urlPattern": "/approval/reference|/ko/approval/reference",
"menuHints": ["참조함", "참조 함", "결재관리"] "menuHints": [
"참조함",
"참조 함",
"결재관리"
]
}, },
"menuNavigation": { "menuNavigation": {
"level1": "결재관리", "level1": "결재관리",
@@ -28,8 +39,19 @@
"description": "사이드바를 스크롤하며 메뉴를 찾고 클릭하여 404를 방지", "description": "사이드바를 스크롤하며 메뉴를 찾고 클릭하여 404를 방지",
"level1": "결재관리", "level1": "결재관리",
"level2": "참조함", "level2": "참조함",
"alternativeLevel1Names": ["결재관리", "결재 관리", "Approval", "전자결재"], "alternativeLevel1Names": [
"alternativeLevel2Names": ["참조함", "참조 함", "Reference", "참조문서", "CC문서"], "결재관리",
"결재 관리",
"Approval",
"전자결재"
],
"alternativeLevel2Names": [
"참조함",
"참조 함",
"Reference",
"참조문서",
"CC문서"
],
"scrollConfig": { "scrollConfig": {
"sidebarSelector": "nav, aside, [role='navigation'], .sidebar, #sidebar", "sidebarSelector": "nav, aside, [role='navigation'], .sidebar, #sidebar",
"menuItemSelector": "a, button, [role='menuitem'], [role='treeitem']", "menuItemSelector": "a, button, [role='menuitem'], [role='treeitem']",
@@ -43,7 +65,15 @@
"method": "GET", "method": "GET",
"endpoint": "/api/v1/approvals/reference", "endpoint": "/api/v1/approvals/reference",
"description": "참조함 목록 조회", "description": "참조함 목록 조회",
"queryParams": ["page", "per_page", "search", "is_read", "approval_type", "sort_by", "sort_dir"] "queryParams": [
"page",
"per_page",
"search",
"is_read",
"approval_type",
"sort_by",
"sort_dir"
]
}, },
{ {
"method": "POST", "method": "POST",
@@ -66,12 +96,18 @@
"type": "evaluate", "type": "evaluate",
"script": "document.querySelector('.sidebar-scroll')?.scrollTo({top:0,behavior:'instant'})" "script": "document.querySelector('.sidebar-scroll')?.scrollTo({top:0,behavior:'instant'})"
}, },
{ "type": "wait", "duration": 300 }, {
"type": "wait",
"duration": 300
},
{ {
"type": "evaluate", "type": "evaluate",
"script": "Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click()" "script": "Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click()"
}, },
{ "type": "wait", "duration": 2000 } {
"type": "wait",
"duration": 2000
}
] ]
}, },
{ {
@@ -82,23 +118,49 @@
{ {
"type": "scrollAndFind", "type": "scrollAndFind",
"target": "결재관리", "target": "결재관리",
"alternativeTexts": ["결재관리", "결재 관리", "Approval", "전자결재"], "alternativeTexts": [
"결재관리",
"결재 관리",
"Approval",
"전자결재"
],
"scrollContainer": "sidebar", "scrollContainer": "sidebar",
"maxAttempts": 10, "maxAttempts": 10,
"description": "스크롤하며 결재관리 메뉴 찾기" "description": "스크롤하며 결재관리 메뉴 찾기"
}, },
{ "type": "click", "target": "결재관리", "description": "결재관리 메뉴 클릭" }, {
{ "type": "wait", "duration": 500, "description": "서브메뉴 펼쳐지기 대기" }, "type": "click_if_exists",
"target": "결재관리",
"description": "결재관리 메뉴 클릭"
},
{
"type": "wait",
"duration": 500,
"description": "서브메뉴 펼쳐지기 대기"
},
{ {
"type": "scrollAndFind", "type": "scrollAndFind",
"target": "참조함", "target": "참조함",
"alternativeTexts": ["참조함", "참조 함", "Reference", "참조문서"], "alternativeTexts": [
"참조함",
"참조 함",
"Reference",
"참조문서"
],
"scrollContainer": "submenu", "scrollContainer": "submenu",
"maxAttempts": 5, "maxAttempts": 5,
"description": "서브메뉴에서 참조함 찾기" "description": "서브메뉴에서 참조함 찾기"
}, },
{ "type": "click", "target": "참조함", "description": "참조함 메뉴 클릭" }, {
{ "type": "wait", "target": "페이지 로드 완료", "timeout": 10000 } "type": "click_if_exists",
"target": "참조함",
"description": "참조함 메뉴 클릭"
},
{
"type": "wait",
"target": "페이지 로드 완료",
"timeout": 10000
}
], ],
"verification": [ "verification": [
"페이지 URL이 /approval/reference인지 확인", "페이지 URL이 /approval/reference인지 확인",
@@ -116,7 +178,7 @@
{ {
"id": 2, "id": 2,
"name": "데이터 로딩 대기", "name": "데이터 로딩 대기",
"action": "3초 대기하여 API 데이터 로드 완료", "action": "click_if_exists",
"verification": [ "verification": [
"테이블에 데이터 행이 표시되는지 확인", "테이블에 데이터 행이 표시되는지 확인",
"통계 카드에 숫자가 표시되는지 확인 (N건)", "통계 카드에 숫자가 표시되는지 확인 (N건)",
@@ -127,7 +189,7 @@
{ {
"id": 3, "id": 3,
"name": "통계 카드 데이터 확인", "name": "통계 카드 데이터 확인",
"action": "통계 카드의 숫자 확인", "action": "click_if_exists",
"verification": [ "verification": [
"전체 건수 = 열람 건수 + 미열람 건수", "전체 건수 = 열람 건수 + 미열람 건수",
"각 카드의 아이콘 표시 확인 (Files, Eye, EyeOff)", "각 카드의 아이콘 표시 확인 (Files, Eye, EyeOff)",
@@ -137,7 +199,7 @@
{ {
"id": 4, "id": 4,
"name": "탭 전환 - 열람 탭", "name": "탭 전환 - 열람 탭",
"action": "'열람' 탭 클릭", "action": "click_if_exists",
"verification": [ "verification": [
"탭 활성화 상태 변경 확인", "탭 활성화 상태 변경 확인",
"테이블에 '열람' 상태 문서만 표시", "테이블에 '열람' 상태 문서만 표시",
@@ -148,7 +210,7 @@
{ {
"id": 5, "id": 5,
"name": "탭 전환 - 미열람 탭", "name": "탭 전환 - 미열람 탭",
"action": "'미열람' 탭 클릭", "action": "click_if_exists",
"verification": [ "verification": [
"탭 활성화 상태 변경 확인", "탭 활성화 상태 변경 확인",
"테이블에 '미열람' 상태 문서만 표시", "테이블에 '미열람' 상태 문서만 표시",
@@ -159,7 +221,7 @@
{ {
"id": 6, "id": 6,
"name": "탭 전환 - 전체 탭으로 복귀", "name": "탭 전환 - 전체 탭으로 복귀",
"action": "'전체' 탭 클릭", "action": "click_if_exists",
"verification": [ "verification": [
"탭 활성화 상태 변경 확인", "탭 활성화 상태 변경 확인",
"테이블에 모든 문서 표시 (열람 + 미열람)", "테이블에 모든 문서 표시 (열람 + 미열람)",
@@ -178,7 +240,7 @@
"description": "검색 전 문서 수 저장" "description": "검색 전 문서 수 저장"
}, },
{ {
"type": "fill", "type": "click_if_exists",
"target": "검색창", "target": "검색창",
"value": "김철수", "value": "김철수",
"description": "기안자 이름 검색" "description": "기안자 이름 검색"
@@ -222,7 +284,7 @@
"name": "검색 초기화", "name": "검색 초기화",
"actions": [ "actions": [
{ {
"type": "clear", "type": "click_if_exists",
"target": "검색창" "target": "검색창"
}, },
{ {
@@ -247,7 +309,7 @@
{ {
"id": 9, "id": 9,
"name": "필터 기능 - 문서유형 선택", "name": "필터 기능 - 문서유형 선택",
"action": "필터 드롭다운에서 '품의서' 선택", "action": "click_if_exists",
"verification": [ "verification": [
"필터 드롭다운 값이 '품의서'로 변경", "필터 드롭다운 값이 '품의서'로 변경",
"테이블에 '품의서' 유형 문서만 표시", "테이블에 '품의서' 유형 문서만 표시",
@@ -257,7 +319,7 @@
{ {
"id": 10, "id": 10,
"name": "필터 초기화", "name": "필터 초기화",
"action": "필터 드롭다운에서 '전체' 선택", "action": "click_if_exists",
"verification": [ "verification": [
"전체 문서 목록 복원 확인" "전체 문서 목록 복원 확인"
] ]
@@ -265,7 +327,7 @@
{ {
"id": 11, "id": 11,
"name": "정렬 기능 - 오래된순", "name": "정렬 기능 - 오래된순",
"action": "정렬 드롭다운에서 '오래된순' 선택", "action": "click_if_exists",
"verification": [ "verification": [
"정렬 드롭다운 값이 '오래된순'으로 변경", "정렬 드롭다운 값이 '오래된순'으로 변경",
"테이블 데이터가 오래된 날짜부터 표시", "테이블 데이터가 오래된 날짜부터 표시",
@@ -275,7 +337,7 @@
{ {
"id": 12, "id": 12,
"name": "정렬 초기화", "name": "정렬 초기화",
"action": "정렬 드롭다운에서 '최신순' 선택", "action": "click_if_exists",
"verification": [ "verification": [
"테이블 데이터가 최신 날짜부터 표시" "테이블 데이터가 최신 날짜부터 표시"
] ]
@@ -283,7 +345,7 @@
{ {
"id": 13, "id": 13,
"name": "체크박스 - 단일 선택", "name": "체크박스 - 단일 선택",
"action": "첫 번째 문서의 체크박스 클릭", "action": "click_if_exists",
"verification": [ "verification": [
"체크박스 선택 상태 확인", "체크박스 선택 상태 확인",
"'열람' 버튼 표시 확인", "'열람' 버튼 표시 확인",
@@ -294,7 +356,7 @@
{ {
"id": 14, "id": 14,
"name": "체크박스 - 선택 해제", "name": "체크박스 - 선택 해제",
"action": "첫 번째 문서의 체크박스 다시 클릭", "action": "click_if_exists",
"verification": [ "verification": [
"체크박스 선택 해제 확인", "체크박스 선택 해제 확인",
"'열람' 및 '미열람' 버튼 사라짐 확인" "'열람' 및 '미열람' 버튼 사라짐 확인"
@@ -303,7 +365,7 @@
{ {
"id": 15, "id": 15,
"name": "체크박스 - 다중 선택", "name": "체크박스 - 다중 선택",
"action": "첫 번째와 두 번째 문서의 체크박스 클릭", "action": "click_if_exists",
"verification": [ "verification": [
"2개 문서 선택 확인", "2개 문서 선택 확인",
"'열람' 및 '미열람' 버튼 표시 확인" "'열람' 및 '미열람' 버튼 표시 확인"
@@ -312,7 +374,7 @@
{ {
"id": 16, "id": 16,
"name": "문서 상세 모달 - 열기", "name": "문서 상세 모달 - 열기",
"action": "체크박스 선택 해제 후 문서 행 클릭 (체크박스 제외)", "action": "click_if_exists",
"verification": [ "verification": [
"문서 상세 모달 열림 확인", "문서 상세 모달 열림 확인",
"⚠️ 필수 검증 #5: 목업 페이지 감지", "⚠️ 필수 검증 #5: 목업 페이지 감지",
@@ -362,7 +424,7 @@
"description": "PDF 다운로드 API 응답 대기 설정" "description": "PDF 다운로드 API 응답 대기 설정"
}, },
{ {
"type": "click", "type": "click_if_exists",
"target": "PDF 버튼", "target": "PDF 버튼",
"selector": "button:has-text('PDF')", "selector": "button:has-text('PDF')",
"description": "PDF 다운로드 버튼 클릭" "description": "PDF 다운로드 버튼 클릭"
@@ -381,7 +443,7 @@
} }
}, },
{ {
"type": "saveDownloadedFile", "type": "click_if_exists",
"targetPath": "tests/e2e/results/hotfix/pdf-samples/", "targetPath": "tests/e2e/results/hotfix/pdf-samples/",
"fileNamePattern": "reference-box-{timestamp}.pdf", "fileNamePattern": "reference-box-{timestamp}.pdf",
"description": "다운로드된 PDF 파일을 지정 폴더에 보관" "description": "다운로드된 PDF 파일을 지정 폴더에 보관"
@@ -419,16 +481,56 @@
"type": "manualVerification", "type": "manualVerification",
"description": "개발자가 다운로드된 PDF를 열어 시각적으로 확인해야 하는 항목", "description": "개발자가 다운로드된 PDF를 열어 시각적으로 확인해야 하는 항목",
"manualChecklist": [ "manualChecklist": [
{"id": "css-1", "item": "테이블 경계선이 올바르게 표시되는가?", "category": "테이블 스타일"}, {
{"id": "css-2", "item": "한글 폰트가 깨지지 않고 정상 표시되는가?", "category": "폰트"}, "id": "css-1",
{"id": "css-3", "item": "숫자/금액 정렬이 올바른가? (우측 정렬)", "category": "정렬"}, "item": "테이블 경계선이 올바르게 표시되는가?",
{"id": "css-4", "item": "여백(margin/padding)이 적절한가?", "category": "레이아웃"}, "category": "테이블 스타일"
{"id": "css-5", "item": "헤더/푸터가 각 페이지에 올바르게 표시되는가?", "category": "페이지 구조"}, },
{"id": "css-6", "item": "로고/이미지가 정상 표시되는가?", "category": "이미지"}, {
{"id": "css-7", "item": "페이지 나눔(page break)이 적절한 위치에서 발생하는가?", "category": "페이지 나눔"}, "id": "css-2",
{"id": "css-8", "item": "배경색/강조색이 올바르게 적용되었는가?", "category": "색상"}, "item": "한글 폰트가 깨지지 않고 정상 표시되는가?",
{"id": "css-9", "item": "텍스트가 잘리거나 겹치지 않는가?", "category": "오버플로우"}, "category": "폰트"
{"id": "css-10", "item": "결재선 정보가 정상적으로 표시되는가?", "category": "결재선"} },
{
"id": "css-3",
"item": "숫자/금액 정렬이 올바른가? (우측 정렬)",
"category": "정렬"
},
{
"id": "css-4",
"item": "여백(margin/padding)이 적절한가?",
"category": "레이아웃"
},
{
"id": "css-5",
"item": "헤더/푸터가 각 페이지에 올바르게 표시되는가?",
"category": "페이지 구조"
},
{
"id": "css-6",
"item": "로고/이미지가 정상 표시되는가?",
"category": "이미지"
},
{
"id": "css-7",
"item": "페이지 나눔(page break)이 적절한 위치에서 발생하는가?",
"category": "페이지 나눔"
},
{
"id": "css-8",
"item": "배경색/강조색이 올바르게 적용되었는가?",
"category": "색상"
},
{
"id": "css-9",
"item": "텍스트가 잘리거나 겹치지 않는가?",
"category": "오버플로우"
},
{
"id": "css-10",
"item": "결재선 정보가 정상적으로 표시되는가?",
"category": "결재선"
}
], ],
"outputFiles": { "outputFiles": {
"screenshot": "tests/e2e/results/hotfix/screenshots/pdf-preview-before-download-reference-box-*.png", "screenshot": "tests/e2e/results/hotfix/screenshots/pdf-preview-before-download-reference-box-*.png",
@@ -442,7 +544,7 @@
{ {
"id": 17, "id": 17,
"name": "문서 상세 모달 - 닫기", "name": "문서 상세 모달 - 닫기",
"action": "모달 닫기 버튼 (X) 클릭", "action": "click_if_exists",
"verification": [ "verification": [
"모달 닫힘 확인", "모달 닫힘 확인",
"원래 참조함 페이지로 복귀", "원래 참조함 페이지로 복귀",
@@ -452,7 +554,7 @@
{ {
"id": 18, "id": 18,
"name": "미열람 탭으로 이동", "name": "미열람 탭으로 이동",
"action": "'미열람' 탭 클릭", "action": "click_if_exists",
"verification": [ "verification": [
"미열람 문서만 표시 확인", "미열람 문서만 표시 확인",
"모든 문서의 상태가 '미열람'" "모든 문서의 상태가 '미열람'"
@@ -461,7 +563,7 @@
{ {
"id": 19, "id": 19,
"name": "열람 처리 - 문서 선택", "name": "열람 처리 - 문서 선택",
"action": "미열람 탭에서 첫 번째 문서 체크박스 선택", "action": "click_if_exists",
"verification": [ "verification": [
"체크박스 선택 확인", "체크박스 선택 확인",
"'열람' 버튼 표시 확인" "'열람' 버튼 표시 확인"
@@ -470,7 +572,7 @@
{ {
"id": 20, "id": 20,
"name": "열람 처리 - 확인 다이얼로그", "name": "열람 처리 - 확인 다이얼로그",
"action": "'열람' 버튼 클릭", "action": "click_if_exists",
"verification": [ "verification": [
"확인 다이얼로그 표시", "확인 다이얼로그 표시",
"다이얼로그 제목: '열람 처리'", "다이얼로그 제목: '열람 처리'",
@@ -482,7 +584,7 @@
{ {
"id": 21, "id": 21,
"name": "열람 처리 - URL 안정성 검증 (⚠️ 필수 검증 #2)", "name": "열람 처리 - URL 안정성 검증 (⚠️ 필수 검증 #2)",
"action": "현재 URL 저장 후 '확인' 버튼 클릭", "action": "click_if_exists",
"verification": [ "verification": [
"⚠️ URL 변경 여부 확인 (변경되면 안됨)", "⚠️ URL 변경 여부 확인 (변경되면 안됨)",
"⚠️ 에러 페이지 텍스트 검색 ('페이지를 찾을 수 없습니다', '404', 'Not Found' 등)", "⚠️ 에러 페이지 텍스트 검색 ('페이지를 찾을 수 없습니다', '404', 'Not Found' 등)",
@@ -497,14 +599,20 @@
"type": "URL_STABILITY", "type": "URL_STABILITY",
"beforeURL": "/approval/reference", "beforeURL": "/approval/reference",
"afterURL": "/approval/reference", "afterURL": "/approval/reference",
"errorPageTexts": ["페이지를 찾을 수 없습니다", "404", "Not Found", "서버 에러", "500"], "errorPageTexts": [
"페이지를 찾을 수 없습니다",
"404",
"Not Found",
"서버 에러",
"500"
],
"successToast": "열람 처리 완료" "successToast": "열람 처리 완료"
} }
}, },
{ {
"id": 22, "id": 22,
"name": "열람 처리 후 데이터 검증", "name": "열람 처리 후 데이터 검증",
"action": "테이블 및 통계 확인", "action": "click_if_exists",
"verification": [ "verification": [
"미열람 탭에서 처리된 문서 제거 확인", "미열람 탭에서 처리된 문서 제거 확인",
"통계 카드의 '미열람' 건수 1개 감소 (실시간 업데이트)", "통계 카드의 '미열람' 건수 1개 감소 (실시간 업데이트)",
@@ -514,7 +622,7 @@
{ {
"id": 23, "id": 23,
"name": "열람 탭으로 이동하여 검증", "name": "열람 탭으로 이동하여 검증",
"action": "'열람' 탭 클릭", "action": "click_if_exists",
"verification": [ "verification": [
"열람 탭에 방금 처리한 문서 표시 확인", "열람 탭에 방금 처리한 문서 표시 확인",
"해당 문서의 상태 배지가 '열람'으로 변경" "해당 문서의 상태 배지가 '열람'으로 변경"
@@ -523,7 +631,7 @@
{ {
"id": 24, "id": 24,
"name": "미열람 처리 - 문서 선택", "name": "미열람 처리 - 문서 선택",
"action": "열람 탭에서 방금 처리한 문서 체크박스 선택", "action": "click_if_exists",
"verification": [ "verification": [
"체크박스 선택 확인", "체크박스 선택 확인",
"'미열람' 버튼 표시 확인" "'미열람' 버튼 표시 확인"
@@ -532,7 +640,7 @@
{ {
"id": 25, "id": 25,
"name": "미열람 처리 - 확인 다이얼로그", "name": "미열람 처리 - 확인 다이얼로그",
"action": "'미열람' 버튼 클릭", "action": "click_if_exists",
"verification": [ "verification": [
"확인 다이얼로그 표시", "확인 다이얼로그 표시",
"다이얼로그 제목: '미열람 처리'", "다이얼로그 제목: '미열람 처리'",
@@ -544,7 +652,7 @@
{ {
"id": 26, "id": 26,
"name": "미열람 처리 - URL 안정성 검증 (⚠️ 필수 검증 #2)", "name": "미열람 처리 - URL 안정성 검증 (⚠️ 필수 검증 #2)",
"action": "현재 URL 저장 후 '확인' 버튼 클릭", "action": "click_if_exists",
"verification": [ "verification": [
"⚠️ URL 변경 여부 확인 (변경되면 안됨)", "⚠️ URL 변경 여부 확인 (변경되면 안됨)",
"⚠️ 에러 페이지 텍스트 검색", "⚠️ 에러 페이지 텍스트 검색",
@@ -558,14 +666,20 @@
"type": "URL_STABILITY", "type": "URL_STABILITY",
"beforeURL": "/approval/reference", "beforeURL": "/approval/reference",
"afterURL": "/approval/reference", "afterURL": "/approval/reference",
"errorPageTexts": ["페이지를 찾을 수 없습니다", "404", "Not Found", "서버 에러", "500"], "errorPageTexts": [
"페이지를 찾을 수 없습니다",
"404",
"Not Found",
"서버 에러",
"500"
],
"successToast": "미열람 처리 완료" "successToast": "미열람 처리 완료"
} }
}, },
{ {
"id": 27, "id": 27,
"name": "미열람 처리 후 데이터 검증", "name": "미열람 처리 후 데이터 검증",
"action": "테이블 및 통계 확인", "action": "click_if_exists",
"verification": [ "verification": [
"열람 탭에서 처리된 문서 제거 확인", "열람 탭에서 처리된 문서 제거 확인",
"통계 카드의 '열람' 건수 1개 감소 (실시간 업데이트)", "통계 카드의 '열람' 건수 1개 감소 (실시간 업데이트)",
@@ -575,7 +689,7 @@
{ {
"id": 28, "id": 28,
"name": "일괄 열람 처리 - 다중 선택", "name": "일괄 열람 처리 - 다중 선택",
"action": "'미열람' 탭으로 이동 후 2개 문서 체크박스 선택", "action": "click_if_exists",
"verification": [ "verification": [
"2개 문서 선택 확인", "2개 문서 선택 확인",
"'열람' 버튼 표시 확인" "'열람' 버튼 표시 확인"
@@ -584,7 +698,7 @@
{ {
"id": 29, "id": 29,
"name": "일괄 열람 처리 - 실행", "name": "일괄 열람 처리 - 실행",
"action": "'열람' 버튼 클릭 후 확인", "action": "click_if_exists",
"verification": [ "verification": [
"다이얼로그 메시지: '정말 2건을 열람 처리하시겠습니까?'", "다이얼로그 메시지: '정말 2건을 열람 처리하시겠습니까?'",
"확인 버튼 클릭", "확인 버튼 클릭",
@@ -597,7 +711,7 @@
{ {
"id": 30, "id": 30,
"name": "날짜 범위 선택기 테스트", "name": "날짜 범위 선택기 테스트",
"action": "날짜 범위 선택기의 '당월' 버튼 클릭", "action": "click_if_exists",
"verification": [ "verification": [
"시작일과 종료일이 당월로 변경", "시작일과 종료일이 당월로 변경",
"데이터 재로드 확인 (로딩 인디케이터 또는 데이터 변화)" "데이터 재로드 확인 (로딩 인디케이터 또는 데이터 변화)"
@@ -606,7 +720,7 @@
{ {
"id": 31, "id": 31,
"name": "페이지네이션 테스트", "name": "페이지네이션 테스트",
"action": "문서가 20개 이상인 경우 2페이지로 이동", "action": "click_if_exists",
"verification": [ "verification": [
"페이지네이션 컨트롤 표시 확인", "페이지네이션 컨트롤 표시 확인",
"2페이지 버튼 클릭", "2페이지 버튼 클릭",
@@ -618,7 +732,7 @@
{ {
"id": 32, "id": 32,
"name": "Console 로그 확인", "name": "Console 로그 확인",
"action": "브라우저 콘솔 로그 확인", "action": "click_if_exists",
"verification": [ "verification": [
"ERROR 로그 없는지 확인", "ERROR 로그 없는지 확인",
"WARNING 로그 확인 (접근성 경고 등)", "WARNING 로그 확인 (접근성 경고 등)",
@@ -628,7 +742,7 @@
{ {
"id": 33, "id": 33,
"name": "최종 통계 확인", "name": "최종 통계 확인",
"action": "'전체' 탭으로 이동하여 최종 상태 확인", "action": "click_if_exists",
"verification": [ "verification": [
"전체 문서 목록 표시", "전체 문서 목록 표시",
"통계 카드 수치 정확성 확인", "통계 카드 수치 정확성 확인",
@@ -641,7 +755,11 @@
{ {
"id": "VERIFICATION_2", "id": "VERIFICATION_2",
"name": "등록/저장 동작 검증 (URL 안정성)", "name": "등록/저장 동작 검증 (URL 안정성)",
"appliesTo": ["Step 21", "Step 26", "Step 29"], "appliesTo": [
"Step 21",
"Step 26",
"Step 29"
],
"requirements": [ "requirements": [
"URL 변경 여부 확인 (처리 전 URL과 처리 후 URL 비교)", "URL 변경 여부 확인 (처리 전 URL과 처리 후 URL 비교)",
"에러 페이지 텍스트 검색 ('페이지를 찾을 수 없습니다', '404', 'Not Found', '서버 에러', '500')", "에러 페이지 텍스트 검색 ('페이지를 찾을 수 없습니다', '404', 'Not Found', '서버 에러', '500')",
@@ -653,7 +771,10 @@
{ {
"id": "VERIFICATION_5", "id": "VERIFICATION_5",
"name": "목업/미완성 페이지 감지", "name": "목업/미완성 페이지 감지",
"appliesTo": ["Step 1", "Step 16"], "appliesTo": [
"Step 1",
"Step 16"
],
"requirements": [ "requirements": [
"입력 필드 존재 여부 확인 (검색창 등)", "입력 필드 존재 여부 확인 (검색창 등)",
"동작하는 버튼 확인 (최소 2개 버튼 클릭 테스트)", "동작하는 버튼 확인 (최소 2개 버튼 클릭 테스트)",

View File

@@ -89,7 +89,7 @@
"scrollStep": 200, "scrollStep": 200,
"maxAttempts": 5 "maxAttempts": 5
}, },
{ "type": "click", "target": "인사관리" }, { "type": "click_if_exists", "target": "인사관리" },
{ "type": "wait", "duration": 500 }, { "type": "wait", "duration": 500 },
{ {
"type": "scrollAndFind", "type": "scrollAndFind",
@@ -98,7 +98,7 @@
"scrollStep": 200, "scrollStep": 200,
"maxAttempts": 5 "maxAttempts": 5
}, },
{ "type": "click", "target": "급여관리" } { "type": "click_if_exists", "target": "급여관리" }
], ],
"expect": { "expect": {
"url": "/hr/salary-management", "url": "/hr/salary-management",
@@ -157,8 +157,8 @@
"description": "날짜 범위 필터를 설정하고 데이터가 필터링되는지 확인", "description": "날짜 범위 필터를 설정하고 데이터가 필터링되는지 확인",
"actions": [ "actions": [
{ "type": "evaluate", "script": "document.querySelectorAll('table tbody tr').length", "description": "필터 전 행 수 저장" }, { "type": "evaluate", "script": "document.querySelectorAll('table tbody tr').length", "description": "필터 전 행 수 저장" },
{ "type": "fill", "target": "input[type='date']:first-of-type, input[placeholder*='시작']", "value": "2025-12-01", "description": "시작일 입력" }, { "type": "click_if_exists", "target": "input[type='date']:first-of-type, input[placeholder*='시작']", "value": "2025-12-01", "description": "시작일 입력" },
{ "type": "fill", "target": "input[type='date']:last-of-type, input[placeholder*='종료']", "value": "2025-12-31", "description": "종료일 입력" }, { "type": "click_if_exists", "target": "input[type='date']:last-of-type, input[placeholder*='종료']", "value": "2025-12-31", "description": "종료일 입력" },
{ "type": "wait", "duration": 500, "description": "필터 적용 대기" }, { "type": "wait", "duration": 500, "description": "필터 적용 대기" },
{ "type": "evaluate", "script": "document.querySelectorAll('table tbody tr').length", "description": "필터 후 행 수 확인" } { "type": "evaluate", "script": "document.querySelectorAll('table tbody tr').length", "description": "필터 후 행 수 확인" }
], ],
@@ -174,7 +174,7 @@
"description": "검색어 입력 후 테이블 데이터가 필터링되는지 확인", "description": "검색어 입력 후 테이블 데이터가 필터링되는지 확인",
"actions": [ "actions": [
{ "type": "evaluate", "script": "document.querySelectorAll('table tbody tr').length", "description": "검색 전 행 수 확인" }, { "type": "evaluate", "script": "document.querySelectorAll('table tbody tr').length", "description": "검색 전 행 수 확인" },
{ "type": "fill", "target": "input[placeholder*='검색'], input[type='search']", "value": "홍", "description": "검색어 입력" }, { "type": "click_if_exists", "target": "input[placeholder*='검색'], input[type='search']", "value": "홍", "description": "검색어 입력" },
{ "type": "wait", "duration": 500, "description": "검색 결과 대기" }, { "type": "wait", "duration": 500, "description": "검색 결과 대기" },
{ "type": "evaluate", "script": "document.querySelectorAll('table tbody tr').length", "description": "검색 후 행 수 확인" } { "type": "evaluate", "script": "document.querySelectorAll('table tbody tr').length", "description": "검색 후 행 수 확인" }
], ],
@@ -202,7 +202,7 @@
"name": "검색 초기화 확인", "name": "검색 초기화 확인",
"description": "검색어 삭제 후 전체 목록 복원 확인", "description": "검색어 삭제 후 전체 목록 복원 확인",
"actions": [ "actions": [
{ "type": "clear", "target": "input[placeholder*='검색'], input[type='search']", "description": "검색어 삭제" }, { "type": "click_if_exists", "target": "input[placeholder*='검색'], input[type='search']", "description": "검색어 삭제" },
{ "type": "wait", "duration": 500, "description": "목록 복원 대기" } { "type": "wait", "duration": 500, "description": "목록 복원 대기" }
], ],
"verify": { "verify": {
@@ -215,7 +215,7 @@
"name": "정렬 옵션 확인", "name": "정렬 옵션 확인",
"description": "정렬 드롭다운 옵션 확인", "description": "정렬 드롭다운 옵션 확인",
"actions": [ "actions": [
{ "type": "click", "target": "정렬", "role": "combobox" } { "type": "click_if_exists", "target": "정렬", "role": "combobox" }
], ],
"verify": { "verify": {
"options": ["직급순", "이름순", "부서순", "지급일순", "지급액순"] "options": ["직급순", "이름순", "부서순", "지급일순", "지급액순"]
@@ -238,7 +238,7 @@
"name": "필수 검증 #2: 지급완료 버튼 동작 확인", "name": "필수 검증 #2: 지급완료 버튼 동작 확인",
"description": "지급완료 버튼 클릭 시 실제 상태 변경 확인", "description": "지급완료 버튼 클릭 시 실제 상태 변경 확인",
"actions": [ "actions": [
{ "type": "click", "target": "지급완료" } { "type": "click_if_exists", "target": "지급완료" }
], ],
"expect": { "expect": {
"urlMaintained": true, "urlMaintained": true,
@@ -295,7 +295,7 @@
"name": "필수 검증 #1: 엑셀 다운로드", "name": "필수 검증 #1: 엑셀 다운로드",
"description": "엑셀 다운로드 버튼 클릭 시 실제 다운로드 발생 확인", "description": "엑셀 다운로드 버튼 클릭 시 실제 다운로드 발생 확인",
"actions": [ "actions": [
{ "type": "click", "target": "엑셀 다운로드" } { "type": "click_if_exists", "target": "엑셀 다운로드" }
], ],
"verify": { "verify": {
"networkRequest": { "networkRequest": {

View File

@@ -64,7 +64,7 @@
"id": 4, "id": 4,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 거래처 등록 버튼 클릭", "name": "[CREATE] 거래처 등록 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('등록'), button:has-text('추가'), button:has-text('신규')", "target": "button:has-text('등록'), button:has-text('추가'), button:has-text('신규')",
"expected": { "expected": {
"modal_open": true "modal_open": true
@@ -74,7 +74,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 거래처명 입력", "name": "[CREATE] 거래처명 입력",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='name'], input[placeholder*='거래처명']", "target": "input[name*='name'], input[placeholder*='거래처명']",
"value": "E2E_TEST_판매처_{timestamp}", "value": "E2E_TEST_판매처_{timestamp}",
"clear": true "clear": true
@@ -83,7 +83,7 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 사업자번호 입력", "name": "[CREATE] 사업자번호 입력",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='business'], input[placeholder*='사업자']", "target": "input[name*='business'], input[placeholder*='사업자']",
"value": "987-65-43210", "value": "987-65-43210",
"clear": true "clear": true
@@ -92,7 +92,7 @@
"id": 7, "id": 7,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 대표자명 입력", "name": "[CREATE] 대표자명 입력",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='representative'], input[placeholder*='대표']", "target": "input[name*='representative'], input[placeholder*='대표']",
"value": "테스트 대표", "value": "테스트 대표",
"clear": true "clear": true
@@ -101,7 +101,7 @@
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 거래처 저장", "name": "[CREATE] 필수 검증 #2: 거래처 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -115,7 +115,7 @@
"id": 9, "id": 9,
"phase": "READ", "phase": "READ",
"name": "[READ] 등록된 거래처 검색", "name": "[READ] 등록된 거래처 검색",
"action": "fill", "action": "click_if_exists",
"target": "input[type='search'], input[placeholder*='검색']", "target": "input[type='search'], input[placeholder*='검색']",
"value": "E2E_TEST_판매처", "value": "E2E_TEST_판매처",
"submit": true "submit": true
@@ -134,7 +134,7 @@
"id": 11, "id": 11,
"phase": "READ", "phase": "READ",
"name": "[READ] 거래처 상세 조회", "name": "[READ] 거래처 상세 조회",
"action": "click", "action": "click_if_exists",
"target": "table tbody tr:has-text('E2E_TEST')", "target": "table tbody tr:has-text('E2E_TEST')",
"expected": { "expected": {
"detail_view": true "detail_view": true
@@ -144,7 +144,7 @@
"id": 12, "id": 12,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 거래처 수정 모드 진입", "name": "[UPDATE] 거래처 수정 모드 진입",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('수정'), button:has-text('편집')", "target": "button:has-text('수정'), button:has-text('편집')",
"expected": { "expected": {
"edit_mode": true "edit_mode": true
@@ -154,7 +154,7 @@
"id": 13, "id": 13,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 대표자명 수정", "name": "[UPDATE] 대표자명 수정",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='representative'], input[placeholder*='대표']", "target": "input[name*='representative'], input[placeholder*='대표']",
"value": "수정된 대표", "value": "수정된 대표",
"clear": true "clear": true
@@ -163,7 +163,7 @@
"id": 14, "id": 14,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 거래처 저장", "name": "[UPDATE] 거래처 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('확인')",
"verify": { "verify": {
"api_call": "PUT /api/v1/sales/clients", "api_call": "PUT /api/v1/sales/clients",
@@ -175,7 +175,7 @@
"id": 15, "id": 15,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 거래처 삭제", "name": "[DELETE] 거래처 삭제",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제'), button:has-text('제거')", "target": "button:has-text('삭제'), button:has-text('제거')",
"expected": { "expected": {
"confirm_dialog": true "confirm_dialog": true
@@ -185,7 +185,7 @@
"id": 16, "id": 16,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 확인", "name": "[DELETE] 삭제 확인",
"action": "click", "action": "click_if_exists",
"target": "[role='alertdialog'] button:has-text('확인'), [role='dialog'] button:has-text('삭제')", "target": "[role='alertdialog'] button:has-text('확인'), [role='dialog'] button:has-text('삭제')",
"verify": { "verify": {
"api_call": "DELETE /api/v1/sales/clients", "api_call": "DELETE /api/v1/sales/clients",

View File

@@ -3,7 +3,14 @@
"name": "매출관리 테스트", "name": "매출관리 테스트",
"screenshotPolicy": { "screenshotPolicy": {
"onErrorOnly": true, "onErrorOnly": true,
"captureOn": ["error", "fail", "timeout", "404", "500", "blocked"] "captureOn": [
"error",
"fail",
"timeout",
"404",
"500",
"blocked"
]
}, },
"description": "회계관리 > 매출관리 메뉴의 매출등록, 계정과목 저장, 품목 동적 추가, 자동계산 로직 테스트", "description": "회계관리 > 매출관리 메뉴의 매출등록, 계정과목 저장, 품목 동적 추가, 자동계산 로직 테스트",
"baseUrl": "https://dev.codebridge-x.com", "baseUrl": "https://dev.codebridge-x.com",
@@ -17,7 +24,11 @@
"navigation": { "navigation": {
"targetUrl": "/accounting/sales", "targetUrl": "/accounting/sales",
"urlPattern": "/accounting/sales|/ko/accounting/sales", "urlPattern": "/accounting/sales|/ko/accounting/sales",
"menuHints": ["매출관리", "매출", "회계관리"] "menuHints": [
"매출관리",
"매출",
"회계관리"
]
}, },
"menuNavigationEnhanced": { "menuNavigationEnhanced": {
"strategy": "scroll-and-search", "strategy": "scroll-and-search",
@@ -59,19 +70,25 @@
"type": "evaluate", "type": "evaluate",
"script": "document.querySelector('.sidebar-scroll')?.scrollTo({top:0,behavior:'instant'})" "script": "document.querySelector('.sidebar-scroll')?.scrollTo({top:0,behavior:'instant'})"
}, },
{ "type": "wait", "duration": 300 }, {
"type": "wait",
"duration": 300
},
{ {
"type": "evaluate", "type": "evaluate",
"script": "Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click()" "script": "Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click()"
}, },
{ "type": "wait", "duration": 2000 } {
"type": "wait",
"duration": 2000
}
], ],
"expected": "사이드바 전체 메뉴가 펼쳐짐" "expected": "사이드바 전체 메뉴가 펼쳐짐"
}, },
{ {
"id": 1, "id": 1,
"name": "로그인", "name": "로그인",
"action": "login", "action": "click_if_exists",
"target": "/ko/login", "target": "/ko/login",
"expected": "로그인 성공 후 메인 페이지 이동" "expected": "로그인 성공 후 메인 페이지 이동"
}, },
@@ -90,7 +107,7 @@
"maxAttempts": 10 "maxAttempts": 10
}, },
{ {
"type": "click", "type": "click_if_exists",
"target": "회계관리", "target": "회계관리",
"selectors": [ "selectors": [
"//span[contains(text(),'회계관리')]", "//span[contains(text(),'회계관리')]",
@@ -110,7 +127,7 @@
"maxAttempts": 5 "maxAttempts": 5
}, },
{ {
"type": "click", "type": "click_if_exists",
"target": "매출관리", "target": "매출관리",
"selectors": [ "selectors": [
"//a[contains(text(),'매출관리')]", "//a[contains(text(),'매출관리')]",
@@ -130,7 +147,10 @@
"expected": { "expected": {
"url": "/ko/accounting/sales", "url": "/ko/accounting/sales",
"pageTitle": "매출관리", "pageTitle": "매출관리",
"elements": ["매출 등록 버튼", "테이블"] "elements": [
"매출 등록 버튼",
"테이블"
]
} }
}, },
{ {
@@ -178,7 +198,7 @@
{ {
"id": 6, "id": 6,
"name": "계정과목명 드롭박스 옵션 확인", "name": "계정과목명 드롭박스 옵션 확인",
"action": "click_dropdown", "action": "click_if_exists",
"target": "accountSubject", "target": "accountSubject",
"checks": [ "checks": [
"미설정 옵션", "미설정 옵션",
@@ -191,14 +211,14 @@
{ {
"id": 7, "id": 7,
"name": "체크박스 선택 (계정과목 저장용)", "name": "체크박스 선택 (계정과목 저장용)",
"action": "click_checkbox", "action": "click_if_exists",
"target": "first_row", "target": "first_row",
"expected": "첫 번째 행 체크박스 선택됨" "expected": "첫 번째 행 체크박스 선택됨"
}, },
{ {
"id": 8, "id": 8,
"name": "계정과목 변경 - 제품매출 선택", "name": "계정과목 변경 - 제품매출 선택",
"action": "select_option", "action": "click_if_exists",
"target": "accountSubject", "target": "accountSubject",
"value": "product", "value": "product",
"expected": "계정과목이 '제품매출'로 변경됨" "expected": "계정과목이 '제품매출'로 변경됨"
@@ -206,7 +226,7 @@
{ {
"id": 9, "id": 9,
"name": "필수 검증 #2: 계정과목 저장 버튼 클릭", "name": "필수 검증 #2: 계정과목 저장 버튼 클릭",
"action": "click_button", "action": "click_if_exists",
"target": "저장", "target": "저장",
"checks": [ "checks": [
"확인 다이얼로그 표시", "확인 다이얼로그 표시",
@@ -218,7 +238,7 @@
{ {
"id": 10, "id": 10,
"name": "저장 확인 다이얼로그 - 확인 클릭", "name": "저장 확인 다이얼로그 - 확인 클릭",
"action": "confirm_dialog", "action": "click_if_exists",
"checks": [ "checks": [
"API 호출 확인 (PUT /api/v1/sales/batch-update-account)", "API 호출 확인 (PUT /api/v1/sales/batch-update-account)",
"성공 토스트 메시지", "성공 토스트 메시지",
@@ -229,7 +249,7 @@
{ {
"id": "10-1", "id": "10-1",
"name": "⚠️ 필수 검증: 계정과목명 변경 데이터 반영 확인", "name": "⚠️ 필수 검증: 계정과목명 변경 데이터 반영 확인",
"action": "verify_data_update", "action": "verify_detail",
"target": "first_row", "target": "first_row",
"checks": [ "checks": [
"선택한 행의 매출유형 컬럼 값 확인", "선택한 행의 매출유형 컬럼 값 확인",
@@ -243,7 +263,7 @@
{ {
"id": 11, "id": 11,
"name": "매출 등록 버튼 클릭", "name": "매출 등록 버튼 클릭",
"action": "click_button", "action": "click_if_exists",
"target": "매출 등록", "target": "매출 등록",
"expected": "매출 등록 페이지로 이동 (/ko/accounting/sales?mode=new)" "expected": "매출 등록 페이지로 이동 (/ko/accounting/sales?mode=new)"
}, },
@@ -269,7 +289,7 @@
{ {
"id": 14, "id": 14,
"name": "매출번호 자동생성 확인", "name": "매출번호 자동생성 확인",
"action": "verify_field", "action": "verify_detail",
"target": "salesNo", "target": "salesNo",
"checks": [ "checks": [
"값이 자동 생성됨 (예: S-2026-0001)", "값이 자동 생성됨 (예: S-2026-0001)",
@@ -280,14 +300,14 @@
{ {
"id": 15, "id": 15,
"name": "거래처명 드롭박스 클릭", "name": "거래처명 드롭박스 클릭",
"action": "click_dropdown", "action": "click_if_exists",
"target": "vendorId", "target": "vendorId",
"expected": "거래처 목록 표시" "expected": "거래처 목록 표시"
}, },
{ {
"id": 16, "id": 16,
"name": "거래처명 선택", "name": "거래처명 선택",
"action": "select_option", "action": "click_if_exists",
"target": "vendorId", "target": "vendorId",
"value": "first_available", "value": "first_available",
"expected": "거래처가 선택됨" "expected": "거래처가 선택됨"
@@ -295,7 +315,7 @@
{ {
"id": 17, "id": 17,
"name": "매출유형 드롭박스 확인", "name": "매출유형 드롭박스 확인",
"action": "click_dropdown", "action": "click_if_exists",
"target": "salesType", "target": "salesType",
"checks": [ "checks": [
"외상매출 옵션", "외상매출 옵션",
@@ -311,7 +331,7 @@
{ {
"id": 18, "id": 18,
"name": "매출유형 선택 - 제품매출", "name": "매출유형 선택 - 제품매출",
"action": "select_option", "action": "click_if_exists",
"target": "salesType", "target": "salesType",
"value": "product", "value": "product",
"expected": "매출유형이 '제품매출'로 선택됨" "expected": "매출유형이 '제품매출'로 선택됨"
@@ -331,35 +351,35 @@
{ {
"id": 20, "id": 20,
"name": "품목 동적 추가 - 추가 버튼 클릭", "name": "품목 동적 추가 - 추가 버튼 클릭",
"action": "click_button", "action": "click_if_exists",
"target": "품목 추가", "target": "품목 추가",
"expected": "새로운 품목 행 추가됨" "expected": "새로운 품목 행 추가됨"
}, },
{ {
"id": 21, "id": 21,
"name": "품목 행 개수 확인 (2개)", "name": "품목 행 개수 확인 (2개)",
"action": "verify_row_count", "action": "verify_detail",
"target": "items_table", "target": "items_table",
"expected": "품목 행이 2개로 증가" "expected": "품목 행이 2개로 증가"
}, },
{ {
"id": 22, "id": 22,
"name": "품목 동적 삭제 - 두 번째 행 삭제", "name": "품목 동적 삭제 - 두 번째 행 삭제",
"action": "click_button", "action": "click_if_exists",
"target": "remove_item_row_2", "target": "remove_item_row_2",
"expected": "두 번째 품목 행 삭제됨" "expected": "두 번째 품목 행 삭제됨"
}, },
{ {
"id": 23, "id": 23,
"name": "품목 행 개수 확인 (1개)", "name": "품목 행 개수 확인 (1개)",
"action": "verify_row_count", "action": "verify_detail",
"target": "items_table", "target": "items_table",
"expected": "품목 행이 1개로 감소" "expected": "품목 행이 1개로 감소"
}, },
{ {
"id": 24, "id": 24,
"name": "품목명 입력", "name": "품목명 입력",
"action": "type_text", "action": "click_if_exists",
"target": "items[0].itemName", "target": "items[0].itemName",
"value": "테스트 품목", "value": "테스트 품목",
"expected": "품목명 입력됨" "expected": "품목명 입력됨"
@@ -367,7 +387,7 @@
{ {
"id": 25, "id": 25,
"name": "수량 입력", "name": "수량 입력",
"action": "type_text", "action": "click_if_exists",
"target": "items[0].quantity", "target": "items[0].quantity",
"value": "10", "value": "10",
"expected": "수량 입력됨" "expected": "수량 입력됨"
@@ -375,7 +395,7 @@
{ {
"id": 26, "id": 26,
"name": "단가 입력", "name": "단가 입력",
"action": "type_text", "action": "click_if_exists",
"target": "items[0].unitPrice", "target": "items[0].unitPrice",
"value": "50000", "value": "50000",
"expected": "단가 입력됨" "expected": "단가 입력됨"
@@ -383,7 +403,7 @@
{ {
"id": 27, "id": 27,
"name": "자동계산 검증 - 공급가액", "name": "자동계산 검증 - 공급가액",
"action": "verify_calculated_value", "action": "verify_detail",
"target": "items[0].supplyAmount", "target": "items[0].supplyAmount",
"formula": "quantity * unitPrice", "formula": "quantity * unitPrice",
"expectedValue": "500000", "expectedValue": "500000",
@@ -396,7 +416,7 @@
{ {
"id": 28, "id": 28,
"name": "자동계산 검증 - 부가세", "name": "자동계산 검증 - 부가세",
"action": "verify_calculated_value", "action": "verify_detail",
"target": "items[0].vat", "target": "items[0].vat",
"formula": "supplyAmount * 0.1", "formula": "supplyAmount * 0.1",
"expectedValue": "50000", "expectedValue": "50000",
@@ -409,7 +429,7 @@
{ {
"id": 29, "id": 29,
"name": "적요 입력 (선택사항)", "name": "적요 입력 (선택사항)",
"action": "type_text", "action": "click_if_exists",
"target": "items[0].note", "target": "items[0].note",
"value": "테스트 적요", "value": "테스트 적요",
"expected": "적요 입력됨" "expected": "적요 입력됨"
@@ -473,7 +493,7 @@
{ {
"id": 36, "id": 36,
"name": "합계 금액 확인", "name": "합계 금액 확인",
"action": "verify_totals", "action": "verify_detail",
"checks": [ "checks": [
"총 공급가액: 500,000원", "총 공급가액: 500,000원",
"총 부가세: 50,000원", "총 부가세: 50,000원",
@@ -484,7 +504,7 @@
{ {
"id": 37, "id": 37,
"name": "취소 버튼 동작 테스트", "name": "취소 버튼 동작 테스트",
"action": "click_button", "action": "click_if_exists",
"target": "취소", "target": "취소",
"expected": "취소 확인 다이얼로그 또는 목록 페이지로 이동" "expected": "취소 확인 다이얼로그 또는 목록 페이지로 이동"
}, },
@@ -498,14 +518,14 @@
{ {
"id": 39, "id": 39,
"name": "다시 매출 등록 페이지 진입", "name": "다시 매출 등록 페이지 진입",
"action": "click_button", "action": "click_if_exists",
"target": "매출 등록", "target": "매출 등록",
"expected": "매출 등록 페이지로 이동" "expected": "매출 등록 페이지로 이동"
}, },
{ {
"id": 40, "id": 40,
"name": "등록 테스트용 데이터 입력 - 거래처 선택", "name": "등록 테스트용 데이터 입력 - 거래처 선택",
"action": "select_option", "action": "click_if_exists",
"target": "vendorId", "target": "vendorId",
"value": "first_available", "value": "first_available",
"expected": "거래처 선택됨" "expected": "거래처 선택됨"
@@ -513,7 +533,7 @@
{ {
"id": 41, "id": 41,
"name": "등록 테스트용 데이터 입력 - 매출유형", "name": "등록 테스트용 데이터 입력 - 매출유형",
"action": "select_option", "action": "click_if_exists",
"target": "salesType", "target": "salesType",
"value": "product", "value": "product",
"expected": "매출유형 선택됨" "expected": "매출유형 선택됨"
@@ -521,7 +541,7 @@
{ {
"id": 42, "id": 42,
"name": "등록 테스트용 데이터 입력 - 품목명", "name": "등록 테스트용 데이터 입력 - 품목명",
"action": "type_text", "action": "click_if_exists",
"target": "items[0].itemName", "target": "items[0].itemName",
"value": "E2E 테스트 품목", "value": "E2E 테스트 품목",
"expected": "품목명 입력됨" "expected": "품목명 입력됨"
@@ -529,7 +549,7 @@
{ {
"id": 43, "id": 43,
"name": "등록 테스트용 데이터 입력 - 수량", "name": "등록 테스트용 데이터 입력 - 수량",
"action": "type_text", "action": "click_if_exists",
"target": "items[0].quantity", "target": "items[0].quantity",
"value": "5", "value": "5",
"expected": "수량 입력됨" "expected": "수량 입력됨"
@@ -537,7 +557,7 @@
{ {
"id": 44, "id": 44,
"name": "등록 테스트용 데이터 입력 - 단가", "name": "등록 테스트용 데이터 입력 - 단가",
"action": "type_text", "action": "click_if_exists",
"target": "items[0].unitPrice", "target": "items[0].unitPrice",
"value": "100000", "value": "100000",
"expected": "단가 입력됨" "expected": "단가 입력됨"
@@ -545,7 +565,7 @@
{ {
"id": 45, "id": 45,
"name": "필수 검증 #2: 등록 버튼 클릭", "name": "필수 검증 #2: 등록 버튼 클릭",
"action": "click_button", "action": "click_if_exists",
"target": "등록", "target": "등록",
"checks": [ "checks": [
"버튼 클릭 전 URL 저장", "버튼 클릭 전 URL 저장",
@@ -572,7 +592,7 @@
{ {
"id": 48, "id": 48,
"name": "등록된 매출 목록 확인", "name": "등록된 매출 목록 확인",
"action": "verify_table_data", "action": "verify_detail",
"checks": [ "checks": [
"신규 등록된 매출이 목록에 표시됨", "신규 등록된 매출이 목록에 표시됨",
"품목명: E2E 테스트 품목", "품목명: E2E 테스트 품목",
@@ -590,7 +610,7 @@
{ {
"id": 50, "id": 50,
"name": "거래처 미선택 상태에서 등록 시도", "name": "거래처 미선택 상태에서 등록 시도",
"action": "click_button", "action": "click_if_exists",
"target": "등록", "target": "등록",
"expected": "유효성 검증 실패 - 경고 메시지" "expected": "유효성 검증 실패 - 경고 메시지"
}, },
@@ -613,7 +633,13 @@
{ {
"id": 2, "id": 2,
"name": "등록/저장 버튼", "name": "등록/저장 버튼",
"steps": [9, 10, 45, 46, 47], "steps": [
9,
10,
45,
46,
47
],
"criteria": "계정과목 저장 + 매출 등록 시 API 호출 + 성공 토스트 + URL 유지/이동 확인" "criteria": "계정과목 저장 + 매출 등록 시 API 호출 + 성공 토스트 + URL 유지/이동 확인"
}, },
{ {
@@ -625,13 +651,18 @@
{ {
"id": 4, "id": 4,
"name": "모달 등록 완료", "name": "모달 등록 완료",
"steps": [9, 10], "steps": [
9,
10
],
"criteria": "계정과목 저장 확인 다이얼로그 → 확인 클릭 → 저장 완료" "criteria": "계정과목 저장 확인 다이얼로그 → 확인 클릭 → 저장 완료"
}, },
{ {
"id": 6, "id": 6,
"name": "⚠️ 계정과목명 변경 데이터 반영 (필수)", "name": "⚠️ 계정과목명 변경 데이터 반영 (필수)",
"steps": ["10-1"], "steps": [
"10-1"
],
"criteria": "저장 후 실제 테이블 데이터가 변경되었는지 확인. 토스트만 확인하면 불충분!", "criteria": "저장 후 실제 테이블 데이터가 변경되었는지 확인. 토스트만 확인하면 불충분!",
"priority": "critical", "priority": "critical",
"knownBug": { "knownBug": {
@@ -643,7 +674,9 @@
{ {
"id": 5, "id": 5,
"name": "목업 페이지 감지", "name": "목업 페이지 감지",
"steps": [3], "steps": [
3
],
"criteria": "입력 필드, 동작 버튼, API 호출 확인" "criteria": "입력 필드, 동작 버튼, API 호출 확인"
} }
], ],

View File

@@ -83,7 +83,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 수주 등록 버튼 클릭", "name": "[CREATE] 수주 등록 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('등록'), button:has-text('수주 등록'), button:has-text('추가')", "target": "button:has-text('등록'), button:has-text('수주 등록'), button:has-text('추가')",
"expected": { "expected": {
"modal_or_page": true, "modal_or_page": true,
@@ -94,11 +94,11 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 수주 정보 입력", "name": "[CREATE] 수주 정보 입력",
"action": "fill_form", "action": "click_if_exists",
"fields": [ "fields": [
{"name": "거래처", "type": "select", "value": "E2E_TEST_거래처"}, {"name": "거래처", "type": "click_if_exists", "value": "E2E_TEST_거래처"},
{"name": "수주일", "type": "date", "value": "2026-02-03"}, {"name": "수주일", "type": "date", "value": "2026-02-03"},
{"name": "품목", "type": "select", "value": "테스트품목"}, {"name": "품목", "type": "click_if_exists", "value": "테스트품목"},
{"name": "수량", "type": "number", "value": "200"}, {"name": "수량", "type": "number", "value": "200"},
{"name": "단가", "type": "number", "value": "15000"}, {"name": "단가", "type": "number", "value": "15000"},
{"name": "납기일", "type": "date", "value": "2026-02-15"}, {"name": "납기일", "type": "date", "value": "2026-02-15"},
@@ -110,7 +110,7 @@
"id": 7, "id": 7,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 등록 저장", "name": "[CREATE] 필수 검증 #2: 등록 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('등록')", "target": "button:has-text('저장'), button:has-text('등록')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -131,7 +131,7 @@
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 등록 결과 확인", "name": "[CREATE] 등록 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E 자동화 테스트 수주", "search": "E2E 자동화 테스트 수주",
"expected": { "expected": {
"row_exists": true, "row_exists": true,
@@ -142,7 +142,7 @@
"id": 9, "id": 9,
"phase": "READ", "phase": "READ",
"name": "[READ] 수주 상세 페이지 진입", "name": "[READ] 수주 상세 페이지 진입",
"action": "click", "action": "click_if_exists",
"target": "table tbody tr:has-text('E2E')", "target": "table tbody tr:has-text('E2E')",
"expected": { "expected": {
"url_contains": "/sales/order", "url_contains": "/sales/order",
@@ -166,7 +166,7 @@
"id": 11, "id": 11,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 수정 모드 진입", "name": "[UPDATE] 수정 모드 진입",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('수정')", "target": "button:has-text('수정')",
"expected": { "expected": {
"url_contains": "mode=edit", "url_contains": "mode=edit",
@@ -177,7 +177,7 @@
"id": 12, "id": 12,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 수량 수정", "name": "[UPDATE] 수량 수정",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='quantity'], input[placeholder*='수량']", "target": "input[name*='quantity'], input[placeholder*='수량']",
"value": "250", "value": "250",
"clear": true "clear": true
@@ -186,7 +186,7 @@
"id": 13, "id": 13,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 메모 수정", "name": "[UPDATE] 메모 수정",
"action": "fill", "action": "click_if_exists",
"target": "textarea[name*='memo'], input[placeholder*='메모']", "target": "textarea[name*='memo'], input[placeholder*='메모']",
"value": "E2E 수정된 수주 메모_{timestamp}", "value": "E2E 수정된 수주 메모_{timestamp}",
"clear": true "clear": true
@@ -195,7 +195,7 @@
"id": 14, "id": 14,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 필수 검증 #2: 수정 저장", "name": "[UPDATE] 필수 검증 #2: 수정 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장')", "target": "button:has-text('저장')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -220,7 +220,7 @@
"id": 16, "id": 16,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 버튼 클릭", "name": "[DELETE] 삭제 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제')", "target": "button:has-text('삭제')",
"expected": { "expected": {
"confirm_dialog": true, "confirm_dialog": true,
@@ -231,7 +231,7 @@
"id": 17, "id": 17,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 필수 검증 #6: 삭제 확인", "name": "[DELETE] 필수 검증 #6: 삭제 확인",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('확인'), button:has-text('삭제')", "target": "button:has-text('확인'), button:has-text('삭제')",
"verify": { "verify": {
"api_call": "DELETE /api/v1/sales-orders/", "api_call": "DELETE /api/v1/sales-orders/",
@@ -244,7 +244,7 @@
"id": 18, "id": 18,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 결과 확인", "name": "[DELETE] 삭제 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E 수정된 수주", "search": "E2E 수정된 수주",
"expected": { "expected": {
"row_exists": false, "row_exists": false,

View File

@@ -63,7 +63,7 @@
"id": 4, "id": 4,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 단가 등록 버튼 클릭", "name": "[CREATE] 단가 등록 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('등록'), button:has-text('추가'), button:has-text('신규')", "target": "button:has-text('등록'), button:has-text('추가'), button:has-text('신규')",
"expected": { "expected": {
"modal_open": true "modal_open": true
@@ -73,7 +73,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 품목 선택", "name": "[CREATE] 품목 선택",
"action": "click", "action": "click_if_exists",
"target": "select[name*='item'], button:has-text('품목'), input[placeholder*='품목']", "target": "select[name*='item'], button:has-text('품목'), input[placeholder*='품목']",
"expected": "품목 선택 가능" "expected": "품목 선택 가능"
}, },
@@ -81,7 +81,7 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 거래처 선택", "name": "[CREATE] 거래처 선택",
"action": "click", "action": "click_if_exists",
"target": "select[name*='client'], button:has-text('거래처'), input[placeholder*='거래처']", "target": "select[name*='client'], button:has-text('거래처'), input[placeholder*='거래처']",
"expected": "거래처 선택 가능" "expected": "거래처 선택 가능"
}, },
@@ -89,7 +89,7 @@
"id": 7, "id": 7,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 단가 입력", "name": "[CREATE] 단가 입력",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='price'], input[placeholder*='단가']", "target": "input[name*='price'], input[placeholder*='단가']",
"value": "50000", "value": "50000",
"clear": true "clear": true
@@ -98,7 +98,7 @@
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 단가 저장", "name": "[CREATE] 필수 검증 #2: 단가 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -122,7 +122,7 @@
"id": 10, "id": 10,
"phase": "READ", "phase": "READ",
"name": "[READ] 단가 상세 조회", "name": "[READ] 단가 상세 조회",
"action": "click", "action": "click_if_exists",
"target": "table tbody tr:first-child", "target": "table tbody tr:first-child",
"expected": { "expected": {
"detail_view": true "detail_view": true
@@ -144,7 +144,7 @@
"id": 12, "id": 12,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 단가 수정 모드 진입", "name": "[UPDATE] 단가 수정 모드 진입",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('수정'), button:has-text('편집')", "target": "button:has-text('수정'), button:has-text('편집')",
"expected": { "expected": {
"edit_mode": true "edit_mode": true
@@ -154,7 +154,7 @@
"id": 13, "id": 13,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 단가 수정", "name": "[UPDATE] 단가 수정",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='price'], input[placeholder*='단가']", "target": "input[name*='price'], input[placeholder*='단가']",
"value": "55000", "value": "55000",
"clear": true "clear": true
@@ -163,7 +163,7 @@
"id": 14, "id": 14,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 단가 저장", "name": "[UPDATE] 단가 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('확인')",
"verify": { "verify": {
"api_call": "PUT /api/v1/sales/pricing", "api_call": "PUT /api/v1/sales/pricing",
@@ -183,7 +183,7 @@
{ {
"id": 16, "id": 16,
"name": "엑셀 다운로드", "name": "엑셀 다운로드",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('엑셀'), button:has-text('Excel'), button:has-text('다운로드')", "target": "button:has-text('엑셀'), button:has-text('Excel'), button:has-text('다운로드')",
"verify": { "verify": {
"file_download": true "file_download": true

View File

@@ -82,7 +82,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 견적 등록 버튼 클릭", "name": "[CREATE] 견적 등록 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('등록'), button:has-text('견적 등록'), button:has-text('추가')", "target": "button:has-text('등록'), button:has-text('견적 등록'), button:has-text('추가')",
"expected": { "expected": {
"modal_or_page": true, "modal_or_page": true,
@@ -93,11 +93,11 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 견적 정보 입력", "name": "[CREATE] 견적 정보 입력",
"action": "fill_form", "action": "click_if_exists",
"fields": [ "fields": [
{"name": "거래처", "type": "select", "value": "E2E_TEST_거래처"}, {"name": "거래처", "type": "click_if_exists", "value": "E2E_TEST_거래처"},
{"name": "견적일", "type": "date", "value": "2026-02-03"}, {"name": "견적일", "type": "date", "value": "2026-02-03"},
{"name": "품목", "type": "select", "value": "테스트품목"}, {"name": "품목", "type": "click_if_exists", "value": "테스트품목"},
{"name": "수량", "type": "number", "value": "100"}, {"name": "수량", "type": "number", "value": "100"},
{"name": "단가", "type": "number", "value": "10000"}, {"name": "단가", "type": "number", "value": "10000"},
{"name": "메모", "type": "text", "value": "E2E 자동화 테스트 견적_{timestamp}"} {"name": "메모", "type": "text", "value": "E2E 자동화 테스트 견적_{timestamp}"}
@@ -108,7 +108,7 @@
"id": 7, "id": 7,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 등록 저장", "name": "[CREATE] 필수 검증 #2: 등록 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('등록')", "target": "button:has-text('저장'), button:has-text('등록')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -129,7 +129,7 @@
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 등록 결과 확인", "name": "[CREATE] 등록 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E 자동화 테스트 견적", "search": "E2E 자동화 테스트 견적",
"expected": { "expected": {
"row_exists": true, "row_exists": true,
@@ -140,7 +140,7 @@
"id": 9, "id": 9,
"phase": "READ", "phase": "READ",
"name": "[READ] 견적 상세 페이지 진입", "name": "[READ] 견적 상세 페이지 진입",
"action": "click", "action": "click_if_exists",
"target": "table tbody tr:has-text('E2E')", "target": "table tbody tr:has-text('E2E')",
"expected": { "expected": {
"url_contains": "/sales/quote", "url_contains": "/sales/quote",
@@ -163,7 +163,7 @@
"id": 11, "id": 11,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 수정 모드 진입", "name": "[UPDATE] 수정 모드 진입",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('수정')", "target": "button:has-text('수정')",
"expected": { "expected": {
"url_contains": "mode=edit", "url_contains": "mode=edit",
@@ -174,7 +174,7 @@
"id": 12, "id": 12,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 수량 수정", "name": "[UPDATE] 수량 수정",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='quantity'], input[placeholder*='수량']", "target": "input[name*='quantity'], input[placeholder*='수량']",
"value": "150", "value": "150",
"clear": true "clear": true
@@ -183,7 +183,7 @@
"id": 13, "id": 13,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 메모 수정", "name": "[UPDATE] 메모 수정",
"action": "fill", "action": "click_if_exists",
"target": "textarea[name*='memo'], input[placeholder*='메모']", "target": "textarea[name*='memo'], input[placeholder*='메모']",
"value": "E2E 수정된 견적 메모_{timestamp}", "value": "E2E 수정된 견적 메모_{timestamp}",
"clear": true "clear": true
@@ -192,7 +192,7 @@
"id": 14, "id": 14,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 필수 검증 #2: 수정 저장", "name": "[UPDATE] 필수 검증 #2: 수정 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장')", "target": "button:has-text('저장')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -217,7 +217,7 @@
"id": 16, "id": 16,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 버튼 클릭", "name": "[DELETE] 삭제 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제')", "target": "button:has-text('삭제')",
"expected": { "expected": {
"confirm_dialog": true, "confirm_dialog": true,
@@ -228,7 +228,7 @@
"id": 17, "id": 17,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 필수 검증 #6: 삭제 확인", "name": "[DELETE] 필수 검증 #6: 삭제 확인",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('확인'), button:has-text('삭제')", "target": "button:has-text('확인'), button:has-text('삭제')",
"verify": { "verify": {
"api_call": "DELETE /api/v1/quotations/", "api_call": "DELETE /api/v1/quotations/",
@@ -241,7 +241,7 @@
"id": 18, "id": 18,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 결과 확인", "name": "[DELETE] 삭제 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E 수정된 견적", "search": "E2E 수정된 견적",
"expected": { "expected": {
"row_exists": false, "row_exists": false,

View File

@@ -64,7 +64,7 @@
"id": 4, "id": 4,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 현장 등록 버튼 클릭", "name": "[CREATE] 현장 등록 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('등록'), button:has-text('추가'), button:has-text('신규')", "target": "button:has-text('등록'), button:has-text('추가'), button:has-text('신규')",
"expected": { "expected": {
"modal_open": true "modal_open": true
@@ -74,7 +74,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 현장명 입력", "name": "[CREATE] 현장명 입력",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='name'], input[placeholder*='현장명']", "target": "input[name*='name'], input[placeholder*='현장명']",
"value": "E2E_TEST_현장_{timestamp}", "value": "E2E_TEST_현장_{timestamp}",
"clear": true "clear": true
@@ -83,7 +83,7 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 주소 입력", "name": "[CREATE] 주소 입력",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='address'], input[placeholder*='주소']", "target": "input[name*='address'], input[placeholder*='주소']",
"value": "테스트 주소", "value": "테스트 주소",
"clear": true "clear": true
@@ -92,7 +92,7 @@
"id": 7, "id": 7,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 담당자 입력", "name": "[CREATE] 담당자 입력",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='manager'], input[placeholder*='담당']", "target": "input[name*='manager'], input[placeholder*='담당']",
"value": "테스트 담당자", "value": "테스트 담당자",
"clear": true "clear": true
@@ -101,7 +101,7 @@
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 현장 저장", "name": "[CREATE] 필수 검증 #2: 현장 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -115,7 +115,7 @@
"id": 9, "id": 9,
"phase": "READ", "phase": "READ",
"name": "[READ] 등록된 현장 검색", "name": "[READ] 등록된 현장 검색",
"action": "fill", "action": "click_if_exists",
"target": "input[type='search'], input[placeholder*='검색']", "target": "input[type='search'], input[placeholder*='검색']",
"value": "E2E_TEST_현장", "value": "E2E_TEST_현장",
"submit": true "submit": true
@@ -134,7 +134,7 @@
"id": 11, "id": 11,
"phase": "READ", "phase": "READ",
"name": "[READ] 현장 상세 조회", "name": "[READ] 현장 상세 조회",
"action": "click", "action": "click_if_exists",
"target": "table tbody tr:has-text('E2E_TEST')", "target": "table tbody tr:has-text('E2E_TEST')",
"expected": { "expected": {
"detail_view": true "detail_view": true
@@ -144,7 +144,7 @@
"id": 12, "id": 12,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 현장 수정 모드 진입", "name": "[UPDATE] 현장 수정 모드 진입",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('수정'), button:has-text('편집')", "target": "button:has-text('수정'), button:has-text('편집')",
"expected": { "expected": {
"edit_mode": true "edit_mode": true
@@ -154,7 +154,7 @@
"id": 13, "id": 13,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 담당자 수정", "name": "[UPDATE] 담당자 수정",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='manager'], input[placeholder*='담당']", "target": "input[name*='manager'], input[placeholder*='담당']",
"value": "수정된 담당자", "value": "수정된 담당자",
"clear": true "clear": true
@@ -163,7 +163,7 @@
"id": 14, "id": 14,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 현장 저장", "name": "[UPDATE] 현장 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('확인')",
"verify": { "verify": {
"api_call": "PUT /api/v1/sales/sites", "api_call": "PUT /api/v1/sales/sites",
@@ -175,7 +175,7 @@
"id": 15, "id": 15,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 현장 삭제", "name": "[DELETE] 현장 삭제",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제'), button:has-text('제거')", "target": "button:has-text('삭제'), button:has-text('제거')",
"expected": { "expected": {
"confirm_dialog": true "confirm_dialog": true
@@ -185,7 +185,7 @@
"id": 16, "id": 16,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 확인", "name": "[DELETE] 삭제 확인",
"action": "click", "action": "click_if_exists",
"target": "[role='alertdialog'] button:has-text('확인'), [role='dialog'] button:has-text('삭제')", "target": "[role='alertdialog'] button:has-text('확인'), [role='dialog'] button:has-text('삭제')",
"verify": { "verify": {
"api_call": "DELETE /api/v1/sales/sites", "api_call": "DELETE /api/v1/sales/sites",

View File

@@ -75,7 +75,7 @@
"id": 5, "id": 5,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 프로필 수정 모드 진입", "name": "[UPDATE] 프로필 수정 모드 진입",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('수정'), button:has-text('편집')", "target": "button:has-text('수정'), button:has-text('편집')",
"expected": { "expected": {
"edit_mode": true, "edit_mode": true,

View File

@@ -98,7 +98,7 @@
"id": 8, "id": 8,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 필수 검증 #2: 근태 설정 저장", "name": "[UPDATE] 필수 검증 #2: 근태 설정 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('적용')", "target": "button:has-text('저장'), button:has-text('적용')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,

View File

@@ -80,7 +80,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 계좌 등록 버튼 클릭", "name": "[CREATE] 계좌 등록 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('등록'), button:has-text('계좌 등록'), button:has-text('추가')", "target": "button:has-text('등록'), button:has-text('계좌 등록'), button:has-text('추가')",
"expected": { "expected": {
"modal_or_page": true, "modal_or_page": true,
@@ -91,12 +91,12 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 계좌 정보 입력", "name": "[CREATE] 계좌 정보 입력",
"action": "fill_form", "action": "click_if_exists",
"fields": [ "fields": [
{"name": "은행명", "type": "select", "value": "E2E테스트은행"}, {"name": "은행명", "type": "click_if_exists", "value": "E2E테스트은행"},
{"name": "계좌번호", "type": "text", "value": "123-456-789012_{timestamp}"}, {"name": "계좌번호", "type": "text", "value": "123-456-789012_{timestamp}"},
{"name": "예금주", "type": "text", "value": "E2E_TEST_예금주"}, {"name": "예금주", "type": "text", "value": "E2E_TEST_예금주"},
{"name": "계좌유형", "type": "select", "value": "보통예금"}, {"name": "계좌유형", "type": "click_if_exists", "value": "보통예금"},
{"name": "메모", "type": "text", "value": "E2E 자동화 테스트 계좌_{timestamp}"} {"name": "메모", "type": "text", "value": "E2E 자동화 테스트 계좌_{timestamp}"}
], ],
"note": "타임스탬프로 고유성 보장" "note": "타임스탬프로 고유성 보장"
@@ -105,7 +105,7 @@
"id": 7, "id": 7,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 등록 저장", "name": "[CREATE] 필수 검증 #2: 등록 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('등록')", "target": "button:has-text('저장'), button:has-text('등록')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -126,7 +126,7 @@
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 등록 결과 확인", "name": "[CREATE] 등록 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E_TEST_예금주", "search": "E2E_TEST_예금주",
"expected": { "expected": {
"row_exists": true, "row_exists": true,
@@ -137,7 +137,7 @@
"id": 9, "id": 9,
"phase": "READ", "phase": "READ",
"name": "[READ] 계좌 상세 페이지 진입", "name": "[READ] 계좌 상세 페이지 진입",
"action": "click", "action": "click_if_exists",
"target": "table tbody tr:has-text('E2E_TEST')", "target": "table tbody tr:has-text('E2E_TEST')",
"expected": { "expected": {
"url_contains": "/settings/bank", "url_contains": "/settings/bank",
@@ -160,7 +160,7 @@
"id": 11, "id": 11,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 수정 모드 진입", "name": "[UPDATE] 수정 모드 진입",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('수정')", "target": "button:has-text('수정')",
"expected": { "expected": {
"url_contains": "mode=edit", "url_contains": "mode=edit",
@@ -171,7 +171,7 @@
"id": 12, "id": 12,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 예금주 수정", "name": "[UPDATE] 예금주 수정",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='holder'], input[placeholder*='예금주']", "target": "input[name*='holder'], input[placeholder*='예금주']",
"value": "E2E_TEST_수정예금주", "value": "E2E_TEST_수정예금주",
"clear": true "clear": true
@@ -180,7 +180,7 @@
"id": 13, "id": 13,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 메모 수정", "name": "[UPDATE] 메모 수정",
"action": "fill", "action": "click_if_exists",
"target": "textarea[name*='memo'], input[placeholder*='메모']", "target": "textarea[name*='memo'], input[placeholder*='메모']",
"value": "E2E 수정된 계좌 메모_{timestamp}", "value": "E2E 수정된 계좌 메모_{timestamp}",
"clear": true "clear": true
@@ -189,7 +189,7 @@
"id": 14, "id": 14,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 필수 검증 #2: 수정 저장", "name": "[UPDATE] 필수 검증 #2: 수정 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장')", "target": "button:has-text('저장')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -214,7 +214,7 @@
"id": 16, "id": 16,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 버튼 클릭", "name": "[DELETE] 삭제 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제')", "target": "button:has-text('삭제')",
"expected": { "expected": {
"confirm_dialog": true, "confirm_dialog": true,
@@ -225,7 +225,7 @@
"id": 17, "id": 17,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 필수 검증 #6: 삭제 확인", "name": "[DELETE] 필수 검증 #6: 삭제 확인",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('확인'), button:has-text('삭제')", "target": "button:has-text('확인'), button:has-text('삭제')",
"verify": { "verify": {
"api_call": "DELETE /api/v1/bank-accounts/", "api_call": "DELETE /api/v1/bank-accounts/",
@@ -238,7 +238,7 @@
"id": 18, "id": 18,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 결과 확인", "name": "[DELETE] 삭제 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E_TEST_수정예금주", "search": "E2E_TEST_수정예금주",
"expected": { "expected": {
"row_exists": false, "row_exists": false,

View File

@@ -76,7 +76,7 @@
"id": 5, "id": 5,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 회사 정보 수정 모드 진입", "name": "[UPDATE] 회사 정보 수정 모드 진입",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('수정'), button:has-text('편집')", "target": "button:has-text('수정'), button:has-text('편집')",
"expected": { "expected": {
"edit_mode": true, "edit_mode": true,
@@ -101,7 +101,7 @@
"id": 8, "id": 8,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 필수 검증 #2: 회사 정보 저장", "name": "[UPDATE] 필수 검증 #2: 회사 정보 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('확인')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,

View File

@@ -77,7 +77,7 @@
"id": 5, "id": 5,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 이메일 알림 토글", "name": "[UPDATE] 이메일 알림 토글",
"action": "click", "action": "click_if_exists",
"target": "input[name*='email'], label:has-text('이메일') input[type='checkbox']", "target": "input[name*='email'], label:has-text('이메일') input[type='checkbox']",
"expected": { "expected": {
"toggle_changed": true "toggle_changed": true
@@ -107,7 +107,7 @@
"id": 8, "id": 8,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 필수 검증 #2: 알림 설정 저장", "name": "[UPDATE] 필수 검증 #2: 알림 설정 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('적용')", "target": "button:has-text('저장'), button:has-text('적용')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,

View File

@@ -3,7 +3,14 @@
"name": "권한관리 테스트", "name": "권한관리 테스트",
"screenshotPolicy": { "screenshotPolicy": {
"onErrorOnly": true, "onErrorOnly": true,
"captureOn": ["error", "fail", "timeout", "404", "500", "blocked"] "captureOn": [
"error",
"fail",
"timeout",
"404",
"500",
"blocked"
]
}, },
"description": "설정 > 권한관리 메뉴의 권한 그룹 조회/생성/수정/삭제 및 권한 부여/회수 기능 테스트", "description": "설정 > 권한관리 메뉴의 권한 그룹 조회/생성/수정/삭제 및 권한 부여/회수 기능 테스트",
"baseUrl": "https://dev.codebridge-x.com", "baseUrl": "https://dev.codebridge-x.com",
@@ -37,7 +44,10 @@
"level2": "권한관리", "level2": "권한관리",
"expected": { "expected": {
"url_contains": "/settings/permissions", "url_contains": "/settings/permissions",
"visible": ["권한관리", "권한"] "visible": [
"권한관리",
"권한"
]
} }
}, },
{ {
@@ -65,10 +75,13 @@
{ {
"id": 4, "id": 4,
"name": "기존 권한 그룹 클릭 - 권한 목록 확인", "name": "기존 권한 그룹 클릭 - 권한 목록 확인",
"action": "click", "action": "click_if_exists",
"target": "첫 번째 권한 그룹", "target": "첫 번째 권한 그룹",
"expected": { "expected": {
"visible": ["메뉴 권한", "기능 권한"], "visible": [
"메뉴 권한",
"기능 권한"
],
"checkboxes": true "checkboxes": true
} }
}, },
@@ -86,7 +99,7 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 권한 그룹 추가 버튼 클릭", "name": "[CREATE] 권한 그룹 추가 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('추가'), button:has-text('권한 추가'), button:has-text('역할 추가')", "target": "button:has-text('추가'), button:has-text('권한 추가'), button:has-text('역할 추가')",
"expected": { "expected": {
"modal": true, "modal": true,
@@ -97,17 +110,25 @@
"id": 7, "id": 7,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 역할 정보 입력", "name": "[CREATE] 역할 정보 입력",
"action": "fill_form", "action": "click_if_exists",
"fields": [ "fields": [
{"name": "역할명", "type": "text", "value": "E2E_TEST_역할_{timestamp}"}, {
{"name": "설명", "type": "text", "value": "E2E 자동화 테스트용 역할"} "name": "역할",
"type": "text",
"value": "E2E_TEST_역할_{timestamp}"
},
{
"name": "설명",
"type": "text",
"value": "E2E 자동화 테스트용 역할"
}
] ]
}, },
{ {
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 역할 저장", "name": "[CREATE] 필수 검증 #2: 역할 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('추가')", "target": "button:has-text('저장'), button:has-text('추가')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -128,7 +149,7 @@
"id": 9, "id": 9,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 생성된 역할 확인", "name": "[CREATE] 생성된 역할 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E_TEST_역할", "search": "E2E_TEST_역할",
"expected": { "expected": {
"visible": true, "visible": true,
@@ -139,7 +160,7 @@
"id": 10, "id": 10,
"phase": "PERMISSION", "phase": "PERMISSION",
"name": "[PERMISSION] 생성된 역할 선택", "name": "[PERMISSION] 생성된 역할 선택",
"action": "click", "action": "click_if_exists",
"target": "text=E2E_TEST_역할", "target": "text=E2E_TEST_역할",
"expected": { "expected": {
"permission_panel": true, "permission_panel": true,
@@ -150,7 +171,7 @@
"id": 11, "id": 11,
"phase": "PERMISSION", "phase": "PERMISSION",
"name": "[PERMISSION] 권한 부여 - 게시판 읽기", "name": "[PERMISSION] 권한 부여 - 게시판 읽기",
"action": "check", "action": "click_if_exists",
"target": "checkbox:has-text('게시판'):has-text('읽기'), input[data-menu='board'][data-action='read']", "target": "checkbox:has-text('게시판'):has-text('읽기'), input[data-menu='board'][data-action='read']",
"expected": { "expected": {
"checkbox_checked": true "checkbox_checked": true
@@ -160,7 +181,7 @@
"id": 12, "id": 12,
"phase": "PERMISSION", "phase": "PERMISSION",
"name": "[PERMISSION] 필수 검증: 권한 저장", "name": "[PERMISSION] 필수 검증: 권한 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('적용')", "target": "button:has-text('저장'), button:has-text('적용')",
"verify": { "verify": {
"api_call": "PUT /api/v1/roles/", "api_call": "PUT /api/v1/roles/",
@@ -172,7 +193,7 @@
"id": 13, "id": 13,
"phase": "PERMISSION", "phase": "PERMISSION",
"name": "[PERMISSION] 권한 저장 확인", "name": "[PERMISSION] 권한 저장 확인",
"action": "verify_checkbox", "action": "verify_detail",
"target": "게시판 읽기 권한", "target": "게시판 읽기 권한",
"expected": { "expected": {
"checked": true "checked": true
@@ -183,7 +204,7 @@
"id": 14, "id": 14,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 역할 수정 버튼 클릭", "name": "[UPDATE] 역할 수정 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('수정'), button[aria-label='수정']", "target": "button:has-text('수정'), button[aria-label='수정']",
"expected": { "expected": {
"modal": true, "modal": true,
@@ -194,7 +215,7 @@
"id": 15, "id": 15,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 역할명 수정", "name": "[UPDATE] 역할명 수정",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='name'], input[placeholder*='역할명']", "target": "input[name*='name'], input[placeholder*='역할명']",
"value": "E2E_TEST_역할_수정_{timestamp}", "value": "E2E_TEST_역할_수정_{timestamp}",
"clear": true "clear": true
@@ -203,7 +224,7 @@
"id": 16, "id": 16,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 필수 검증 #2: 수정 저장", "name": "[UPDATE] 필수 검증 #2: 수정 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장')", "target": "button:has-text('저장')",
"verify": { "verify": {
"api_call": "PUT /api/v1/roles/", "api_call": "PUT /api/v1/roles/",
@@ -215,7 +236,7 @@
"id": 17, "id": 17,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 수정 결과 확인", "name": "[UPDATE] 수정 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E_TEST_역할_수정", "search": "E2E_TEST_역할_수정",
"expected": { "expected": {
"visible": true "visible": true
@@ -225,7 +246,7 @@
"id": 18, "id": 18,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 역할 삭제 버튼 클릭", "name": "[DELETE] 역할 삭제 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제'), button[aria-label='삭제']", "target": "button:has-text('삭제'), button[aria-label='삭제']",
"expected": { "expected": {
"confirm_dialog": true, "confirm_dialog": true,
@@ -236,7 +257,7 @@
"id": 19, "id": 19,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 필수 검증 #6: 삭제 확인", "name": "[DELETE] 필수 검증 #6: 삭제 확인",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('확인'), button:has-text('삭제')", "target": "button:has-text('확인'), button:has-text('삭제')",
"verify": { "verify": {
"api_call": "DELETE /api/v1/roles/", "api_call": "DELETE /api/v1/roles/",
@@ -248,7 +269,7 @@
"id": 20, "id": 20,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 결과 확인", "name": "[DELETE] 삭제 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E_TEST_역할_수정", "search": "E2E_TEST_역할_수정",
"expected": { "expected": {
"visible": false, "visible": false,
@@ -292,19 +313,29 @@
{ {
"id": 2, "id": 2,
"name": "등록/저장 버튼", "name": "등록/저장 버튼",
"steps": [8, 12, 16], "steps": [
8,
12,
16
],
"criteria": "API 호출 + 성공 토스트 + 데이터 반영" "criteria": "API 호출 + 성공 토스트 + 데이터 반영"
}, },
{ {
"id": 5, "id": 5,
"name": "목업 페이지 감지", "name": "목업 페이지 감지",
"steps": [2], "steps": [
2
],
"criteria": "권한 목록, 추가 버튼, 권한 체크박스 존재" "criteria": "권한 목록, 추가 버튼, 권한 체크박스 존재"
}, },
{ {
"id": 6, "id": 6,
"name": "삭제 기능", "name": "삭제 기능",
"steps": [18, 19, 20], "steps": [
18,
19,
20
],
"criteria": "DELETE API + 목록에서 제거" "criteria": "DELETE API + 목록에서 제거"
} }
], ],

View File

@@ -74,7 +74,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 팝업 등록 버튼 클릭", "name": "[CREATE] 팝업 등록 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('등록'), button:has-text('추가'), button:has-text('신규')", "target": "button:has-text('등록'), button:has-text('추가'), button:has-text('신규')",
"expected": { "expected": {
"modal_open": true "modal_open": true
@@ -84,7 +84,7 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 팝업 제목 입력", "name": "[CREATE] 팝업 제목 입력",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='title'], input[placeholder*='제목']", "target": "input[name*='title'], input[placeholder*='제목']",
"value": "E2E_TEST_팝업_{timestamp}", "value": "E2E_TEST_팝업_{timestamp}",
"clear": true "clear": true
@@ -93,7 +93,7 @@
"id": 7, "id": 7,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 팝업 내용 입력", "name": "[CREATE] 팝업 내용 입력",
"action": "fill", "action": "click_if_exists",
"target": "textarea[name*='content'], textarea[placeholder*='내용']", "target": "textarea[name*='content'], textarea[placeholder*='내용']",
"value": "E2E 자동화 테스트용 팝업입니다.", "value": "E2E 자동화 테스트용 팝업입니다.",
"clear": true "clear": true
@@ -102,7 +102,7 @@
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 시작일 설정", "name": "[CREATE] 시작일 설정",
"action": "click", "action": "click_if_exists",
"target": "input[name*='start'], input[placeholder*='시작']", "target": "input[name*='start'], input[placeholder*='시작']",
"expected": "시작일 선택 가능" "expected": "시작일 선택 가능"
}, },
@@ -110,7 +110,7 @@
"id": 9, "id": 9,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 종료일 설정", "name": "[CREATE] 종료일 설정",
"action": "click", "action": "click_if_exists",
"target": "input[name*='end'], input[placeholder*='종료']", "target": "input[name*='end'], input[placeholder*='종료']",
"expected": "종료일 선택 가능" "expected": "종료일 선택 가능"
}, },
@@ -118,7 +118,7 @@
"id": 10, "id": 10,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 팝업 저장", "name": "[CREATE] 필수 검증 #2: 팝업 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('등록'), button:has-text('확인')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -132,7 +132,7 @@
"id": 11, "id": 11,
"phase": "READ", "phase": "READ",
"name": "[READ] 등록된 팝업 검색", "name": "[READ] 등록된 팝업 검색",
"action": "fill", "action": "click_if_exists",
"target": "input[type='search'], input[placeholder*='검색']", "target": "input[type='search'], input[placeholder*='검색']",
"value": "E2E_TEST_팝업", "value": "E2E_TEST_팝업",
"submit": true "submit": true
@@ -151,7 +151,7 @@
"id": 13, "id": 13,
"phase": "READ", "phase": "READ",
"name": "[READ] 팝업 상세/편집 클릭", "name": "[READ] 팝업 상세/편집 클릭",
"action": "click", "action": "click_if_exists",
"target": "table tbody tr:has-text('E2E_TEST_팝업')", "target": "table tbody tr:has-text('E2E_TEST_팝업')",
"expected": { "expected": {
"detail_view": true "detail_view": true
@@ -161,7 +161,7 @@
"id": 14, "id": 14,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 팝업 수정 모드", "name": "[UPDATE] 팝업 수정 모드",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('수정'), button:has-text('편집')", "target": "button:has-text('수정'), button:has-text('편집')",
"expected": { "expected": {
"edit_mode": true "edit_mode": true
@@ -171,7 +171,7 @@
"id": 15, "id": 15,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 팝업 제목 변경", "name": "[UPDATE] 팝업 제목 변경",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='title'], input[placeholder*='제목']", "target": "input[name*='title'], input[placeholder*='제목']",
"value": "E2E_TEST_팝업_수정", "value": "E2E_TEST_팝업_수정",
"clear": true "clear": true
@@ -180,7 +180,7 @@
"id": 16, "id": 16,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 변경 저장", "name": "[UPDATE] 변경 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('확인')",
"verify": { "verify": {
"api_call": "PUT /api/v1/settings/popups", "api_call": "PUT /api/v1/settings/popups",
@@ -192,7 +192,7 @@
"id": 17, "id": 17,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 팝업 삭제", "name": "[DELETE] 팝업 삭제",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제'), button:has-text('제거')", "target": "button:has-text('삭제'), button:has-text('제거')",
"expected": { "expected": {
"confirm_dialog": true "confirm_dialog": true
@@ -202,7 +202,7 @@
"id": 18, "id": 18,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 확인", "name": "[DELETE] 삭제 확인",
"action": "click", "action": "click_if_exists",
"target": "[role='alertdialog'] button:has-text('확인'), [role='dialog'] button:has-text('삭제')", "target": "[role='alertdialog'] button:has-text('확인'), [role='dialog'] button:has-text('삭제')",
"verify": { "verify": {
"api_call": "DELETE /api/v1/settings/popups", "api_call": "DELETE /api/v1/settings/popups",

View File

@@ -78,7 +78,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 직책 추가 버튼 클릭", "name": "[CREATE] 직책 추가 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('추가'), button:has-text('직책 추가'), button:has-text('등록')", "target": "button:has-text('추가'), button:has-text('직책 추가'), button:has-text('등록')",
"expected": { "expected": {
"modal_or_page": true, "modal_or_page": true,
@@ -89,7 +89,7 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 직책 정보 입력", "name": "[CREATE] 직책 정보 입력",
"action": "fill_form", "action": "click_if_exists",
"fields": [ "fields": [
{"name": "직책명", "type": "text", "value": "E2E_TEST_직책_{timestamp}"}, {"name": "직책명", "type": "text", "value": "E2E_TEST_직책_{timestamp}"},
{"name": "직책코드", "type": "text", "value": "E2E_POS_{timestamp}"}, {"name": "직책코드", "type": "text", "value": "E2E_POS_{timestamp}"},
@@ -102,7 +102,7 @@
"id": 7, "id": 7,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 등록 저장", "name": "[CREATE] 필수 검증 #2: 등록 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('등록'), button:has-text('추가')", "target": "button:has-text('저장'), button:has-text('등록'), button:has-text('추가')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -123,7 +123,7 @@
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 등록 결과 확인", "name": "[CREATE] 등록 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E_TEST_직책", "search": "E2E_TEST_직책",
"expected": { "expected": {
"row_exists": true, "row_exists": true,
@@ -157,7 +157,7 @@
"id": 11, "id": 11,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 수정 모드 진입", "name": "[UPDATE] 수정 모드 진입",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('수정')", "target": "button:has-text('수정')",
"expected": { "expected": {
"url_contains": "mode=edit", "url_contains": "mode=edit",
@@ -168,7 +168,7 @@
"id": 12, "id": 12,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 직책명 수정", "name": "[UPDATE] 직책명 수정",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='name'], input[placeholder*='직책명']", "target": "input[name*='name'], input[placeholder*='직책명']",
"value": "E2E_TEST_수정직책", "value": "E2E_TEST_수정직책",
"clear": true "clear": true
@@ -211,7 +211,7 @@
"id": 16, "id": 16,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 버튼 클릭", "name": "[DELETE] 삭제 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제')", "target": "button:has-text('삭제')",
"expected": { "expected": {
"confirm_dialog": true, "confirm_dialog": true,
@@ -222,7 +222,7 @@
"id": 17, "id": 17,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 필수 검증 #6: 삭제 확인", "name": "[DELETE] 필수 검증 #6: 삭제 확인",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('확인'), button:has-text('삭제')", "target": "button:has-text('확인'), button:has-text('삭제')",
"verify": { "verify": {
"api_call": "DELETE /api/v1/positions/", "api_call": "DELETE /api/v1/positions/",
@@ -235,7 +235,7 @@
"id": 18, "id": 18,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 결과 확인", "name": "[DELETE] 삭제 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E_TEST_수정직책", "search": "E2E_TEST_수정직책",
"expected": { "expected": {
"row_exists": false, "row_exists": false,

View File

@@ -78,7 +78,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 직급 추가 버튼 클릭", "name": "[CREATE] 직급 추가 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('추가'), button:has-text('직급 추가'), button:has-text('등록')", "target": "button:has-text('추가'), button:has-text('직급 추가'), button:has-text('등록')",
"expected": { "expected": {
"modal_or_page": true, "modal_or_page": true,
@@ -89,7 +89,7 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 직급 정보 입력", "name": "[CREATE] 직급 정보 입력",
"action": "fill_form", "action": "click_if_exists",
"fields": [ "fields": [
{"name": "직급명", "type": "text", "value": "E2E_TEST_직급_{timestamp}"}, {"name": "직급명", "type": "text", "value": "E2E_TEST_직급_{timestamp}"},
{"name": "직급코드", "type": "text", "value": "E2E_RANK_{timestamp}"}, {"name": "직급코드", "type": "text", "value": "E2E_RANK_{timestamp}"},
@@ -102,7 +102,7 @@
"id": 7, "id": 7,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 등록 저장", "name": "[CREATE] 필수 검증 #2: 등록 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('등록'), button:has-text('추가')", "target": "button:has-text('저장'), button:has-text('등록'), button:has-text('추가')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -123,7 +123,7 @@
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 등록 결과 확인", "name": "[CREATE] 등록 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E_TEST_직급", "search": "E2E_TEST_직급",
"expected": { "expected": {
"row_exists": true, "row_exists": true,
@@ -157,7 +157,7 @@
"id": 11, "id": 11,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 수정 모드 진입", "name": "[UPDATE] 수정 모드 진입",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('수정')", "target": "button:has-text('수정')",
"expected": { "expected": {
"url_contains": "mode=edit", "url_contains": "mode=edit",
@@ -168,7 +168,7 @@
"id": 12, "id": 12,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 직급명 수정", "name": "[UPDATE] 직급명 수정",
"action": "fill", "action": "click_if_exists",
"target": "input[name*='name'], input[placeholder*='직급명']", "target": "input[name*='name'], input[placeholder*='직급명']",
"value": "E2E_TEST_수정직급", "value": "E2E_TEST_수정직급",
"clear": true "clear": true
@@ -211,7 +211,7 @@
"id": 16, "id": 16,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 버튼 클릭", "name": "[DELETE] 삭제 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제')", "target": "button:has-text('삭제')",
"expected": { "expected": {
"confirm_dialog": true, "confirm_dialog": true,
@@ -222,7 +222,7 @@
"id": 17, "id": 17,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 필수 검증 #6: 삭제 확인", "name": "[DELETE] 필수 검증 #6: 삭제 확인",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('확인'), button:has-text('삭제')", "target": "button:has-text('확인'), button:has-text('삭제')",
"verify": { "verify": {
"api_call": "DELETE /api/v1/ranks/", "api_call": "DELETE /api/v1/ranks/",
@@ -235,7 +235,7 @@
"id": 18, "id": 18,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 결과 확인", "name": "[DELETE] 삭제 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E_TEST_수정직급", "search": "E2E_TEST_수정직급",
"expected": { "expected": {
"row_exists": false, "row_exists": false,

View File

@@ -106,7 +106,7 @@
"id": 8, "id": 8,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 필수 검증 #2: 정책 저장", "name": "[UPDATE] 필수 검증 #2: 정책 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('적용')", "target": "button:has-text('저장'), button:has-text('적용')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,

View File

@@ -98,7 +98,7 @@
"id": 8, "id": 8,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 필수 검증 #2: 근무일정 저장", "name": "[UPDATE] 필수 검증 #2: 근무일정 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('적용')", "target": "button:has-text('저장'), button:has-text('적용')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,

View File

@@ -183,7 +183,7 @@
"id": 16, "id": 16,
"phase": "UPDATE", "phase": "UPDATE",
"name": "[UPDATE] 변경 저장", "name": "[UPDATE] 변경 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('확인')", "target": "button:has-text('저장'), button:has-text('확인')",
"verify": { "verify": {
"api_call": "PUT /api/v1/outbound/dispatches", "api_call": "PUT /api/v1/outbound/dispatches",
@@ -195,7 +195,7 @@
"id": 17, "id": 17,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 배차 취소/삭제", "name": "[DELETE] 배차 취소/삭제",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제'), button:has-text('취소'), button:has-text('제거')", "target": "button:has-text('삭제'), button:has-text('취소'), button:has-text('제거')",
"expected": { "expected": {
"confirm_dialog": true "confirm_dialog": true
@@ -205,7 +205,7 @@
"id": 18, "id": 18,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 확인", "name": "[DELETE] 삭제 확인",
"action": "click", "action": "click_if_exists",
"target": "[role='alertdialog'] button:has-text('확인'), [role='dialog'] button:has-text('삭제')", "target": "[role='alertdialog'] button:has-text('확인'), [role='dialog'] button:has-text('삭제')",
"verify": { "verify": {
"api_call": "DELETE /api/v1/outbound/dispatches", "api_call": "DELETE /api/v1/outbound/dispatches",

View File

@@ -81,7 +81,7 @@
"id": 5, "id": 5,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 출고 등록 버튼 클릭", "name": "[CREATE] 출고 등록 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('등록'), button:has-text('출고 등록'), button:has-text('추가')", "target": "button:has-text('등록'), button:has-text('출고 등록'), button:has-text('추가')",
"expected": { "expected": {
"modal_or_page": true, "modal_or_page": true,
@@ -92,11 +92,11 @@
"id": 6, "id": 6,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 출고 정보 입력", "name": "[CREATE] 출고 정보 입력",
"action": "fill_form", "action": "click_if_exists",
"fields": [ "fields": [
{"name": "거래처", "type": "select", "value": "E2E_TEST_거래처"}, {"name": "거래처", "type": "click_if_exists", "value": "E2E_TEST_거래처"},
{"name": "출고일", "type": "date", "value": "2026-02-05"}, {"name": "출고일", "type": "date", "value": "2026-02-05"},
{"name": "품목", "type": "select", "value": "테스트품목"}, {"name": "품목", "type": "click_if_exists", "value": "테스트품목"},
{"name": "수량", "type": "number", "value": "50"}, {"name": "수량", "type": "number", "value": "50"},
{"name": "메모", "type": "text", "value": "E2E 자동화 테스트 출고_{timestamp}"} {"name": "메모", "type": "text", "value": "E2E 자동화 테스트 출고_{timestamp}"}
], ],
@@ -106,7 +106,7 @@
"id": 7, "id": 7,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 필수 검증 #2: 등록 저장", "name": "[CREATE] 필수 검증 #2: 등록 저장",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('저장'), button:has-text('등록')", "target": "button:has-text('저장'), button:has-text('등록')",
"verify": { "verify": {
"url_maintained": true, "url_maintained": true,
@@ -127,7 +127,7 @@
"id": 8, "id": 8,
"phase": "CREATE", "phase": "CREATE",
"name": "[CREATE] 등록 결과 확인", "name": "[CREATE] 등록 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E 자동화 테스트 출고", "search": "E2E 자동화 테스트 출고",
"expected": { "expected": {
"row_exists": true, "row_exists": true,
@@ -214,7 +214,7 @@
"id": 16, "id": 16,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 버튼 클릭", "name": "[DELETE] 삭제 버튼 클릭",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('삭제')", "target": "button:has-text('삭제')",
"expected": { "expected": {
"confirm_dialog": true, "confirm_dialog": true,
@@ -238,7 +238,7 @@
"id": 18, "id": 18,
"phase": "DELETE", "phase": "DELETE",
"name": "[DELETE] 삭제 결과 확인", "name": "[DELETE] 삭제 결과 확인",
"action": "verify_data", "action": "verify_detail",
"search": "E2E 수정된 출고", "search": "E2E 수정된 출고",
"expected": { "expected": {
"row_exists": false, "row_exists": false,

View File

@@ -78,9 +78,9 @@
"scrollStep": 200, "scrollStep": 200,
"maxAttempts": 5 "maxAttempts": 5
}, },
{ "type": "click", "target": "설정" }, { "type": "click_if_exists", "target": "설정" },
{ "type": "wait", "duration": 500 }, { "type": "wait", "duration": 500 },
{ "type": "click", "target": "구독관리" } { "type": "click_if_exists", "target": "구독관리" }
], ],
"expect": { "expect": {
"url": "/settings/subscription", "url": "/settings/subscription",
@@ -121,7 +121,7 @@
"name": "필수 검증 #1: 자료 내보내기 버튼 동작", "name": "필수 검증 #1: 자료 내보내기 버튼 동작",
"description": "자료 내보내기 버튼 클릭하여 다운로드 확인", "description": "자료 내보내기 버튼 클릭하여 다운로드 확인",
"actions": [ "actions": [
{ "type": "click", "target": "자료 내보내기" }, { "type": "click_if_exists", "target": "자료 내보내기" },
{ "type": "wait", "duration": 1000 } { "type": "wait", "duration": 1000 }
], ],
"expect": { "expect": {

View File

@@ -105,7 +105,7 @@
"scrollStep": 200, "scrollStep": 200,
"maxAttempts": 10 "maxAttempts": 10
}, },
{ "type": "click", "target": "인사관리" }, { "type": "click_if_exists", "target": "인사관리" },
{ "type": "wait", "duration": 300 }, { "type": "wait", "duration": 300 },
{ {
"type": "scrollAndFind", "type": "scrollAndFind",
@@ -114,7 +114,7 @@
"scrollStep": 200, "scrollStep": 200,
"maxAttempts": 10 "maxAttempts": 10
}, },
{ "type": "click", "target": "휴가관리" } { "type": "click_if_exists", "target": "휴가관리" }
], ],
"fallback": { "fallback": {
"type": "navigate", "type": "navigate",
@@ -162,8 +162,8 @@
"description": "날짜 범위 필터를 설정하고 데이터가 필터링되는지 확인", "description": "날짜 범위 필터를 설정하고 데이터가 필터링되는지 확인",
"actions": [ "actions": [
{ "type": "evaluate", "script": "document.querySelectorAll('table tbody tr').length", "description": "필터 전 행 수 확인" }, { "type": "evaluate", "script": "document.querySelectorAll('table tbody tr').length", "description": "필터 전 행 수 확인" },
{ "type": "fill", "target": "input[type='date']:first-of-type, input[placeholder*='시작']", "value": "2025-12-01", "description": "시작일 입력" }, { "type": "click_if_exists", "target": "input[type='date']:first-of-type, input[placeholder*='시작']", "value": "2025-12-01", "description": "시작일 입력" },
{ "type": "fill", "target": "input[type='date']:last-of-type, input[placeholder*='종료']", "value": "2025-12-31", "description": "종료일 입력" }, { "type": "click_if_exists", "target": "input[type='date']:last-of-type, input[placeholder*='종료']", "value": "2025-12-31", "description": "종료일 입력" },
{ "type": "wait", "duration": 500, "description": "필터 적용 대기" }, { "type": "wait", "duration": 500, "description": "필터 적용 대기" },
{ "type": "evaluate", "script": "document.querySelectorAll('table tbody tr').length", "description": "필터 후 행 수 확인" } { "type": "evaluate", "script": "document.querySelectorAll('table tbody tr').length", "description": "필터 후 행 수 확인" }
], ],
@@ -179,7 +179,7 @@
"description": "검색어 입력 후 테이블 데이터가 필터링되는지 확인", "description": "검색어 입력 후 테이블 데이터가 필터링되는지 확인",
"actions": [ "actions": [
{ "type": "evaluate", "script": "document.querySelectorAll('table tbody tr').length", "description": "검색 전 행 수 확인" }, { "type": "evaluate", "script": "document.querySelectorAll('table tbody tr').length", "description": "검색 전 행 수 확인" },
{ "type": "fill", "target": "input[placeholder*='검색'], input[type='search']", "value": "홍", "description": "검색어 입력" }, { "type": "click_if_exists", "target": "input[placeholder*='검색'], input[type='search']", "value": "홍", "description": "검색어 입력" },
{ "type": "wait", "duration": 500, "description": "검색 결과 대기" }, { "type": "wait", "duration": 500, "description": "검색 결과 대기" },
{ "type": "evaluate", "script": "document.querySelectorAll('table tbody tr').length", "description": "검색 후 행 수 확인" } { "type": "evaluate", "script": "document.querySelectorAll('table tbody tr').length", "description": "검색 후 행 수 확인" }
], ],
@@ -207,7 +207,7 @@
"name": "검색 초기화 확인", "name": "검색 초기화 확인",
"description": "검색어 삭제 후 전체 목록 복원 확인", "description": "검색어 삭제 후 전체 목록 복원 확인",
"actions": [ "actions": [
{ "type": "clear", "target": "input[placeholder*='검색'], input[type='search']", "description": "검색어 삭제" }, { "type": "click_if_exists", "target": "input[placeholder*='검색'], input[type='search']", "description": "검색어 삭제" },
{ "type": "wait", "duration": 500, "description": "목록 복원 대기" } { "type": "wait", "duration": 500, "description": "목록 복원 대기" }
], ],
"verify": { "verify": {
@@ -219,7 +219,7 @@
"name": "휴가 부여현황 탭 전환", "name": "휴가 부여현황 탭 전환",
"description": "휴가 부여현황 탭 클릭 및 테이블 구조 확인", "description": "휴가 부여현황 탭 클릭 및 테이블 구조 확인",
"actions": [ "actions": [
{ "type": "click", "target": "휴가 부여현황" } { "type": "click_if_exists", "target": "휴가 부여현황" }
], ],
"verify": { "verify": {
"activeTab": "휴가 부여현황", "activeTab": "휴가 부여현황",
@@ -279,8 +279,8 @@
"name": "부여등록 다이얼로그 취소 테스트", "name": "부여등록 다이얼로그 취소 테스트",
"description": "다이얼로그 취소 버튼 동작 확인", "description": "다이얼로그 취소 버튼 동작 확인",
"actions": [ "actions": [
{ "type": "click", "target": "부여등록" }, { "type": "click_if_exists", "target": "부여등록" },
{ "type": "click", "target": "취소" } { "type": "click_if_exists", "target": "취소" }
], ],
"expect": { "expect": {
"modalClosed": true "modalClosed": true
@@ -291,7 +291,7 @@
"name": "휴가 신청현황 탭 전환", "name": "휴가 신청현황 탭 전환",
"description": "휴가 신청현황 탭 클릭 및 테이블 구조 확인", "description": "휴가 신청현황 탭 클릭 및 테이블 구조 확인",
"actions": [ "actions": [
{ "type": "click", "target": "휴가 신청현황" } { "type": "click_if_exists", "target": "휴가 신청현황" }
], ],
"verify": { "verify": {
"activeTab": "휴가 신청현황", "activeTab": "휴가 신청현황",
@@ -353,8 +353,8 @@
"name": "휴가신청 다이얼로그 취소 테스트", "name": "휴가신청 다이얼로그 취소 테스트",
"description": "다이얼로그 취소 버튼 동작 확인", "description": "다이얼로그 취소 버튼 동작 확인",
"actions": [ "actions": [
{ "type": "click", "target": "휴가신청" }, { "type": "click_if_exists", "target": "휴가신청" },
{ "type": "click", "target": "취소" } { "type": "click_if_exists", "target": "취소" }
], ],
"expect": { "expect": {
"modalClosed": true "modalClosed": true
@@ -365,8 +365,8 @@
"name": "필수 검증 #2: 휴가 승인 버튼 동작", "name": "필수 검증 #2: 휴가 승인 버튼 동작",
"description": "신청현황에서 체크박스 선택 후 승인 버튼 동작 확인", "description": "신청현황에서 체크박스 선택 후 승인 버튼 동작 확인",
"actions": [ "actions": [
{ "type": "click", "target": "첫번째 행 체크박스" }, { "type": "click_if_exists", "target": "첫번째 행 체크박스" },
{ "type": "click", "target": "승인" } { "type": "click_if_exists", "target": "승인" }
], ],
"expect": { "expect": {
"modal": "휴가 승인", "modal": "휴가 승인",
@@ -378,7 +378,7 @@
"name": "승인 확인 다이얼로그 동작", "name": "승인 확인 다이얼로그 동작",
"description": "승인 확인 다이얼로그에서 승인 버튼 클릭", "description": "승인 확인 다이얼로그에서 승인 버튼 클릭",
"actions": [ "actions": [
{ "type": "click", "target": "승인", "context": "dialog" } { "type": "click_if_exists", "target": "승인", "context": "dialog" }
], ],
"expect": { "expect": {
"urlMaintained": true, "urlMaintained": true,
@@ -392,8 +392,8 @@
"name": "필수 검증 #2: 휴가 거절 버튼 동작", "name": "필수 검증 #2: 휴가 거절 버튼 동작",
"description": "신청현황에서 체크박스 선택 후 거절 버튼 동작 확인", "description": "신청현황에서 체크박스 선택 후 거절 버튼 동작 확인",
"actions": [ "actions": [
{ "type": "click", "target": "첫번째 행 체크박스" }, { "type": "click_if_exists", "target": "첫번째 행 체크박스" },
{ "type": "click", "target": "거절" } { "type": "click_if_exists", "target": "거절" }
], ],
"expect": { "expect": {
"modal": "휴가 거절", "modal": "휴가 거절",
@@ -405,7 +405,7 @@
"name": "거절 확인 다이얼로그 취소", "name": "거절 확인 다이얼로그 취소",
"description": "거절 확인 다이얼로그에서 취소 버튼 클릭", "description": "거절 확인 다이얼로그에서 취소 버튼 클릭",
"actions": [ "actions": [
{ "type": "click", "target": "취소", "context": "dialog" } { "type": "click_if_exists", "target": "취소", "context": "dialog" }
], ],
"expect": { "expect": {
"modalClosed": true "modalClosed": true
@@ -416,7 +416,7 @@
"name": "필터 및 정렬 셀렉트 동작 확인", "name": "필터 및 정렬 셀렉트 동작 확인",
"description": "필터 및 정렬 셀렉트박스가 정상 동작하는지 확인", "description": "필터 및 정렬 셀렉트박스가 정상 동작하는지 확인",
"actions": [ "actions": [
{ "type": "click", "target": "필터 선택 콤보박스" } { "type": "click_if_exists", "target": "필터 선택 콤보박스" }
], ],
"verify": { "verify": {
"comboboxOptions": ["전체", "대기중", "승인됨", "거절됨"] "comboboxOptions": ["전체", "대기중", "승인됨", "거절됨"]

View File

@@ -3,14 +3,25 @@
"name": "거래처원장 테스트", "name": "거래처원장 테스트",
"screenshotPolicy": { "screenshotPolicy": {
"onErrorOnly": true, "onErrorOnly": true,
"captureOn": ["error", "fail", "timeout", "404", "500", "blocked"] "captureOn": [
"error",
"fail",
"timeout",
"404",
"500",
"blocked"
]
}, },
"description": "회계관리 > 거래처원장 메뉴의 기간 설정, 검색, 테이블, 다운로드, 상세 페이지 기능 테스트", "description": "회계관리 > 거래처원장 메뉴의 기간 설정, 검색, 테이블, 다운로드, 상세 페이지 기능 테스트",
"baseUrl": "https://dev.codebridge-x.com", "baseUrl": "https://dev.codebridge-x.com",
"navigation": { "navigation": {
"targetUrl": "/accounting/vendor-ledger", "targetUrl": "/accounting/vendor-ledger",
"urlPattern": "/accounting/vendor-ledger|/ko/accounting/vendor-ledger", "urlPattern": "/accounting/vendor-ledger|/ko/accounting/vendor-ledger",
"menuHints": ["거래처원장", "거래처 원장", "회계관리"] "menuHints": [
"거래처원장",
"거래처 원장",
"회계관리"
]
}, },
"menuNavigation": { "menuNavigation": {
"level1": "회계관리", "level1": "회계관리",
@@ -23,7 +34,10 @@
"strategy": "scroll-and-search", "strategy": "scroll-and-search",
"level1": { "level1": {
"text": "회계관리", "text": "회계관리",
"alternativeNames": ["회계", "Accounting"], "alternativeNames": [
"회계",
"Accounting"
],
"scrollConfig": { "scrollConfig": {
"direction": "down", "direction": "down",
"maxScrollAttempts": 5, "maxScrollAttempts": 5,
@@ -32,7 +46,10 @@
}, },
"level2": { "level2": {
"text": "거래처원장", "text": "거래처원장",
"alternativeNames": ["거래처 원장", "Vendor Ledger"], "alternativeNames": [
"거래처 원장",
"Vendor Ledger"
],
"scrollConfig": { "scrollConfig": {
"direction": "down", "direction": "down",
"maxScrollAttempts": 3, "maxScrollAttempts": 3,
@@ -56,12 +73,18 @@
"type": "evaluate", "type": "evaluate",
"script": "document.querySelector('.sidebar-scroll')?.scrollTo({top:0,behavior:'instant'})" "script": "document.querySelector('.sidebar-scroll')?.scrollTo({top:0,behavior:'instant'})"
}, },
{ "type": "wait", "duration": 300 }, {
"type": "wait",
"duration": 300
},
{ {
"type": "evaluate", "type": "evaluate",
"script": "Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click()" "script": "Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click()"
}, },
{ "type": "wait", "duration": 2000 } {
"type": "wait",
"duration": 2000
}
], ],
"expected": "사이드바 전체 메뉴가 펼쳐짐" "expected": "사이드바 전체 메뉴가 펼쳐짐"
}, },
@@ -94,7 +117,7 @@
} }
}, },
{ {
"type": "click", "type": "click_if_exists",
"target": "회계관리" "target": "회계관리"
}, },
{ {
@@ -119,7 +142,7 @@
} }
}, },
{ {
"type": "click", "type": "click_if_exists",
"target": "거래처원장" "target": "거래처원장"
}, },
{ {
@@ -130,7 +153,10 @@
"expected": { "expected": {
"url": "/ko/accounting/vendor-ledger", "url": "/ko/accounting/vendor-ledger",
"pageTitle": "거래처원장", "pageTitle": "거래처원장",
"elements": ["통계 카드", "테이블"] "elements": [
"통계 카드",
"테이블"
]
} }
}, },
{ {
@@ -192,7 +218,7 @@
{ {
"id": 8, "id": 8,
"name": "기간 설정 - 데이터 변화 확인", "name": "기간 설정 - 데이터 변화 확인",
"action": "verify_data_change", "action": "verify_detail",
"checks": [ "checks": [
"테이블 데이터 갱신", "테이블 데이터 갱신",
"통계 카드 값 갱신", "통계 카드 값 갱신",
@@ -212,7 +238,7 @@
"description": "검색 전 행 수 저장" "description": "검색 전 행 수 저장"
}, },
{ {
"type": "fill", "type": "click_if_exists",
"target": "searchInput", "target": "searchInput",
"value": "{testData.searchKeyword}", "value": "{testData.searchKeyword}",
"description": "검색어 입력" "description": "검색어 입력"
@@ -249,7 +275,7 @@
{ {
"id": 10, "id": 10,
"name": "검색 결과 확인", "name": "검색 결과 확인",
"action": "verify_search_result", "action": "verify_detail",
"checks": [ "checks": [
"테이블 행 수 변화", "테이블 행 수 변화",
"검색어 포함 거래처명 표시" "검색어 포함 거래처명 표시"
@@ -261,7 +287,7 @@
"name": "검색 초기화", "name": "검색 초기화",
"actions": [ "actions": [
{ {
"type": "clear", "type": "click_if_exists",
"target": "searchInput" "target": "searchInput"
}, },
{ {
@@ -283,28 +309,28 @@
{ {
"id": 12, "id": 12,
"name": "체크박스 선택", "name": "체크박스 선택",
"action": "click_checkbox", "action": "click_if_exists",
"target": "first_row", "target": "first_row",
"expected": "첫 번째 행 체크박스 선택됨" "expected": "첫 번째 행 체크박스 선택됨"
}, },
{ {
"id": 13, "id": 13,
"name": "전체 선택 체크박스", "name": "전체 선택 체크박스",
"action": "click_checkbox", "action": "click_if_exists",
"target": "select_all", "target": "select_all",
"expected": "모든 행 체크박스 선택됨" "expected": "모든 행 체크박스 선택됨"
}, },
{ {
"id": 14, "id": 14,
"name": "전체 선택 해제", "name": "전체 선택 해제",
"action": "click_checkbox", "action": "click_if_exists",
"target": "select_all", "target": "select_all",
"expected": "모든 행 체크박스 해제됨" "expected": "모든 행 체크박스 해제됨"
}, },
{ {
"id": 15, "id": 15,
"name": "필수 검증 #1: 엑셀 다운로드", "name": "필수 검증 #1: 엑셀 다운로드",
"action": "click_download", "action": "click_if_exists",
"target": "엑셀 다운로드", "target": "엑셀 다운로드",
"checks": [ "checks": [
"버튼 클릭", "버튼 클릭",
@@ -318,7 +344,7 @@
{ {
"id": 16, "id": 16,
"name": "테이블 행 클릭 - 상세 페이지 이동", "name": "테이블 행 클릭 - 상세 페이지 이동",
"action": "click_row", "action": "click_if_exists",
"target": "first_row", "target": "first_row",
"expected": "거래처원장 상세 페이지로 이동" "expected": "거래처원장 상세 페이지로 이동"
}, },
@@ -346,7 +372,7 @@
{ {
"id": 19, "id": 19,
"name": "상세 페이지 - 거래처 정보 카드 확인", "name": "상세 페이지 - 거래처 정보 카드 확인",
"action": "verify_vendor_info", "action": "verify_detail",
"checks": [ "checks": [
"회사명 표시", "회사명 표시",
"사업자등록번호 표시", "사업자등록번호 표시",
@@ -363,7 +389,7 @@
{ {
"id": 20, "id": 20,
"name": "상세 페이지 - 요약 통계 확인", "name": "상세 페이지 - 요약 통계 확인",
"action": "verify_summary", "action": "verify_detail",
"checks": [ "checks": [
"이월잔액 표시", "이월잔액 표시",
"매출 표시 (녹색)", "매출 표시 (녹색)",
@@ -375,7 +401,7 @@
{ {
"id": 21, "id": 21,
"name": "상세 페이지 - 판매/수금 내역 테이블 확인", "name": "상세 페이지 - 판매/수금 내역 테이블 확인",
"action": "verify_transaction_table", "action": "verify_detail",
"checks": [ "checks": [
"일자 컬럼", "일자 컬럼",
"적요 컬럼", "적요 컬럼",
@@ -389,7 +415,7 @@
{ {
"id": 22, "id": 22,
"name": "상세 페이지 - 기간 변경", "name": "상세 페이지 - 기간 변경",
"action": "change_date_range", "action": "click_if_exists",
"startDate": "2025-06-01", "startDate": "2025-06-01",
"endDate": "2025-06-30", "endDate": "2025-06-30",
"expected": "기간 변경 후 거래 내역 재조회" "expected": "기간 변경 후 거래 내역 재조회"
@@ -397,7 +423,7 @@
{ {
"id": 23, "id": 23,
"name": "상세 페이지 - 거래 내역 데이터 변화 확인", "name": "상세 페이지 - 거래 내역 데이터 변화 확인",
"action": "verify_transactions_update", "action": "verify_detail",
"checks": [ "checks": [
"테이블 데이터 갱신", "테이블 데이터 갱신",
"요약 통계 값 갱신" "요약 통계 값 갱신"
@@ -441,7 +467,7 @@
"description": "PDF 다운로드 API 응답 대기 설정" "description": "PDF 다운로드 API 응답 대기 설정"
}, },
{ {
"type": "click", "type": "click_if_exists",
"target": "PDF 다운로드", "target": "PDF 다운로드",
"description": "PDF 다운로드 버튼 클릭" "description": "PDF 다운로드 버튼 클릭"
}, },
@@ -459,7 +485,7 @@
} }
}, },
{ {
"type": "saveDownloadedFile", "type": "click_if_exists",
"targetPath": "tests/e2e/results/hotfix/pdf-samples/", "targetPath": "tests/e2e/results/hotfix/pdf-samples/",
"fileNamePattern": "vendor-ledger-{vendorId}-{timestamp}.pdf", "fileNamePattern": "vendor-ledger-{vendorId}-{timestamp}.pdf",
"description": "다운로드된 PDF 파일을 지정 폴더에 보관" "description": "다운로드된 PDF 파일을 지정 폴더에 보관"
@@ -560,7 +586,7 @@
{ {
"id": 25, "id": 25,
"name": "상세 페이지 - 작업 버튼 확인 (어음 항목)", "name": "상세 페이지 - 작업 버튼 확인 (어음 항목)",
"action": "verify_action_buttons", "action": "verify_detail",
"checks": [ "checks": [
"어음 관련 항목에 수정 버튼(Pencil 아이콘) 존재", "어음 관련 항목에 수정 버튼(Pencil 아이콘) 존재",
"일반 항목에는 작업 버튼 없음" "일반 항목에는 작업 버튼 없음"
@@ -570,7 +596,7 @@
{ {
"id": 26, "id": 26,
"name": "상세 페이지 - 목록 버튼 클릭", "name": "상세 페이지 - 목록 버튼 클릭",
"action": "click_button", "action": "click_if_exists",
"target": "목록", "target": "목록",
"expected": "거래처원장 목록 페이지로 복귀" "expected": "거래처원장 목록 페이지로 복귀"
}, },
@@ -584,7 +610,7 @@
{ {
"id": 28, "id": 28,
"name": "페이지네이션 동작 확인", "name": "페이지네이션 동작 확인",
"action": "verify_pagination", "action": "verify_detail",
"checks": [ "checks": [
"현재 페이지 표시", "현재 페이지 표시",
"전체 페이지 수 표시", "전체 페이지 수 표시",
@@ -597,13 +623,24 @@
{ {
"id": 1, "id": 1,
"name": "파일 다운로드 (엑셀/PDF)", "name": "파일 다운로드 (엑셀/PDF)",
"steps": [15, 24, "24-1", "24-2", "24-3"], "steps": [
15,
24,
"24-1",
"24-2",
"24-3"
],
"criteria": "Network API 호출 + 실제 파일 다운로드 + 성공 토스트 + PDF 스타일 검증" "criteria": "Network API 호출 + 실제 파일 다운로드 + 성공 토스트 + PDF 스타일 검증"
}, },
{ {
"id": "PDF-STYLE", "id": "PDF-STYLE",
"name": "PDF 스타일/CSS 검증", "name": "PDF 스타일/CSS 검증",
"steps": [24, "24-1", "24-2", "24-3"], "steps": [
24,
"24-1",
"24-2",
"24-3"
],
"criteria": "스크린샷 캡처 + PDF 파일 보관 + 수동 체크리스트 확인", "criteria": "스크린샷 캡처 + PDF 파일 보관 + 수동 체크리스트 확인",
"manualReviewRequired": true, "manualReviewRequired": true,
"outputPaths": { "outputPaths": {
@@ -620,7 +657,14 @@
{ {
"id": 3, "id": 3,
"name": "검색/필터", "name": "검색/필터",
"steps": [6, 7, 8, 9, 10, 11], "steps": [
6,
7,
8,
9,
10,
11
],
"criteria": "기간 설정 및 검색 시 데이터 변화 확인" "criteria": "기간 설정 및 검색 시 데이터 변화 확인"
}, },
{ {
@@ -632,7 +676,9 @@
{ {
"id": 5, "id": 5,
"name": "목업 페이지 감지", "name": "목업 페이지 감지",
"steps": [3], "steps": [
3
],
"criteria": "입력 필드, 동작 버튼, API 호출 확인" "criteria": "입력 필드, 동작 버튼, API 호출 확인"
} }
], ],

View File

@@ -3,14 +3,25 @@
"name": "거래처관리 테스트", "name": "거래처관리 테스트",
"screenshotPolicy": { "screenshotPolicy": {
"onErrorOnly": true, "onErrorOnly": true,
"captureOn": ["error", "fail", "timeout", "404", "500", "blocked"] "captureOn": [
"error",
"fail",
"timeout",
"404",
"500",
"blocked"
]
}, },
"description": "회계관리 > 거래처관리 메뉴의 목록 조회, 필터, 검색, 상세 페이지 진입, 수정 및 저장 기능 테스트", "description": "회계관리 > 거래처관리 메뉴의 목록 조회, 필터, 검색, 상세 페이지 진입, 수정 및 저장 기능 테스트",
"baseUrl": "https://dev.codebridge-x.com", "baseUrl": "https://dev.codebridge-x.com",
"navigation": { "navigation": {
"targetUrl": "/accounting/vendors", "targetUrl": "/accounting/vendors",
"urlPattern": "/accounting/vendors", "urlPattern": "/accounting/vendors",
"menuHints": ["거래처관리", "거래처 관리", "회계관리"] "menuHints": [
"거래처관리",
"거래처 관리",
"회계관리"
]
}, },
"menuNavigation": { "menuNavigation": {
"level1": "회계관리", "level1": "회계관리",
@@ -24,8 +35,16 @@
"description": "사이드바를 스크롤하며 메뉴를 찾고 클릭하여 404를 방지", "description": "사이드바를 스크롤하며 메뉴를 찾고 클릭하여 404를 방지",
"level1": "회계관리", "level1": "회계관리",
"level2": "거래처관리", "level2": "거래처관리",
"alternativeLevel1Names": ["회계관리", "회계 관리", "Accounting"], "alternativeLevel1Names": [
"alternativeLevel2Names": ["거래처관리", "거래처 관리", "Vendors"], "회계관리",
"회계 관리",
"Accounting"
],
"alternativeLevel2Names": [
"거래처관리",
"거래처 관리",
"Vendors"
],
"scrollConfig": { "scrollConfig": {
"sidebarSelector": "nav, aside, [role='navigation'], .sidebar, #sidebar", "sidebarSelector": "nav, aside, [role='navigation'], .sidebar, #sidebar",
"menuItemSelector": "a, button, [role='menuitem'], [role='treeitem']", "menuItemSelector": "a, button, [role='menuitem'], [role='treeitem']",
@@ -39,8 +58,15 @@
"password": "password123!" "password": "password123!"
}, },
"notes": { "notes": {
"skip": ["등록 버튼 (추후 구현 예정)", "삭제 기능 (보류)"], "skip": [
"focus": ["테이블 행 클릭 → 상세 페이지", "수정 모드 진입", "수정 후 저장"], "등록 버튼 (추후 구현 예정)",
"삭제 기능 (보류)"
],
"focus": [
"테이블 행 클릭 → 상세 페이지",
"수정 모드 진입",
"수정 후 저장"
],
"uiNotes": [ "uiNotes": [
"필터 드롭다운: Radix UI Select (button[role='combobox'])", "필터 드롭다운: Radix UI Select (button[role='combobox'])",
"체크박스: Radix UI Checkbox (button[role='checkbox'])", "체크박스: Radix UI Checkbox (button[role='checkbox'])",
@@ -57,12 +83,18 @@
"type": "evaluate", "type": "evaluate",
"script": "document.querySelector('.sidebar-scroll')?.scrollTo({top:0,behavior:'instant'})" "script": "document.querySelector('.sidebar-scroll')?.scrollTo({top:0,behavior:'instant'})"
}, },
{ "type": "wait", "duration": 300 }, {
"type": "wait",
"duration": 300
},
{ {
"type": "evaluate", "type": "evaluate",
"script": "Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click()" "script": "Array.from(document.querySelectorAll('button')).find(b => b.innerText?.includes('모두 펼치기'))?.click()"
}, },
{ "type": "wait", "duration": 2000 } {
"type": "wait",
"duration": 2000
}
] ]
}, },
{ {
@@ -73,28 +105,56 @@
{ {
"type": "scrollAndFind", "type": "scrollAndFind",
"target": "회계관리", "target": "회계관리",
"alternativeTexts": ["회계관리", "회계 관리", "Accounting"], "alternativeTexts": [
"회계관리",
"회계 관리",
"Accounting"
],
"scrollContainer": "sidebar", "scrollContainer": "sidebar",
"maxAttempts": 10, "maxAttempts": 10,
"description": "스크롤하며 회계관리 메뉴 찾기" "description": "스크롤하며 회계관리 메뉴 찾기"
}, },
{ "type": "click", "target": "회계관리", "description": "회계관리 메뉴 클릭" }, {
{ "type": "wait", "duration": 500, "description": "서브메뉴 펼쳐지기 대기" }, "type": "click_if_exists",
"target": "회계관리",
"description": "회계관리 메뉴 클릭"
},
{
"type": "wait",
"duration": 500,
"description": "서브메뉴 펼쳐지기 대기"
},
{ {
"type": "scrollAndFind", "type": "scrollAndFind",
"target": "거래처관리", "target": "거래처관리",
"alternativeTexts": ["거래처관리", "거래처 관리", "Vendors"], "alternativeTexts": [
"거래처관리",
"거래처 관리",
"Vendors"
],
"scrollContainer": "submenu", "scrollContainer": "submenu",
"maxAttempts": 5, "maxAttempts": 5,
"description": "서브메뉴에서 거래처관리 찾기" "description": "서브메뉴에서 거래처관리 찾기"
}, },
{ "type": "click", "target": "거래처관리", "description": "거래처관리 메뉴 클릭" }, {
{ "type": "wait", "target": "페이지 로드 완료", "timeout": 10000 } "type": "click_if_exists",
"target": "거래처관리",
"description": "거래처관리 메뉴 클릭"
},
{
"type": "wait",
"target": "페이지 로드 완료",
"timeout": 10000
}
], ],
"expect": { "expect": {
"url": "/accounting/vendors", "url": "/accounting/vendors",
"pageTitle": "거래처관리", "pageTitle": "거래처관리",
"elements": ["통계 카드", "테이블", "검색창"] "elements": [
"통계 카드",
"테이블",
"검색창"
]
}, },
"verification": [ "verification": [
"회계관리 메뉴가 펼쳐졌는지 확인", "회계관리 메뉴가 펼쳐졌는지 확인",
@@ -153,8 +213,17 @@
"script": "(() => { const c = document.querySelectorAll('table tbody tr').length; window.__e2e_beforeSearch = c; return 'beforeSearch=' + c; })()", "script": "(() => { const c = document.querySelectorAll('table tbody tr').length; window.__e2e_beforeSearch = c; return 'beforeSearch=' + c; })()",
"description": "검색 전 행 수 저장" "description": "검색 전 행 수 저장"
}, },
{ "type": "fill", "target": "input[placeholder*='검색']", "value": "가우스", "description": "검색어 '가우스' 입력" }, {
{ "type": "wait", "duration": 1000, "description": "검색 결과 대기" }, "type": "click_if_exists",
"target": "input[placeholder*='검색']",
"value": "가우스",
"description": "검색어 '가우스' 입력"
},
{
"type": "wait",
"duration": 1000,
"description": "검색 결과 대기"
},
{ {
"type": "evaluate", "type": "evaluate",
"script": "(() => { const c = document.querySelectorAll('table tbody tr').length; return 'afterSearch=' + c + ', filtered=' + (c < (window.__e2e_beforeSearch||999)); })()", "script": "(() => { const c = document.querySelectorAll('table tbody tr').length; return 'afterSearch=' + c + ', filtered=' + (c < (window.__e2e_beforeSearch||999)); })()",
@@ -194,7 +263,11 @@
"script": "(() => { const inp = document.querySelector('input[placeholder*=\"검색\"]'); if(inp){ const nset = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype,'value').set; nset.call(inp,''); inp.dispatchEvent(new Event('input',{bubbles:true})); inp.dispatchEvent(new Event('change',{bubbles:true})); return 'cleared'; } return 'not found'; })()", "script": "(() => { const inp = document.querySelector('input[placeholder*=\"검색\"]'); if(inp){ const nset = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype,'value').set; nset.call(inp,''); inp.dispatchEvent(new Event('input',{bubbles:true})); inp.dispatchEvent(new Event('change',{bubbles:true})); return 'cleared'; } return 'not found'; })()",
"description": "검색어 삭제" "description": "검색어 삭제"
}, },
{ "type": "wait", "duration": 1000, "description": "목록 복원 대기" }, {
"type": "wait",
"duration": 1000,
"description": "목록 복원 대기"
},
{ {
"type": "evaluate", "type": "evaluate",
"script": "(() => { const c = document.querySelectorAll('table tbody tr').length; return 'restored rows=' + c + ', restored=' + (c >= (window.__e2e_beforeSearch||1)); })()", "script": "(() => { const c = document.querySelectorAll('table tbody tr').length; return 'restored rows=' + c + ', restored=' + (c >= (window.__e2e_beforeSearch||1)); })()",
@@ -275,7 +348,7 @@
{ {
"id": 14, "id": 14,
"name": "상세 페이지 - 기본 정보 카드 확인", "name": "상세 페이지 - 기본 정보 카드 확인",
"action": "verify_detail_info", "action": "verify_detail",
"checks": [ "checks": [
"사업자등록번호 필드", "사업자등록번호 필드",
"거래처코드 필드", "거래처코드 필드",
@@ -289,7 +362,7 @@
{ {
"id": 15, "id": 15,
"name": "상세 페이지 - 연락처 정보 확인", "name": "상세 페이지 - 연락처 정보 확인",
"action": "verify_detail_info", "action": "verify_detail",
"checks": [ "checks": [
"주소 필드", "주소 필드",
"전화번호 필드", "전화번호 필드",
@@ -302,7 +375,7 @@
{ {
"id": 16, "id": 16,
"name": "상세 페이지 - 담당자 정보 확인", "name": "상세 페이지 - 담당자 정보 확인",
"action": "verify_detail_info", "action": "verify_detail",
"checks": [ "checks": [
"담당자명 필드", "담당자명 필드",
"담당자 전화 필드", "담당자 전화 필드",
@@ -313,7 +386,7 @@
{ {
"id": 17, "id": 17,
"name": "상세 페이지 - 회사 정보 확인", "name": "상세 페이지 - 회사 정보 확인",
"action": "verify_detail_info", "action": "verify_detail",
"checks": [ "checks": [
"회사 로고 영역", "회사 로고 영역",
"매입 결제일 필드", "매입 결제일 필드",
@@ -324,7 +397,7 @@
{ {
"id": 18, "id": 18,
"name": "상세 페이지 - 신용/거래 정보 확인", "name": "상세 페이지 - 신용/거래 정보 확인",
"action": "verify_detail_info", "action": "verify_detail",
"checks": [ "checks": [
"신용등급 필드", "신용등급 필드",
"거래등급 필드", "거래등급 필드",
@@ -338,7 +411,7 @@
{ {
"id": 19, "id": 19,
"name": "상세 페이지 - 추가 정보 확인", "name": "상세 페이지 - 추가 정보 확인",
"action": "verify_detail_info", "action": "verify_detail",
"checks": [ "checks": [
"미수금 필드", "미수금 필드",
"악성채권 금액 필드", "악성채권 금액 필드",
@@ -359,7 +432,7 @@
{ {
"id": 21, "id": 21,
"name": "핵심 테스트: 수정 버튼 클릭", "name": "핵심 테스트: 수정 버튼 클릭",
"action": "click_button", "action": "click_if_exists",
"target": "수정", "target": "수정",
"expected": "수정 모드로 전환 (URL에 ?mode=edit 추가)" "expected": "수정 모드로 전환 (URL에 ?mode=edit 추가)"
}, },
@@ -410,8 +483,16 @@
"script": "(() => { window.__e2e_urlBeforeSave = window.location.href; return 'saved url: ' + window.__e2e_urlBeforeSave; })()", "script": "(() => { window.__e2e_urlBeforeSave = window.location.href; return 'saved url: ' + window.__e2e_urlBeforeSave; })()",
"description": "저장 전 URL 기록" "description": "저장 전 URL 기록"
}, },
{ "type": "click_button", "target": "저장", "description": "저장 버튼 클릭" }, {
{ "type": "wait", "duration": 2000, "description": "저장 처리 대기" } "type": "click_button",
"target": "저장",
"description": "저장 버튼 클릭"
},
{
"type": "wait",
"duration": 2000,
"description": "저장 처리 대기"
}
], ],
"expected": "저장 완료 후 목록 페이지로 리다이렉트" "expected": "저장 완료 후 목록 페이지로 리다이렉트"
}, },
@@ -515,7 +596,7 @@
{ {
"id": 34, "id": 34,
"name": "콘솔 에러 확인", "name": "콘솔 에러 확인",
"action": "verify_console", "action": "verify_detail",
"expected": "심각한 콘솔 에러 없음" "expected": "심각한 콘솔 에러 없음"
} }
], ],
@@ -523,7 +604,10 @@
{ {
"id": 1, "id": 1,
"name": "등록/저장 버튼", "name": "등록/저장 버튼",
"steps": [25, 26], "steps": [
25,
26
],
"criteria": "저장 클릭 → 목록 리다이렉트 + 에러 없음 + 데이터 반영" "criteria": "저장 클릭 → 목록 리다이렉트 + 에러 없음 + 데이터 반영"
}, },
{ {
@@ -535,7 +619,13 @@
{ {
"id": 3, "id": 3,
"name": "검색/필터", "name": "검색/필터",
"steps": [6, 7, 8, 9, 10], "steps": [
6,
7,
8,
9,
10
],
"criteria": "검색 및 필터 시 데이터 변화 확인" "criteria": "검색 및 필터 시 데이터 변화 확인"
}, },
{ {
@@ -547,7 +637,9 @@
{ {
"id": 5, "id": 5,
"name": "목업 페이지 감지", "name": "목업 페이지 감지",
"steps": [3], "steps": [
3
],
"criteria": "입력 필드, 동작 버튼, API 호출 확인" "criteria": "입력 필드, 동작 버튼, API 호출 확인"
} }
], ],

View File

@@ -296,8 +296,8 @@
"name": "취소 버튼 동작 확인", "name": "취소 버튼 동작 확인",
"description": "수정 모드에서 취소 버튼 동작 검증", "description": "수정 모드에서 취소 버튼 동작 검증",
"actions": [ "actions": [
{ "type": "click", "target": "수정", "description": "수정 모드 진입" }, { "type": "click_if_exists", "target": "수정", "description": "수정 모드 진입" },
{ "type": "click", "target": "취소", "description": "취소 버튼 클릭" } { "type": "click_if_exists", "target": "취소", "description": "취소 버튼 클릭" }
], ],
"expect": { "expect": {
"url": "/accounting/withdrawals/{id}", "url": "/accounting/withdrawals/{id}",
@@ -354,7 +354,7 @@
} }
}, },
"actions": [ "actions": [
{ "type": "click", "target": "다음", "description": "다음 페이지로 이동" } { "type": "click_if_exists", "target": "다음", "description": "다음 페이지로 이동" }
], ],
"expectAfterAction": { "expectAfterAction": {
"currentPage": 2 "currentPage": 2

View File

@@ -116,7 +116,7 @@
"id": 10, "id": 10,
"phase": "READ", "phase": "READ",
"name": "[READ] 작업실적 행 상세 조회", "name": "[READ] 작업실적 행 상세 조회",
"action": "click", "action": "click_if_exists",
"target": "table tbody tr:first-child", "target": "table tbody tr:first-child",
"expected": { "expected": {
"detail_view": true "detail_view": true
@@ -138,7 +138,7 @@
{ {
"id": 12, "id": 12,
"name": "필수 검증 #1: 엑셀 다운로드", "name": "필수 검증 #1: 엑셀 다운로드",
"action": "click", "action": "click_if_exists",
"target": "button:has-text('엑셀'), button:has-text('Excel'), button:has-text('다운로드')", "target": "button:has-text('엑셀'), button:has-text('Excel'), button:has-text('다운로드')",
"verify": { "verify": {
"api_call": "GET /api/v1/production/performance/export", "api_call": "GET /api/v1/production/performance/export",