Files
lucia-frontend/tests/stores/files.test.js
2026-03-08 10:47:49 +08:00

253 lines
7.4 KiB
JavaScript

// 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();
});
});
});