// The Lucia project. // Copyright 2026-2026 DSP, inc. All rights reserved. // Authors: // imacat.yang@dsp.im (imacat), 2026/03/05 import { describe, it, expect, beforeEach, vi } from "vitest"; import { setActivePinia, createPinia } from "pinia"; import { http, HttpResponse } from "msw"; import { server } from "@/mocks/node.js"; import { findRequest, captureRequest } from "@/mocks/request-log.js"; vi.mock("@/module/apiError.js", () => ({ default: vi.fn(), })); import { useAllMapDataStore } from "@/stores/allMapData"; describe("allMapDataStore", () => { let store; beforeEach(() => { setActivePinia(createPinia()); store = useAllMapDataStore(); document.cookie = "luciaToken=fake-test-token"; }); it("has correct default state", () => { expect(store.logId).toBeNull(); expect(store.allProcessMap).toEqual({}); expect(store.allTrace).toEqual([]); }); describe("getAllMapData", () => { it("fetches log discover data", async () => { store.logId = 1; const mockData = { process_map: { nodes: [] }, bpmn: { nodes: [] }, stats: { cases: 10 }, insights: {}, }; server.use( http.get("/api/logs/:id/discover", ({ request }) => { captureRequest("GET", new URL(request.url).pathname); return HttpResponse.json(mockData); }), ); await store.getAllMapData(); const reqs = findRequest("GET", "/api/logs/1/discover"); expect(reqs).toHaveLength(1); expect(store.allProcessMap).toEqual({ nodes: [] }); expect(store.allStats).toEqual({ cases: 10 }); }); it("fetches temp filter discover data when set", async () => { store.logId = 1; store.tempFilterId = 5; server.use( http.get("/api/temp-filters/:id/discover", ({ request }) => { captureRequest("GET", new URL(request.url).pathname); return HttpResponse.json({ process_map: {}, bpmn: {}, stats: {}, insights: {}, }); }), ); await store.getAllMapData(); const reqs = findRequest("GET", "/api/temp-filters/5/discover"); expect(reqs).toHaveLength(1); }); it("fetches created filter discover data", async () => { store.logId = 1; store.createFilterId = 3; server.use( http.get("/api/filters/:id/discover", ({ request }) => { captureRequest("GET", new URL(request.url).pathname); return HttpResponse.json({ process_map: {}, bpmn: {}, stats: {}, insights: {}, }); }), ); await store.getAllMapData(); const reqs = findRequest("GET", "/api/filters/3/discover"); expect(reqs).toHaveLength(1); }); it("does not throw on API failure", async () => { store.logId = 1; server.use( http.get("/api/logs/:id/discover", () => new HttpResponse(null, { status: 500 }), ), ); await expect(store.getAllMapData()).resolves.not.toThrow(); }); }); describe("getFilterParams", () => { it("fetches filter params and transforms timeframe", async () => { store.logId = 1; const mockData = { tasks: ["A", "B"], sources: ["A"], sinks: ["B"], timeframe: { x_axis: { min: "2023-01-01T00:00:00Z", max: "2023-12-31T00:00:00Z", }, }, trace: [], attrs: [], }; server.use( http.get("/api/filters/params", ({ request }) => { const url = new URL(request.url); captureRequest("GET", url.pathname + url.search); return HttpResponse.json(mockData); }), ); await store.getFilterParams(); const reqs = findRequest("GET", "/api/filters/params?log_id=1"); expect(reqs).toHaveLength(1); expect(store.allFilterTask).toEqual(["A", "B"]); // Check that min_base and max_base are stored expect(store.allFilterTimeframe.x_axis.min_base).toBe( "2023-01-01T00:00:00Z", ); }); }); describe("checkHasResult", () => { it("posts rule data and stores result", async () => { store.logId = 1; store.postRuleData = [{ type: "task" }]; server.use( http.post("/api/filters/has-result", async ({ request }) => { const url = new URL(request.url); const body = await request.json(); captureRequest("POST", url.pathname + url.search, body); return HttpResponse.json({ result: true }); }), ); await store.checkHasResult(); const reqs = findRequest("POST", "/api/filters/has-result?log_id=1"); expect(reqs).toHaveLength(1); expect(reqs[0].body).toEqual([{ type: "task" }]); expect(store.hasResultRule).toBe(true); }); }); describe("addTempFilterId", () => { it("creates temp filter and stores id", async () => { store.logId = 1; store.postRuleData = []; server.use( http.post("/api/temp-filters", () => HttpResponse.json({ id: 77 }), ), ); await store.addTempFilterId(); expect(store.tempFilterId).toBe(77); }); }); describe("addFilterId", () => { it("creates filter and clears temp id", async () => { store.logId = 1; store.tempFilterId = 77; store.postRuleData = [{ type: "rule" }]; server.use( http.post("/api/filters", async ({ request }) => { const url = new URL(request.url); const body = await request.json(); captureRequest("POST", url.pathname + url.search, body); return HttpResponse.json({ id: 88 }); }), ); await store.addFilterId("myFilter"); const reqs = findRequest("POST", "/api/filters?log_id=1"); expect(reqs).toHaveLength(1); expect(reqs[0].body).toEqual({ name: "myFilter", rules: [{ type: "rule" }], }); expect(store.createFilterId).toBe(88); expect(store.tempFilterId).toBeNull(); }); }); describe("updateFilter", () => { it("updates filter and clears temp id", async () => { store.createFilterId = 88; store.tempFilterId = 77; store.postRuleData = [{ type: "updated" }]; server.use( http.put("/api/filters/:id", async ({ request, params }) => { const body = await request.json(); captureRequest("PUT", `/api/filters/${params.id}`, body); return new HttpResponse(null, { status: 200 }); }), ); await store.updateFilter(); const reqs = findRequest("PUT", "/api/filters/88"); expect(reqs).toHaveLength(1); expect(reqs[0].body).toEqual([{ type: "updated" }]); expect(store.isUpdateFilter).toBe(true); expect(store.tempFilterId).toBeNull(); }); }); describe("getAllTrace", () => { it("does not crash when baseLogId is falsy", async () => { store.logId = 1; store.baseLogId = null; server.use( http.get("/api/logs/:id/traces", () => HttpResponse.json([{ id: 1 }]), ), ); await store.getAllTrace(); expect(store.allTrace).toEqual([{ id: 1 }]); // allBaseTrace should not be set when baseLogId is falsy expect(store.allBaseTrace).toEqual([]); }); }); describe("getters", () => { it("traces getter sorts by id", () => { store.allTrace = [ { id: 3, name: "C" }, { id: 1, name: "A" }, { id: 2, name: "B" }, ]; expect(store.traces.map((t) => t.id)).toEqual([1, 2, 3]); }); it("processMap getter returns state", () => { store.allProcessMap = { nodes: [1, 2] }; expect(store.processMap).toEqual({ nodes: [1, 2] }); }); it("BaseInfiniteFirstCases returns allBaseCase when baseInfiniteStart is 0", () => { store.baseInfiniteStart = 0; store.allBaseCase = [{ id: 1 }, { id: 2 }]; expect(store.BaseInfiniteFirstCases).toEqual([{ id: 1 }, { id: 2 }]); }); it("BaseInfiniteFirstCases returns undefined when baseInfiniteStart is not 0", () => { store.baseInfiniteStart = 5; store.allBaseCase = [{ id: 1 }]; expect(store.BaseInfiniteFirstCases).toBeUndefined(); }); it("filterAttrs getter does not corrupt original state on repeated access", () => { const originalDate = "2023-06-15T10:30:00Z"; store.allFilterAttrs = [ { type: "date", min: originalDate, max: "2023-12-31T23:59:00Z" }, ]; // Access the getter once to trigger any side effects expect(store.filterAttrs).toBeDefined(); // The original state should still contain the ISO date, not a formatted string expect(store.allFilterAttrs[0].min).toBe(originalDate); }); it("filterAttrs getter returns consistent float values on repeated access", () => { store.allFilterAttrs = [{ type: "float", min: 1.239, max: 5.671 }]; const first = store.filterAttrs; const second = store.filterAttrs; // min rounds down (ROUND_DOWN=1), max rounds up (ROUND_UP=0) // Both accesses should produce the same result expect(first[0].min).toBe(second[0].min); expect(first[0].max).toBe(second[0].max); }); }); });