import { getLocalVue } from "@tests/vitest/helpers"; import { mount } from "@vue/test-utils"; import flushPromises from "flush-promises"; import { describe, expect, it, vi } from "vitest"; import { useServerMock } from "@/api/client/__mocks__"; import pageTemplate from "@/components/PageDisplay/pageTemplate.yml"; import PageForm from "./PageForm.vue"; const { server, http } = useServerMock(); const localVue = getLocalVue(); const mockPush = vi.fn(); vi.mock("vue-router/composables", () => ({ useRouter: () => ({ push: (...args) => mockPush(...args), }), })); function mountTarget(props = {}) { return mount(PageForm, { localVue, propsData: props, stubs: { FontAwesomeIcon: true, BButton: true, BAlert: true, }, directives: { localize: () => {}, }, }); } describe("PageForm.vue - Create mode", () => { it("renders loading spinner when fetching report", async () => { server.use( http.get("/api/invocations/:invocation_id/report", ({ response }) => response(200).json({ id: 42, title: "Invoked Report Title", invocation_markdown: "## Report Content", }), ), ); server.use( http.post("/api/pages", async ({ request, response }) => { const body = await request.json(); expect(body.title).toBe("Invoked Report Title"); expect(body.slug).toBe("invocation-42"); expect(body.annotation).toBe(""); expect(body.content).toBe("## Report Content"); return response(200).json({ id: "new-page-321" }); }), ); const wrapper = mountTarget({ mode: "create", invocationId: "42" }); expect(wrapper.findComponent({ name: "LoadingSpan" }).exists()).toBe(true); await flushPromises(); expect(wrapper.findComponent({ name: "LoadingSpan" }).exists()).toBe(false); expect(wrapper.find("#page-title").element.value).toBe("Invoked Report Title"); expect(wrapper.find("#page-slug").element.value).toBe("invocation-42"); await wrapper.find("#page-submit").trigger("click"); await flushPromises(); expect(mockPush).toHaveBeenCalledWith("/pages/editor?id=new-page-321"); }); it("shows error alert if fetching report fails", async () => { server.use( http.get("/api/invocations/:invocation_id/report", ({ response }) => response(500).json({ err_msg: "Failed to fetch report" }), ), ); const wrapper = mountTarget({ mode: "create", invocationId: "fail" }); await flushPromises(); const alert = wrapper.findComponent({ name: "BAlert" }); expect(alert.exists()).toBe(true); expect(alert.text()).toContain("Failed to fetch report"); }); it("shows validation error when required fields are missing on submit", async () => { const wrapper = mountTarget({ mode: "create" }); await flushPromises(); await wrapper.find("#page-submit").trigger("click"); await flushPromises(); const alert = wrapper.findComponent({ name: "BAlert" }); expect(alert.exists()).toBe(true); expect(alert.text()).toContain("Please complete all required inputs."); }); it("submits page creation with correct fields", async () => { server.use( http.post("/api/pages", async ({ request, response }) => { const body = await request.json(); expect(body.title).toBe("My Title"); expect(body.slug).toBe("my-title"); expect(body.annotation).toBe("An annotation"); expect(body.content).toBe(pageTemplate.content); return response(200).json({ id: "new-page-123" }); }), ); const wrapper = mountTarget({ mode: "create" }); await flushPromises(); await wrapper.find("#page-title").setValue("My Title"); await wrapper.find("#page-slug").setValue("my-title"); await wrapper.find("#page-annotation").setValue("An annotation"); await wrapper.find("#page-submit").trigger("click"); await flushPromises(); expect(mockPush).toHaveBeenCalledWith("/pages/editor?id=new-page-123"); }); it("shows API error if creation fails", async () => { server.use(http.post("/api/pages", ({ response }) => response(400).json({ err_msg: "Creation failed" }))); const wrapper = mountTarget({ mode: "create" }); await flushPromises(); await wrapper.find("#page-title").setValue("Some Title"); await wrapper.find("#page-slug").setValue("some-title"); await wrapper.find("#page-submit").trigger("click"); await flushPromises(); const alert = wrapper.findComponent({ name: "BAlert" }); expect(alert.exists()).toBe(true); expect(alert.text()).toContain("Creation failed"); }); }); describe("PageForm.vue - Edit mode", () => { it("renders loading spinner and fetches page details", async () => { server.use( http.get("/api/pages/:id", ({ response }) => response(200).json({ id: "123", title: "Test Page", slug: "test-page", annotation: "Testing page edit", content: "## Sample Content", }), ), ); const wrapper = mountTarget({ mode: "edit", id: "123" }); expect(wrapper.findComponent({ name: "LoadingSpan" }).exists()).toBe(true); await flushPromises(); expect(wrapper.find("#page-title").element.value).toBe("Test Page"); expect(wrapper.find("#page-slug").element.value).toBe("test-page"); expect(wrapper.find("#page-annotation").element.value).toBe("Testing page edit"); }); it("shows error alert if fetching page fails", async () => { server.use(http.get("/api/pages/:id", ({ response }) => response(500).json({ err_msg: "Page load failed" }))); const wrapper = mountTarget({ mode: "edit", id: "error-id" }); await flushPromises(); const alert = wrapper.findComponent({ name: "BAlert" }); expect(alert.exists()).toBe(true); expect(alert.text()).toContain("Page load failed"); }); it("shows validation error if required fields are missing on update", async () => { const wrapper = mountTarget({ mode: "edit", id: "123" }); await flushPromises(); await wrapper.find("#page-submit").trigger("click"); await flushPromises(); const alert = wrapper.findComponent({ name: "BAlert" }); expect(alert.exists()).toBe(true); expect(alert.text()).toContain("Please complete all required inputs."); }); it("submits page update with correct fields", async () => { server.use( http.put("/api/pages/:id", async ({ request, response }) => { const body = await request.json(); expect(body.title).toBe("Updated Title"); expect(body.slug).toBe("updated-title"); expect(body.annotation).toBe("Updated annotation"); return response(200).json({}); }), ); const wrapper = mountTarget({ mode: "edit", id: "456" }); await flushPromises(); await wrapper.find("#page-title").setValue("Updated Title"); await wrapper.find("#page-slug").setValue("updated-title"); await wrapper.find("#page-annotation").setValue("Updated annotation"); await wrapper.find("#page-submit").trigger("click"); await flushPromises(); expect(mockPush).toHaveBeenCalledWith("/pages/list"); }); it("shows API error if update fails", async () => { server.use(http.put("/api/pages/:id", ({ response }) => response(400).json({ err_msg: "Update failed" }))); const wrapper = mountTarget({ mode: "edit", id: "789" }); await flushPromises(); await wrapper.find("#page-title").setValue("Error Title"); await wrapper.find("#page-slug").setValue("error-title"); await wrapper.find("#page-submit").trigger("click"); await flushPromises(); const alert = wrapper.findComponent({ name: "BAlert" }); expect(alert.exists()).toBe(true); expect(alert.text()).toContain("Update failed"); }); });