diff --git a/packages/editor-ui/src/composables/useDataSchema.test.ts b/packages/editor-ui/src/composables/useDataSchema.test.ts index c359f60f57..3c685550c7 100644 --- a/packages/editor-ui/src/composables/useDataSchema.test.ts +++ b/packages/editor-ui/src/composables/useDataSchema.test.ts @@ -1,6 +1,16 @@ import jp from 'jsonpath'; import { useDataSchema } from '@/composables/useDataSchema'; -import type { Schema } from '@/Interface'; +import type { IExecutionResponse, INodeUi, Schema } from '@/Interface'; +import { setActivePinia } from 'pinia'; +import { createTestingPinia } from '@pinia/testing'; +import { + NodeConnectionType, + type INodeExecutionData, + type ITaskDataConnections, +} from 'n8n-workflow'; +import { useWorkflowsStore } from '@/stores/workflows.store'; + +vi.mock('@/stores/workflows.store'); describe('useDataSchema', () => { const getSchema = useDataSchema().getSchema; @@ -524,4 +534,118 @@ describe('useDataSchema', () => { expect(filterSchema(flatSchema, '')).toEqual(flatSchema); }); }); + describe('getNodeInputData', () => { + const getNodeInputData = useDataSchema().getNodeInputData; + + beforeEach(() => { + setActivePinia(createTestingPinia()); + }); + + afterEach(() => { + vi.clearAllMocks(); + }); + + const name = 'a'; + const makeMockData = (data: ITaskDataConnections | undefined, runDataKey?: string) => ({ + data: { + resultData: { + runData: { + [runDataKey ?? name]: [{ data, startTime: 0, executionTime: 0, source: [] }], + }, + }, + }, + }); + + const mockExecutionDataMarker = Symbol() as unknown as INodeExecutionData[]; + const Main = NodeConnectionType.Main; + + test.each< + [ + [Partial | null, number, number, Partial | null], + ReturnType, + ] + >([ + // + // Null / Out of Bounds Cases + // + [[null, 0, 0, null], []], + [[{ name }, 0, 0, null], []], + [[{ name }, 0, 0, { data: undefined }], []], + [[{ name }, 0, 0, { data: { resultData: { runData: {} } } }], []], + [[{ name }, 0, 0, { data: { resultData: { runData: { [name]: [] } } } }], []], + [[{ name }, 0, 0, makeMockData(undefined)], []], + [[{ name }, 1, 0, makeMockData({})], []], + [[{ name }, -1, 0, makeMockData({})], []], + [[{ name }, 0, 0, makeMockData({}, 'DIFFERENT_NAME')], []], + // getMainInputData cases + [[{ name }, 0, 0, makeMockData({ [Main]: [] })], []], + [[{ name }, 0, 0, makeMockData({ [Main]: [null] })], []], + [[{ name }, 0, 1, makeMockData({ [Main]: [null] })], []], + [[{ name }, 0, -1, makeMockData({ [Main]: [null] })], []], + [ + [{ name }, 0, 0, makeMockData({ [Main]: [mockExecutionDataMarker] })], + mockExecutionDataMarker, + ], + [ + [{ name }, 0, 0, makeMockData({ [Main]: [mockExecutionDataMarker, null] })], + mockExecutionDataMarker, + ], + [ + [{ name }, 0, 1, makeMockData({ [Main]: [null, mockExecutionDataMarker] })], + mockExecutionDataMarker, + ], + [ + [ + { name }, + 0, + 1, + makeMockData({ DIFFERENT_NAME: [], [Main]: [null, mockExecutionDataMarker] }), + ], + mockExecutionDataMarker, + ], + [ + [ + { name }, + 2, + 1, + { + data: { + resultData: { + runData: { + [name]: [ + { + startTime: 0, + executionTime: 0, + source: [], + }, + { + startTime: 0, + executionTime: 0, + source: [], + }, + { + data: { [Main]: [null, mockExecutionDataMarker] }, + startTime: 0, + executionTime: 0, + source: [], + }, + ], + }, + }, + }, + }, + ], + mockExecutionDataMarker, + ], + ])( + 'should return correct output %s', + ([node, runIndex, outputIndex, getWorkflowExecution], output) => { + vi.mocked(useWorkflowsStore).mockReturnValue({ + ...useWorkflowsStore(), + getWorkflowExecution: getWorkflowExecution as IExecutionResponse, + }); + expect(getNodeInputData(node as INodeUi, runIndex, outputIndex)).toEqual(output); + }, + ); + }); }); diff --git a/packages/editor-ui/src/composables/useDataSchema.ts b/packages/editor-ui/src/composables/useDataSchema.ts index 4e3d35d31e..8b20ab93fc 100644 --- a/packages/editor-ui/src/composables/useDataSchema.ts +++ b/packages/editor-ui/src/composables/useDataSchema.ts @@ -72,12 +72,13 @@ export function useDataSchema() { if ( !connectionsData?.hasOwnProperty(NodeConnectionType.Main) || connectionsData.main === undefined || - connectionsData.main.length < outputIndex || + outputIndex < 0 || + outputIndex >= connectionsData.main.length || connectionsData.main[outputIndex] === null ) { return []; } - return connectionsData.main[outputIndex] as INodeExecutionData[]; + return connectionsData.main[outputIndex]; } function getNodeInputData( @@ -100,11 +101,12 @@ export function useDataSchema() { } const runData = executionData.resultData.runData; - if (!runData?.[node.name]?.[runIndex].data || runData[node.name][runIndex].data === undefined) { + const taskData = runData?.[node.name]?.[runIndex]; + if (taskData?.data === undefined) { return []; } - return getMainInputData(runData[node.name][runIndex].data!, outputIndex); + return getMainInputData(taskData.data, outputIndex); } function getInputDataWithPinned(