diff --git a/__tests__/pages/Login.jsx b/__tests__/pages/Login.jsx index 09eb67b8dc..49bcffce5c 100644 --- a/__tests__/pages/Login.jsx +++ b/__tests__/pages/Login.jsx @@ -3,12 +3,12 @@ import { MemoryRouter } from 'react-router-dom'; import { mount, shallow } from 'enzyme'; import { I18nProvider } from '@lingui/react'; import { asyncFlush } from '../../jest.setup'; -import AtLogin from '../../src/pages/Login'; +import AWXLogin from '../../src/pages/Login'; import APIClient from '../../src/api'; describe('', () => { let loginWrapper; - let atLogin; + let awxLogin; let loginPage; let loginForm; let usernameInput; @@ -19,7 +19,7 @@ describe('', () => { const api = new APIClient({}); const findChildren = () => { - atLogin = loginWrapper.find('AtLogin'); + awxLogin = loginWrapper.find('AWXLogin'); loginPage = loginWrapper.find('LoginPage'); loginForm = loginWrapper.find('LoginForm'); usernameInput = loginWrapper.find('input#pf-login-username-id'); @@ -32,7 +32,7 @@ describe('', () => { loginWrapper = mount( - + ); @@ -51,7 +51,7 @@ describe('', () => { expect(usernameInput.props().value).toBe(''); expect(passwordInput.length).toBe(1); expect(passwordInput.props().value).toBe(''); - expect(atLogin.state().isValidPassword).toBe(true); + expect(awxLogin.state().isInputValid).toBe(true); expect(submitButton.length).toBe(1); expect(submitButton.props().isDisabled).toBe(false); expect(loginHeaderLogo.length).toBe(1); @@ -61,7 +61,7 @@ describe('', () => { loginWrapper = mount( - + ); @@ -75,7 +75,7 @@ describe('', () => { loginWrapper = mount( - + ); @@ -86,49 +86,49 @@ describe('', () => { }); test('state maps to un/pw input value props', () => { - atLogin.setState({ username: 'un', password: 'pw' }); - expect(atLogin.state().username).toBe('un'); - expect(atLogin.state().password).toBe('pw'); + awxLogin.setState({ username: 'un', password: 'pw' }); + expect(awxLogin.state().username).toBe('un'); + expect(awxLogin.state().password).toBe('pw'); findChildren(); expect(usernameInput.props().value).toBe('un'); expect(passwordInput.props().value).toBe('pw'); }); test('updating un/pw clears out error', () => { - atLogin.setState({ isValidPassword: false }); + awxLogin.setState({ isInputValid: false }); expect(loginWrapper.find('.pf-c-form__helper-text.pf-m-error').length).toBe(1); usernameInput.instance().value = 'uname'; usernameInput.simulate('change'); - expect(atLogin.state().username).toBe('uname'); - expect(atLogin.state().isValidPassword).toBe(true); + expect(awxLogin.state().username).toBe('uname'); + expect(awxLogin.state().isInputValid).toBe(true); expect(loginWrapper.find('.pf-c-form__helper-text.pf-m-error').length).toBe(0); - atLogin.setState({ isValidPassword: false }); + awxLogin.setState({ isInputValid: false }); expect(loginWrapper.find('.pf-c-form__helper-text.pf-m-error').length).toBe(1); passwordInput.instance().value = 'pword'; passwordInput.simulate('change'); - expect(atLogin.state().password).toBe('pword'); - expect(atLogin.state().isValidPassword).toBe(true); + expect(awxLogin.state().password).toBe('pword'); + expect(awxLogin.state().isInputValid).toBe(true); expect(loginWrapper.find('.pf-c-form__helper-text.pf-m-error').length).toBe(0); }); test('api.login not called when loading', () => { api.login = jest.fn().mockImplementation(() => Promise.resolve({})); - expect(atLogin.state().loading).toBe(false); - atLogin.setState({ loading: true }); + expect(awxLogin.state().isLoading).toBe(false); + awxLogin.setState({ isLoading: true }); submitButton.simulate('click'); expect(api.login).toHaveBeenCalledTimes(0); }); test('submit calls api.login successfully', async () => { api.login = jest.fn().mockImplementation(() => Promise.resolve({})); - expect(atLogin.state().loading).toBe(false); - atLogin.setState({ username: 'unamee', password: 'pwordd' }); + expect(awxLogin.state().isLoading).toBe(false); + awxLogin.setState({ username: 'unamee', password: 'pwordd' }); submitButton.simulate('click'); expect(api.login).toHaveBeenCalledTimes(1); expect(api.login).toHaveBeenCalledWith('unamee', 'pwordd'); - expect(atLogin.state().loading).toBe(true); + expect(awxLogin.state().isLoading).toBe(true); await asyncFlush(); - expect(atLogin.state().loading).toBe(false); + expect(awxLogin.state().isLoading).toBe(false); }); test('submit calls api.login handles 401 error', async () => { @@ -137,16 +137,16 @@ describe('', () => { err.response = { status: 401, message: 'problem' }; return Promise.reject(err); }); - expect(atLogin.state().loading).toBe(false); - expect(atLogin.state().isValidPassword).toBe(true); - atLogin.setState({ username: 'unamee', password: 'pwordd' }); + expect(awxLogin.state().isLoading).toBe(false); + expect(awxLogin.state().isInputValid).toBe(true); + awxLogin.setState({ username: 'unamee', password: 'pwordd' }); submitButton.simulate('click'); expect(api.login).toHaveBeenCalledTimes(1); expect(api.login).toHaveBeenCalledWith('unamee', 'pwordd'); - expect(atLogin.state().loading).toBe(true); + expect(awxLogin.state().isLoading).toBe(true); await asyncFlush(); - expect(atLogin.state().isValidPassword).toBe(false); - expect(atLogin.state().loading).toBe(false); + expect(awxLogin.state().isInputValid).toBe(false); + expect(awxLogin.state().isLoading).toBe(false); }); test('submit calls api.login handles non-401 error', async () => { @@ -155,20 +155,20 @@ describe('', () => { err.response = { status: 500, message: 'problem' }; return Promise.reject(err); }); - expect(atLogin.state().loading).toBe(false); - atLogin.setState({ username: 'unamee', password: 'pwordd' }); + expect(awxLogin.state().isLoading).toBe(false); + awxLogin.setState({ username: 'unamee', password: 'pwordd' }); submitButton.simulate('click'); expect(api.login).toHaveBeenCalledTimes(1); expect(api.login).toHaveBeenCalledWith('unamee', 'pwordd'); - expect(atLogin.state().loading).toBe(true); + expect(awxLogin.state().isLoading).toBe(true); await asyncFlush(); - expect(atLogin.state().loading).toBe(false); + expect(awxLogin.state().isLoading).toBe(false); }); test('render Redirect to / when already authenticated', () => { api.isAuthenticated = jest.fn(); api.isAuthenticated.mockReturnValue(true); - loginWrapper = shallow(); + loginWrapper = shallow(); const redirectElem = loginWrapper.find('Redirect'); expect(redirectElem.length).toBe(1); expect(redirectElem.props().to).toBe('/'); diff --git a/src/pages/Login.jsx b/src/pages/Login.jsx index 207aa1491d..a2353542a9 100644 --- a/src/pages/Login.jsx +++ b/src/pages/Login.jsx @@ -9,52 +9,56 @@ import { import towerLogo from '../../images/tower-logo-header.svg'; -class AtLogin extends Component { +class AWXLogin extends Component { constructor (props) { super(props); this.state = { username: '', password: '', - isValidPassword: true, - loading: false + isInputValid: true, + isLoading: false }; + + this.onChangeUsername = this.onChangeUsername.bind(this); + this.onChangePassword = this.onChangePassword.bind(this); + this.onLoginButtonClick = this.onLoginButtonClick.bind(this); } - componentWillUnmount () { - this.unmounting = true; // todo: state management + onChangeUsername (value) { + this.setState({ username: value, isInputValid: true }); } - safeSetState = obj => !this.unmounting && this.setState(obj); + onChangePassword (value) { + this.setState({ password: value, isInputValid: true }); + } - handleUsernameChange = value => this.safeSetState({ username: value, isValidPassword: true }); - - handlePasswordChange = value => this.safeSetState({ password: value, isValidPassword: true }); - - handleSubmit = async event => { - const { username, password, loading } = this.state; + async onLoginButtonClick (event) { + const { username, password, isLoading } = this.state; const { api } = this.props; event.preventDefault(); - if (!loading) { - this.safeSetState({ loading: true }); + if (isLoading) { + return; + } - try { - await api.login(username, password); - } catch (error) { - if (error.response.status === 401) { - this.safeSetState({ isValidPassword: false }); - } - } finally { - this.safeSetState({ loading: false }); + this.setState({ isLoading: true }); + + try { + await api.login(username, password); + } catch (error) { + if (error.response.status === 401) { + this.setState({ isInputValid: false }); } + } finally { + this.setState({ isLoading: false }); } } render () { - const { username, password, isValidPassword } = this.state; - const { api, alt, logo } = this.props; + const { username, password, isInputValid } = this.state; + const { api, alt, loginInfo, logo } = this.props; const logoSrc = logo ? `data:image/jpeg;${logo}` : towerLogo; if (api.isAuthenticated()) { @@ -68,17 +72,18 @@ class AtLogin extends Component { brandImgSrc={logoSrc} brandImgAlt={alt || 'Ansible Tower'} loginTitle={i18n._(t`Welcome to Ansible Tower! Please Sign In.`)} + textContent={loginInfo} > )} @@ -87,4 +92,4 @@ class AtLogin extends Component { } } -export default AtLogin; +export default AWXLogin;