diff --git a/client/src/components/WorkflowInvocationState/WorkflowInvocationHeader.test.ts b/client/src/components/WorkflowInvocationState/WorkflowInvocationHeader.test.ts index b0ff5d2b050d..a0d325455b81 100644 --- a/client/src/components/WorkflowInvocationState/WorkflowInvocationHeader.test.ts +++ b/client/src/components/WorkflowInvocationState/WorkflowInvocationHeader.test.ts @@ -1,5 +1,6 @@ import { createTestingPinia } from "@pinia/testing"; import { shallowMount } from "@vue/test-utils"; +import flushPromises from "flush-promises"; import { getLocalVue } from "tests/jest/helpers"; import sampleInvocation from "@/components/Workflow/test/json/invocation.json"; @@ -10,12 +11,16 @@ import WorkflowInvocationHeader from "./WorkflowInvocationHeader.vue"; // Constants const WORKFLOW_OWNER = "test-user"; const OTHER_USER = "other-user"; +const UNIMPORTABLE_WORKFLOW_ID = "invalid-workflow-id"; +const UNIMPORTABLE_WORKFLOW_INSTANCE_ID = "invalid-instance-id"; const SAMPLE_WORKFLOW = { id: "workflow-id", name: "workflow-name", owner: WORKFLOW_OWNER, version: 1, }; +const IMPORT_ERROR_MESSAGE = "Failed to import workflow"; + const SELECTORS = { INVOKED_WORKFLOW_HEADING: "anonymous-stub[h1='true']", RETURN_TO_INVOCATIONS_LIST_BUTTON: "bbutton-stub[title='Return to Invocations List']", @@ -23,27 +28,52 @@ const SELECTORS = { EDIT_WORKFLOW_BUTTON: `bbutton-stub[title='Edit
${SAMPLE_WORKFLOW.name}']`, IMPORT_WORKFLOW_BUTTON: "anonymous-stub[title='Import this workflow']", RUN_WORKFLOW_BUTTON: `anonymous-stub[id='${SAMPLE_WORKFLOW.id}']`, + ALERT_MESSAGE: "balert-stub", }; -// Mock the workflow store to return the expected workflow data given the stored workflow ID +// Mock the copyWorkflow function for importing a workflow +jest.mock("components/Workflow/workflows.services", () => ({ + copyWorkflow: jest.fn().mockImplementation((workflowId: string) => { + if (workflowId === UNIMPORTABLE_WORKFLOW_ID) { + throw new Error(IMPORT_ERROR_MESSAGE); + } + return SAMPLE_WORKFLOW; + }), +})); + +// Mock the workflow store to return the sample workflow jest.mock("@/stores/workflowStore", () => { const originalModule = jest.requireActual("@/stores/workflowStore"); return { ...originalModule, useWorkflowStore: () => ({ ...originalModule.useWorkflowStore(), - getStoredWorkflowByInstanceId: jest.fn().mockImplementation(() => SAMPLE_WORKFLOW), - fetchWorkflowForInstanceId: jest.fn().mockImplementation(() => {}), + getStoredWorkflowByInstanceId: jest.fn().mockImplementation((instanceId: string) => { + if (instanceId === UNIMPORTABLE_WORKFLOW_INSTANCE_ID) { + return { ...SAMPLE_WORKFLOW, id: UNIMPORTABLE_WORKFLOW_ID }; + } + return SAMPLE_WORKFLOW; + }), }), }; }); const localVue = getLocalVue(); -async function mountWorkflowRunButton(ownsWorkflow = true, hasReturnBtn = false) { +/** + * Mounts the WorkflowInvocationHeader component with props/stores adjusted given the parameters + * @param ownsWorkflow Whether the user owns the workflow associated with the invocation + * @param hasReturnBtn Whether the component should have a return to invocations list button + * @param unimportableWorkflow Whether the workflow import should fail + * @returns The wrapper object + */ +async function mountWorkflowRunButton(ownsWorkflow = true, hasReturnBtn = false, unimportableWorkflow = false) { const wrapper = shallowMount(WorkflowInvocationHeader as object, { propsData: { - invocation: sampleInvocation, + invocation: { + ...sampleInvocation, + workflow_id: !unimportableWorkflow ? sampleInvocation.workflow_id : UNIMPORTABLE_WORKFLOW_INSTANCE_ID, + }, fromPanel: !hasReturnBtn, }, localVue, @@ -53,7 +83,7 @@ async function mountWorkflowRunButton(ownsWorkflow = true, hasReturnBtn = false) const userStore = useUserStore(); userStore.currentUser = { id: "1", - email: "", + email: "test@mail.test", tags_used: [], isAnonymous: false, total_disk_usage: 0, @@ -99,25 +129,32 @@ describe("WorkflowInvocationHeader renders", () => { }); }); -// describe("Importing a workflow in WorkflowInvocationHeader", () => { -// it("should show a confirmation dialog when the import is successful", async () => { -// const { wrapper } = await mountWorkflowRunButton(false); -// const actionsGroup = wrapper.find(SELECTORS.ACTIONS_BUTTON_GROUP); -// const importButton = actionsGroup.find(SELECTORS.IMPORT_WORKFLOW_BUTTON); -// // await importButton.trigger("click"); -// // await flushPromises(); - -// // Clicking doesn't work because the button is an anonymous-stub which has a child button -// // So we need to call the function the action="[Function]" event which is the attributes("action") of the anonymous-stub -// const action = importButton.attributes("action"); -// // await (action as any)(); -// // await flushPromises(); -// // logging action just gives [Function], print the actual function -// if (typeof action === "string") { -// console.log(action.toString()); -// } else { -// console.log("Action is not a string"); -// } -// console.log(wrapper.html()); -// }); -// }); +describe("Importing a workflow in WorkflowInvocationHeader", () => { + it("should show a confirmation dialog when the import is successful", async () => { + const { wrapper } = await mountWorkflowRunButton(false); + const actionsGroup = wrapper.find(SELECTORS.ACTIONS_BUTTON_GROUP); + const importButton = actionsGroup.find(SELECTORS.IMPORT_WORKFLOW_BUTTON); + + // Cannot `.trigger("click")` on `AsyncButton` because it is a stubbed custom component + await importButton.props().action(); + await flushPromises(); + + const alert = wrapper.find(SELECTORS.ALERT_MESSAGE); + expect(alert.attributes("variant")).toBe("info"); + expect(alert.text()).toContain(`Workflow ${SAMPLE_WORKFLOW.name} imported successfully`); + }); + + it("should show an error dialog when the import fails", async () => { + const { wrapper } = await mountWorkflowRunButton(false, false, true); + const actionsGroup = wrapper.find(SELECTORS.ACTIONS_BUTTON_GROUP); + const importButton = actionsGroup.find(SELECTORS.IMPORT_WORKFLOW_BUTTON); + + // Cannot `.trigger("click")` on `AsyncButton` because it is a stubbed custom component + await importButton.props().action(); + await flushPromises(); + + const alert = wrapper.find(SELECTORS.ALERT_MESSAGE); + expect(alert.attributes("variant")).toBe("danger"); + expect(alert.text()).toContain(IMPORT_ERROR_MESSAGE); + }); +});