From ad2b36117f5844ad7e8bf58028542f413a1e30e8 Mon Sep 17 00:00:00 2001 From: Csaba Tuncsik Date: Tue, 4 Mar 2025 15:21:54 +0100 Subject: [PATCH] test(editor): Add node execute button tests --- .../src/components/NodeExecuteButton.test.ts | 109 ++++++++++++++++++ .../src/components/NodeExecuteButton.vue | 43 +++---- 2 files changed, 127 insertions(+), 25 deletions(-) create mode 100644 packages/frontend/editor-ui/src/components/NodeExecuteButton.test.ts diff --git a/packages/frontend/editor-ui/src/components/NodeExecuteButton.test.ts b/packages/frontend/editor-ui/src/components/NodeExecuteButton.test.ts new file mode 100644 index 0000000000..6dea949378 --- /dev/null +++ b/packages/frontend/editor-ui/src/components/NodeExecuteButton.test.ts @@ -0,0 +1,109 @@ +import { reactive } from 'vue'; +import { createTestingPinia } from '@pinia/testing'; +import userEvent from '@testing-library/user-event'; +import { createComponentRenderer } from '@/__tests__/render'; +import { type MockedStore, mockedStore } from '@/__tests__/utils'; +import { mockNode } from '@/__tests__/mocks'; +import { CODE_NODE_TYPE } from '@/constants'; +import NodeExecuteButton from '@/components/NodeExecuteButton.vue'; +import { useWorkflowsStore } from '@/stores/workflows.store'; +import { useUIStore } from '@/stores/ui.store'; +import { useNodeTypesStore } from '@/stores/nodeTypes.store'; + +vi.mock('vue-router', () => ({ + useRouter: () => ({}), + useRoute: () => reactive({}), + RouterLink: vi.fn(), +})); + +let renderComponent: ReturnType; +let workflowsStore: MockedStore; +let uiStore: MockedStore; +let nodeTypesStore: MockedStore; + +describe('NodeExecuteButton', () => { + beforeEach(() => { + renderComponent = createComponentRenderer(NodeExecuteButton, { + pinia: createTestingPinia(), + }); + + workflowsStore = mockedStore(useWorkflowsStore); + uiStore = mockedStore(useUIStore); + nodeTypesStore = mockedStore(useNodeTypesStore); + }); + + it('renders without error', () => { + expect(() => + renderComponent({ + props: { + nodeName: 'test', + telemetrySource: 'test', + }, + }), + ).not.toThrow(); + }); + + it('should be disabled if the node is disabled and show tooltip', async () => { + workflowsStore.getNodeByName.mockReturnValue( + mockNode({ name: 'test', type: CODE_NODE_TYPE, disabled: true }), + ); + + const { getByRole, queryByRole } = renderComponent({ + props: { + nodeName: 'test', + telemetrySource: 'test', + }, + }); + + const button = getByRole('button'); + expect(button).toBeDisabled(); + expect(queryByRole('tooltip')).not.toBeInTheDocument(); + + await userEvent.hover(button); + expect(getByRole('tooltip')).toBeVisible(); + expect(getByRole('tooltip')).toHaveTextContent('Enable node to execute'); + }); + + it('should be disabled when workflow is running but node is not executing', async () => { + uiStore.isActionActive.workflowRunning = true; + workflowsStore.isNodeExecuting.mockReturnValue(false); + workflowsStore.getNodeByName.mockReturnValue(mockNode({ name: 'test', type: CODE_NODE_TYPE })); + + const { getByRole, queryByRole } = renderComponent({ + props: { + nodeName: 'test', + telemetrySource: 'test', + }, + }); + + const button = getByRole('button'); + expect(button).toBeDisabled(); + expect(queryByRole('tooltip')).not.toBeInTheDocument(); + + await userEvent.hover(button); + expect(getByRole('tooltip')).toBeVisible(); + expect(getByRole('tooltip')).toHaveTextContent('Workflow is already running'); + }); + + it('disables button when trigger node has issues', async () => { + nodeTypesStore.isTriggerNode = () => true; + workflowsStore.getNodeByName.mockReturnValue( + mockNode({ + name: 'test', + type: CODE_NODE_TYPE, + issues: { + typeUnknown: true, + }, + }), + ); + + const { getByRole } = renderComponent({ + props: { + nodeName: 'test', + telemetrySource: 'test', + }, + }); + + expect(getByRole('button')).toBeDisabled(); + }); +}); diff --git a/packages/frontend/editor-ui/src/components/NodeExecuteButton.vue b/packages/frontend/editor-ui/src/components/NodeExecuteButton.vue index ea11462dd6..a807fdde94 100644 --- a/packages/frontend/editor-ui/src/components/NodeExecuteButton.vue +++ b/packages/frontend/editor-ui/src/components/NodeExecuteButton.vue @@ -26,7 +26,7 @@ import { useUIStore } from '@/stores/ui.store'; import { useRouter } from 'vue-router'; import { useI18n } from '@/composables/useI18n'; import { useTelemetry } from '@/composables/useTelemetry'; -import { type IUpdateInformation } from '../Interface'; +import { type IUpdateInformation } from '@/Interface'; import { generateCodeForAiTransform } from '@/components/ButtonParameter/utils'; const NODE_TEST_STEP_POPUP_COUNT_KEY = 'N8N_NODE_TEST_STEP_POPUP_COUNT'; @@ -367,28 +367,21 @@ async function onClick() {