import React from 'react'; import { mountWithContexts, waitForElement } from '../enzymeHelpers'; import AWXLogin from '../../src/pages/Login'; import { RootAPI } from '../../src/api'; jest.mock('../../src/api'); describe('', () => { async function findChildren (wrapper) { const [ awxLogin, loginPage, loginForm, usernameInput, passwordInput, submitButton, loginHeaderLogo, ] = await Promise.all([ waitForElement(wrapper, 'AWXLogin', (el) => el.length === 1), waitForElement(wrapper, 'LoginPage', (el) => el.length === 1), waitForElement(wrapper, 'LoginForm', (el) => el.length === 1), waitForElement(wrapper, 'input#pf-login-username-id', (el) => el.length === 1), waitForElement(wrapper, 'input#pf-login-password-id', (el) => el.length === 1), waitForElement(wrapper, 'Button[type="submit"]', (el) => el.length === 1), waitForElement(wrapper, 'img', (el) => el.length === 1), ]); return { awxLogin, loginPage, loginForm, usernameInput, passwordInput, submitButton, loginHeaderLogo, }; } beforeEach(() => { RootAPI.read.mockResolvedValue({ data: { custom_login_info: '', custom_logo: 'images/foo.jpg' } }); }); afterEach(() => { jest.clearAllMocks(); }); test('initially renders without crashing', async (done) => { const loginWrapper = mountWithContexts( false} /> ); const { awxLogin, usernameInput, passwordInput, submitButton, } = await findChildren(loginWrapper); expect(usernameInput.props().value).toBe(''); expect(passwordInput.props().value).toBe(''); expect(awxLogin.state('validationError')).toBe(false); expect(submitButton.props().isDisabled).toBe(false); done(); }); test('custom logo renders Brand component with correct src and alt', async (done) => { const loginWrapper = mountWithContexts( false} /> ); const { loginHeaderLogo } = await findChildren(loginWrapper); const { alt, src } = loginHeaderLogo.props(); expect([alt, src]).toEqual(['Foo Application', 'data:image/jpeg;images/foo.jpg']); done(); }); test('default logo renders Brand component with correct src and alt', async (done) => { RootAPI.read.mockResolvedValue({ data: {} }); const loginWrapper = mountWithContexts( false} /> ); const { loginHeaderLogo } = await findChildren(loginWrapper); const { alt, src } = loginHeaderLogo.props(); expect([alt, src]).toEqual(['AWX', 'brand-logo.svg']); done(); }); test('default logo renders on data initialization error', async (done) => { RootAPI.read.mockRejectedValueOnce({ response: { status: 500 } }); const loginWrapper = mountWithContexts( false} /> ); const { loginHeaderLogo } = await findChildren(loginWrapper); const { alt, src } = loginHeaderLogo.props(); expect([alt, src]).toEqual(['AWX', 'brand-logo.svg']); done(); }); test('state maps to un/pw input value props', async (done) => { const loginWrapper = mountWithContexts( false} /> ); const { usernameInput, passwordInput } = await findChildren(loginWrapper); usernameInput.props().onChange({ currentTarget: { value: 'un' } }); passwordInput.props().onChange({ currentTarget: { value: 'pw' } }); await waitForElement(loginWrapper, 'AWXLogin', (el) => el.state('username') === 'un'); await waitForElement(loginWrapper, 'AWXLogin', (el) => el.state('password') === 'pw'); done(); }); test('handles input validation errors and clears on input value change', async (done) => { const formError = '.pf-c-form__helper-text.pf-m-error'; const loginWrapper = mountWithContexts( false} /> ); const { usernameInput, passwordInput, submitButton } = await findChildren(loginWrapper); RootAPI.login.mockRejectedValueOnce({ response: { status: 401 } }); usernameInput.props().onChange({ currentTarget: { value: 'invalid' } }); passwordInput.props().onChange({ currentTarget: { value: 'invalid' } }); submitButton.simulate('click'); await waitForElement(loginWrapper, 'AWXLogin', (el) => el.state('username') === 'invalid'); await waitForElement(loginWrapper, 'AWXLogin', (el) => el.state('password') === 'invalid'); await waitForElement(loginWrapper, 'AWXLogin', (el) => el.state('validationError') === true); await waitForElement(loginWrapper, formError, (el) => el.length === 1); usernameInput.props().onChange({ currentTarget: { value: 'dsarif' } }); passwordInput.props().onChange({ currentTarget: { value: 'freneticpny' } }); await waitForElement(loginWrapper, 'AWXLogin', (el) => el.state('username') === 'dsarif'); await waitForElement(loginWrapper, 'AWXLogin', (el) => el.state('password') === 'freneticpny'); await waitForElement(loginWrapper, 'AWXLogin', (el) => el.state('validationError') === false); await waitForElement(loginWrapper, formError, (el) => el.length === 0); done(); }); test('handles other errors and clears on resubmit', async (done) => { const loginWrapper = mountWithContexts( false} /> ); const { usernameInput, passwordInput, submitButton } = await findChildren(loginWrapper); RootAPI.login.mockRejectedValueOnce({ response: { status: 500 } }); submitButton.simulate('click'); await waitForElement(loginWrapper, 'AWXLogin', (el) => el.state('authenticationError') === true); usernameInput.props().onChange({ currentTarget: { value: 'sgrimes' } }); passwordInput.props().onChange({ currentTarget: { value: 'ovid' } }); await waitForElement(loginWrapper, 'AWXLogin', (el) => el.state('username') === 'sgrimes'); await waitForElement(loginWrapper, 'AWXLogin', (el) => el.state('password') === 'ovid'); await waitForElement(loginWrapper, 'AWXLogin', (el) => el.state('authenticationError') === true); submitButton.simulate('click'); await waitForElement(loginWrapper, 'AWXLogin', (el) => el.state('authenticationError') === false); done(); }); test('no login requests are made when already authenticating', async (done) => { const loginWrapper = mountWithContexts( false} /> ); const { awxLogin, submitButton } = await findChildren(loginWrapper); awxLogin.setState({ isAuthenticating: true }); submitButton.simulate('click'); submitButton.simulate('click'); expect(RootAPI.login).toHaveBeenCalledTimes(0); awxLogin.setState({ isAuthenticating: false }); submitButton.simulate('click'); submitButton.simulate('click'); expect(RootAPI.login).toHaveBeenCalledTimes(1); done(); }); test('submit calls api.login successfully', async (done) => { const loginWrapper = mountWithContexts( false} /> ); const { usernameInput, passwordInput, submitButton, } = await findChildren(loginWrapper); usernameInput.props().onChange({ currentTarget: { value: 'gthorpe' } }); passwordInput.props().onChange({ currentTarget: { value: 'hydro' } }); submitButton.simulate('click'); await waitForElement(loginWrapper, 'AWXLogin', (el) => el.state('isAuthenticating') === true); await waitForElement(loginWrapper, 'AWXLogin', (el) => el.state('isAuthenticating') === false); expect(RootAPI.login).toHaveBeenCalledTimes(1); expect(RootAPI.login).toHaveBeenCalledWith('gthorpe', 'hydro'); done(); }); test('render Redirect to / when already authenticated', async (done) => { const loginWrapper = mountWithContexts( true} /> ); await waitForElement(loginWrapper, 'Redirect', (el) => el.length === 1); await waitForElement(loginWrapper, 'Redirect', (el) => el.props().to === '/'); done(); }); });