-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add jest for importing a workflow in
WorkflowInvocationHeader
- Loading branch information
1 parent
6b057d7
commit 552d135
Showing
1 changed file
with
69 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"; | ||
|
@@ -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, | ||
|
@@ -53,7 +83,7 @@ async function mountWorkflowRunButton(ownsWorkflow = true, hasReturnBtn = false) | |
const userStore = useUserStore(); | ||
userStore.currentUser = { | ||
id: "1", | ||
email: "", | ||
email: "[email protected]", | ||
tags_used: [], | ||
isAnonymous: false, | ||
total_disk_usage: 0, | ||
|
@@ -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}"`); | ||
|
@@ -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( | ||
|
@@ -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); | ||
}); | ||
}); |