import React from 'react'; const {shallowWithIntl} = require('../../helpers/intl-helpers.jsx'); const defaults = require('lodash.defaultsdeep'); import configureStore from 'redux-mock-store'; import JoinFlow from '../../../src/components/join-flow/join-flow'; import Progression from '../../../src/components/progression/progression.jsx'; import RegistrationErrorStep from '../../../src/components/join-flow/registration-error-step'; describe('JoinFlow', () => { const mockStore = configureStore(); let store; const responseBodyMultipleErrs = [ { msg: 'This field is required.', errors: { username: ['This field is required.'], recaptcha: ['Incorrect, please try again.'] }, success: false } ]; const responseBodySingleErr = [ { msg: 'This field is required.', errors: { recaptcha: ['Incorrect, please try again.'] }, success: false } ]; const responseBodySuccess = [ { msg: 'This field is required.', errors: { recaptcha: ['Incorrect, please try again.'] }, success: true } ]; beforeEach(() => { store = mockStore({sessionActions: { refreshSessionWithRetry: jest.fn() }}); }); const getJoinFlowWrapper = props => { const wrapper = shallowWithIntl( <JoinFlow {...props} /> , {context: {store}} ); return wrapper .dive() // unwrap redux connect(injectIntl(JoinFlow)) .dive(); // unwrap injectIntl(JoinFlow) }; test('handleCaptchaError gives state with captcha message', () => { const joinFlowInstance = getJoinFlowWrapper().instance(); joinFlowInstance.setState({}); joinFlowInstance.handleCaptchaError(); expect(joinFlowInstance.state.registrationError).toEqual({ errorAllowsTryAgain: false, errorMsg: 'registration.errorCaptcha' }); }); test('sendAnalytics calls GTM with correct params', () => { const joinFlowInstance = getJoinFlowWrapper().instance(); global.window.dataLayer = {push: jest.fn()}; global.window.GA_ID = '1234'; joinFlowInstance.sendAnalytics('page-path'); expect(global.window.dataLayer.push).toHaveBeenCalledWith({ event: 'join_flow', joinFlowStep: 'page-path' }); }); test('handleAdvanceStep', () => { const joinFlowInstance = getJoinFlowWrapper().instance(); joinFlowInstance.setState({formData: {username: 'ScratchCat123'}, step: 2}); joinFlowInstance.handleAdvanceStep({email: 'scratchcat123@scratch.mit.edu'}); expect(joinFlowInstance.state.formData.username).toBe('ScratchCat123'); expect(joinFlowInstance.state.formData.email).toBe('scratchcat123@scratch.mit.edu'); expect(joinFlowInstance.state.step).toBe(3); }); test('when state.registrationError has error message, we show RegistrationErrorStep', () => { const joinFlowWrapper = getJoinFlowWrapper(); joinFlowWrapper.instance().setState({registrationError: 'halp there is a errors!!'}); const registrationErrorWrapper = joinFlowWrapper.find(RegistrationErrorStep); const progressionWrapper = joinFlowWrapper.find(Progression); expect(registrationErrorWrapper).toHaveLength(1); expect(progressionWrapper).toHaveLength(0); }); test('when state.registrationError has null error message, we show Progression', () => { const joinFlowWrapper = getJoinFlowWrapper(); joinFlowWrapper.instance().setState({registrationError: null}); const registrationErrorWrapper = joinFlowWrapper.find(RegistrationErrorStep); const progressionWrapper = joinFlowWrapper.find(Progression); expect(registrationErrorWrapper).toHaveLength(0); expect(progressionWrapper).toHaveLength(1); }); test('when state.registrationError has empty error message, we show Progression', () => { const joinFlowWrapper = getJoinFlowWrapper(); joinFlowWrapper.instance().setState({registrationError: ''}); const registrationErrorWrapper = joinFlowWrapper.find(RegistrationErrorStep); const progressionWrapper = joinFlowWrapper.find(Progression); expect(registrationErrorWrapper).toHaveLength(0); expect(progressionWrapper).toHaveLength(1); }); test('when numAttempts is 0 and registrationError errorAllowsTryAgain is true, ' + 'RegistrationErrorStep receives errorAllowsTryAgain prop with value true', () => { const joinFlowWrapper = getJoinFlowWrapper(); joinFlowWrapper.instance().setState({ numAttempts: 0, registrationError: { errorAllowsTryAgain: true, errorMsg: 'halp there is a errors!!' } }); const registrationErrorWrapper = joinFlowWrapper.find(RegistrationErrorStep); expect(registrationErrorWrapper.first().props().canTryAgain).toEqual(true); }); test('when numAttempts is 1 and registrationError errorAllowsTryAgain is true, ' + 'RegistrationErrorStep receives errorAllowsTryAgain prop with value true', () => { const joinFlowWrapper = getJoinFlowWrapper(); joinFlowWrapper.instance().setState({ numAttempts: 1, registrationError: { errorAllowsTryAgain: true, errorMsg: 'halp there is a errors!!' } }); const registrationErrorWrapper = joinFlowWrapper.find(RegistrationErrorStep); expect(registrationErrorWrapper.first().props().canTryAgain).toEqual(true); }); test('when numAttempts is 2 and registrationError errorAllowsTryAgain is true, ' + 'RegistrationErrorStep receives errorAllowsTryAgain prop with value false', () => { const joinFlowWrapper = getJoinFlowWrapper(); joinFlowWrapper.instance().setState({ numAttempts: 2, registrationError: { errorAllowsTryAgain: true, errorMsg: 'halp there is a errors!!' } }); const registrationErrorWrapper = joinFlowWrapper.find(RegistrationErrorStep); expect(registrationErrorWrapper.first().props().canTryAgain).toEqual(false); }); test('when numAttempts is 0 and registrationError errorAllowsTryAgain is false, ' + 'RegistrationErrorStep receives errorAllowsTryAgain prop with value false', () => { const joinFlowWrapper = getJoinFlowWrapper(); joinFlowWrapper.instance().setState({ numAttempts: 0, registrationError: { errorAllowsTryAgain: false, errorMsg: 'halp there is a errors!!' } }); const registrationErrorWrapper = joinFlowWrapper.find(RegistrationErrorStep); expect(registrationErrorWrapper.first().props().canTryAgain).toEqual(false); }); test('resetState resets entire state, does not leave any state keys out', () => { const joinFlowInstance = getJoinFlowWrapper().instance(); Object.keys(joinFlowInstance.state).forEach(key => { joinFlowInstance.setState({[key]: 'Different than the initial value'}); }); joinFlowInstance.resetState(); Object.keys(joinFlowInstance.state).forEach(key => { expect(joinFlowInstance.state[key]).not.toEqual('Different than the initial value'); }); }); test('resetState makes each state field match initial state', () => { const joinFlowInstance = getJoinFlowWrapper().instance(); const stateSnapshot = {}; Object.keys(joinFlowInstance.state).forEach(key => { stateSnapshot[key] = joinFlowInstance.state[key]; }); joinFlowInstance.resetState(); Object.keys(joinFlowInstance.state).forEach(key => { expect(stateSnapshot[key]).toEqual(joinFlowInstance.state[key]); }); }); test('calling resetState results in state.formData which is not same reference as before', () => { const joinFlowInstance = getJoinFlowWrapper().instance(); joinFlowInstance.setState({ formData: defaults({}, {username: 'abcdef'}) }); const formDataReference = joinFlowInstance.state.formData; joinFlowInstance.resetState(); expect(formDataReference).not.toBe(joinFlowInstance.state.formData); expect(formDataReference).not.toEqual(joinFlowInstance.state.formData); }); test('getErrorsFromResponse returns object of errors', () => { const joinFlowInstance = getJoinFlowWrapper().instance(); const errorsFromResponse = joinFlowInstance.getErrorsFromResponse(null, responseBodyMultipleErrs, {statusCode: 200}); expect(errorsFromResponse).toEqual([ { fieldName: 'username', errorStr: 'This field is required.' }, { fieldName: 'recaptcha', errorStr: 'Incorrect, please try again.' } ]); }); test('getErrorsFromResponse called with non-null err returns empty array', () => { const joinFlowInstance = getJoinFlowWrapper().instance(); const errorsFromResponse = joinFlowInstance.getErrorsFromResponse({}, responseBodyMultipleErrs, {statusCode: 200}); expect(errorsFromResponse).toEqual([]); }); test('getErrorsFromResponse called with non-200 status code returns empty array', () => { const joinFlowInstance = getJoinFlowWrapper().instance(); const errorsFromResponse = joinFlowInstance.getErrorsFromResponse({}, responseBodyMultipleErrs, {statusCode: 400}); expect(errorsFromResponse).toEqual([]); }); test('getErrorsFromResponse gets single error, when given response body with only one error', () => { const joinFlowInstance = getJoinFlowWrapper().instance(); const errorsFromResponse = joinFlowInstance.getErrorsFromResponse(null, responseBodySingleErr, {statusCode: 200}); expect(errorsFromResponse.length).toEqual(1); }); test('getCustomErrMsg string when given response body with multiple errors', () => { const joinFlowInstance = getJoinFlowWrapper().instance(); const errorsFromResponse = joinFlowInstance.getErrorsFromResponse(null, responseBodyMultipleErrs, {statusCode: 200}); const customErrMsg = joinFlowInstance.getCustomErrMsg(errorsFromResponse); expect(customErrMsg).toEqual('registration.problemsAre: "username: This field is required.; ' + 'recaptcha: Incorrect, please try again."'); }); test('getCustomErrMsg string when given response body with single error', () => { const joinFlowInstance = getJoinFlowWrapper().instance(); const errorsFromResponse = joinFlowInstance.getErrorsFromResponse(null, responseBodySingleErr, {statusCode: 200}); const customErrMsg = joinFlowInstance.getCustomErrMsg(errorsFromResponse); expect(customErrMsg).toEqual('registration.problemsAre: "recaptcha: Incorrect, please try again."'); }); test('registrationIsSuccessful returns true when given response body with single error', () => { const joinFlowInstance = getJoinFlowWrapper().instance(); const success = joinFlowInstance.registrationIsSuccessful(null, responseBodySuccess, {statusCode: 200}); expect(success).toEqual(true); }); test('registrationIsSuccessful returns false when given status code not 200', () => { const joinFlowInstance = getJoinFlowWrapper().instance(); const success = joinFlowInstance.registrationIsSuccessful(null, responseBodySuccess, {statusCode: 500}); expect(success).toEqual(false); }); test('registrationIsSuccessful returns false when given body with success field false', () => { const joinFlowInstance = getJoinFlowWrapper().instance(); const success = joinFlowInstance.registrationIsSuccessful(null, responseBodySingleErr, {statusCode: 200}); expect(success).toEqual(false); }); test('registrationIsSuccessful returns false when given non null err', () => { const joinFlowInstance = getJoinFlowWrapper().instance(); const success = joinFlowInstance.registrationIsSuccessful({}, responseBodySuccess, {statusCode: 200}); expect(success).toEqual(false); }); test('handleRegistrationResponse calls refreshSessionWithRetry() when passed body with success', done => { const props = { refreshSessionWithRetry: () => (new Promise(() => { // eslint-disable-line no-undef done(); // ensures that joinFlowInstance.props.refreshSessionWithRetry() was called })) }; const joinFlowInstance = getJoinFlowWrapper(props).instance(); joinFlowInstance.handleRegistrationResponse(null, responseBodySuccess, {statusCode: 200}); }); test('handleRegistrationResponse advances to next step when passed body with success', () => { const props = { refreshSessionWithRetry: () => (new Promise(resolve => { // eslint-disable-line no-undef resolve(); })) }; const joinFlowInstance = getJoinFlowWrapper(props).instance(); joinFlowInstance.handleRegistrationResponse(null, responseBodySuccess, {statusCode: 200}); process.nextTick( () => { expect(joinFlowInstance.state.registrationError).toEqual(null); expect(joinFlowInstance.state.step).toEqual(1); expect(joinFlowInstance.state.waiting).toBeFalsy(); } ); }); test('handleRegistrationResponse when passed body with preset server error', () => { const joinFlowInstance = getJoinFlowWrapper().instance(); joinFlowInstance.handleRegistrationResponse(null, responseBodySingleErr, {statusCode: 200}); expect(joinFlowInstance.state.registrationError).toEqual({ errorAllowsTryAgain: false, errorMsg: 'registration.errorCaptcha' }); }); test('handleRegistrationResponse with failure response, with error fields missing', () => { const props = { refreshSessionWithRetry: jest.fn() }; const joinFlowInstance = getJoinFlowWrapper(props).instance(); const responseErr = null; const responseBody = [ { msg: 'This field is required.', success: false } ]; const responseObj = { statusCode: 200 }; joinFlowInstance.handleRegistrationResponse(responseErr, responseBody, responseObj); expect(joinFlowInstance.props.refreshSessionWithRetry).not.toHaveBeenCalled(); expect(joinFlowInstance.state.registrationError).toEqual({ errorAllowsTryAgain: false, errorMsg: null }); }); test('handleRegistrationResponse when passed body with unfamiliar server error', () => { const joinFlowInstance = getJoinFlowWrapper().instance(); joinFlowInstance.handleRegistrationResponse(null, responseBodyMultipleErrs, {statusCode: 200}); expect(joinFlowInstance.state.registrationError).toEqual({ errorAllowsTryAgain: false, errorMsg: 'registration.problemsAre: "username: This field is required.; ' + 'recaptcha: Incorrect, please try again."' }); }); test('handleRegistrationResponse with failure response, with no text explanation', () => { const props = { refreshSessionWithRetry: jest.fn() }; const joinFlowInstance = getJoinFlowWrapper(props).instance(); const responseErr = null; const responseBody = [ { success: false } ]; const responseObj = { statusCode: 200 }; joinFlowInstance.handleRegistrationResponse(responseErr, responseBody, responseObj); expect(joinFlowInstance.props.refreshSessionWithRetry).not.toHaveBeenCalled(); expect(joinFlowInstance.state.registrationError).toEqual({ errorAllowsTryAgain: false, errorMsg: null }); }); test('handleRegistrationResponse when passed non null outgoing request error', () => { const joinFlowInstance = getJoinFlowWrapper().instance(); joinFlowInstance.handleRegistrationResponse({}, responseBodyMultipleErrs, {statusCode: 200}); expect(joinFlowInstance.state.registrationError).toEqual({ errorAllowsTryAgain: true }); }); test('handleRegistrationResponse when passed status 400', () => { const props = { refreshSessionWithRetry: jest.fn() }; const joinFlowInstance = getJoinFlowWrapper(props).instance(); joinFlowInstance.handleRegistrationResponse({}, responseBodyMultipleErrs, {statusCode: 400}); expect(joinFlowInstance.props.refreshSessionWithRetry).not.toHaveBeenCalled(); expect(joinFlowInstance.state.registrationError).toEqual({ errorAllowsTryAgain: true }); }); test('handleRegistrationResponse when passed status 500', () => { const joinFlowInstance = getJoinFlowWrapper().instance(); joinFlowInstance.handleRegistrationResponse(null, responseBodyMultipleErrs, {statusCode: 500}); expect(joinFlowInstance.state.registrationError).toEqual({ errorAllowsTryAgain: true }); }); });