diff --git a/packages/editor-ui/src/components/AssignmentCollection/AssignmentCollection.vue b/packages/editor-ui/src/components/AssignmentCollection/AssignmentCollection.vue index fb13948302d30..24545bd7b9085 100644 --- a/packages/editor-ui/src/components/AssignmentCollection/AssignmentCollection.vue +++ b/packages/editor-ui/src/components/AssignmentCollection/AssignmentCollection.vue @@ -98,10 +98,10 @@ function getIssues(index: number): string[] { return issues.value[`${props.parameter.name}.${index}`] ?? []; } -function optionSelected(action: 'clearAll' | 'addAll') { +function optionSelected(action: string) { if (action === 'clearAll') { state.paramValue.assignments = []; - } else { + } else if (action === 'addAll' && inputData.value) { const newAssignments = inputDataToAssignments(inputData.value); state.paramValue.assignments = state.paramValue.assignments.concat(newAssignments); } diff --git a/packages/editor-ui/src/components/ParameterOptions.test.ts b/packages/editor-ui/src/components/ParameterOptions.test.ts new file mode 100644 index 0000000000000..e3984d6e50642 --- /dev/null +++ b/packages/editor-ui/src/components/ParameterOptions.test.ts @@ -0,0 +1,123 @@ +import { renderComponent } from '@/__tests__/render'; +import userEvent from '@testing-library/user-event'; +import { within } from '@testing-library/vue'; +import { waitFor } from '@testing-library/vue'; +import ParameterOptions from './ParameterOptions.vue'; + +const DEFAULT_PARAMETER = { + displayName: 'Fields to Set', + name: 'assignments', + type: 'assignmentCollection', + default: {}, +}; + +describe('ParameterOptions', () => { + it('renders default options properly', () => { + const { getByTestId } = renderComponent(ParameterOptions, { + props: { + parameter: DEFAULT_PARAMETER, + isReadOnly: false, + }, + }); + expect(getByTestId('parameter-options-container')).toBeInTheDocument(); + expect(getByTestId('action-toggle')).toBeInTheDocument(); + expect(getByTestId('radio-button-fixed')).toBeInTheDocument(); + expect(getByTestId('radio-button-expression')).toBeInTheDocument(); + }); + + it("doesn't render expression with showExpression set to false", () => { + const { getByTestId, queryByTestId, container } = renderComponent(ParameterOptions, { + props: { + parameter: DEFAULT_PARAMETER, + isReadOnly: false, + showExpressionSelector: false, + value: 'manual', + }, + }); + expect(getByTestId('parameter-options-container')).toBeInTheDocument(); + expect(getByTestId('action-toggle')).toBeInTheDocument(); + expect(queryByTestId('radio-button-fixed')).not.toBeInTheDocument(); + expect(queryByTestId('radio-button-expression')).not.toBeInTheDocument(); + expect(container.querySelector('.noExpressionSelector')).toBeInTheDocument(); + }); + + it('should render loading state', () => { + const CUSTOM_LOADING_MESSAGE = 'Loading...'; + const { getByTestId, getByText } = renderComponent(ParameterOptions, { + props: { + parameter: DEFAULT_PARAMETER, + isReadOnly: false, + showExpressionSelector: false, + value: 'manual', + loading: true, + loadingMessage: CUSTOM_LOADING_MESSAGE, + }, + }); + expect(getByTestId('parameter-options-loader')).toBeInTheDocument(); + expect(getByText(CUSTOM_LOADING_MESSAGE)).toBeInTheDocument(); + }); + + it('should render horizontal icon', () => { + const { container } = renderComponent(ParameterOptions, { + props: { + parameter: DEFAULT_PARAMETER, + value: 'manual', + isReadOnly: false, + iconOrientation: 'horizontal', + }, + }); + expect(container.querySelector('[data-icon="ellipsis-h"]')).toBeInTheDocument(); + }); + + it('should render custom actions', async () => { + const CUSTOM_ACTIONS = [ + { label: 'Action 1', value: 'action1' }, + { label: 'Action 2', value: 'action2' }, + ]; + const { getByTestId } = renderComponent(ParameterOptions, { + props: { + parameter: DEFAULT_PARAMETER, + value: 'manual', + isReadOnly: false, + customActions: CUSTOM_ACTIONS, + }, + }); + const actionToggle = getByTestId('action-toggle'); + const actionToggleButton = within(actionToggle).getByRole('button'); + expect(actionToggleButton).toBeVisible(); + await userEvent.click(actionToggle); + const actionToggleId = actionToggleButton.getAttribute('aria-controls'); + const actionDropdown = document.getElementById(actionToggleId as string) as HTMLElement; + expect(actionDropdown).toBeInTheDocument(); + // All custom actions should be rendered + CUSTOM_ACTIONS.forEach((action) => { + expect(within(actionDropdown).getByText(action.label)).toBeInTheDocument(); + }); + }); + + it('should emit update:modelValue when changing to expression', async () => { + const { emitted, getByTestId } = renderComponent(ParameterOptions, { + props: { + parameter: DEFAULT_PARAMETER, + value: 'manual', + isReadOnly: false, + }, + }); + expect(getByTestId('radio-button-expression')).toBeInTheDocument(); + await userEvent.click(getByTestId('radio-button-expression')); + await waitFor(() => expect(emitted('update:modelValue')).toEqual([['addExpression']])); + }); + + it('should emit update:modelValue when changing to fixed', async () => { + const { emitted, getByTestId } = renderComponent(ParameterOptions, { + props: { + parameter: DEFAULT_PARAMETER, + value: '=manual', + isReadOnly: false, + }, + }); + expect(getByTestId('radio-button-fixed')).toBeInTheDocument(); + await userEvent.click(getByTestId('radio-button-fixed')); + await waitFor(() => expect(emitted('update:modelValue')).toEqual([['removeExpression']])); + }); +}); diff --git a/packages/editor-ui/src/components/ParameterOptions.vue b/packages/editor-ui/src/components/ParameterOptions.vue index bfe99398055cc..10c3759324ca1 100644 --- a/packages/editor-ui/src/components/ParameterOptions.vue +++ b/packages/editor-ui/src/components/ParameterOptions.vue @@ -1,169 +1,134 @@ - diff --git a/packages/editor-ui/src/components/ResourceMapper/MatchingColumnsSelect.vue b/packages/editor-ui/src/components/ResourceMapper/MatchingColumnsSelect.vue index 7a40e244003d1..e663190c951e3 100644 --- a/packages/editor-ui/src/components/ResourceMapper/MatchingColumnsSelect.vue +++ b/packages/editor-ui/src/components/ResourceMapper/MatchingColumnsSelect.vue @@ -187,6 +187,7 @@ defineExpose({ :loading="props.refreshInProgress" :loading-message="fetchingFieldsLabel" :is-read-only="isReadOnly" + :value="state.selected" @update:model-value="onParameterActionSelected" />