// The Lucia project. // Copyright 2026-2026 DSP, inc. All rights reserved. // Authors: // imacat.yang@dsp.im (imacat), 2026/03/06 import { describe, it, expect, beforeEach, vi } from 'vitest'; import { setActivePinia, createPinia } from 'pinia'; // Mock modules that have deep import chains (router, Swal, pinia, toast) vi.mock('@/module/apiError.js', () => ({ default: vi.fn(), })); vi.mock('@/module/alertModal.js', () => ({ uploadFailedFirst: vi.fn(), uploadFailedSecond: vi.fn(), uploadloader: vi.fn(), uploadSuccess: vi.fn(), deleteSuccess: vi.fn(), })); vi.mock('sweetalert2', () => ({ default: { close: vi.fn(), fire: vi.fn() }, })); // Prevent module-level store init in cytoscapeMap.js (loaded via router → Map.vue) vi.mock('@/module/cytoscapeMap.js', () => ({})); vi.mock('@/router/index.ts', () => ({ default: { push: vi.fn(), currentRoute: { value: { path: '/' } } }, })); const { mockGet, mockPost, mockPut, mockDelete } = vi.hoisted(() => ({ mockGet: vi.fn(), mockPost: vi.fn(), mockPut: vi.fn(), mockDelete: vi.fn(), })); vi.mock('@/api/client.js', () => ({ default: { get: mockGet, post: mockPost, put: mockPut, delete: mockDelete }, })); import { useFilesStore } from '@/stores/files'; describe('filesStore', () => { let store; beforeEach(() => { setActivePinia(createPinia()); store = useFilesStore(); store.$router = { push: vi.fn() }; vi.clearAllMocks(); }); it('has correct default state', () => { expect(store.filesTag).toBe('ALL'); expect(store.httpStatus).toBe(200); expect(store.uploadId).toBeNull(); }); describe('allFiles getter', () => { it('filters files by current filesTag', () => { store.allEventFiles = [ { fileType: 'Log', name: 'a.xes' }, { fileType: 'Filter', name: 'b' }, { fileType: 'Design', name: 'c' }, ]; store.filesTag = 'COMPARE'; expect(store.allFiles.map((f) => f.name)).toEqual(['a.xes', 'b']); store.filesTag = 'ALL'; expect(store.allFiles).toHaveLength(3); }); }); describe('fetchAllFiles', () => { it('fetches and transforms file data', async () => { mockGet.mockResolvedValue({ data: [ { type: 'log', name: 'test.xes', owner: { name: 'Alice' }, updated_at: '2024-01-15T10:00:00Z', accessed_at: '2024-01-15T11:00:00Z', }, { type: 'filter', name: 'filter1', parent: { name: 'test.xes' }, owner: { name: 'Bob' }, updated_at: '2024-01-16T10:00:00Z', accessed_at: null, }, ], }); await store.fetchAllFiles(); expect(mockGet).toHaveBeenCalledWith('/api/files'); expect(store.allEventFiles).toHaveLength(2); expect(store.allEventFiles[0].fileType).toBe('Log'); expect(store.allEventFiles[0].icon).toBe('work_history'); expect(store.allEventFiles[0].ownerName).toBe('Alice'); expect(store.allEventFiles[1].fileType).toBe('Filter'); expect(store.allEventFiles[1].parentLog).toBe('test.xes'); expect(store.allEventFiles[1].accessed_at).toBeNull(); }); it('does not throw on API failure', async () => { mockGet.mockRejectedValue(new Error('Network error')); await expect(store.fetchAllFiles()).resolves.toBeUndefined(); }); it('maps design files without leaking metadata from previous file items', async () => { mockGet.mockResolvedValue({ data: [ { type: 'log', name: 'order-log', owner: { name: 'Alice' }, updated_at: '2024-01-15T10:00:00Z', accessed_at: null, }, { type: 'design', name: 'diagram-a', owner: { name: 'Bob' }, updated_at: '2024-01-16T10:00:00Z', accessed_at: null, }, ], }); await store.fetchAllFiles(); expect(store.allEventFiles[1].icon).toBe('shape_line'); expect(store.allEventFiles[1].fileType).toBe('Design'); expect(store.allEventFiles[1].parentLog).toBe('diagram-a'); }); }); describe('upload', () => { it('uploads file and navigates to Upload page', async () => { mockPost.mockResolvedValue({ data: { id: 42 } }); const formData = new FormData(); await store.upload(formData); expect(mockPost).toHaveBeenCalledWith( '/api/logs/csv-uploads', formData, expect.objectContaining({ headers: { 'Content-Type': 'multipart/form-data' }, }), ); expect(store.uploadId).toBe(42); expect(store.$router.push).toHaveBeenCalledWith({ name: 'Upload' }); }); }); describe('getUploadDetail', () => { it('fetches upload preview', async () => { store.uploadId = 10; mockGet.mockResolvedValue({ data: { preview: { columns: ['a', 'b'] } }, }); await store.getUploadDetail(); expect(mockGet).toHaveBeenCalledWith('/api/logs/csv-uploads/10'); expect(store.allUploadDetail).toEqual({ columns: ['a', 'b'] }); }); }); describe('rename', () => { it('renames a log file', async () => { mockPut.mockResolvedValue({}); mockGet.mockResolvedValue({ data: [] }); await store.rename('log', 5, 'new-name'); expect(mockPut).toHaveBeenCalledWith('/api/logs/5/name', { name: 'new-name', }); }); }); describe('getDependents', () => { it('fetches dependents for a log', async () => { mockGet.mockResolvedValue({ data: [{ id: 1 }, { id: 2 }] }); await store.getDependents('log', 7); expect(mockGet).toHaveBeenCalledWith('/api/logs/7/dependents'); expect(store.allDependentsData).toEqual([{ id: 1 }, { id: 2 }]); }); }); describe('deleteFile', () => { it('calls mockDelete before fetchAllFiles', async () => { const callOrder = []; mockDelete.mockImplementation(async () => { callOrder.push('delete'); return {}; }); mockGet.mockImplementation(async () => { callOrder.push('get'); return { data: [] }; }); await store.deleteFile('log', 1); expect(mockDelete).toHaveBeenCalledWith('/api/logs/1'); expect(callOrder.indexOf('delete')).toBeLessThan( callOrder.indexOf('get'), ); }); it('returns early for invalid id without throwing', async () => { await expect( store.deleteFile('log', null), ).resolves.toBeUndefined(); expect(mockDelete).not.toHaveBeenCalled(); }); }); describe('deletionRecord', () => { it('deletes a deletion record', async () => { mockDelete.mockResolvedValue({}); await store.deletionRecord(5); expect(mockDelete).toHaveBeenCalledWith('/api/deletion/5'); }); }); describe('downloadFileCSV', () => { it('downloads CSV for a log', async () => { mockGet.mockResolvedValue({ data: 'col1,col2\na,b' }); window.URL.createObjectURL = vi.fn().mockReturnValue('blob:test'); window.URL.revokeObjectURL = vi.fn(); await store.downloadFileCSV('log', 3, 'my-file'); expect(mockGet).toHaveBeenCalledWith('/api/logs/3/csv'); expect(window.URL.revokeObjectURL).toHaveBeenCalledWith('blob:test'); }); it('returns early for unsupported type', async () => { await store.downloadFileCSV('log-check', 3, 'file'); expect(mockGet).not.toHaveBeenCalled(); }); }); });