diff --git a/src/register/RegistrationFailure.jsx b/src/register/RegistrationFailure.jsx index d53e6e5b..2a3de062 100644 --- a/src/register/RegistrationFailure.jsx +++ b/src/register/RegistrationFailure.jsx @@ -1,47 +1,55 @@ import React, { useEffect } from 'react'; import PropTypes from 'prop-types'; -import { FormattedMessage } from '@edx/frontend-platform/i18n'; +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; import { Alert } from '@edx/paragon'; - -const hasNoErrors = (userErrors) => ( - userErrors.every((errorList) => (!errorList[0])) -); +import { INTERNAL_SERVER_ERROR } from '../login/data/constants'; +import messages from './messages'; const RegistrationFailureMessage = (props) => { const errorMessage = props.errors; + const { errorCode } = props.errors; const userErrors = []; useEffect(() => { window.scrollTo({ left: 0, top: 0, behavior: 'smooth' }); }, [props.submitCount]); - Object.keys(errorMessage).forEach((key) => { - const errors = errorMessage[key]; - const errorList = errors.map((error) => ( - (error.user_message) ? ( -
  • - {error.user_message} + let serverError; + switch (errorCode) { + case INTERNAL_SERVER_ERROR: + serverError = ( +
  • + {props.intl.formatMessage(messages['registration.request.server.error'])}
  • - ) : null - )); - userErrors.push(errorList); - }); + ); + userErrors.push(serverError); + break; + + default: + Object.keys(errorMessage).forEach((key) => { + const errors = errorMessage[key]; + const errorList = errors.map((error) => ( + (error.user_message) ? ( +
  • + {error.user_message} +
  • + ) : null + )); + userErrors.push(errorList); + }); + } return ( - hasNoErrors(userErrors) ? null : ( + !userErrors.length ? null : ( - + {props.intl.formatMessage(messages['registration.request.failure.header'])} -
    - -
    + + +
    ) ); @@ -56,8 +64,10 @@ RegistrationFailureMessage.propTypes = { errors: PropTypes.shape({ email: PropTypes.array, username: PropTypes.array, + errorCode: PropTypes.string, }), submitCount: PropTypes.number, + intl: intlShape.isRequired, }; -export default RegistrationFailureMessage; +export default injectIntl(RegistrationFailureMessage); diff --git a/src/register/data/sagas.js b/src/register/data/sagas.js index f1c55427..00165df4 100644 --- a/src/register/data/sagas.js +++ b/src/register/data/sagas.js @@ -24,6 +24,7 @@ import { getRegistrationForm, registerRequest, } from './service'; +import { INTERNAL_SERVER_ERROR } from '../../login/data/constants'; export function* handleNewUserRegistration(action) { try { @@ -39,6 +40,8 @@ export function* handleNewUserRegistration(action) { const statusCodes = [400, 409, 403]; if (e.response && statusCodes.includes(e.response.status)) { yield put(registerNewUserFailure(e.response.data)); + } else { + yield put(registerNewUserFailure({ errorCode: INTERNAL_SERVER_ERROR })); } logError(e); } diff --git a/src/register/data/tests/sagas.test.js b/src/register/data/tests/sagas.test.js index a2d5457b..94cb83ee 100644 --- a/src/register/data/tests/sagas.test.js +++ b/src/register/data/tests/sagas.test.js @@ -1,5 +1,6 @@ import { runSaga } from 'redux-saga'; +import { camelCaseObject } from '@edx/frontend-platform'; import * as actions from '../actions'; import { fetchRealtimeValidations, @@ -188,6 +189,32 @@ describe('handleNewUserRegistration', () => { registerRequest.mockClear(); }); + it('should handle 500 error code', async () => { + const registerErrorResponse = { + response: { + status: 500, + data: { + errorCode: 'internal-server-error', + }, + }, + }; + + const registerRequest = jest.spyOn(api, 'registerRequest').mockImplementation(() => Promise.reject(registerErrorResponse)); + + const dispatched = []; + await runSaga( + { dispatch: (action) => dispatched.push(action) }, + handleNewUserRegistration, + params, + ); + + expect(dispatched).toEqual([ + actions.registerNewUserBegin(), + actions.registerNewUserFailure(camelCaseObject(registerErrorResponse.response.data)), + ]); + registerRequest.mockClear(); + }); + it('should call service and dispatch error action', async () => { const loginErrorResponse = { response: { diff --git a/src/register/messages.jsx b/src/register/messages.jsx index a3c60915..dcd892f8 100644 --- a/src/register/messages.jsx +++ b/src/register/messages.jsx @@ -116,6 +116,16 @@ const messages = defineMessages({ defaultMessage: '(optional)', description: 'Text that appears with optional field labels', }, + 'registration.request.server.error': { + id: 'registration.request.server.error', + defaultMessage: 'An error has occurred. Try refreshing the page, or check your Internet connection.', + description: 'error message on server error.', + }, + 'registration.request.failure.header': { + id: 'registration.request.failure.header', + defaultMessage: 'We couldn\'t create your account.', + description: 'error message when registration failure.', + }, }); export default messages; diff --git a/src/register/tests/RegistrationPage.test.jsx b/src/register/tests/RegistrationPage.test.jsx index 706324c1..0d02c4d6 100644 --- a/src/register/tests/RegistrationPage.test.jsx +++ b/src/register/tests/RegistrationPage.test.jsx @@ -9,7 +9,9 @@ import * as analytics from '@edx/frontend-platform/analytics'; import RegistrationPage from '../RegistrationPage'; import { RenderInstitutionButton } from '../../common-components'; +import RegistrationFailureMessage from '../RegistrationFailure'; import { PENDING_STATE } from '../../data/constants'; +import { INTERNAL_SERVER_ERROR } from '../../login/data/constants'; import { fetchRegistrationForm, fetchRealtimeValidations, registerNewUser } from '../data/actions'; jest.mock('@edx/frontend-platform/analytics'); @@ -18,6 +20,7 @@ analytics.sendTrackEvent = jest.fn(); analytics.sendPageEvent = jest.fn(); const IntlRegistrationPage = injectIntl(RegistrationPage); +const IntlRegistrationFailure = injectIntl(RegistrationFailureMessage); const mockStore = configureStore(); describe('./RegistrationPage.js', () => { @@ -326,6 +329,19 @@ describe('./RegistrationPage.js', () => { expect(tree.toJSON()).toMatchSnapshot(); }); + it('should match internal server error message', () => { + props = { + errors: { + errorCode: INTERNAL_SERVER_ERROR, + }, + }; + + const registrationPage = mount(reduxWrapper()); + expect(registrationPage.find('div.alert-heading').length).toEqual(1); + const expectedMessage = 'We couldn\'t create your account.An error has occurred. Try refreshing the page, or check your Internet connection.'; + expect(registrationPage.find('div.alert').first().text()).toEqual(expectedMessage); + }); + it('should match pending button state snapshot', () => { store = mockStore({ ...initialState, diff --git a/src/register/tests/__snapshots__/RegistrationPage.test.jsx.snap b/src/register/tests/__snapshots__/RegistrationPage.test.jsx.snap index bd5603d9..e6b8da4b 100644 --- a/src/register/tests/__snapshots__/RegistrationPage.test.jsx.snap +++ b/src/register/tests/__snapshots__/RegistrationPage.test.jsx.snap @@ -976,24 +976,20 @@ exports[`./RegistrationPage.js should show error message on 409 1`] = `
    - - We couldn't create your account. - -
    -
    - + We couldn't create your account.
    +