mirror of
https://github.com/ansible/awx.git
synced 2026-02-19 04:00:06 -03:30
unwind error handling use auth cookie as source of truth, fetch config only when authenticated
216 lines
8.0 KiB
JavaScript
216 lines
8.0 KiB
JavaScript
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('<Login />', () => {
|
|
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(
|
|
<AWXLogin isAuthenticated={() => 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(
|
|
<AWXLogin alt="Foo Application" isAuthenticated={() => 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(
|
|
<AWXLogin isAuthenticated={() => 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(
|
|
<AWXLogin isAuthenticated={() => 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(
|
|
<AWXLogin isAuthenticated={() => 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(
|
|
<AWXLogin isAuthenticated={() => 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(
|
|
<AWXLogin isAuthenticated={() => 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(
|
|
<AWXLogin isAuthenticated={() => 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(
|
|
<AWXLogin isAuthenticated={() => 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(
|
|
<AWXLogin isAuthenticated={() => true} />
|
|
);
|
|
await waitForElement(loginWrapper, 'Redirect', (el) => el.length === 1);
|
|
await waitForElement(loginWrapper, 'Redirect', (el) => el.props().to === '/');
|
|
done();
|
|
});
|
|
});
|