Files
sam-manage/resources/views/dev-tools/flow-tester/partials/example-flows.blade.php

450 lines
19 KiB
PHP
Raw Normal View History

{{-- 예제 플로우 모달 --}}
<div id="examples-modal"
class="hidden fixed inset-0 z-50 overflow-y-auto"
aria-labelledby="examples-modal-title"
role="dialog"
aria-modal="true">
{{-- 배경 오버레이 --}}
<div class="fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity"
onclick="ExamplesModal.close()"></div>
{{-- 모달 컨테이너 --}}
<div class="flex min-h-full items-start justify-center p-4 pt-8">
<div class="relative bg-white rounded-lg shadow-xl w-full max-w-5xl max-h-[90vh] flex flex-col">
{{-- 모달 헤더 --}}
<div class="flex items-center justify-between px-6 py-4 border-b border-gray-200 flex-shrink-0">
<h2 id="examples-modal-title" class="text-xl font-semibold text-gray-800">
예제 플로우
</h2>
<button type="button"
onclick="ExamplesModal.close()"
class="text-gray-400 hover:text-gray-600 transition-colors">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
{{-- 예제 선택 --}}
<div class="px-6 py-3 border-b border-gray-200 flex-shrink-0">
<div class="flex gap-2 flex-wrap">
<button type="button" class="example-tab active px-4 py-2 text-sm font-medium rounded-lg transition-colors" data-example="item-master-full">
Item Master (전체)
</button>
<button type="button" class="example-tab px-4 py-2 text-sm font-medium rounded-lg transition-colors" data-example="item-master-simple">
Item Master (기본)
</button>
<button type="button" class="example-tab px-4 py-2 text-sm font-medium rounded-lg transition-colors" data-example="auth-flow">
인증 플로우
</button>
</div>
</div>
{{-- 모달 콘텐츠 --}}
<div class="flex-1 overflow-y-auto p-6">
{{-- Item Master 전체 플로우 --}}
<div id="example-item-master-full" class="example-content">
<div class="mb-4">
<h3 class="text-lg font-semibold text-gray-800">Item Master 전체 테스트 (18 스텝)</h3>
<p class="text-sm text-gray-600 mt-1">페이지, 섹션, 필드의 CRUD + 연결/해제 전체 시나리오</p>
</div>
<div class="relative">
<button onclick="ExamplesModal.copy('item-master-full')"
class="absolute top-2 right-2 px-3 py-1 text-xs bg-gray-700 hover:bg-gray-600 text-white rounded transition-colors z-10">
복사
</button>
<pre id="json-item-master-full" class="bg-gray-800 text-gray-100 p-4 rounded-lg text-xs overflow-x-auto max-h-[60vh]"></pre>
</div>
</div>
{{-- Item Master 기본 플로우 --}}
<div id="example-item-master-simple" class="example-content hidden">
<div class="mb-4">
<h3 class="text-lg font-semibold text-gray-800">Item Master 기본 테스트 (3 스텝)</h3>
<p class="text-sm text-gray-600 mt-1">페이지 생성 조회 삭제 기본 CRUD</p>
</div>
<div class="relative">
<button onclick="ExamplesModal.copy('item-master-simple')"
class="absolute top-2 right-2 px-3 py-1 text-xs bg-gray-700 hover:bg-gray-600 text-white rounded transition-colors z-10">
복사
</button>
<pre id="json-item-master-simple" class="bg-gray-800 text-gray-100 p-4 rounded-lg text-xs overflow-x-auto max-h-[60vh]"></pre>
</div>
</div>
{{-- 인증 플로우 --}}
<div id="example-auth-flow" class="example-content hidden">
<div class="mb-4">
<h3 class="text-lg font-semibold text-gray-800">인증 플로우 테스트 (4 스텝)</h3>
<p class="text-sm text-gray-600 mt-1">로그인 프로필 조회 토큰 갱신 로그아웃</p>
</div>
<div class="relative">
<button onclick="ExamplesModal.copy('auth-flow')"
class="absolute top-2 right-2 px-3 py-1 text-xs bg-gray-700 hover:bg-gray-600 text-white rounded transition-colors z-10">
복사
</button>
<pre id="json-auth-flow" class="bg-gray-800 text-gray-100 p-4 rounded-lg text-xs overflow-x-auto max-h-[60vh]"></pre>
</div>
</div>
</div>
{{-- 모달 푸터 --}}
<div class="flex justify-end px-6 py-4 border-t border-gray-200 flex-shrink-0">
<button type="button"
onclick="ExamplesModal.close()"
class="px-4 py-2 bg-gray-600 hover:bg-gray-700 text-white rounded-lg transition-colors">
닫기
</button>
</div>
</div>
</div>
</div>
<style>
.example-tab {
background-color: #f3f4f6;
color: #374151;
}
.example-tab:hover {
background-color: #e5e7eb;
}
.example-tab.active {
background-color: #7c3aed;
color: white;
}
</style>
<script>
const ExampleFlows = {
'item-master-full': {
"version": "1.0",
"meta": {
"author": "SAM Admin",
"description": "품목관리 API 통합 테스트 - CRUD 및 연결/해제 검증",
"tags": ["item-master", "integration", "full-test"]
},
"config": {
"baseUrl": "https://sam.kr/api/v1",
"timeout": 30000,
"stopOnFailure": false,
"headers": {
"Accept": "application/json",
"Content-Type": "application/json"
}
},
"variables": {
"testPrefix": "TEST_",
"timestamp": "{{$timestamp}}"
},
"steps": [
{
"id": "page_create_1",
"name": "[페이지] 1차 생성",
"description": "테스트 페이지 최초 생성",
"method": "POST",
"endpoint": "/item-master/pages",
"body": {
"page_name": "{{variables.testPrefix}}Page_{{variables.timestamp}}",
"item_type": "PRODUCT",
"description": "테스트용 페이지 (삭제 예정)"
},
"expect": {
"status": [200, 201],
"jsonPath": { "$.success": true, "$.data.id": "@isNumber" }
},
"extract": { "tempPageId": "$.data.id" }
},
{
"id": "page_delete_1",
"name": "[페이지] 1차 삭제",
"dependsOn": ["page_create_1"],
"method": "DELETE",
"endpoint": "/item-master/pages/{{page_create_1.tempPageId}}",
"expect": { "status": [200, 204] }
},
{
"id": "page_create_2",
"name": "[페이지] 2차 생성 (유지)",
"dependsOn": ["page_delete_1"],
"method": "POST",
"endpoint": "/item-master/pages",
"body": {
"page_name": "{{variables.testPrefix}}MainPage_{{variables.timestamp}}",
"item_type": "PRODUCT",
"description": "통합 테스트 메인 페이지"
},
"expect": { "status": [200, 201] },
"extract": { "mainPageId": "$.data.id", "mainPageName": "$.data.page_name" }
},
{
"id": "section_create_1",
"name": "[섹션] 독립 1차 생성",
"dependsOn": ["page_create_2"],
"method": "POST",
"endpoint": "/item-master/sections",
"body": { "title": "{{variables.testPrefix}}Section_Temp", "type": "form" },
"expect": { "status": [200, 201] },
"extract": { "tempSectionId": "$.data.id" }
},
{
"id": "section_delete_1",
"name": "[섹션] 1차 삭제",
"dependsOn": ["section_create_1"],
"method": "DELETE",
"endpoint": "/item-master/sections/{{section_create_1.tempSectionId}}",
"expect": { "status": [200, 204] }
},
{
"id": "section_create_2",
"name": "[섹션] 독립 2차 생성 (유지)",
"dependsOn": ["section_delete_1"],
"method": "POST",
"endpoint": "/item-master/sections",
"body": { "title": "{{variables.testPrefix}}MainSection_{{variables.timestamp}}", "type": "form" },
"expect": { "status": [200, 201] },
"extract": { "mainSectionId": "$.data.id" }
},
{
"id": "field_create_1",
"name": "[필드] 독립 1차 생성",
"dependsOn": ["section_create_2"],
"method": "POST",
"endpoint": "/item-master/fields",
"body": { "field_name": "{{variables.testPrefix}}Field_Temp", "field_type": "text", "is_required": false },
"expect": { "status": [200, 201] },
"extract": { "tempFieldId": "$.data.id" }
},
{
"id": "field_delete_1",
"name": "[필드] 1차 삭제",
"dependsOn": ["field_create_1"],
"method": "DELETE",
"endpoint": "/item-master/fields/{{field_create_1.tempFieldId}}",
"expect": { "status": [200, 204] }
},
{
"id": "field_create_2",
"name": "[필드] 독립 2차 생성 (유지)",
"dependsOn": ["field_delete_1"],
"method": "POST",
"endpoint": "/item-master/fields",
"body": { "field_name": "{{variables.testPrefix}}MainField_{{variables.timestamp}}", "field_type": "text", "is_required": true },
"expect": { "status": [200, 201] },
"extract": { "mainFieldId": "$.data.id" }
},
{
"id": "page_link_section_1",
"name": "[연결] 페이지에 섹션 연결",
"dependsOn": ["field_create_2"],
"method": "POST",
"endpoint": "/item-master/pages/{{page_create_2.mainPageId}}/link-section",
"body": { "section_id": "{{section_create_2.mainSectionId}}", "sort_order": 1 },
"expect": { "status": [200, 201] }
},
{
"id": "page_unlink_section",
"name": "[연결] 페이지-섹션 연결 해제",
"dependsOn": ["page_link_section_1"],
"method": "DELETE",
"endpoint": "/item-master/pages/{{page_create_2.mainPageId}}/unlink-section/{{section_create_2.mainSectionId}}",
"expect": { "status": [200, 204] }
},
{
"id": "page_link_section_2",
"name": "[연결] 페이지에 섹션 재연결",
"dependsOn": ["page_unlink_section"],
"method": "POST",
"endpoint": "/item-master/pages/{{page_create_2.mainPageId}}/link-section",
"body": { "section_id": "{{section_create_2.mainSectionId}}", "sort_order": 1 },
"expect": { "status": [200, 201] }
},
{
"id": "section_link_field_1",
"name": "[연결] 섹션에 필드 연결",
"dependsOn": ["page_link_section_2"],
"method": "POST",
"endpoint": "/item-master/sections/{{section_create_2.mainSectionId}}/link-field",
"body": { "field_id": "{{field_create_2.mainFieldId}}", "sort_order": 1 },
"expect": { "status": [200, 201] }
},
{
"id": "section_unlink_field",
"name": "[연결] 섹션-필드 연결 해제",
"dependsOn": ["section_link_field_1"],
"method": "DELETE",
"endpoint": "/item-master/sections/{{section_create_2.mainSectionId}}/unlink-field/{{field_create_2.mainFieldId}}",
"expect": { "status": [200, 204] }
},
{
"id": "cleanup_field",
"name": "[정리] 필드 삭제",
"dependsOn": ["section_unlink_field"],
"method": "DELETE",
"endpoint": "/item-master/fields/{{field_create_2.mainFieldId}}",
"expect": { "status": [200, 204] },
"continueOnFailure": true
},
{
"id": "cleanup_section",
"name": "[정리] 섹션 삭제",
"dependsOn": ["cleanup_field"],
"method": "DELETE",
"endpoint": "/item-master/sections/{{section_create_2.mainSectionId}}",
"expect": { "status": [200, 204] },
"continueOnFailure": true
},
{
"id": "cleanup_page",
"name": "[정리] 페이지 삭제",
"dependsOn": ["cleanup_section"],
"method": "DELETE",
"endpoint": "/item-master/pages/{{page_create_2.mainPageId}}",
"expect": { "status": [200, 204] },
"continueOnFailure": true
}
]
},
'item-master-simple': {
"version": "1.0",
"config": {
"baseUrl": "https://sam.kr/api/v1",
"timeout": 30000,
"stopOnFailure": true
},
"variables": {
"testPrefix": "SIMPLE_"
},
"steps": [
{
"id": "create_page",
"name": "페이지 생성",
"method": "POST",
"endpoint": "/item-master/pages",
"body": { "page_name": "{{variables.testPrefix}}Page_{{$timestamp}}", "item_type": "PRODUCT" },
"expect": { "status": [200, 201] },
"extract": { "pageId": "$.data.id" }
},
{
"id": "get_page",
"name": "페이지 조회",
"dependsOn": ["create_page"],
"method": "GET",
"endpoint": "/item-master/pages",
"expect": { "status": [200], "jsonPath": { "$.success": true } }
},
{
"id": "delete_page",
"name": "페이지 삭제",
"dependsOn": ["get_page"],
"method": "DELETE",
"endpoint": "/item-master/pages/{{create_page.pageId}}",
"expect": { "status": [200, 204] }
}
]
},
'auth-flow': {
"version": "1.0",
"config": {
"baseUrl": "https://sam.kr/api/v1",
"timeout": 30000,
"stopOnFailure": true
},
"variables": {
"email": "test@example.com",
"password": "password123"
},
"steps": [
{
"id": "login",
"name": "로그인",
"method": "POST",
"endpoint": "/auth/login",
"body": { "email": "{{variables.email}}", "password": "{{variables.password}}" },
"expect": { "status": [200], "jsonPath": { "$.success": true, "$.data.token": "@isString" } },
"extract": { "accessToken": "$.data.token", "refreshToken": "$.data.refresh_token" }
},
{
"id": "get_profile",
"name": "프로필 조회",
"dependsOn": ["login"],
"method": "GET",
"endpoint": "/auth/me",
"headers": { "Authorization": "Bearer {{login.accessToken}}" },
"expect": { "status": [200], "jsonPath": { "$.data.email": "{{variables.email}}" } }
},
{
"id": "refresh_token",
"name": "토큰 갱신",
"dependsOn": ["get_profile"],
"method": "POST",
"endpoint": "/auth/refresh",
"body": { "refresh_token": "{{login.refreshToken}}" },
"expect": { "status": [200], "jsonPath": { "$.data.token": "@isString" } },
"extract": { "newToken": "$.data.token" }
},
{
"id": "logout",
"name": "로그아웃",
"dependsOn": ["refresh_token"],
"method": "POST",
"endpoint": "/auth/logout",
"headers": { "Authorization": "Bearer {{refresh_token.newToken}}" },
"expect": { "status": [200, 204] }
}
]
}
};
const ExamplesModal = {
open() {
document.getElementById('examples-modal').classList.remove('hidden');
document.body.style.overflow = 'hidden';
this.renderAllExamples();
},
close() {
document.getElementById('examples-modal').classList.add('hidden');
document.body.style.overflow = '';
},
switchExample(exampleId) {
document.querySelectorAll('.example-tab').forEach(tab => tab.classList.remove('active'));
document.querySelector(`.example-tab[data-example="${exampleId}"]`).classList.add('active');
document.querySelectorAll('.example-content').forEach(content => content.classList.add('hidden'));
document.getElementById(`example-${exampleId}`).classList.remove('hidden');
},
renderAllExamples() {
Object.keys(ExampleFlows).forEach(key => {
const element = document.getElementById(`json-${key}`);
if (element) {
element.textContent = JSON.stringify(ExampleFlows[key], null, 2);
}
});
},
copy(exampleId) {
const json = JSON.stringify(ExampleFlows[exampleId], null, 2);
navigator.clipboard.writeText(json).then(() => {
alert('JSON이 클립보드에 복사되었습니다.');
}).catch(err => {
console.error('복사 실패:', err);
});
}
};
document.querySelectorAll('.example-tab').forEach(tab => {
tab.addEventListener('click', function() {
ExamplesModal.switchExample(this.dataset.example);
});
});
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape' && !document.getElementById('examples-modal').classList.contains('hidden')) {
ExamplesModal.close();
}
});
</script>