From 91fee0ca667f233c0bde0dc6089bbed7d7db5b5f Mon Sep 17 00:00:00 2001 From: Csaba Tuncsik Date: Thu, 4 May 2023 12:04:23 +0200 Subject: [PATCH] fix(editor): Remove duplicate mapping of `item.json` key in data pinning (#6135) * fix(editor): Remove duplicate mapping of `item.json` key in data pinning * fix(editor): Remove duplicate mapping of `item.json` key in data pinning * fix(editor): Remove duplicate mapping of `item.json` key in data pinning * test(editor): Unit test the fix of duplicate mapping of `item.json` key in data pinning --- packages/editor-ui/src/components/RunData.vue | 6 +- .../src/components/__tests__/RunData.test.ts | 164 ++++++++++++++++++ 2 files changed, 166 insertions(+), 4 deletions(-) create mode 100644 packages/editor-ui/src/components/__tests__/RunData.test.ts diff --git a/packages/editor-ui/src/components/RunData.vue b/packages/editor-ui/src/components/RunData.vue index 41b3291afb..8c61488ff4 100644 --- a/packages/editor-ui/src/components/RunData.vue +++ b/packages/editor-ui/src/components/RunData.vue @@ -1062,16 +1062,14 @@ export default mixins(externalHooks, genericHelpers, nodeHelpers, pinData).exten return; } - const data = executionDataToJson(this.rawInputData) as INodeExecutionData[]; - - if (!this.isValidPinDataSize(data)) { + if (!this.isValidPinDataSize(this.inputData)) { this.onDataPinningError({ errorType: 'data-too-large', source: 'pin-icon-click' }); return; } this.onDataPinningSuccess({ source: 'pin-icon-click' }); - this.workflowsStore.pinData({ node: this.node, data }); + this.workflowsStore.pinData({ node: this.node, data: this.inputData }); if (this.maxRunIndex > 0) { this.$showToast({ diff --git a/packages/editor-ui/src/components/__tests__/RunData.test.ts b/packages/editor-ui/src/components/__tests__/RunData.test.ts new file mode 100644 index 0000000000..f6e16fb004 --- /dev/null +++ b/packages/editor-ui/src/components/__tests__/RunData.test.ts @@ -0,0 +1,164 @@ +import type Vue from 'vue'; +import { defineComponent } from 'vue'; +import { PiniaVuePlugin } from 'pinia'; +import { render, waitFor } from '@testing-library/vue'; +import userEvent from '@testing-library/user-event'; +import { createTestingPinia } from '@pinia/testing'; +import { merge } from 'lodash-es'; +import RunData from '@/components/RunData.vue'; +import { STORES, VIEWS } from '@/constants'; +import { useSSOStore } from '@/stores/sso'; +import { SETTINGS_STORE_DEFAULT_STATE } from '@/__tests__/utils'; +import { externalHooks } from '@/mixins/externalHooks'; +import { genericHelpers } from '@/mixins/genericHelpers'; +import { pinData } from '@/mixins/pinData'; +import { useNDVStore, useWorkflowsStore } from '@/stores'; + +let pinia: ReturnType; +let ssoStore: ReturnType; +let workflowsStore: ReturnType; +let ndvStore: ReturnType; + +function TelemetryPlugin(vue: typeof Vue): void { + Object.defineProperty(vue, '$telemetry', { + get() { + return { + track: () => {}, + }; + }, + }); + Object.defineProperty(vue.prototype, '$telemetry', { + get() { + return { + track: () => {}, + }; + }, + }); +} + +const nodeHelpers = defineComponent({ + methods: { + getNodeInputData: vi.fn().mockReturnValue([ + { + json: { + id: 1, + name: 'Test 1', + json: { + data: 'Json data 1', + }, + }, + }, + { + json: { + id: 2, + name: 'Test 2', + json: { + data: 'Json data 2', + }, + }, + }, + ]), + }, +}); + +const renderComponent = (renderOptions: Parameters[1] = {}) => + render( + RunData, + merge( + { + pinia, + mocks: { + $route: { + name: VIEWS.WORKFLOW, + }, + }, + mixins: [externalHooks, genericHelpers, nodeHelpers, pinData], + }, + renderOptions, + ), + (vue) => { + vue.use(TelemetryPlugin); + vue.use(PiniaVuePlugin); + }, + ); + +describe('RunData', () => { + beforeEach(() => { + pinia = createTestingPinia({ + initialState: { + [STORES.SETTINGS]: { + settings: merge({}, SETTINGS_STORE_DEFAULT_STATE.settings), + }, + }, + }); + ssoStore = useSSOStore(); + workflowsStore = useWorkflowsStore(); + ndvStore = useNDVStore(); + + vi.spyOn(workflowsStore, 'getWorkflowExecution', 'get').mockReturnValue({ + id: '1', + finished: true, + mode: 'trigger', + startedAt: new Date(), + workflowData: { + id: '1', + name: 'Test Workflow', + versionId: '1', + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + active: false, + nodes: [], + connections: {}, + }, + data: { + resultData: { + runData: { + 'Test Node': [ + { + startTime: new Date().getTime(), + executionTime: new Date().getTime(), + data: {}, + source: [null], + }, + ], + }, + }, + }, + }); + }); + + afterEach(() => { + vi.clearAllMocks(); + }); + + it('should render data correctly even when "item.json" has another "json" key', async () => { + vi.spyOn(ndvStore, 'getPanelDisplayMode').mockReturnValue('schema'); + vi.spyOn(ndvStore, 'activeNode', 'get').mockReturnValue({ + id: '1', + typeVersion: 1, + name: 'Test Node', + position: [0, 0], + type: 'test', + parameters: {}, + }); + + const { getByText, getAllByTestId, getByTestId } = renderComponent({ + props: { + nodeUi: { + name: 'Test Node', + position: [0, 0], + }, + runIndex: 0, + paneType: 'output', + isExecuting: false, + mappingEnabled: true, + distanceFromActive: 0, + }, + }); + + await userEvent.click(getByTestId('ndv-pin-data')); + await waitFor(() => getAllByTestId('run-data-schema-item')); + expect(getByText('Test 1')).toBeInTheDocument(); + expect(getByText('Json data 1')).toBeInTheDocument(); + }); +});