import { getLocalVue } from "@tests/vitest/helpers"; import { mount, type Wrapper } from "@vue/test-utils"; import flushPromises from "flush-promises"; import { describe, expect, it } from "vitest"; import { type CleanableItem, CleanableSummary, type CleanupOperation, CleanupResult } from "./model"; import ReviewCleanupDialog from "./ReviewCleanupDialog.vue"; const localVue = getLocalVue(); const REVIEW_TABLE = '[data-test-id="review-table"]'; const DELETE_BUTTON = '[data-test-id="delete-button"]'; const SELECT_ALL_CHECKBOX = '[data-test-id="select-all-checkbox"]'; const AGREEMENT_CHECKBOX = '[data-test-id="agreement-checkbox"]'; const CONFIRMATION_MODAL = "#confirmation-modal"; const EXPECTED_ITEMS: CleanableItem[] = [ { id: "1", name: "Item 1", size: 512, type: "dataset", update_time: new Date().toISOString() }, { id: "2", name: "Item 2", size: 512, type: "dataset", update_time: new Date().toISOString() }, ]; const EXPECTED_TOTAL_ITEMS = EXPECTED_ITEMS.length; const FAKE_OPERATION: CleanupOperation = { id: "operation-id", name: "operation name", description: "operation description", fetchSummary: async () => new CleanableSummary({ total_size: 1024, total_items: EXPECTED_TOTAL_ITEMS, }), fetchItems: async () => EXPECTED_ITEMS, cleanupItems: async () => new CleanupResult( { total_item_count: EXPECTED_TOTAL_ITEMS, success_item_count: EXPECTED_TOTAL_ITEMS, total_free_bytes: 1024, errors: [], }, EXPECTED_ITEMS, ), }; async function mountReviewCleanupDialogWith(operation: CleanupOperation, totalItems = EXPECTED_TOTAL_ITEMS) { const wrapper = mount(ReviewCleanupDialog as object, { propsData: { operation, totalItems, modalStatic: true }, localVue, }); await flushPromises(); return wrapper; } async function setAllItemsChecked(wrapper: Wrapper) { await wrapper.find(SELECT_ALL_CHECKBOX).setChecked(); await flushPromises(); } describe("ReviewCleanupDialog.vue", () => { it("should display a table with items to review", async () => { const wrapper = await mountReviewCleanupDialogWith(FAKE_OPERATION); (wrapper.vm as any).openModal(); await flushPromises(); expect(wrapper.find(REVIEW_TABLE).exists()).toBe(true); expect(wrapper.findAll("tbody > tr").length).toBe(EXPECTED_TOTAL_ITEMS); }); it("should disable the delete button if no items are selected", async () => { const wrapper = await mountReviewCleanupDialogWith(FAKE_OPERATION); const deleteButton = wrapper.find(DELETE_BUTTON); expect(deleteButton.attributes().disabled).toBeTruthy(); // TODO: explicit any because the type of the vm is not correctly inferred, remove when fixed expect((wrapper.vm as any).selectedItems.length).toBe(0); await setAllItemsChecked(wrapper); // TODO: explicit any because the type of the vm is not correctly inferred, remove when fixed expect((wrapper.vm as any).selectedItems.length).toBe(EXPECTED_TOTAL_ITEMS); expect(deleteButton.attributes().disabled).toBeFalsy(); }); it("should show a confirmation message when deleting items", async () => { const wrapper = await mountReviewCleanupDialogWith(FAKE_OPERATION); await setAllItemsChecked(wrapper); const confirmationModal = wrapper.find(CONFIRMATION_MODAL); expect(confirmationModal.attributes("aria-hidden")).toBeTruthy(); await wrapper.find(DELETE_BUTTON).trigger("click"); expect(confirmationModal.attributes("aria-hidden")).toBeFalsy(); }); it("should disable the confirmation button until the agreement has been accepted", async () => { const wrapper = await mountReviewCleanupDialogWith(FAKE_OPERATION); await setAllItemsChecked(wrapper); await wrapper.find(DELETE_BUTTON).trigger("click"); const allButtons = wrapper.findAll(".btn"); const permanentlyDeleteBtn = withNameFilter(allButtons.wrappers).hasText("Permanently delete").at(0)!; expect(permanentlyDeleteBtn.attributes().disabled).toBeTruthy(); await wrapper.find(AGREEMENT_CHECKBOX).setChecked(); expect(permanentlyDeleteBtn.attributes().disabled).toBeFalsy(); }); it("should emit the confirmation event when the agreement and deletion has been confirmed", async () => { const wrapper = await mountReviewCleanupDialogWith(FAKE_OPERATION); await setAllItemsChecked(wrapper); await wrapper.find(DELETE_BUTTON).trigger("click"); await wrapper.find(AGREEMENT_CHECKBOX).setChecked(); const allButtons = wrapper.findAll(".btn"); const permanentlyDeleteBtn = withNameFilter(allButtons.wrappers).hasText("Permanently delete").at(0)!; expect(wrapper.emitted().onConfirmCleanupSelectedItems).toBeFalsy(); await permanentlyDeleteBtn.trigger("click"); expect(wrapper.emitted().onConfirmCleanupSelectedItems).toBeTruthy(); expect(wrapper.emitted().onConfirmCleanupSelectedItems?.length).toBe(1); }); // From: https://github.com/vuejs/vue-test-utils/issues/960#issuecomment-626327505 function withNameFilter(wrapperArray: Wrapper[]) { return { childSelectorHasText: (selector: string, str: string): Wrapper[] => wrapperArray.filter((i) => i.find(selector).text().match(str)), hasText: (str: string): Wrapper[] => wrapperArray.filter((i) => i.text().match(str)), }; } });