From 3e5567c990dd03ee4e45aa9cd0222dfec302d2a5 Mon Sep 17 00:00:00 2001
From: ivan <ivan@opensupports.com>
Date: Tue, 2 Aug 2016 15:51:21 -0300
Subject: [PATCH] Ivan - Add unit testing for loading behavior [skip ci]

---
 .../actions/__mocks__/user-actions-mock.js    |  2 +
 client/src/actions/user-actions.js            |  2 +-
 .../main-home-page-login-widget-test.js       | 93 ++++++++++++++++++-
 .../main-home/main-home-page-login-widget.js  |  2 +-
 .../main-recover-password-page-test.js        | 74 +++++++++++++++
 .../main-recover-password-page.js             |  2 +-
 .../core-components/__tests__/form-test.js    | 18 ++++
 client/src/stores/user-store.js               |  2 +-
 8 files changed, 187 insertions(+), 8 deletions(-)
 create mode 100644 client/src/app/main/main-recover-password/__tests__/main-recover-password-page-test.js

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(
+                <MainHomePageLoginWidget />
+            );
+            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(
+            <MainRecoverPasswordPage location={{query}}/>
+        );
+        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() {