mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
fix(editor): Store last entered cURL command for each HTTP node (#17834)
This commit is contained in:
@@ -0,0 +1,157 @@
|
|||||||
|
import { createComponentRenderer } from '@/__tests__/render';
|
||||||
|
import ImportCurlModal from './ImportCurlModal.vue';
|
||||||
|
import { createTestingPinia } from '@pinia/testing';
|
||||||
|
import { IMPORT_CURL_MODAL_KEY } from '@/constants';
|
||||||
|
import { cleanupAppModals, createAppModals, mockedStore } from '@/__tests__/utils';
|
||||||
|
import { nextTick } from 'vue';
|
||||||
|
import { useUIStore } from '@/stores/ui.store';
|
||||||
|
import { useNDVStore } from '@/stores/ndv.store';
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
|
|
||||||
|
const mockTelemetryTrack = vi.fn();
|
||||||
|
vi.mock('@/composables/useTelemetry', () => ({
|
||||||
|
useTelemetry: () => ({
|
||||||
|
track: mockTelemetryTrack,
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock('@/composables/useImportCurlCommand', () => ({
|
||||||
|
useImportCurlCommand: (options: {
|
||||||
|
onImportSuccess: () => void;
|
||||||
|
onAfterImport: () => void;
|
||||||
|
}) => ({
|
||||||
|
importCurlCommand: () => {
|
||||||
|
options.onImportSuccess();
|
||||||
|
options.onAfterImport();
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
|
const renderModal = createComponentRenderer(ImportCurlModal, {
|
||||||
|
pinia: createTestingPinia(),
|
||||||
|
});
|
||||||
|
|
||||||
|
const testNode = {
|
||||||
|
id: 'node-1',
|
||||||
|
name: 'HTTP Request',
|
||||||
|
type: 'n8n-nodes-base.httpRequest',
|
||||||
|
position: [0, 0] as [number, number],
|
||||||
|
typeVersion: 1,
|
||||||
|
parameters: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('ImportCurlModal', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
vi.clearAllMocks();
|
||||||
|
createAppModals();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
cleanupAppModals();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show empty input when no curl command exists for active node', async () => {
|
||||||
|
const uiStore = mockedStore(useUIStore);
|
||||||
|
uiStore.modalsById = {
|
||||||
|
[IMPORT_CURL_MODAL_KEY]: {
|
||||||
|
open: true,
|
||||||
|
data: {
|
||||||
|
curlCommands: {
|
||||||
|
'node-2': 'curl -X GET https://api.example.com/data',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
uiStore.modalStack = [IMPORT_CURL_MODAL_KEY];
|
||||||
|
const ndvStore = mockedStore(useNDVStore);
|
||||||
|
ndvStore.activeNode = testNode;
|
||||||
|
|
||||||
|
const { getByTestId } = renderModal();
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
|
const input = getByTestId('import-curl-modal-input');
|
||||||
|
expect(input).toHaveValue('');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show curl command for active node', async () => {
|
||||||
|
const uiStore = mockedStore(useUIStore);
|
||||||
|
uiStore.modalsById = {
|
||||||
|
[IMPORT_CURL_MODAL_KEY]: {
|
||||||
|
open: true,
|
||||||
|
data: {
|
||||||
|
curlCommands: {
|
||||||
|
'node-1': 'curl -X GET https://api.example.com/data',
|
||||||
|
'node-2': 'curl -X POST https://api.example.com/submit',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
uiStore.modalStack = [IMPORT_CURL_MODAL_KEY];
|
||||||
|
const ndvStore = mockedStore(useNDVStore);
|
||||||
|
ndvStore.activeNode = testNode;
|
||||||
|
|
||||||
|
const { getByTestId } = renderModal();
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
|
const input = getByTestId('import-curl-modal-input');
|
||||||
|
expect(input).toHaveValue('curl -X GET https://api.example.com/data');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set the input value when the import button is clicked', async () => {
|
||||||
|
const uiStore = mockedStore(useUIStore);
|
||||||
|
uiStore.modalsById = {
|
||||||
|
[IMPORT_CURL_MODAL_KEY]: {
|
||||||
|
open: true,
|
||||||
|
data: {
|
||||||
|
curlCommands: {
|
||||||
|
'node-2': 'curl -X POST https://api.example.com/submit',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
uiStore.modalStack = [IMPORT_CURL_MODAL_KEY];
|
||||||
|
const ndvStore = mockedStore(useNDVStore);
|
||||||
|
ndvStore.activeNode = testNode;
|
||||||
|
|
||||||
|
const { getByTestId } = renderModal();
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
|
const input = getByTestId('import-curl-modal-input');
|
||||||
|
await userEvent.type(input, 'curl -X GET https://api.example.com/data');
|
||||||
|
const button = getByTestId('import-curl-modal-button');
|
||||||
|
await userEvent.click(button);
|
||||||
|
expect(uiStore.modalsById[IMPORT_CURL_MODAL_KEY].data?.curlCommands).toEqual({
|
||||||
|
'node-1': 'curl -X GET https://api.example.com/data',
|
||||||
|
'node-2': 'curl -X POST https://api.example.com/submit',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should override the input value when the import button is clicked', async () => {
|
||||||
|
const uiStore = mockedStore(useUIStore);
|
||||||
|
uiStore.modalsById = {
|
||||||
|
[IMPORT_CURL_MODAL_KEY]: {
|
||||||
|
open: true,
|
||||||
|
data: {
|
||||||
|
curlCommands: {
|
||||||
|
'node-1': 'curl -X GET https://api.example.com/data',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
uiStore.modalStack = [IMPORT_CURL_MODAL_KEY];
|
||||||
|
const ndvStore = mockedStore(useNDVStore);
|
||||||
|
ndvStore.activeNode = testNode;
|
||||||
|
|
||||||
|
const { getByTestId } = renderModal();
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
|
const input = getByTestId('import-curl-modal-input');
|
||||||
|
await userEvent.clear(input);
|
||||||
|
await userEvent.type(input, 'curl -X GET https://api.example.com/other');
|
||||||
|
const button = getByTestId('import-curl-modal-button');
|
||||||
|
await userEvent.click(button);
|
||||||
|
expect(uiStore.modalsById[IMPORT_CURL_MODAL_KEY].data?.curlCommands).toEqual({
|
||||||
|
'node-1': 'curl -X GET https://api.example.com/other',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -6,11 +6,13 @@ import { useUIStore } from '@/stores/ui.store';
|
|||||||
import { createEventBus } from '@n8n/utils/event-bus';
|
import { createEventBus } from '@n8n/utils/event-bus';
|
||||||
import { useTelemetry } from '@/composables/useTelemetry';
|
import { useTelemetry } from '@/composables/useTelemetry';
|
||||||
import { useI18n } from '@n8n/i18n';
|
import { useI18n } from '@n8n/i18n';
|
||||||
|
import { useNDVStore } from '@/stores/ndv.store';
|
||||||
|
|
||||||
const telemetry = useTelemetry();
|
const telemetry = useTelemetry();
|
||||||
const i18n = useI18n();
|
const i18n = useI18n();
|
||||||
|
|
||||||
const uiStore = useUIStore();
|
const uiStore = useUIStore();
|
||||||
|
const ndvStore = useNDVStore();
|
||||||
|
|
||||||
const curlCommand = ref('');
|
const curlCommand = ref('');
|
||||||
const modalBus = createEventBus();
|
const modalBus = createEventBus();
|
||||||
@@ -18,8 +20,13 @@ const modalBus = createEventBus();
|
|||||||
const inputRef = ref<HTMLTextAreaElement | null>(null);
|
const inputRef = ref<HTMLTextAreaElement | null>(null);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
curlCommand.value = (uiStore.modalsById[IMPORT_CURL_MODAL_KEY].data?.curlCommand as string) ?? '';
|
const curlCommands = uiStore.modalsById[IMPORT_CURL_MODAL_KEY].data?.curlCommands as Record<
|
||||||
|
string,
|
||||||
|
string
|
||||||
|
>;
|
||||||
|
const nodeId = ndvStore.activeNode?.id ?? '';
|
||||||
|
const command = curlCommands?.[nodeId];
|
||||||
|
curlCommand.value = command ?? '';
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
inputRef.value?.focus();
|
inputRef.value?.focus();
|
||||||
});
|
});
|
||||||
@@ -43,9 +50,13 @@ function onImportFailure(data: { invalidProtocol: boolean; protocol?: string })
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onAfterImport() {
|
function onAfterImport() {
|
||||||
|
const nodeId = ndvStore.activeNode?.id as string;
|
||||||
|
const curlCommands =
|
||||||
|
(uiStore.modalsById[IMPORT_CURL_MODAL_KEY].data?.curlCommands as Record<string, string>) ?? {};
|
||||||
|
curlCommands[nodeId] = curlCommand.value;
|
||||||
uiStore.setModalData({
|
uiStore.setModalData({
|
||||||
name: IMPORT_CURL_MODAL_KEY,
|
name: IMPORT_CURL_MODAL_KEY,
|
||||||
data: { curlCommand: curlCommand.value },
|
data: { curlCommands },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,6 +101,7 @@ async function onImport() {
|
|||||||
:model-value="curlCommand"
|
:model-value="curlCommand"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
:rows="5"
|
:rows="5"
|
||||||
|
data-test-id="import-curl-modal-input"
|
||||||
:placeholder="i18n.baseText('importCurlModal.input.placeholder')"
|
:placeholder="i18n.baseText('importCurlModal.input.placeholder')"
|
||||||
@update:model-value="onInput"
|
@update:model-value="onInput"
|
||||||
@focus="$event.target.select()"
|
@focus="$event.target.select()"
|
||||||
@@ -107,6 +119,7 @@ async function onImport() {
|
|||||||
<N8nButton
|
<N8nButton
|
||||||
float="right"
|
float="right"
|
||||||
:label="i18n.baseText('importCurlModal.button.label')"
|
:label="i18n.baseText('importCurlModal.button.label')"
|
||||||
|
data-test-id="import-curl-modal-button"
|
||||||
@click="onImport"
|
@click="onImport"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ export const useUIStore = defineStore(STORES.UI, () => {
|
|||||||
[IMPORT_CURL_MODAL_KEY]: {
|
[IMPORT_CURL_MODAL_KEY]: {
|
||||||
open: false,
|
open: false,
|
||||||
data: {
|
data: {
|
||||||
curlCommand: '',
|
curlCommands: {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[LOG_STREAM_MODAL_KEY]: {
|
[LOG_STREAM_MODAL_KEY]: {
|
||||||
|
|||||||
Reference in New Issue
Block a user