Skip to content

Commit

Permalink
add jest for importing a workflow in WorkflowInvocationHeader
Browse files Browse the repository at this point in the history
  • Loading branch information
ahmedhamidawan committed Oct 3, 2024
1 parent 6b057d7 commit 552d135
Showing 1 changed file with 69 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -10,40 +11,69 @@ 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']",
ACTIONS_BUTTON_GROUP: "bbuttongroup-stub",
EDIT_WORKFLOW_BUTTON: `bbutton-stub[title='<b>Edit</b><br>${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 mountWorkflowInvocationHeader(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,
Expand All @@ -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,
Expand All @@ -66,7 +96,7 @@ async function mountWorkflowRunButton(ownsWorkflow = true, hasReturnBtn = false)
describe("WorkflowInvocationHeader renders", () => {
// Included both cases in one test because these are always constant
it("(always) the workflow name in header and run button in actions", async () => {
const { wrapper } = await mountWorkflowRunButton();
const { wrapper } = await mountWorkflowInvocationHeader();

const heading = wrapper.find(SELECTORS.INVOKED_WORKFLOW_HEADING);
expect(heading.text()).toBe(`Invoked Workflow: "${SAMPLE_WORKFLOW.name}"`);
Expand All @@ -77,13 +107,13 @@ describe("WorkflowInvocationHeader renders", () => {
});

it("return to invocations list button if not from panel", async () => {
const { wrapper } = await mountWorkflowRunButton(false, true);
const { wrapper } = await mountWorkflowInvocationHeader(false, true);
const returnButton = wrapper.find(SELECTORS.RETURN_TO_INVOCATIONS_LIST_BUTTON);
expect(returnButton.text()).toBe("Invocations List");
});

it("edit button if user owns the workflow", async () => {
const { wrapper } = await mountWorkflowRunButton();
const { wrapper } = await mountWorkflowInvocationHeader();
const actionsGroup = wrapper.find(SELECTORS.ACTIONS_BUTTON_GROUP);
const editButton = actionsGroup.find(SELECTORS.EDIT_WORKFLOW_BUTTON);
expect(editButton.attributes("to")).toBe(
Expand All @@ -92,32 +122,39 @@ describe("WorkflowInvocationHeader renders", () => {
});

it("import button instead if user does not own the workflow", async () => {
const { wrapper } = await mountWorkflowRunButton(false);
const { wrapper } = await mountWorkflowInvocationHeader(false);
const actionsGroup = wrapper.find(SELECTORS.ACTIONS_BUTTON_GROUP);
const importButton = actionsGroup.find(SELECTORS.IMPORT_WORKFLOW_BUTTON);
expect(importButton.exists()).toBe(true);
});
});

// 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 mountWorkflowInvocationHeader(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 mountWorkflowInvocationHeader(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);
});
});

0 comments on commit 552d135

Please sign in to comment.