Migrate Vitest store tests from vi.mock to MSW request handlers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,9 @@
|
||||
|
||||
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";
|
||||
|
||||
// Mock modules that have deep import chains (router, Swal, pinia, toast)
|
||||
vi.mock("@/module/apiError.js", () => ({
|
||||
@@ -26,16 +29,6 @@ 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", () => {
|
||||
@@ -45,7 +38,7 @@ describe("filesStore", () => {
|
||||
setActivePinia(createPinia());
|
||||
store = useFilesStore();
|
||||
store.$router = { push: vi.fn() };
|
||||
vi.clearAllMocks();
|
||||
document.cookie = "luciaToken=fake-test-token";
|
||||
});
|
||||
|
||||
it("has correct default state", () => {
|
||||
@@ -72,29 +65,33 @@ describe("filesStore", () => {
|
||||
|
||||
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,
|
||||
},
|
||||
],
|
||||
});
|
||||
server.use(
|
||||
http.get("/api/files", ({ request }) => {
|
||||
captureRequest("GET", new URL(request.url).pathname);
|
||||
return HttpResponse.json([
|
||||
{
|
||||
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");
|
||||
const reqs = findRequest("GET", "/api/files");
|
||||
expect(reqs).toHaveLength(1);
|
||||
expect(store.allEventFiles).toHaveLength(2);
|
||||
expect(store.allEventFiles[0].fileType).toBe("Log");
|
||||
expect(store.allEventFiles[0].icon).toBe("work_history");
|
||||
@@ -105,29 +102,35 @@ describe("filesStore", () => {
|
||||
});
|
||||
|
||||
it("does not throw on API failure", async () => {
|
||||
mockGet.mockRejectedValue(new Error("Network error"));
|
||||
server.use(
|
||||
http.get("/api/files", () =>
|
||||
new HttpResponse(null, { status: 500 }),
|
||||
),
|
||||
);
|
||||
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,
|
||||
},
|
||||
],
|
||||
});
|
||||
server.use(
|
||||
http.get("/api/files", () =>
|
||||
HttpResponse.json([
|
||||
{
|
||||
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();
|
||||
|
||||
@@ -139,18 +142,18 @@ describe("filesStore", () => {
|
||||
|
||||
describe("upload", () => {
|
||||
it("uploads file and navigates to Upload page", async () => {
|
||||
mockPost.mockResolvedValue({ data: { id: 42 } });
|
||||
server.use(
|
||||
http.post("/api/logs/csv-uploads", async ({ request }) => {
|
||||
captureRequest("POST", new URL(request.url).pathname);
|
||||
return HttpResponse.json({ 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" },
|
||||
}),
|
||||
);
|
||||
const reqs = findRequest("POST", "/api/logs/csv-uploads");
|
||||
expect(reqs).toHaveLength(1);
|
||||
expect(store.uploadId).toBe(42);
|
||||
expect(store.$router.push).toHaveBeenCalledWith({ name: "Upload" });
|
||||
});
|
||||
@@ -159,56 +162,76 @@ describe("filesStore", () => {
|
||||
describe("getUploadDetail", () => {
|
||||
it("fetches upload preview", async () => {
|
||||
store.uploadId = 10;
|
||||
mockGet.mockResolvedValue({
|
||||
data: { preview: { columns: ["a", "b"] } },
|
||||
});
|
||||
server.use(
|
||||
http.get("/api/logs/csv-uploads/:id", ({ request }) => {
|
||||
captureRequest("GET", new URL(request.url).pathname);
|
||||
return HttpResponse.json({ preview: { columns: ["a", "b"] } });
|
||||
}),
|
||||
);
|
||||
|
||||
await store.getUploadDetail();
|
||||
|
||||
expect(mockGet).toHaveBeenCalledWith("/api/logs/csv-uploads/10");
|
||||
const reqs = findRequest("GET", "/api/logs/csv-uploads/10");
|
||||
expect(reqs).toHaveLength(1);
|
||||
expect(store.allUploadDetail).toEqual({ columns: ["a", "b"] });
|
||||
});
|
||||
});
|
||||
|
||||
describe("rename", () => {
|
||||
it("renames a log file", async () => {
|
||||
mockPut.mockResolvedValue({});
|
||||
mockGet.mockResolvedValue({ data: [] });
|
||||
server.use(
|
||||
http.put("/api/logs/:id/name", async ({ request, params }) => {
|
||||
const body = await request.json();
|
||||
captureRequest("PUT", `/api/logs/${params.id}/name`, body);
|
||||
return HttpResponse.json({});
|
||||
}),
|
||||
http.get("/api/files", () => HttpResponse.json([])),
|
||||
);
|
||||
|
||||
await store.rename("log", 5, "new-name");
|
||||
|
||||
expect(mockPut).toHaveBeenCalledWith("/api/logs/5/name", {
|
||||
name: "new-name",
|
||||
});
|
||||
const reqs = findRequest("PUT", "/api/logs/5/name");
|
||||
expect(reqs).toHaveLength(1);
|
||||
expect(reqs[0].body).toEqual({ name: "new-name" });
|
||||
});
|
||||
});
|
||||
|
||||
describe("getDependents", () => {
|
||||
it("fetches dependents for a log", async () => {
|
||||
mockGet.mockResolvedValue({ data: [{ id: 1 }, { id: 2 }] });
|
||||
server.use(
|
||||
http.get("/api/logs/:id/dependents", ({ request }) => {
|
||||
captureRequest("GET", new URL(request.url).pathname);
|
||||
return HttpResponse.json([{ id: 1 }, { id: 2 }]);
|
||||
}),
|
||||
);
|
||||
|
||||
await store.getDependents("log", 7);
|
||||
|
||||
expect(mockGet).toHaveBeenCalledWith("/api/logs/7/dependents");
|
||||
const reqs = findRequest("GET", "/api/logs/7/dependents");
|
||||
expect(reqs).toHaveLength(1);
|
||||
expect(store.allDependentsData).toEqual([{ id: 1 }, { id: 2 }]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("deleteFile", () => {
|
||||
it("calls mockDelete before fetchAllFiles", async () => {
|
||||
it("calls delete before fetchAllFiles", async () => {
|
||||
const callOrder = [];
|
||||
mockDelete.mockImplementation(async () => {
|
||||
callOrder.push("delete");
|
||||
return {};
|
||||
});
|
||||
mockGet.mockImplementation(async () => {
|
||||
callOrder.push("get");
|
||||
return { data: [] };
|
||||
});
|
||||
server.use(
|
||||
http.delete("/api/logs/:id", ({ params }) => {
|
||||
callOrder.push("delete");
|
||||
captureRequest("DELETE", `/api/logs/${params.id}`);
|
||||
return HttpResponse.json({});
|
||||
}),
|
||||
http.get("/api/files", () => {
|
||||
callOrder.push("get");
|
||||
return HttpResponse.json([]);
|
||||
}),
|
||||
);
|
||||
|
||||
await store.deleteFile("log", 1);
|
||||
|
||||
expect(mockDelete).toHaveBeenCalledWith("/api/logs/1");
|
||||
const reqs = findRequest("DELETE", "/api/logs/1");
|
||||
expect(reqs).toHaveLength(1);
|
||||
expect(callOrder.indexOf("delete")).toBeLessThan(
|
||||
callOrder.indexOf("get"),
|
||||
);
|
||||
@@ -219,7 +242,6 @@ describe("filesStore", () => {
|
||||
|
||||
await expect(store.deleteFile("log", null)).resolves.toBeUndefined();
|
||||
|
||||
expect(mockDelete).not.toHaveBeenCalled();
|
||||
expect(spy).toHaveBeenCalledWith("Delete File API Error: invalid id");
|
||||
spy.mockRestore();
|
||||
});
|
||||
@@ -227,31 +249,44 @@ describe("filesStore", () => {
|
||||
|
||||
describe("deletionRecord", () => {
|
||||
it("deletes a deletion record", async () => {
|
||||
mockDelete.mockResolvedValue({});
|
||||
server.use(
|
||||
http.delete("/api/deletion/:id", ({ params }) => {
|
||||
captureRequest("DELETE", `/api/deletion/${params.id}`);
|
||||
return HttpResponse.json({});
|
||||
}),
|
||||
);
|
||||
|
||||
await store.deletionRecord(5);
|
||||
|
||||
expect(mockDelete).toHaveBeenCalledWith("/api/deletion/5");
|
||||
const reqs = findRequest("DELETE", "/api/deletion/5");
|
||||
expect(reqs).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("downloadFileCSV", () => {
|
||||
it("downloads CSV for a log", async () => {
|
||||
mockGet.mockResolvedValue({ data: "col1,col2\na,b" });
|
||||
server.use(
|
||||
http.get("/api/logs/:id/csv", ({ request }) => {
|
||||
captureRequest("GET", new URL(request.url).pathname);
|
||||
return new HttpResponse("col1,col2\na,b");
|
||||
}),
|
||||
);
|
||||
|
||||
globalThis.URL.createObjectURL = vi.fn().mockReturnValue("blob:test");
|
||||
globalThis.URL.revokeObjectURL = vi.fn();
|
||||
|
||||
await store.downloadFileCSV("log", 3, "my-file");
|
||||
|
||||
expect(mockGet).toHaveBeenCalledWith("/api/logs/3/csv");
|
||||
const reqs = findRequest("GET", "/api/logs/3/csv");
|
||||
expect(reqs).toHaveLength(1);
|
||||
expect(globalThis.URL.revokeObjectURL).toHaveBeenCalledWith("blob:test");
|
||||
});
|
||||
|
||||
it("returns early for unsupported type", async () => {
|
||||
await store.downloadFileCSV("log-check", 3, "file");
|
||||
|
||||
expect(mockGet).not.toHaveBeenCalled();
|
||||
const reqs = findRequest("GET", /\/api\/.*\/csv/);
|
||||
expect(reqs).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user