mirror of
https://github.com/ansible/awx.git
synced 2026-03-23 11:55:04 -02:30
Merge pull request #10 from jlmitch5/loginPageTests
Add login page tests
This commit is contained in:
@@ -34,4 +34,4 @@ describe('<App />', () => {
|
|||||||
const login = appWrapper.find(Login);
|
const login = appWrapper.find(Login);
|
||||||
expect(login.length).toBe(0);
|
expect(login.length).toBe(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { Component } from 'react';
|
import React from 'react';
|
||||||
import {
|
import {
|
||||||
Route,
|
Route,
|
||||||
Redirect
|
Redirect
|
||||||
@@ -9,7 +9,11 @@ import ConditionalRedirect from '../../src/components/ConditionalRedirect';
|
|||||||
describe('<ConditionalRedirect />', () => {
|
describe('<ConditionalRedirect />', () => {
|
||||||
test('renders Redirect when shouldRedirect is passed truthy func', () => {
|
test('renders Redirect when shouldRedirect is passed truthy func', () => {
|
||||||
const truthyFunc = () => true;
|
const truthyFunc = () => true;
|
||||||
const shouldHaveRedirectChild = shallow(<ConditionalRedirect shouldRedirect={() => truthyFunc()} />);
|
const shouldHaveRedirectChild = shallow(
|
||||||
|
<ConditionalRedirect
|
||||||
|
shouldRedirect={() => truthyFunc()}
|
||||||
|
/>
|
||||||
|
);
|
||||||
const redirectChild = shouldHaveRedirectChild.find(Redirect);
|
const redirectChild = shouldHaveRedirectChild.find(Redirect);
|
||||||
expect(redirectChild.length).toBe(1);
|
expect(redirectChild.length).toBe(1);
|
||||||
const routeChild = shouldHaveRedirectChild.find(Route);
|
const routeChild = shouldHaveRedirectChild.find(Route);
|
||||||
@@ -18,10 +22,14 @@ describe('<ConditionalRedirect />', () => {
|
|||||||
|
|
||||||
test('renders Route when shouldRedirect is passed falsy func', () => {
|
test('renders Route when shouldRedirect is passed falsy func', () => {
|
||||||
const falsyFunc = () => false;
|
const falsyFunc = () => false;
|
||||||
const shouldHaveRouteChild = shallow(<ConditionalRedirect shouldRedirect={() => falsyFunc()} />);
|
const shouldHaveRouteChild = shallow(
|
||||||
|
<ConditionalRedirect
|
||||||
|
shouldRedirect={() => falsyFunc()}
|
||||||
|
/>
|
||||||
|
);
|
||||||
const routeChild = shouldHaveRouteChild.find(Route);
|
const routeChild = shouldHaveRouteChild.find(Route);
|
||||||
expect(routeChild.length).toBe(1);
|
expect(routeChild.length).toBe(1);
|
||||||
const redirectChild = shouldHaveRouteChild.find(Redirect);
|
const redirectChild = shouldHaveRouteChild.find(Redirect);
|
||||||
expect(redirectChild.length).toBe(0);
|
expect(redirectChild.length).toBe(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,37 +1,141 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
import { shallow, mount } from 'enzyme';
|
import { mount, shallow } from 'enzyme';
|
||||||
|
import { asyncFlush } from '../../jest.setup';
|
||||||
import LoginPage from '../../src/pages/Login';
|
import LoginPage from '../../src/pages/Login';
|
||||||
import api from '../../src/api';
|
import api from '../../src/api';
|
||||||
import Dashboard from '../../src/pages/Dashboard';
|
|
||||||
|
const LOGIN_ERROR_MESSAGE = 'Invalid username or password. Please try again.';
|
||||||
|
|
||||||
describe('<LoginPage />', () => {
|
describe('<LoginPage />', () => {
|
||||||
let loginWrapper, usernameInput, passwordInput, errorTextArea, submitButton;
|
let loginWrapper;
|
||||||
|
let loginPage;
|
||||||
|
let loginForm;
|
||||||
|
let usernameInput;
|
||||||
|
let passwordInput;
|
||||||
|
let errorTextArea;
|
||||||
|
let submitButton;
|
||||||
|
let defaultLogo;
|
||||||
|
|
||||||
beforeEach(() => {
|
const findChildren = () => {
|
||||||
loginWrapper = mount(<MemoryRouter><LoginPage /></MemoryRouter>);
|
loginPage = loginWrapper.find('LoginPage');
|
||||||
|
loginForm = loginWrapper.find('form.pf-c-form');
|
||||||
usernameInput = loginWrapper.find('.pf-c-form__group#username TextInput');
|
usernameInput = loginWrapper.find('.pf-c-form__group#username TextInput');
|
||||||
passwordInput = loginWrapper.find('.pf-c-form__group#password TextInput');
|
passwordInput = loginWrapper.find('.pf-c-form__group#password TextInput');
|
||||||
errorTextArea = loginWrapper.find('.pf-c-form__helper-text.pf-m-error');
|
errorTextArea = loginWrapper.find('.pf-c-form__helper-text.pf-m-error');
|
||||||
submitButton = loginWrapper.find('Button[type="submit"]');
|
submitButton = loginWrapper.find('Button[type="submit"]');
|
||||||
|
defaultLogo = loginWrapper.find('TowerLogo');
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
loginWrapper = mount(<MemoryRouter><LoginPage /></MemoryRouter>);
|
||||||
|
findChildren();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
loginWrapper.unmount();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('initially renders without crashing', () => {
|
test('initially renders without crashing', () => {
|
||||||
expect(loginWrapper.length).toBe(1);
|
expect(loginWrapper.length).toBe(1);
|
||||||
|
expect(loginForm.length).toBe(1);
|
||||||
expect(usernameInput.length).toBe(1);
|
expect(usernameInput.length).toBe(1);
|
||||||
|
expect(usernameInput.props().value).toBe('');
|
||||||
expect(passwordInput.length).toBe(1);
|
expect(passwordInput.length).toBe(1);
|
||||||
|
expect(passwordInput.props().value).toBe('');
|
||||||
expect(errorTextArea.length).toBe(1);
|
expect(errorTextArea.length).toBe(1);
|
||||||
|
expect(loginPage.state().error).toBe('');
|
||||||
expect(submitButton.length).toBe(1);
|
expect(submitButton.length).toBe(1);
|
||||||
|
expect(submitButton.props().isDisabled).toBe(false);
|
||||||
|
expect(defaultLogo.length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
// initially renders empty username and password fields, sets empty error message and makes submit button not disabled
|
test('custom logo renders Brand component', () => {
|
||||||
|
loginWrapper = mount(<MemoryRouter><LoginPage logo="hey" /></MemoryRouter>);
|
||||||
|
findChildren();
|
||||||
|
expect(defaultLogo.length).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
// typing into username and password fields (if the component is not unmounting) will clear out any error message
|
test('state maps to un/pw input value props', () => {
|
||||||
|
loginPage.setState({ username: 'un', password: 'pw' });
|
||||||
|
expect(loginPage.state().username).toBe('un');
|
||||||
|
expect(loginPage.state().password).toBe('pw');
|
||||||
|
findChildren();
|
||||||
|
expect(usernameInput.props().value).toBe('un');
|
||||||
|
expect(passwordInput.props().value).toBe('pw');
|
||||||
|
});
|
||||||
|
|
||||||
// when the submit Button is clicked, as long as it is not disabled state.loading is set to true
|
test('updating un/pw clears out error', () => {
|
||||||
// api.login is called with param 1 username and param 2 password
|
loginPage.setState({ error: 'error!' });
|
||||||
// if api.login returns an error, the state.error should be set to LOGIN_ERROR_MESSAGE, if the error object returned has response.status set to 401.
|
usernameInput.instance().props.onChange('uname');
|
||||||
// regardless of error or not, after api.login returns, state.loading should be set to false
|
expect(loginPage.state().username).toBe('uname');
|
||||||
|
expect(loginPage.state().error).toBe('');
|
||||||
|
loginPage.setState({ error: 'error!' });
|
||||||
|
passwordInput.instance().props.onChange('pword');
|
||||||
|
expect(loginPage.state().password).toBe('pword');
|
||||||
|
expect(loginPage.state().error).toBe('');
|
||||||
|
});
|
||||||
|
|
||||||
// if api.isAuthenticated mock returns true, Redirect to / should be rendered
|
test('api.login not called when loading', () => {
|
||||||
});
|
api.login = jest.fn().mockImplementation(() => Promise.resolve({}));
|
||||||
|
expect(loginPage.state().loading).toBe(false);
|
||||||
|
loginPage.setState({ loading: true });
|
||||||
|
submitButton.simulate('submit');
|
||||||
|
expect(api.login).toHaveBeenCalledTimes(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('submit calls api.login successfully', async () => {
|
||||||
|
api.login = jest.fn().mockImplementation(() => Promise.resolve({}));
|
||||||
|
expect(loginPage.state().loading).toBe(false);
|
||||||
|
loginPage.setState({ username: 'unamee', password: 'pwordd' });
|
||||||
|
submitButton.simulate('submit');
|
||||||
|
expect(api.login).toHaveBeenCalledTimes(1);
|
||||||
|
expect(api.login).toHaveBeenCalledWith('unamee', 'pwordd');
|
||||||
|
expect(loginPage.state().loading).toBe(true);
|
||||||
|
await asyncFlush();
|
||||||
|
expect(loginPage.state().loading).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('submit calls api.login handles 401 error', async () => {
|
||||||
|
api.login = jest.fn().mockImplementation(() => {
|
||||||
|
const err = new Error('401 error');
|
||||||
|
err.response = { status: 401, message: 'problem' };
|
||||||
|
return Promise.reject(err);
|
||||||
|
});
|
||||||
|
expect(loginPage.state().loading).toBe(false);
|
||||||
|
loginPage.setState({ username: 'unamee', password: 'pwordd' });
|
||||||
|
submitButton.simulate('submit');
|
||||||
|
expect(api.login).toHaveBeenCalledTimes(1);
|
||||||
|
expect(api.login).toHaveBeenCalledWith('unamee', 'pwordd');
|
||||||
|
expect(loginPage.state().loading).toBe(true);
|
||||||
|
await asyncFlush();
|
||||||
|
expect(loginPage.state().error).toBe(LOGIN_ERROR_MESSAGE);
|
||||||
|
expect(loginPage.state().loading).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('submit calls api.login handles non-401 error', async () => {
|
||||||
|
api.login = jest.fn().mockImplementation(() => {
|
||||||
|
const err = new Error('500 error');
|
||||||
|
err.response = { status: 500, message: 'problem' };
|
||||||
|
return Promise.reject(err);
|
||||||
|
});
|
||||||
|
expect(loginPage.state().loading).toBe(false);
|
||||||
|
loginPage.setState({ username: 'unamee', password: 'pwordd' });
|
||||||
|
submitButton.simulate('submit');
|
||||||
|
expect(api.login).toHaveBeenCalledTimes(1);
|
||||||
|
expect(api.login).toHaveBeenCalledWith('unamee', 'pwordd');
|
||||||
|
expect(loginPage.state().loading).toBe(true);
|
||||||
|
await asyncFlush();
|
||||||
|
expect(loginPage.state().error).toBe('');
|
||||||
|
expect(loginPage.state().loading).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('render Redirect to / when already authenticated', () => {
|
||||||
|
api.isAuthenticated = jest.fn();
|
||||||
|
api.isAuthenticated.mockReturnValue(true);
|
||||||
|
loginWrapper = shallow(<LoginPage />);
|
||||||
|
const redirectElem = loginWrapper.find('Redirect');
|
||||||
|
expect(redirectElem.length).toBe(1);
|
||||||
|
expect(redirectElem.props().to).toBe('/');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
require('@babel/polyfill');
|
require('@babel/polyfill');
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/prefer-default-export
|
||||||
|
export const asyncFlush = () => new Promise((resolve) => setImmediate(resolve));
|
||||||
|
|
||||||
const enzyme = require('enzyme');
|
const enzyme = require('enzyme');
|
||||||
const Adapter = require('enzyme-adapter-react-16');
|
const Adapter = require('enzyme-adapter-react-16');
|
||||||
|
|
||||||
|
|||||||
@@ -41,22 +41,24 @@ class LoginPage extends Component {
|
|||||||
|
|
||||||
handlePasswordChange = value => this.safeSetState({ password: value, error: '' });
|
handlePasswordChange = value => this.safeSetState({ password: value, error: '' });
|
||||||
|
|
||||||
handleSubmit = event => {
|
handleSubmit = async event => {
|
||||||
const { username, password } = this.state;
|
const { username, password, loading } = this.state;
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
this.safeSetState({ loading: true });
|
if (!loading) {
|
||||||
|
this.safeSetState({ loading: true });
|
||||||
|
|
||||||
api.login(username, password)
|
try {
|
||||||
.catch(error => {
|
await api.login(username, password);
|
||||||
|
} catch (error) {
|
||||||
if (error.response.status === 401) {
|
if (error.response.status === 401) {
|
||||||
this.safeSetState({ error: LOGIN_ERROR_MESSAGE });
|
this.safeSetState({ error: LOGIN_ERROR_MESSAGE });
|
||||||
}
|
}
|
||||||
})
|
} finally {
|
||||||
.finally(() => {
|
|
||||||
this.safeSetState({ loading: false });
|
this.safeSetState({ loading: false });
|
||||||
});
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
|
|||||||
Reference in New Issue
Block a user