import assert from 'node:assert/strict' import test from 'node:test' import { computed } from 'vue' import { useAdminMarkdownMediaPicker } from '../composables/useAdminMarkdownMediaPicker.js' const uploadSizeLimits = computed(() => ({ image: 10485760, video: 209715200, audio: 52428800, document: 52428800 })) test('관리자 Markdown 미디어 선택 모달은 열기와 닫기 상태를 관리한다', () => { const picker = useAdminMarkdownMediaPicker({ uploadSizeLimits }) picker.openMediaPickerState('gallery') assert.equal(picker.isMediaPickerOpen.value, true) assert.equal(picker.mediaPickerTarget.value, 'gallery') assert.equal(picker.activeMediaPickerTab.value, 'upload') assert.equal(picker.mediaSearchQuery.value, '') assert.equal(picker.mediaPickerPage.value, 1) assert.deepEqual(picker.selectedMediaUrls.value, []) assert.equal(picker.isGalleryMediaPicker.value, true) assert.equal(picker.mediaPickerAccept.value, 'image/*') assert.equal(picker.mediaPickerTitle.value, '갤러리 이미지 선택') assert.equal(picker.closeMediaPickerState(), true) assert.equal(picker.isMediaPickerOpen.value, false) assert.equal(picker.activeMediaPickerTab.value, 'upload') assert.deepEqual(picker.mediaItems.value, []) }) test('관리자 Markdown 미디어 선택 모달은 업로드 중 닫기를 막는다', () => { const picker = useAdminMarkdownMediaPicker({ uploadSizeLimits }) picker.openMediaPickerState('image') picker.isUploading.value = true assert.equal(picker.closeMediaPickerState(), false) assert.equal(picker.isMediaPickerOpen.value, true) }) test('관리자 Markdown 미디어 선택 모달은 API 응답과 페이지를 상태에 반영한다', () => { const picker = useAdminMarkdownMediaPicker({ uploadSizeLimits, pageSize: 20 }) picker.applyMediaPickerResponse({ items: [{ url: '/uploads/a.png' }], pagination: { page: 3, pageSize: 20, total: 42, pageCount: 3 } }) assert.equal(picker.mediaPickerPage.value, 3) assert.equal(picker.mediaPickerPageCount.value, 3) assert.equal(picker.mediaPickerRangeLabel.value, '42개 중 41-42개') assert.deepEqual(picker.filteredMediaItems.value, [{ url: '/uploads/a.png' }]) picker.setMediaPickerPage(99) assert.equal(picker.mediaPickerPage.value, 3) }) test('관리자 Markdown 미디어 선택 모달은 단일·갤러리 선택을 관리한다', () => { const picker = useAdminMarkdownMediaPicker({ uploadSizeLimits }) picker.openMediaPickerState('image') picker.mediaItems.value = [ { url: '/uploads/a.png' }, { url: '/uploads/b.png' } ] picker.toggleMediaSelection({ url: '/uploads/a.png' }) picker.toggleMediaSelection({ url: '/uploads/b.png' }) assert.deepEqual(picker.selectedMediaUrls.value, ['/uploads/b.png']) assert.deepEqual(picker.resolveCurrentSelectedMediaItems(), [{ url: '/uploads/b.png' }]) picker.openMediaPickerState('gallery') picker.toggleMediaSelection({ url: '/uploads/a.png' }) picker.toggleMediaSelection({ url: '/uploads/b.png' }) assert.deepEqual(picker.selectedMediaUrls.value, ['/uploads/a.png', '/uploads/b.png']) assert.equal(picker.getGallerySelectionOrder('/uploads/b.png'), 2) assert.deepEqual(picker.mediaPickerApplyState.value, { disabled: false, label: '2개 삽입' }) }) test('관리자 Markdown 미디어 선택 모달은 업로드 파일 선택 상태와 fallback 목록을 만든다', () => { const picker = useAdminMarkdownMediaPicker({ uploadSizeLimits }) picker.openMediaPickerState('image') picker.selectUploadedMediaFiles([ { url: '/uploads/a.png', kind: 'image' }, { url: '/uploads/a.mp4', kind: 'video' } ]) assert.deepEqual(picker.selectedMediaUrls.value, ['/uploads/a.png']) picker.prependUploadedMediaItems([{ url: '/uploads/a.png' }]) assert.deepEqual(picker.mediaItems.value, [{ url: '/uploads/a.png' }]) assert.equal(picker.isUploadFileAllowedForPicker({ type: 'image/png' }), true) assert.equal(picker.isUploadFileAllowedForPicker({ type: 'video/mp4' }), false) }) test('관리자 Markdown 미디어 선택 모달은 서버 목록 조회를 상태에 반영한다', async () => { const originalFetch = globalThis.$fetch const calls = [] globalThis.$fetch = async (url, options) => { calls.push({ url, options }) return { items: [{ url: '/uploads/a.png', kind: 'image' }], pagination: { page: 2, pageSize: 20, total: 21, pageCount: 2 } } } try { const picker = useAdminMarkdownMediaPicker({ uploadSizeLimits, pageSize: 20 }) picker.openMediaPickerState('image') picker.mediaSearchQuery.value = ' a ' picker.mediaPickerPage.value = 2 await picker.fetchMediaItems() assert.equal(picker.isLoadingMedia.value, false) assert.deepEqual(picker.mediaItems.value, [{ url: '/uploads/a.png', kind: 'image' }]) assert.equal(picker.mediaPickerPage.value, 2) assert.deepEqual(calls[0], { url: '/admin/api/media', options: { query: { paged: '1', tab: 'library', page: 2, pageSize: 20, kind: 'image', search: 'a' } } }) } finally { globalThis.$fetch = originalFetch } }) test('관리자 Markdown 미디어 선택 모달은 업로드 후 라이브러리 탭과 선택 상태를 갱신한다', async () => { const originalFetch = globalThis.$fetch const uploadedFile = { url: '/uploads/a.png', kind: 'image' } const calls = [] globalThis.$fetch = async (url, options) => { calls.push({ url, options }) if (url === '/admin/api/uploads') { return { files: [uploadedFile] } } return { items: [uploadedFile], pagination: { page: 1, pageSize: 50, total: 1, pageCount: 1 } } } try { const picker = useAdminMarkdownMediaPicker({ uploadSizeLimits, uploadMaxFileCount: computed(() => 3), uploadMaxTotalSize: computed(() => 1024 * 1024) }) picker.openMediaPickerState('image') const uploadedFiles = await picker.uploadFilesIntoMediaPicker([ new File(['image'], 'a.png', { type: 'image/png' }) ]) assert.deepEqual(uploadedFiles, [uploadedFile]) assert.equal(picker.isUploading.value, false) assert.equal(picker.activeMediaPickerTab.value, 'library') assert.deepEqual(picker.selectedMediaUrls.value, ['/uploads/a.png']) assert.deepEqual(picker.mediaItems.value, [uploadedFile]) assert.equal(calls[0].url, '/admin/api/uploads') assert.equal(calls[0].options.method, 'POST') assert.ok(calls[0].options.body instanceof FormData) assert.equal(calls[1].url, '/admin/api/media') } finally { globalThis.$fetch = originalFetch } }) test('관리자 Markdown 미디어 선택 모달 업로드는 한도 초과 시 요청하지 않는다', async () => { const originalFetch = globalThis.$fetch let called = false globalThis.$fetch = async () => { called = true return { files: [] } } try { const picker = useAdminMarkdownMediaPicker({ uploadSizeLimits, uploadMaxFileCount: computed(() => 1), uploadMaxTotalSize: computed(() => 1024 * 1024) }) await assert.rejects( () => picker.uploadMediaFiles([ new File(['a'], 'a.png', { type: 'image/png' }), new File(['b'], 'b.png', { type: 'image/png' }) ]), /최대 1개/ ) assert.equal(called, false) } finally { globalThis.$fetch = originalFetch } })