fix(editor): Quick fix to password change form validation (#16565)

This commit is contained in:
Csaba Tuncsik
2025-06-23 11:09:56 +02:00
committed by GitHub
parent 20e2d8e36f
commit ef28d25ba2
3 changed files with 95 additions and 9 deletions

View File

@@ -0,0 +1,84 @@
import userEvent from '@testing-library/user-event';
import { createComponentRenderer } from '@n8n/design-system/__tests__/render';
import N8nFormInput from '.';
const renderComponent = createComponentRenderer(N8nFormInput);
describe('N8nFormInput', () => {
it('should render correctly with label and placeholder', () => {
const { getByRole, container } = renderComponent({
props: {
modelValue: 'test',
label: 'Test Label',
placeholder: 'Enter text',
},
});
expect(getByRole('textbox')).toHaveValue('test');
expect(getByRole('textbox')).toHaveAttribute('placeholder', 'Enter text');
expect(container.querySelector('label')).toHaveTextContent('Test Label');
});
it('should validate required', async () => {
const { getByRole, emitted, rerender } = renderComponent({
props: {
modelValue: '',
label: 'Test Label',
required: true,
},
});
expect(emitted('validate')).toEqual([[false]]);
const input = getByRole('textbox');
expect(input).toHaveValue('');
await userEvent.type(input, 'test');
await userEvent.tab();
// Re-render to comply with controlled component behavior
await rerender({
modelValue: 'test',
label: 'Test Label',
required: true,
});
expect(input).toHaveValue('test');
expect(emitted('validate')).toEqual([[false], [true]]);
await userEvent.clear(input);
await userEvent.tab();
// Re-render to comply with controlled component behavior
await rerender({
modelValue: '',
label: 'Test Label',
required: true,
});
expect(emitted('validate')).toEqual([[false], [true], [false]]);
});
it('should emit error even with missing or empty error message', async () => {
const { emitted } = renderComponent({
props: {
modelValue: 'test',
label: 'Test Label',
required: true,
showValidationWarnings: true,
validators: {
MY_VALIDATION: {
validate: (value: string) => {
if (value === 'test') {
return { messageKey: 'key.noTestAllowed' };
}
return false;
},
},
},
validationRules: [{ name: 'MY_VALIDATION' }],
},
});
expect(emitted('validate')).toEqual([[false]]);
});
});

View File

@@ -142,14 +142,18 @@ function onEnter(event: Event) {
emit('enter'); emit('enter');
} }
const validationError = computed<string | null>(() => { const validationError = computed<{ message: string } | null>(() => {
const error = getInputValidationError(); const error = getInputValidationError();
if (error) { if (error) {
if ('messageKey' in error) { if ('messageKey' in error) {
return t(error.messageKey, error.options); return {
} else if ('message' in error) { message: t(error.messageKey, error.options),
return error.message; };
} else {
return {
message: error.message,
};
} }
} }
@@ -170,10 +174,7 @@ onMounted(() => {
if (props.focusInitially && inputRef.value) inputRef.value.focus(); if (props.focusInitially && inputRef.value) inputRef.value.focus();
}); });
watch( watch(validationError, (error) => emit('validate', !error));
() => validationError.value,
(error) => emit('validate', !error),
);
defineExpose({ inputRef }); defineExpose({ inputRef });
</script> </script>
@@ -259,7 +260,7 @@ defineExpose({ inputRef });
/> />
</div> </div>
<div v-if="showErrors" :class="$style.errors"> <div v-if="showErrors" :class="$style.errors">
<span v-text="validationError" /> <span v-text="validationError?.message" />
<n8n-link <n8n-link
v-if="documentationUrl && documentationText" v-if="documentationUrl && documentationText"
:to="documentationUrl" :to="documentationUrl"

View File

@@ -66,4 +66,5 @@ export default {
'iconPicker.tabs.icons': 'Icons', 'iconPicker.tabs.icons': 'Icons',
'iconPicker.tabs.emojis': 'Emojis', 'iconPicker.tabs.emojis': 'Emojis',
'selectableList.addDefault': '+ Add a', 'selectableList.addDefault': '+ Add a',
'auth.changePassword.passwordsMustMatchError': 'Passwords must match',
} as N8nLocale; } as N8nLocale;