diff --git a/packages/editor-ui/src/components/ExpressionEditModal.vue b/packages/editor-ui/src/components/ExpressionEditModal.vue index 934876f75e..08e3848c43 100644 --- a/packages/editor-ui/src/components/ExpressionEditModal.vue +++ b/packages/editor-ui/src/components/ExpressionEditModal.vue @@ -22,6 +22,7 @@ import DraggableTarget from './DraggableTarget.vue'; import { dropInExpressionEditor } from '@/plugins/codemirror/dragAndDrop'; import { APP_MODALS_ELEMENT_ID } from '@/constants'; +import { N8nInput, N8nText } from 'n8n-design-system'; type Props = { parameter: INodeProperties; diff --git a/packages/editor-ui/src/components/FixedCollectionParameter.test.ts b/packages/editor-ui/src/components/FixedCollectionParameter.test.ts new file mode 100644 index 0000000000..9438a5a78a --- /dev/null +++ b/packages/editor-ui/src/components/FixedCollectionParameter.test.ts @@ -0,0 +1,110 @@ +import { createComponentRenderer } from '@/__tests__/render'; +import { cleanupAppModals, createAppModals, SETTINGS_STORE_DEFAULT_STATE } from '@/__tests__/utils'; +import FixedCollectionParameter, { type Props } from '@/components/FixedCollectionParameter.vue'; +import { STORES } from '@/constants'; +import { createTestingPinia } from '@pinia/testing'; +import userEvent from '@testing-library/user-event'; +import { setActivePinia } from 'pinia'; +describe('FixedCollectionParameter.vue', () => { + const pinia = createTestingPinia({ + initialState: { + [STORES.SETTINGS]: { + settings: SETTINGS_STORE_DEFAULT_STATE.settings, + }, + }, + }); + setActivePinia(pinia); + + const props: Props = { + parameter: { + displayName: 'Routing Rules', + name: 'rules', + placeholder: 'Add Routing Rule', + type: 'fixedCollection', + typeOptions: { + multipleValues: true, + sortable: true, + }, + default: '', + options: [ + { + name: 'values', + displayName: 'Values', + values: [ + { + displayName: 'Output Name', + name: 'outputKey', + type: 'string', + default: 'Default Output Name', + }, + ], + }, + ], + }, + path: 'parameters.rules', + nodeValues: { + parameters: { + rules: { values: [{ outputKey: 'Test Output Name' }] }, + }, + }, + values: { + values: [{ outputKey: 'Test Output Name' }], + }, + isReadOnly: false, + }; + const renderComponent = createComponentRenderer(FixedCollectionParameter, { props }); + + beforeEach(() => { + createAppModals(); + }); + + afterEach(() => { + cleanupAppModals(); + }); + + it('renders the component', () => { + const { getByTestId } = renderComponent(); + expect(getByTestId('fixed-collection-rules')).toBeInTheDocument(); + expect(getByTestId('fixed-collection-add')).toBeInTheDocument(); + expect(getByTestId('fixed-collection-delete')).toBeInTheDocument(); + expect(getByTestId('parameter-item')).toBeInTheDocument(); + }); + + it('computes placeholder text correctly', () => { + const { getByTestId } = renderComponent(); + expect(getByTestId('fixed-collection-add')).toHaveTextContent('Add Routing Rule'); + }); + + it('emits valueChanged event on option creation', async () => { + const { getByTestId, emitted } = renderComponent(); + await userEvent.click(getByTestId('fixed-collection-add')); + expect(emitted('valueChanged')).toEqual([ + [ + { + name: 'parameters.rules.values', + value: [{ outputKey: 'Test Output Name' }, { outputKey: 'Default Output Name' }], + }, + ], + ]); + }); + + it('emits valueChanged event on option deletion', async () => { + const { getByTestId, emitted } = renderComponent({ + props: { + ...props, + values: { + values: [{ outputKey: 'Test' }], + }, + }, + }); + await userEvent.click(getByTestId('fixed-collection-delete')); + expect(emitted('valueChanged')).toEqual([ + [ + { + name: 'parameters.rules.values', + value: undefined, + }, + ], + ]); + }); +}); diff --git a/packages/editor-ui/src/components/FixedCollectionParameter.vue b/packages/editor-ui/src/components/FixedCollectionParameter.vue index 98c5ef5971..de7359dfdd 100644 --- a/packages/editor-ui/src/components/FixedCollectionParameter.vue +++ b/packages/editor-ui/src/components/FixedCollectionParameter.vue @@ -1,226 +1,236 @@ -