diff --git a/frontend/app/components/auth/auth.spec.tsx b/frontend/app/components/auth/auth.spec.tsx index 5a2d205e..f5db67b8 100644 --- a/frontend/app/components/auth/auth.spec.tsx +++ b/frontend/app/components/auth/auth.spec.tsx @@ -211,4 +211,42 @@ describe('', () => { expect(getByRole('presentation')).toHaveAttribute('aria-label', 'Loading...'); await waitFor(() => expect(api.anonymousSignin).toBeCalled()); }); + + it.each` + value | expected + ${'username '} | ${'username'} + ${' username'} | ${'username'} + ${' username '} | ${'username'} + `('should remove spaces in the first/last postion in username', async ({ value, expected }) => { + StaticStore.config.auth_providers = ['email']; + + const { getByText, getByPlaceholderText } = render(); + fireEvent.click(getByText('Sign In')); + + const input = getByPlaceholderText('Username'); + + fireEvent.change(input, { target: { value } }); + fireEvent.blur(input); + + expect(input).toHaveValue(expected); + }); + + it.each` + value | expected + ${'user name '} | ${'user name'} + ${' user name'} | ${'user name'} + ${' user name '} | ${'user name'} + `('should leave spaces in the middle of username', ({ value, expected }) => { + StaticStore.config.auth_providers = ['email']; + + const { getByText, getByPlaceholderText } = render(); + fireEvent.click(getByText('Sign In')); + + const input = getByPlaceholderText('Username'); + + fireEvent.change(input, { target: { value } }); + fireEvent.blur(input); + + expect(input).toHaveValue(expected); + }); }); diff --git a/frontend/app/components/auth/auth.tsx b/frontend/app/components/auth/auth.tsx index b09c75ac..94f5ef73 100644 --- a/frontend/app/components/auth/auth.tsx +++ b/frontend/app/components/auth/auth.tsx @@ -233,10 +233,14 @@ export default function Auth() { required name="username" minLength={3} - pattern="^[\p{L}\d_]+$" + pattern="[\p{L}\d\s_]+" title={intl.formatMessage(messages.usernameRestriction)} placeholder={intl.formatMessage(messages.username)} disabled={isLoading} + onBlur={(evt) => { + const element = evt.target as HTMLInputElement; + element.value = element.value.trim(); + }} /> {view === 'email' && (