Files
lucia-frontend/tests/stores/files.test.js
2026-03-08 12:11:57 +08:00

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