import { getLocalVue } from "@tests/vitest/helpers"; import { mount } from "@vue/test-utils"; import flushPromises from "flush-promises"; import { createPinia } from "pinia"; import { beforeEach, expect, it } from "vitest"; import { useServerMock } from "@/api/client/__mocks__"; import { useHistoryStore } from "@/stores/historyStore"; import DatasetCopy from "./DatasetCopy.vue"; const { server, http } = useServerMock(); const localVue = getLocalVue(); const pinia = createPinia(); beforeEach(() => { server.resetHandlers(); }); function mountComponent() { const wrapper = mount(DatasetCopy, { localVue, directives: { localize: () => {} }, stubs: { RouterLink: { template: "" } }, pinia, }); const historyStore = useHistoryStore(); historyStore.setCurrentHistoryId("h1"); return wrapper; } async function setupBase(histories, contents) { server.use( http.get("/api/histories", ({ response }) => response(200).json(histories)), http.get("/api/histories/{history_id}", ({ params, response }) => response(200).json({ id: params.history_id, name: "H1" }), ), http.get("/api/histories/{history_id}/contents", ({ response }) => response(200).json(contents)), ); const wrapper = mountComponent(); await flushPromises(); const checkbox = wrapper.find("input[type='checkbox']"); await checkbox.setChecked(true); return wrapper; } it("loads histories and contents on mount", async () => { server.use( http.get("/api/histories", ({ response }) => response(200).json([ { id: "h1", name: "History One" }, { id: "h2", name: "History Two" }, ]), ), http.get("/api/histories/{history_id}", ({ params, response }) => response(200).json({ id: params.history_id, name: `History ${params.history_id}` }), ), http.get("/api/histories/{history_id}/contents", ({ response }) => response(200).json([ { id: "d1", name: "A", hid: 1, history_content_type: "dataset" }, { id: "d2", name: "B", hid: 2, history_content_type: "collection" }, ]), ), ); const wrapper = mountComponent(); await flushPromises(); expect(wrapper.text()).toContain("History One"); expect(wrapper.text()).toContain("History Two"); expect(wrapper.text()).toContain("A"); expect(wrapper.text()).toContain("B"); }); it("copies selected items and shows success", async () => { server.use( http.get("/api/histories", ({ response }) => response(200).json([{ id: "h1", name: "H1" }])), http.get("/api/histories/{history_id}", ({ params, response }) => response(200).json({ id: params.history_id, name: "H1" }), ), http.get("/api/histories/{history_id}/contents", ({ response }) => response(200).json([{ id: "d1", name: "X", hid: 1, history_content_type: "dataset" }]), ), http.post("/api/histories/{history_id}/copy_contents", async ({ request, response }) => { const body = await request.json(); if (body.source_content.length > 0) { return response(200).json({ history_ids: ["h1"] }); } return response(400).json({ err_msg: "No data" }); }), ); const wrapper = mountComponent(); await flushPromises(); const checkbox = wrapper.find("input[type='checkbox']"); await checkbox.setChecked(true); await wrapper.find("button.btn-primary").trigger("click"); await flushPromises(); expect(wrapper.text()).toMatch(/1 item[s]? copied/); }); it("shows error when nothing selected", async () => { server.use( http.get("/api/histories", ({ response }) => response(200).json([{ id: "h1", name: "H1" }])), http.get("/api/histories/{history_id}", ({ params, response }) => response(200).json({ id: params.history_id, name: "H1" }), ), http.get("/api/histories/{history_id}/contents", ({ response }) => response(200).json([])), ); const wrapper = mountComponent(); await flushPromises(); await wrapper.find("button.btn-primary").trigger("click"); await flushPromises(); expect(wrapper.text()).toContain("Please select datasets and collections."); }); it("handles API error from copy call", async () => { server.use( http.get("/api/histories", ({ response }) => response(200).json([{ id: "h1", name: "H1" }])), http.get("/api/histories/{history_id}", ({ params, response }) => response(200).json({ id: params.history_id, name: "H1" }), ), http.get("/api/histories/{history_id}/contents", ({ response }) => response(200).json([{ id: "d1", name: "X", hid: 1, history_content_type: "dataset" }]), ), http.post("/api/histories/{history_id}/copy_contents", ({ response }) => response(500).json({ err_msg: "Copy failed" }), ), ); const wrapper = mountComponent(); await flushPromises(); const checkbox = wrapper.find("input[type='checkbox']"); await checkbox.setChecked(true); await wrapper.find("button.btn-primary").trigger("click"); await flushPromises(); expect(wrapper.text()).toContain("Copy failed"); }); it("toggleAll selects and unselects all", async () => { server.use( http.get("/api/histories", ({ response }) => response(200).json([{ id: "h1", name: "H1" }])), http.get("/api/histories/{history_id}", ({ params, response }) => response(200).json({ id: params.history_id, name: "H1" }), ), http.get("/api/histories/{history_id}/contents", ({ response }) => response(200).json([ { id: "d1", name: "X", hid: 1, history_content_type: "dataset" }, { id: "d2", name: "Y", hid: 2, history_content_type: "dataset" }, ]), ), ); const wrapper = mountComponent(); await flushPromises(); const buttons = wrapper.findAll("button.btn-outline-primary"); await buttons.at(0).trigger("click"); await flushPromises(); const sel1 = wrapper.vm.sourceContentSelection?.value || wrapper.vm.sourceContentSelection; expect(sel1["dataset|d1"]).toBe(true); expect(sel1["dataset|d2"]).toBe(true); await buttons.at(1).trigger("click"); await flushPromises(); const sel2 = wrapper.vm.sourceContentSelection?.value || wrapper.vm.sourceContentSelection; expect(sel2["dataset|d1"]).toBe(false); expect(sel2["dataset|d2"]).toBe(false); }); it("shows success for single existing target", async () => { server.use( http.get("/api/histories", ({ response }) => response(200).json([{ id: "h1", name: "H1" }])), http.get("/api/histories/{history_id}", ({ params, response }) => response(200).json({ id: params.history_id, name: "H1" }), ), http.get("/api/histories/{history_id}/contents", ({ response }) => response(200).json([{ id: "d1", name: "X", hid: 1, history_content_type: "dataset" }]), ), http.post("/api/histories/{history_id}/copy_contents", ({ response }) => response(200).json({ history_ids: ["h1"] }), ), ); const wrapper = mountComponent(); await flushPromises(); const checkbox = wrapper.find("input[type='checkbox']"); await checkbox.setChecked(true); await wrapper.find("button.btn-primary").trigger("click"); await flushPromises(); expect(wrapper.text()).toMatch(/1 item[s]? copied to/); expect(wrapper.text()).toContain("H1"); }); it("shows success for multiple target histories", async () => { server.use( http.get("/api/histories", ({ response }) => response(200).json([ { id: "h1", name: "H1" }, { id: "h2", name: "H2" }, ]), ), http.get("/api/histories/{history_id}", ({ params, response }) => response(200).json({ id: params.history_id, name: `History ${params.history_id}` }), ), http.get("/api/histories/{history_id}/contents", ({ response }) => response(200).json([{ id: "d1", name: "X", hid: 1, history_content_type: "dataset" }]), ), http.post("/api/histories/{history_id}/copy_contents", ({ response }) => response(200).json({ history_ids: ["h1", "h2"] }), ), ); const wrapper = mountComponent(); await flushPromises(); const checkbox = wrapper.find("input[type='checkbox']"); await checkbox.setChecked(true); wrapper.vm.targetMultiSelections = { h1: true, h2: true }; await wrapper.vm.$nextTick(); await wrapper.find("button.btn-primary").trigger("click"); await flushPromises(); expect(wrapper.text()).toMatch(/1 item[s]? copied to/); expect(wrapper.text()).toContain("H1"); expect(wrapper.text()).toContain("H2"); }); it("shows success for new history creation", async () => { server.use( http.get("/api/histories", ({ response }) => response(200).json([{ id: "h1", name: "H1" }])), http.get("/api/histories/{history_id}", ({ params, response }) => response(200).json({ id: params.history_id, name: "H1" }), ), http.get("/api/histories/{history_id}/contents", ({ response }) => response(200).json([{ id: "d1", name: "X", hid: 1, history_content_type: "dataset" }]), ), http.post("/api/histories/{history_id}/copy_contents", ({ response }) => response(200).json({ history_ids: ["h2"] }), ), ); const wrapper = await setupBase( [{ id: "h1", name: "H1" }], [{ id: "d1", name: "X", hid: 1, history_content_type: "dataset" }], ); await wrapper.find("input[data-description='copy history name']").setValue("New History"); await wrapper.find("button.btn-primary").trigger("click"); await flushPromises(); expect(wrapper.text()).toContain("1 item copied to"); expect(wrapper.text()).toContain("New History"); });