diff --git a/client/src/actions/__mocks__/user-actions-mock.js b/client/src/actions/__mocks__/user-actions-mock.js index b8a568db..cb0e9a4a 100644 --- a/client/src/actions/__mocks__/user-actions-mock.js +++ b/client/src/actions/__mocks__/user-actions-mock.js @@ -1,5 +1,7 @@ export default { checkLoginStatus: stub(), + sendRecoverPassword: stub(), + recoverPassword: stub(), login: stub(), logout: stub() }; \ No newline at end of file diff --git a/client/src/actions/user-actions.js b/client/src/actions/user-actions.js index dc9cd0b6..9279fa53 100644 --- a/client/src/actions/user-actions.js +++ b/client/src/actions/user-actions.js @@ -4,7 +4,7 @@ const UserActions = Reflux.createActions([ 'checkLoginStatus', 'login', 'logout', - 'sendRecover', + 'sendRecoverPassword', 'recoverPassword' ]); diff --git a/client/src/app/main/main-home/__tests__/main-home-page-login-widget-test.js b/client/src/app/main/main-home/__tests__/main-home-page-login-widget-test.js index 9e1a6b1c..2d2fe3fa 100644 --- a/client/src/app/main/main-home/__tests__/main-home-page-login-widget-test.js +++ b/client/src/app/main/main-home/__tests__/main-home-page-login-widget-test.js @@ -1,18 +1,22 @@ const UserActions = require('actions/__mocks__/user-actions-mock'); const UserStore = require('stores/__mocks__/user-store-mock'); +const SubmitButton = ReactMock(); const Button = ReactMock(); const Input = ReactMock(); const Form = ReactMock(); const Checkbox = ReactMock(); +const Message = ReactMock(); const Widget = ReactMock(); const WidgetTransition = ReactMock(); const MainHomePageLoginWidget = requireUnit('app/main/main-home/main-home-page-login-widget', { + 'core-components/submit-button': SubmitButton, 'core-components/button': Button, 'core-components/input': Input, 'core-components/form': Form, 'core-components/checkbox': Checkbox, + 'core-components/message': Message, 'core-components/widget': Widget, 'core-components/widget-transition': WidgetTransition, 'actions/user-actions': UserActions, @@ -23,7 +27,7 @@ const MainHomePageLoginWidget = requireUnit('app/main/main-home/main-home-page-l describe('Login/Recover Widget', function () { describe('Login Form', function () { let loginWidget, loginForm, widgetTransition, inputs, checkbox, component, - forgotPasswordButton; + forgotPasswordButton, submitButton; beforeEach(function () { component = TestUtils.renderIntoDocument( @@ -34,7 +38,8 @@ describe('Login/Recover Widget', function () { loginForm = TestUtils.scryRenderedComponentsWithType(component, Form)[0]; inputs = TestUtils.scryRenderedComponentsWithType(component, Input); checkbox = TestUtils.scryRenderedComponentsWithType(component, Checkbox)[0]; - forgotPasswordButton = TestUtils.scryRenderedComponentsWithType(component, Button)[1]; + submitButton = TestUtils.scryRenderedComponentsWithType(component, SubmitButton)[0]; + forgotPasswordButton = TestUtils.scryRenderedComponentsWithType(component, Button)[0]; component.refs.loginForm = { refs: { @@ -58,11 +63,19 @@ describe('Login/Recover Widget', function () { loginForm.props.onSubmit(mockSubmitData); expect(UserActions.login).to.have.been.calledWith(mockSubmitData); }); - - it('should add error if login fails', function () { + + it('should set loading true in the form when submitted', function () { + let mockSubmitData = {email: 'MOCK_VALUE', password: 'MOCK_VALUE'}; + + loginForm.props.onSubmit(mockSubmitData); + expect(loginForm.props.loading).to.equal(true); + }); + + it('should add error and stop loading if login fails', function () { component.refs.loginForm.refs.password.focus.reset(); component.onUserStoreChanged('LOGIN_FAIL'); expect(loginForm.props.errors).to.deep.equal({password: 'Invalid password'}); + expect(loginForm.props.loading).to.equal(false); expect(component.refs.loginForm.refs.password.focus).to.have.been.called; }); @@ -72,4 +85,76 @@ describe('Login/Recover Widget', function () { expect(widgetTransition.props.sideToShow).to.equal('back'); }); }); + + describe('Recover Password form', function () { + let recoverWidget, recoverForm, widgetTransition, emailInput, component, + backToLoginButton, submitButton; + + beforeEach(function () { + component = TestUtils.renderIntoDocument( + + ); + widgetTransition = TestUtils.scryRenderedComponentsWithType(component, WidgetTransition)[0]; + recoverWidget = TestUtils.scryRenderedComponentsWithType(component, Widget)[1]; + recoverForm = TestUtils.scryRenderedComponentsWithType(component, Form)[1]; + emailInput = TestUtils.scryRenderedComponentsWithType(component, Input)[2]; + submitButton = TestUtils.scryRenderedComponentsWithType(component, SubmitButton)[1]; + backToLoginButton = TestUtils.scryRenderedComponentsWithType(component, Button)[1]; + + component.refs.recoverForm = { + refs: { + email: { + focus: stub() + } + } + }; + }); + + it('should control form errors by prop', function () { + expect(recoverForm.props.errors).to.deep.equal({}); + recoverForm.props.onValidateErrors({email: 'MOCK_ERROR'}); + expect(recoverForm.props.errors).to.deep.equal({email: 'MOCK_ERROR'}); + }); + + it('should trigger sendRecoverPassword action when submitted', function () { + let mockSubmitData = {email: 'MOCK_VALUE'}; + + UserActions.sendRecoverPassword.reset(); + recoverForm.props.onSubmit(mockSubmitData); + expect(UserActions.sendRecoverPassword).to.have.been.calledWith(mockSubmitData); + }); + + it('should set loading true in the form when submitted', function () { + let mockSubmitData = {email: 'MOCK_VALUE'}; + + recoverForm.props.onSubmit(mockSubmitData); + expect(recoverForm.props.loading).to.equal(true); + }); + + it('should add error and stop loading when send recover fails', function () { + component.refs.recoverForm.refs.email.focus.reset(); + component.onUserStoreChanged('SEND_RECOVER_FAIL'); + expect(recoverForm.props.errors).to.deep.equal({email: 'Email does not exist'}); + expect(recoverForm.props.loading).to.equal(false); + expect(component.refs.recoverForm.refs.email.focus).to.have.been.called; + }); + + it('should show message when send recover success', function () { + let message = TestUtils.scryRenderedComponentsWithType(component, Message)[0]; + expect(message).to.equal(undefined); + + component.onUserStoreChanged('SEND_RECOVER_SUCCESS'); + message = TestUtils.scryRenderedComponentsWithType(component, Message)[0]; + + expect(recoverForm.props.loading).to.equal(false); + expect(message).to.not.equal(null); + expect(message.props.type).to.equal('info'); + expect(message.props.children).to.equal('An email with recover instructions has been sent.'); + }); + + it('should show front side if \'Back to login form\' link is clicked', function () { + backToLoginButton.props.onClick(); + expect(widgetTransition.props.sideToShow).to.equal('front'); + }); + }); }); \ No newline at end of file diff --git a/client/src/app/main/main-home/main-home-page-login-widget.js b/client/src/app/main/main-home/main-home-page-login-widget.js index c569ce04..4ba19b47 100644 --- a/client/src/app/main/main-home/main-home-page-login-widget.js +++ b/client/src/app/main/main-home/main-home-page-login-widget.js @@ -125,7 +125,7 @@ let MainHomePageLoginWidget = React.createClass({ }, handleForgotPasswordSubmit(formState) { - UserActions.sendRecover(formState); + UserActions.sendRecoverPassword(formState); this.setState({ loadingRecover: true diff --git a/client/src/app/main/main-recover-password/__tests__/main-recover-password-page-test.js b/client/src/app/main/main-recover-password/__tests__/main-recover-password-page-test.js new file mode 100644 index 00000000..7408dce4 --- /dev/null +++ b/client/src/app/main/main-recover-password/__tests__/main-recover-password-page-test.js @@ -0,0 +1,74 @@ +const CommonActions = require('actions/__mocks__/common-actions-mock'); +const UserActions = require('actions/__mocks__/user-actions-mock'); +const UserStore = require('stores/__mocks__/user-store-mock'); + +const SubmitButton = ReactMock(); +const Button = ReactMock(); +const Input = ReactMock(); +const Form = ReactMock(); +const Message = ReactMock(); +const Widget = ReactMock(); + +const MainRecoverPasswordPage = requireUnit('app/main/main-recover-password/main-recover-password-page', { + 'core-components/submit-button': SubmitButton, + 'core-components/button': Button, + 'core-components/input': Input, + 'core-components/form': Form, + 'core-components/message': Message, + 'core-components/widget': Widget, + 'actions/common-actions': CommonActions, + 'actions/user-actions': UserActions, + 'stores/user-store': UserStore +}); + +describe('Recover Password form', function () { + let recoverForm, inputs, component, submitButton; + let query = { + token: 'SOME_TOKEN', + email: 'SOME_EMAIL' + }; + + beforeEach(function () { + component = TestUtils.renderIntoDocument( + + ); + recoverForm = TestUtils.scryRenderedComponentsWithType(component, Form)[0]; + inputs = TestUtils.scryRenderedComponentsWithType(component, Input); + submitButton = TestUtils.scryRenderedComponentsWithType(component, SubmitButton)[0]; + }); + + it('should trigger recoverPassword action when submitted', function () { + UserActions.sendRecoverPassword.reset(); + recoverForm.props.onSubmit({password: 'MOCK_VALUE'}); + expect(UserActions.recoverPassword).to.have.been.calledWith({ + password: 'MOCK_VALUE', + token: 'SOME_TOKEN', + email: 'SOME_EMAIL' + }); + }); + + it('should set loading true in the form when submitted', function () { + recoverForm.props.onSubmit({password: 'MOCK_VALUE'}); + expect(recoverForm.props.loading).to.equal(true); + }); + + it('should show message when recover fails', function () { + component.onUserStoreChanged('INVALID_RECOVER'); + expect(recoverForm.props.loading).to.equal(false); + + let message = TestUtils.scryRenderedComponentsWithType(component, Message)[0]; + expect(message).to.not.equal(null); + expect(message.props.type).to.equal('error'); + expect(message.props.children).to.equal('Invalid recover data'); + }); + + it('should show message when recover success', function () { + component.onUserStoreChanged('VALID_RECOVER'); + expect(recoverForm.props.loading).to.equal(false); + + let message = TestUtils.scryRenderedComponentsWithType(component, Message)[0]; + expect(message).to.not.equal(null); + expect(message.props.type).to.equal('success'); + expect(message.props.children).to.equal('Password recovered successfully'); + }); +}); diff --git a/client/src/app/main/main-recover-password/main-recover-password-page.js b/client/src/app/main/main-recover-password/main-recover-password-page.js index d8bd22fd..0909f457 100644 --- a/client/src/app/main/main-recover-password/main-recover-password-page.js +++ b/client/src/app/main/main-recover-password/main-recover-password-page.js @@ -74,7 +74,7 @@ const MainRecoverPasswordPage = React.createClass({ recoverData.token = this.props.location.query.token; recoverData.email = this.props.location.query.email; - UserActions.recoverPassword(formState); + UserActions.recoverPassword(recoverData); this.setState({ loading: true }); diff --git a/client/src/core-components/__tests__/form-test.js b/client/src/core-components/__tests__/form-test.js index a6962ffc..ea1e1f7a 100644 --- a/client/src/core-components/__tests__/form-test.js +++ b/client/src/core-components/__tests__/form-test.js @@ -203,4 +203,22 @@ describe('Form component', function () { expect(fields[1].focus).to.have.been.called; }); }); + + describe('when using loading prop', function () { + it('should pass loading context in true if enabled', function () { + renderForm({ loading: true }); + + expect(fields[0].context.loading).to.equal(true); + expect(fields[1].context.loading).to.equal(true); + expect(fields[2].context.loading).to.equal(true); + }); + + it('should pass loading context in true if disabled', function () { + renderForm({ loading: false }); + + expect(fields[0].context.loading).to.equal(false); + expect(fields[1].context.loading).to.equal(false); + expect(fields[2].context.loading).to.equal(false); + }); + }); }); diff --git a/client/src/stores/user-store.js b/client/src/stores/user-store.js index 00df5c96..f70461d1 100644 --- a/client/src/stores/user-store.js +++ b/client/src/stores/user-store.js @@ -14,7 +14,7 @@ const UserStore = Reflux.createStore({ this.listenTo(UserActions.login, this.loginUser); this.listenTo(UserActions.logout, this.logoutUser); this.listenTo(UserActions.recoverPassword, this.recoverPassword); - this.listenTo(UserActions.sendRecover, this.sendRecoverPassword); + this.listenTo(UserActions.sendRecoverPassword, this.sendRecoverPassword); }, initSession() {