Files
frontend-app-authn/src/register/RegistrationFields/EmailField/EmailField.test.jsx
2025-08-07 10:50:11 -05:00

237 lines
8.2 KiB
JavaScript

import { Provider } from 'react-redux';
import { getConfig } from '@edx/frontend-platform';
import { IntlProvider } from '@edx/frontend-platform/i18n';
import { fireEvent, render } from '@testing-library/react';
import { BrowserRouter as Router } from 'react-router-dom';
import configureStore from 'redux-mock-store';
import { clearRegistrationBackendError, fetchRealtimeValidations } from '../../data/actions';
import { EmailField } from '../index';
const mockStore = configureStore();
jest.mock('react-router-dom', () => {
const mockNavigation = jest.fn();
// eslint-disable-next-line react/prop-types
const Navigate = ({ to }) => {
mockNavigation(to);
return <div />;
};
return {
...jest.requireActual('react-router-dom'),
Navigate,
mockNavigate: mockNavigation,
};
});
describe('EmailField', () => {
let props = {};
let store = {};
const reduxWrapper = children => (
<IntlProvider locale="en">
<Provider store={store}>{children}</Provider>
</IntlProvider>
);
const routerWrapper = children => (
<Router>
{children}
</Router>
);
const initialState = {
register: {
registrationFormData: {
emailSuggestion: {
suggestion: 'example@gmail.com',
type: 'warning',
},
},
},
};
beforeEach(() => {
store = mockStore(initialState);
props = {
name: 'email',
value: '',
errorMessage: '',
handleChange: jest.fn(),
floatingLabel: '',
handleErrorChange: jest.fn(),
confirmEmailValue: '',
};
window.location = { search: '' };
});
afterEach(() => {
jest.clearAllMocks();
});
describe('Test Email Field', () => {
const emptyFieldValidation = {
email: 'Enter your email',
};
it('should run email field validation when onBlur is fired', () => {
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
const emailInput = container.querySelector('input#email');
fireEvent.blur(emailInput, { target: { value: '', name: 'email' } });
expect(props.handleErrorChange).toHaveBeenCalledTimes(1);
expect(props.handleErrorChange).toHaveBeenCalledWith(
'email',
emptyFieldValidation.email,
);
});
it('should update errors for frontend validations', () => {
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
const emailInput = container.querySelector('input#email');
fireEvent.blur(emailInput, { target: { value: 'ab', name: 'email' } });
expect(props.handleErrorChange).toHaveBeenCalledTimes(1);
expect(props.handleErrorChange).toHaveBeenCalledWith(
'email',
'Enter a valid email address',
);
});
it('should clear error on focus', () => {
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
const emailInput = container.querySelector('input#email');
fireEvent.focus(emailInput, { target: { value: '', name: 'email' } });
expect(props.handleErrorChange).toHaveBeenCalledTimes(1);
expect(props.handleErrorChange).toHaveBeenCalledWith(
'email',
'',
);
});
it('should call backend validation api on blur event, if frontend validations have passed', () => {
store.dispatch = jest.fn(store.dispatch);
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
// Enter a valid email so that frontend validations are passed
const emailInput = container.querySelector('input#email');
fireEvent.blur(emailInput, { target: { value: 'test@gmail.com', name: 'email' } });
expect(store.dispatch).toHaveBeenCalledWith(fetchRealtimeValidations({ email: 'test@gmail.com' }));
});
it('should give email suggestions for common service provider domain typos', () => {
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
const emailInput = container.querySelector('input#email');
fireEvent.blur(emailInput, { target: { value: 'john@yopmail.com', name: 'email' } });
const emailWarning = container.querySelector('#email-warning');
expect(emailWarning.textContent).toEqual('Did you mean: john@hotmail.com?');
});
it('should be able to click on email suggestions and set it as value', () => {
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
const emailInput = container.querySelector('input#email');
fireEvent.blur(emailInput, { target: { value: 'john@yopmail.com', name: 'email' } });
const emailSuggestion = container.querySelector('.email-suggestion-alert-warning');
fireEvent.click(emailSuggestion);
expect(props.handleChange).toHaveBeenCalledTimes(1);
expect(props.handleChange).toHaveBeenCalledWith(
{ target: { name: 'email', value: 'john@hotmail.com' } },
);
});
it('should give error for common top level domain mistakes', () => {
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
const emailInput = container.querySelector('input#email');
fireEvent.blur(emailInput, { target: { value: 'john@gmail.mistake', name: 'email' } });
const errorElement = container.querySelector('.alert-danger');
expect(errorElement.textContent).toEqual('Did you mean john@gmail.com?');
});
it('should give error and suggestion for invalid email', () => {
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
const emailInput = container.querySelector('input#email');
fireEvent.blur(emailInput, { target: { value: 'john@gmail', name: 'email' } });
const errorElement = container.querySelector('.alert-danger');
expect(errorElement.textContent).toEqual('Did you mean john@gmail.com?');
expect(props.handleErrorChange).toHaveBeenCalledTimes(1);
expect(props.handleErrorChange).toHaveBeenCalledWith(
'email',
'Enter a valid email address',
);
});
it('should clear the registration validation error on focus on field', () => {
store.dispatch = jest.fn(store.dispatch);
store = mockStore({
...initialState,
register: {
...initialState.register,
registrationError: {
errorCode: 'duplicate-email',
email: [{ userMessage: `This email is already associated with an existing or previous ${ getConfig().SITE_NAME } account` }],
},
},
});
store.dispatch = jest.fn(store.dispatch);
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
const emailInput = container.querySelector('input#email');
fireEvent.focus(emailInput, { target: { value: 'a@gmail.com', name: 'email' } });
expect(store.dispatch).toHaveBeenCalledWith(clearRegistrationBackendError('email'));
});
it('should clear email suggestions when close icon is clicked', () => {
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
const emailInput = container.querySelector('input#email');
fireEvent.blur(emailInput, { target: { value: 'john@gmail.mistake', name: 'email' } });
const suggestionText = container.querySelector('.alert-danger');
expect(suggestionText.textContent).toEqual('Did you mean john@gmail.com?');
const closeButton = container.querySelector('.email-suggestion__close');
fireEvent.click(closeButton);
const closedSuggestionText = container.querySelector('.alert-danger');
expect(closedSuggestionText).toBeNull();
});
it('should set confirm email error if it exist', () => {
props = {
...props,
confirmEmailValue: 'confirmEmail@yopmail.com',
};
const { container } = render(routerWrapper(reduxWrapper(<EmailField {...props} />)));
const emailInput = container.querySelector('input#email');
fireEvent.blur(emailInput, { target: { value: 'differentEmail@yopmail.com', name: 'email' } });
expect(props.handleErrorChange).toHaveBeenCalledTimes(1);
expect(props.handleErrorChange).toHaveBeenCalledWith(
'confirm_email',
'The email addresses do not match.',
);
});
});
});