{ "$schema": "E2E Global API Monitoring Configuration", "version": "1.0.0", "description": "모든 E2E 테스트 시나리오에 적용되는 API 요청/응답 검증 설정", "lastUpdated": "2026-01-31", "apiMonitoring": { "enabled": true, "captureAllRequests": true, "baseUrl": "https://dev.codebridge-x.com", "apiPathPrefix": "/api/", "captureConfig": { "includePatterns": [ "/api/v1/**", "/api/**" ], "excludePatterns": [ "/_next/**", "/static/**", "*.js", "*.css", "*.png", "*.jpg", "*.svg", "*.woff", "*.woff2" ], "captureRequestBody": true, "captureResponseBody": true, "maxBodySize": 10240 } }, "validation": { "defaultRules": { "statusCodes": { "success": [200, 201, 204], "clientError": [400, 401, 403, 404], "serverError": [500, 502, 503] }, "responseTime": { "warning": 2000, "error": 5000 }, "contentType": { "json": "application/json", "pdf": "application/pdf", "excel": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" } }, "methodRules": { "GET": { "expectedStatus": [200], "maxResponseTime": 3000 }, "POST": { "expectedStatus": [200, 201], "maxResponseTime": 5000, "requireResponseBody": true }, "PUT": { "expectedStatus": [200], "maxResponseTime": 5000 }, "DELETE": { "expectedStatus": [200, 204], "maxResponseTime": 3000 } } }, "scripts": { "setupApiMonitoring": "(function() { window.__API_LOGS__ = []; window.__API_ERRORS__ = []; const originalFetch = window.fetch; window.fetch = async function(...args) { const startTime = Date.now(); const url = typeof args[0] === 'string' ? args[0] : args[0].url; const method = args[1]?.method || 'GET'; try { const response = await originalFetch.apply(this, args); const endTime = Date.now(); const logEntry = { url, method, status: response.status, duration: endTime - startTime, timestamp: new Date().toISOString(), ok: response.ok }; window.__API_LOGS__.push(logEntry); if (!response.ok) { window.__API_ERRORS__.push(logEntry); } return response; } catch (error) { const errorEntry = { url, method, error: error.message, timestamp: new Date().toISOString() }; window.__API_ERRORS__.push(errorEntry); throw error; } }; return 'API monitoring initialized'; })()", "getApiLogs": "(function() { return JSON.stringify(window.__API_LOGS__ || []); })()", "getApiErrors": "(function() { return JSON.stringify(window.__API_ERRORS__ || []); })()", "clearApiLogs": "(function() { window.__API_LOGS__ = []; window.__API_ERRORS__ = []; return 'API logs cleared'; })()", "getApiSummary": "(function() { const logs = window.__API_LOGS__ || []; const errors = window.__API_ERRORS__ || []; const summary = { total: logs.length, success: logs.filter(l => l.ok).length, failed: errors.length, avgResponseTime: logs.length > 0 ? Math.round(logs.reduce((sum, l) => sum + (l.duration || 0), 0) / logs.length) : 0, slowRequests: logs.filter(l => l.duration > 2000).length, byMethod: {}, byStatus: {} }; logs.forEach(l => { summary.byMethod[l.method] = (summary.byMethod[l.method] || 0) + 1; summary.byStatus[l.status] = (summary.byStatus[l.status] || 0) + 1; }); return JSON.stringify(summary); })()", "waitForApiCall": "(async function(urlPattern, timeout = 5000) { const start = Date.now(); while (Date.now() - start < timeout) { const logs = window.__API_LOGS__ || []; const found = logs.find(l => l.url.includes(urlPattern)); if (found) return JSON.stringify(found); await new Promise(r => setTimeout(r, 100)); } return JSON.stringify({ error: 'timeout', pattern: urlPattern }); })", "validateApiCall": "(function(urlPattern, expectedStatus) { const logs = window.__API_LOGS__ || []; const matching = logs.filter(l => l.url.includes(urlPattern)); if (matching.length === 0) return JSON.stringify({ valid: false, error: 'API call not found', pattern: urlPattern }); const latest = matching[matching.length - 1]; const statusMatch = Array.isArray(expectedStatus) ? expectedStatus.includes(latest.status) : latest.status === expectedStatus; return JSON.stringify({ valid: statusMatch, call: latest, expected: expectedStatus }); })" }, "commonApiEndpoints": { "auth": { "login": { "method": "POST", "path": "/api/v1/auth/login", "expectedStatus": 200 }, "logout": { "method": "POST", "path": "/api/v1/auth/logout", "expectedStatus": 200 }, "refresh": { "method": "POST", "path": "/api/v1/auth/refresh", "expectedStatus": 200 } }, "clients": { "list": { "method": "GET", "path": "/api/v1/clients", "expectedStatus": 200 }, "detail": { "method": "GET", "path": "/api/v1/clients/{id}", "expectedStatus": 200 }, "create": { "method": "POST", "path": "/api/v1/clients", "expectedStatus": [200, 201] }, "update": { "method": "PUT", "path": "/api/v1/clients/{id}", "expectedStatus": 200 }, "delete": { "method": "DELETE", "path": "/api/v1/clients/{id}", "expectedStatus": [200, 204] } }, "approvals": { "inbox": { "method": "GET", "path": "/api/v1/approvals/inbox", "expectedStatus": 200 }, "detail": { "method": "GET", "path": "/api/v1/approvals/{id}", "expectedStatus": 200 }, "approve": { "method": "POST", "path": "/api/v1/approvals/{id}/approve", "expectedStatus": 200 }, "reject": { "method": "POST", "path": "/api/v1/approvals/{id}/reject", "expectedStatus": 200 } } }, "reportTemplate": { "apiSection": { "title": "API 호출 검증 결과", "fields": [ "총 API 호출 수", "성공 호출", "실패 호출", "평균 응답 시간", "느린 요청 (>2초)" ] }, "errorSection": { "title": "API 오류 상세", "fields": [ "URL", "Method", "Status", "응답 시간", "오류 메시지" ] } }, "actionHooks": { "beforeScenario": { "description": "시나리오 시작 전 API 모니터링 초기화", "actions": [ "setupApiMonitoring", "clearApiLogs" ] }, "afterStep": { "description": "각 스텝 후 API 호출 확인", "actions": [ "checkForApiErrors" ] }, "afterScenario": { "description": "시나리오 종료 후 API 요약 생성", "actions": [ "getApiSummary", "generateApiReport" ] } }, "errorHandling": { "on500Error": { "action": "captureAndReport", "screenshot": true, "logApiDetails": true, "continueTest": false }, "on401Error": { "action": "reAuthenticate", "maxRetries": 1, "continueTest": true }, "on404Error": { "action": "logAndContinue", "screenshot": true, "continueTest": true }, "onTimeout": { "action": "retry", "maxRetries": 2, "continueTest": true } } }