mirror of
https://github.com/ansible/awx.git
synced 2026-02-04 11:08:13 -03:30
Reorganize file locations/directory structure (#270)
Reorganize file locations
This commit is contained in:
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"rules": {
|
||||
"react/jsx-pascal-case": 0
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import { mountWithContexts, waitForElement } from './enzymeHelpers';
|
||||
import { asyncFlush } from '../jest.setup';
|
||||
|
||||
import App from '../src/App';
|
||||
import { ConfigAPI, MeAPI, RootAPI } from '../src/api';
|
||||
|
||||
jest.mock('../src/api');
|
||||
|
||||
describe('<App />', () => {
|
||||
const ansible_version = '111';
|
||||
const custom_virtualenvs = [];
|
||||
const version = '222';
|
||||
|
||||
beforeEach(() => {
|
||||
ConfigAPI.read = () => Promise.resolve({
|
||||
data: {
|
||||
ansible_version,
|
||||
custom_virtualenvs,
|
||||
version
|
||||
}
|
||||
});
|
||||
MeAPI.read = () => Promise.resolve({ data: { results: [{}] } });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('expected content is rendered', () => {
|
||||
const appWrapper = mountWithContexts(
|
||||
<App
|
||||
routeGroups={[
|
||||
{
|
||||
groupTitle: 'Group One',
|
||||
groupId: 'group_one',
|
||||
routes: [
|
||||
{ title: 'Foo', path: '/foo' },
|
||||
{ title: 'Bar', path: '/bar' },
|
||||
],
|
||||
},
|
||||
{
|
||||
groupTitle: 'Group Two',
|
||||
groupId: 'group_two',
|
||||
routes: [
|
||||
{ title: 'Fiz', path: '/fiz' },
|
||||
]
|
||||
}
|
||||
]}
|
||||
render={({ routeGroups }) => (
|
||||
routeGroups.map(({ groupId }) => (<div key={groupId} id={groupId} />))
|
||||
)}
|
||||
/>,
|
||||
);
|
||||
|
||||
// page components
|
||||
expect(appWrapper.length).toBe(1);
|
||||
expect(appWrapper.find('PageHeader').length).toBe(1);
|
||||
expect(appWrapper.find('PageSidebar').length).toBe(1);
|
||||
|
||||
// sidebar groups and route links
|
||||
expect(appWrapper.find('NavExpandableGroup').length).toBe(2);
|
||||
expect(appWrapper.find('a[href="/#/foo"]').length).toBe(1);
|
||||
expect(appWrapper.find('a[href="/#/bar"]').length).toBe(1);
|
||||
expect(appWrapper.find('a[href="/#/fiz"]').length).toBe(1);
|
||||
|
||||
// inline render
|
||||
expect(appWrapper.find('#group_one').length).toBe(1);
|
||||
expect(appWrapper.find('#group_two').length).toBe(1);
|
||||
});
|
||||
|
||||
test('opening the about modal renders prefetched config data', async (done) => {
|
||||
const wrapper = mountWithContexts(<App />);
|
||||
wrapper.update();
|
||||
|
||||
// open about modal
|
||||
const aboutDropdown = 'Dropdown QuestionCircleIcon';
|
||||
const aboutButton = 'DropdownItem li button';
|
||||
const aboutModalContent = 'AboutModalBoxContent';
|
||||
const aboutModalClose = 'button[aria-label="Close Dialog"]';
|
||||
|
||||
await waitForElement(wrapper, aboutDropdown);
|
||||
wrapper.find(aboutDropdown).simulate('click');
|
||||
|
||||
const button = await waitForElement(wrapper, aboutButton, el => !el.props().disabled);
|
||||
button.simulate('click');
|
||||
|
||||
// check about modal content
|
||||
const content = await waitForElement(wrapper, aboutModalContent);
|
||||
expect(content.find('dd').text()).toContain(ansible_version);
|
||||
expect(content.find('pre').text()).toContain(`< AWX ${version} >`);
|
||||
|
||||
// close about modal
|
||||
wrapper.find(aboutModalClose).simulate('click');
|
||||
expect(wrapper.find(aboutModalContent)).toHaveLength(0);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
test('handleNavToggle sets state.isNavOpen to opposite', () => {
|
||||
const appWrapper = mountWithContexts(<App />).find('App');
|
||||
|
||||
const { handleNavToggle } = appWrapper.instance();
|
||||
[true, false, true, false, true].forEach(expected => {
|
||||
expect(appWrapper.state().isNavOpen).toBe(expected);
|
||||
handleNavToggle();
|
||||
});
|
||||
});
|
||||
|
||||
test('onLogout makes expected call to api client', async (done) => {
|
||||
const appWrapper = mountWithContexts(<App />).find('App');
|
||||
appWrapper.instance().handleLogout();
|
||||
await asyncFlush();
|
||||
expect(RootAPI.logout).toHaveBeenCalledTimes(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -1,10 +0,0 @@
|
||||
import { getLanguage } from '../src/RootProvider';
|
||||
|
||||
describe('RootProvider.jsx', () => {
|
||||
test('getLanguage returns the expected language code', () => {
|
||||
expect(getLanguage({ languages: ['es-US'] })).toEqual('es');
|
||||
expect(getLanguage({ languages: ['es-US'], language: 'fr-FR', userLanguage: 'en-US' })).toEqual('es');
|
||||
expect(getLanguage({ language: 'fr-FR', userLanguage: 'en-US' })).toEqual('fr');
|
||||
expect(getLanguage({ userLanguage: 'en-US' })).toEqual('en');
|
||||
});
|
||||
});
|
||||
@@ -1,58 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`mountWithContexts injected ConfigProvider should mount and render with custom Config value 1`] = `
|
||||
<Foo>
|
||||
<div>
|
||||
Fizz
|
||||
1.1
|
||||
</div>
|
||||
</Foo>
|
||||
`;
|
||||
|
||||
exports[`mountWithContexts injected ConfigProvider should mount and render with default values 1`] = `
|
||||
<Foo>
|
||||
<div />
|
||||
</Foo>
|
||||
`;
|
||||
|
||||
exports[`mountWithContexts injected I18nProvider should mount and render 1`] = `
|
||||
<div>
|
||||
<span>
|
||||
Text content
|
||||
</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`mountWithContexts injected I18nProvider should mount and render deeply nested consumer 1`] = `
|
||||
<Parent>
|
||||
<WithI18n>
|
||||
<I18n
|
||||
update={true}
|
||||
withHash={true}
|
||||
>
|
||||
<Component
|
||||
i18n={"/i18n/"}
|
||||
>
|
||||
<div>
|
||||
Text content
|
||||
</div>
|
||||
</Component>
|
||||
</I18n>
|
||||
</WithI18n>
|
||||
</Parent>
|
||||
`;
|
||||
|
||||
exports[`mountWithContexts injected Router should mount and render 1`] = `
|
||||
<div>
|
||||
<Link
|
||||
replace={false}
|
||||
to="/"
|
||||
>
|
||||
<a
|
||||
onClick={[Function]}
|
||||
>
|
||||
home
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
`;
|
||||
@@ -1,97 +0,0 @@
|
||||
import Base from '../../src/api/Base';
|
||||
|
||||
describe('Base', () => {
|
||||
const createPromise = () => Promise.resolve();
|
||||
const mockBaseURL = '/api/v2/organizations/';
|
||||
const mockHttp = ({
|
||||
delete: jest.fn(createPromise),
|
||||
get: jest.fn(createPromise),
|
||||
options: jest.fn(createPromise),
|
||||
patch: jest.fn(createPromise),
|
||||
post: jest.fn(createPromise),
|
||||
put: jest.fn(createPromise)
|
||||
});
|
||||
|
||||
const BaseAPI = new Base(mockHttp, mockBaseURL);
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('create calls http method with expected data', async (done) => {
|
||||
const data = { name: 'test ' };
|
||||
await BaseAPI.create(data);
|
||||
|
||||
expect(mockHttp.post).toHaveBeenCalledTimes(1);
|
||||
expect(mockHttp.post.mock.calls[0][1]).toEqual(data);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
test('destroy calls http method with expected data', async (done) => {
|
||||
const resourceId = 1;
|
||||
await BaseAPI.destroy(resourceId);
|
||||
|
||||
expect(mockHttp.delete).toHaveBeenCalledTimes(1);
|
||||
expect(mockHttp.delete.mock.calls[0][0]).toEqual(`${mockBaseURL}${resourceId}/`);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
test('read calls http method with expected data', async (done) => {
|
||||
const defaultParams = {};
|
||||
const testParams = { foo: 'bar' };
|
||||
|
||||
await BaseAPI.read(testParams);
|
||||
await BaseAPI.read();
|
||||
|
||||
expect(mockHttp.get).toHaveBeenCalledTimes(2);
|
||||
expect(mockHttp.get.mock.calls[0][1]).toEqual({ params: testParams });
|
||||
expect(mockHttp.get.mock.calls[1][1]).toEqual({ params: defaultParams });
|
||||
done();
|
||||
});
|
||||
|
||||
test('readDetail calls http method with expected data', async (done) => {
|
||||
const resourceId = 1;
|
||||
|
||||
await BaseAPI.readDetail(resourceId);
|
||||
|
||||
expect(mockHttp.get).toHaveBeenCalledTimes(1);
|
||||
expect(mockHttp.get.mock.calls[0][0]).toEqual(`${mockBaseURL}${resourceId}/`);
|
||||
done();
|
||||
});
|
||||
|
||||
test('readOptions calls http method with expected data', async (done) => {
|
||||
await BaseAPI.readOptions();
|
||||
|
||||
expect(mockHttp.options).toHaveBeenCalledTimes(1);
|
||||
expect(mockHttp.options.mock.calls[0][0]).toEqual(`${mockBaseURL}`);
|
||||
done();
|
||||
});
|
||||
|
||||
test('replace calls http method with expected data', async (done) => {
|
||||
const resourceId = 1;
|
||||
const data = { name: 'test ' };
|
||||
|
||||
await BaseAPI.replace(resourceId, data);
|
||||
|
||||
expect(mockHttp.put).toHaveBeenCalledTimes(1);
|
||||
expect(mockHttp.put.mock.calls[0][0]).toEqual(`${mockBaseURL}${resourceId}/`);
|
||||
expect(mockHttp.put.mock.calls[0][1]).toEqual(data);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
test('update calls http method with expected data', async (done) => {
|
||||
const resourceId = 1;
|
||||
const data = { name: 'test ' };
|
||||
|
||||
await BaseAPI.update(resourceId, data);
|
||||
|
||||
expect(mockHttp.patch).toHaveBeenCalledTimes(1);
|
||||
expect(mockHttp.patch.mock.calls[0][0]).toEqual(`${mockBaseURL}${resourceId}/`);
|
||||
expect(mockHttp.patch.mock.calls[0][1]).toEqual(data);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -1,39 +0,0 @@
|
||||
import Organizations from '../../src/api/models/Organizations';
|
||||
import { describeNotificationMixin } from './reusable';
|
||||
|
||||
describe('OrganizationsAPI', () => {
|
||||
const orgId = 1;
|
||||
const searchParams = { foo: 'bar' };
|
||||
const createPromise = () => Promise.resolve();
|
||||
const mockHttp = ({ get: jest.fn(createPromise) });
|
||||
|
||||
const OrganizationsAPI = new Organizations(mockHttp);
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('read access list calls get with expected params', async (done) => {
|
||||
await OrganizationsAPI.readAccessList(orgId);
|
||||
await OrganizationsAPI.readAccessList(orgId, searchParams);
|
||||
|
||||
expect(mockHttp.get).toHaveBeenCalledTimes(2);
|
||||
expect(mockHttp.get.mock.calls[0]).toContainEqual(`/api/v2/organizations/${orgId}/access_list/`, { params: {} });
|
||||
expect(mockHttp.get.mock.calls[1]).toContainEqual(`/api/v2/organizations/${orgId}/access_list/`, { params: searchParams });
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
test('read teams calls get with expected params', async (done) => {
|
||||
await OrganizationsAPI.readTeams(orgId);
|
||||
await OrganizationsAPI.readTeams(orgId, searchParams);
|
||||
|
||||
expect(mockHttp.get).toHaveBeenCalledTimes(2);
|
||||
expect(mockHttp.get.mock.calls[0]).toContainEqual(`/api/v2/organizations/${orgId}/teams/`, { params: {} });
|
||||
expect(mockHttp.get.mock.calls[1]).toContainEqual(`/api/v2/organizations/${orgId}/teams/`, { params: searchParams });
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describeNotificationMixin(Organizations, 'Organizations[NotificationsMixin]');
|
||||
@@ -1,34 +0,0 @@
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export function describeNotificationMixin (Model, name) {
|
||||
describe(name, () => {
|
||||
const mockHttp = ({ post: jest.fn(() => Promise.resolve()) });
|
||||
const ModelAPI = new Model(mockHttp);
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
const parameters = [
|
||||
['success', true],
|
||||
['success', false],
|
||||
['error', true],
|
||||
['error', false],
|
||||
];
|
||||
parameters.forEach(([type, state]) => {
|
||||
const label = `[notificationType=${type}, associationState=${state}]`;
|
||||
const testName = `updateNotificationTemplateAssociation ${label} makes expected http calls`;
|
||||
|
||||
test(testName, async (done) => {
|
||||
await ModelAPI.updateNotificationTemplateAssociation(1, 21, type, state);
|
||||
|
||||
const expectedPath = `${ModelAPI.baseUrl}1/notification_templates_${type}/`;
|
||||
expect(mockHttp.post).toHaveBeenCalledTimes(1);
|
||||
|
||||
const expectedParams = state ? { id: 21 } : { id: 21, disassociate: true };
|
||||
expect(mockHttp.post.mock.calls.pop()).toEqual([expectedPath, expectedParams]);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import Root from '../../src/api/models/Root';
|
||||
|
||||
describe('RootAPI', () => {
|
||||
const createPromise = () => Promise.resolve();
|
||||
const mockHttp = ({ get: jest.fn(createPromise), post: jest.fn(createPromise) });
|
||||
|
||||
const RootAPI = new Root(mockHttp);
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('login calls get and post with expected content headers', async (done) => {
|
||||
const headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
|
||||
|
||||
await RootAPI.login('username', 'password');
|
||||
|
||||
expect(mockHttp.get).toHaveBeenCalledTimes(1);
|
||||
expect(mockHttp.get.mock.calls[0]).toContainEqual({ headers });
|
||||
|
||||
expect(mockHttp.post).toHaveBeenCalledTimes(1);
|
||||
expect(mockHttp.post.mock.calls[0]).toContainEqual({ headers });
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
test('login sends expected data', async (done) => {
|
||||
await RootAPI.login('foo', 'bar');
|
||||
await RootAPI.login('foo', 'bar', 'baz');
|
||||
|
||||
expect(mockHttp.post).toHaveBeenCalledTimes(2);
|
||||
expect(mockHttp.post.mock.calls[0]).toContainEqual('username=foo&password=bar&next=%2Fapi%2Fv2%2Fconfig%2F');
|
||||
expect(mockHttp.post.mock.calls[1]).toContainEqual('username=foo&password=bar&next=baz');
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
test('logout calls expected http method', async (done) => {
|
||||
await RootAPI.logout();
|
||||
|
||||
expect(mockHttp.get).toHaveBeenCalledTimes(1);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -1,35 +0,0 @@
|
||||
import Teams from '../../src/api/models/Teams';
|
||||
|
||||
describe('TeamsAPI', () => {
|
||||
const teamId = 1;
|
||||
const roleId = 7;
|
||||
const createPromise = () => Promise.resolve();
|
||||
const mockHttp = ({ post: jest.fn(createPromise) });
|
||||
|
||||
const TeamsAPI = new Teams(mockHttp);
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('associate role calls post with expected params', async (done) => {
|
||||
await TeamsAPI.associateRole(teamId, roleId);
|
||||
|
||||
expect(mockHttp.post).toHaveBeenCalledTimes(1);
|
||||
expect(mockHttp.post.mock.calls[0]).toContainEqual(`/api/v2/teams/${teamId}/roles/`, { id: roleId });
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
test('read teams calls post with expected params', async (done) => {
|
||||
await TeamsAPI.disassociateRole(teamId, roleId);
|
||||
|
||||
expect(mockHttp.post).toHaveBeenCalledTimes(1);
|
||||
expect(mockHttp.post.mock.calls[0]).toContainEqual(`/api/v2/teams/${teamId}/roles/`, {
|
||||
id: roleId,
|
||||
disassociate: true
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -1,35 +0,0 @@
|
||||
import Users from '../../src/api/models/Users';
|
||||
|
||||
describe('UsersAPI', () => {
|
||||
const userId = 1;
|
||||
const roleId = 7;
|
||||
const createPromise = () => Promise.resolve();
|
||||
const mockHttp = ({ post: jest.fn(createPromise) });
|
||||
|
||||
const UsersAPI = new Users(mockHttp);
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('associate role calls post with expected params', async (done) => {
|
||||
await UsersAPI.associateRole(userId, roleId);
|
||||
|
||||
expect(mockHttp.post).toHaveBeenCalledTimes(1);
|
||||
expect(mockHttp.post.mock.calls[0]).toContainEqual(`/api/v2/users/${userId}/roles/`, { id: roleId });
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
test('read users calls post with expected params', async (done) => {
|
||||
await UsersAPI.disassociateRole(userId, roleId);
|
||||
|
||||
expect(mockHttp.post).toHaveBeenCalledTimes(1);
|
||||
expect(mockHttp.post.mock.calls[0]).toContainEqual(`/api/v2/users/${userId}/roles/`, {
|
||||
id: roleId,
|
||||
disassociate: true
|
||||
});
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -1,26 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import About from '../../src/components/About';
|
||||
|
||||
describe('<About />', () => {
|
||||
let aboutWrapper;
|
||||
let closeButton;
|
||||
const onClose = jest.fn();
|
||||
test('initially renders without crashing', () => {
|
||||
aboutWrapper = mountWithContexts(
|
||||
<About isOpen onClose={onClose} />
|
||||
);
|
||||
expect(aboutWrapper.length).toBe(1);
|
||||
aboutWrapper.unmount();
|
||||
});
|
||||
|
||||
test('close button calls onClose handler', () => {
|
||||
aboutWrapper = mountWithContexts(
|
||||
<About isOpen onClose={onClose} />
|
||||
);
|
||||
closeButton = aboutWrapper.find('AboutModalBoxCloseButton Button');
|
||||
closeButton.simulate('click');
|
||||
expect(onClose).toBeCalled();
|
||||
aboutWrapper.unmount();
|
||||
});
|
||||
});
|
||||
@@ -1,223 +0,0 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import AddResourceRole, { _AddResourceRole } from '../../src/components/AddRole/AddResourceRole';
|
||||
import { TeamsAPI, UsersAPI } from '../../src/api';
|
||||
|
||||
jest.mock('../../src/api');
|
||||
|
||||
describe('<_AddResourceRole />', () => {
|
||||
UsersAPI.read.mockResolvedValue({
|
||||
data: {
|
||||
count: 2,
|
||||
results: [
|
||||
{ id: 1, username: 'foo' },
|
||||
{ id: 2, username: 'bar' }
|
||||
]
|
||||
}
|
||||
});
|
||||
const roles = {
|
||||
admin_role: {
|
||||
description: 'Can manage all aspects of the organization',
|
||||
id: 1,
|
||||
name: 'Admin'
|
||||
},
|
||||
execute_role: {
|
||||
description: 'May run any executable resources in the organization',
|
||||
id: 2,
|
||||
name: 'Execute'
|
||||
}
|
||||
};
|
||||
test('initially renders without crashing', () => {
|
||||
shallow(
|
||||
<_AddResourceRole
|
||||
onClose={() => {}}
|
||||
onSave={() => {}}
|
||||
roles={roles}
|
||||
i18n={{ _: val => val.toString() }}
|
||||
/>
|
||||
);
|
||||
});
|
||||
test('handleRoleCheckboxClick properly updates state', () => {
|
||||
const wrapper = shallow(
|
||||
<_AddResourceRole
|
||||
onClose={() => {}}
|
||||
onSave={() => {}}
|
||||
roles={roles}
|
||||
i18n={{ _: val => val.toString() }}
|
||||
/>
|
||||
);
|
||||
wrapper.setState({
|
||||
selectedRoleRows: [
|
||||
{
|
||||
description: 'Can manage all aspects of the organization',
|
||||
name: 'Admin',
|
||||
id: 1
|
||||
}
|
||||
]
|
||||
});
|
||||
wrapper.instance().handleRoleCheckboxClick({
|
||||
description: 'Can manage all aspects of the organization',
|
||||
name: 'Admin',
|
||||
id: 1
|
||||
});
|
||||
expect(wrapper.state('selectedRoleRows')).toEqual([]);
|
||||
wrapper.instance().handleRoleCheckboxClick({
|
||||
description: 'Can manage all aspects of the organization',
|
||||
name: 'Admin',
|
||||
id: 1
|
||||
});
|
||||
expect(wrapper.state('selectedRoleRows')).toEqual([{
|
||||
description: 'Can manage all aspects of the organization',
|
||||
name: 'Admin',
|
||||
id: 1
|
||||
}]);
|
||||
});
|
||||
test('handleResourceCheckboxClick properly updates state', () => {
|
||||
const wrapper = shallow(
|
||||
<_AddResourceRole
|
||||
onClose={() => {}}
|
||||
onSave={() => {}}
|
||||
roles={roles}
|
||||
i18n={{ _: val => val.toString() }}
|
||||
/>
|
||||
);
|
||||
wrapper.setState({
|
||||
selectedResourceRows: [
|
||||
{
|
||||
id: 1,
|
||||
username: 'foobar'
|
||||
}
|
||||
]
|
||||
});
|
||||
wrapper.instance().handleResourceCheckboxClick({
|
||||
id: 1,
|
||||
username: 'foobar'
|
||||
});
|
||||
expect(wrapper.state('selectedResourceRows')).toEqual([]);
|
||||
wrapper.instance().handleResourceCheckboxClick({
|
||||
id: 1,
|
||||
username: 'foobar'
|
||||
});
|
||||
expect(wrapper.state('selectedResourceRows')).toEqual([{
|
||||
id: 1,
|
||||
username: 'foobar'
|
||||
}]);
|
||||
});
|
||||
test('clicking user/team cards updates state', () => {
|
||||
const spy = jest.spyOn(_AddResourceRole.prototype, 'handleResourceSelect');
|
||||
const wrapper = mountWithContexts(
|
||||
<AddResourceRole
|
||||
onClose={() => {}}
|
||||
onSave={() => {}}
|
||||
roles={roles}
|
||||
/>, { context: { network: { handleHttpError: () => {} } } }
|
||||
).find('AddResourceRole');
|
||||
const selectableCardWrapper = wrapper.find('SelectableCard');
|
||||
expect(selectableCardWrapper.length).toBe(2);
|
||||
selectableCardWrapper.first().simulate('click');
|
||||
expect(spy).toHaveBeenCalledWith('users');
|
||||
expect(wrapper.state('selectedResource')).toBe('users');
|
||||
selectableCardWrapper.at(1).simulate('click');
|
||||
expect(spy).toHaveBeenCalledWith('teams');
|
||||
expect(wrapper.state('selectedResource')).toBe('teams');
|
||||
});
|
||||
test('handleResourceSelect clears out selected lists and sets selectedResource', () => {
|
||||
const wrapper = shallow(
|
||||
<_AddResourceRole
|
||||
onClose={() => {}}
|
||||
onSave={() => {}}
|
||||
roles={roles}
|
||||
i18n={{ _: val => val.toString() }}
|
||||
/>
|
||||
);
|
||||
wrapper.setState({
|
||||
selectedResource: 'teams',
|
||||
selectedResourceRows: [
|
||||
{
|
||||
id: 1,
|
||||
username: 'foobar'
|
||||
}
|
||||
],
|
||||
selectedRoleRows: [
|
||||
{
|
||||
description: 'Can manage all aspects of the organization',
|
||||
id: 1,
|
||||
name: 'Admin'
|
||||
}
|
||||
]
|
||||
});
|
||||
wrapper.instance().handleResourceSelect('users');
|
||||
expect(wrapper.state()).toEqual({
|
||||
selectedResource: 'users',
|
||||
selectedResourceRows: [],
|
||||
selectedRoleRows: [],
|
||||
currentStepId: 1,
|
||||
});
|
||||
wrapper.instance().handleResourceSelect('teams');
|
||||
expect(wrapper.state()).toEqual({
|
||||
selectedResource: 'teams',
|
||||
selectedResourceRows: [],
|
||||
selectedRoleRows: [],
|
||||
currentStepId: 1
|
||||
});
|
||||
});
|
||||
test('handleWizardSave makes correct api calls, calls onSave when done', async () => {
|
||||
const handleSave = jest.fn();
|
||||
const wrapper = mountWithContexts(
|
||||
<AddResourceRole
|
||||
onClose={() => {}}
|
||||
onSave={handleSave}
|
||||
roles={roles}
|
||||
/>, { context: { network: { handleHttpError: () => {} } } }
|
||||
).find('AddResourceRole');
|
||||
wrapper.setState({
|
||||
selectedResource: 'users',
|
||||
selectedResourceRows: [
|
||||
{
|
||||
id: 1,
|
||||
username: 'foobar'
|
||||
}
|
||||
],
|
||||
selectedRoleRows: [
|
||||
{
|
||||
description: 'Can manage all aspects of the organization',
|
||||
id: 1,
|
||||
name: 'Admin'
|
||||
},
|
||||
{
|
||||
description: 'May run any executable resources in the organization',
|
||||
id: 2,
|
||||
name: 'Execute'
|
||||
}
|
||||
]
|
||||
});
|
||||
await wrapper.instance().handleWizardSave();
|
||||
expect(UsersAPI.associateRole).toHaveBeenCalledTimes(2);
|
||||
expect(handleSave).toHaveBeenCalled();
|
||||
wrapper.setState({
|
||||
selectedResource: 'teams',
|
||||
selectedResourceRows: [
|
||||
{
|
||||
id: 1,
|
||||
name: 'foobar'
|
||||
}
|
||||
],
|
||||
selectedRoleRows: [
|
||||
{
|
||||
description: 'Can manage all aspects of the organization',
|
||||
id: 1,
|
||||
name: 'Admin'
|
||||
},
|
||||
{
|
||||
description: 'May run any executable resources in the organization',
|
||||
id: 2,
|
||||
name: 'Execute'
|
||||
}
|
||||
]
|
||||
});
|
||||
await wrapper.instance().handleWizardSave();
|
||||
expect(TeamsAPI.associateRole).toHaveBeenCalledTimes(2);
|
||||
expect(handleSave).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -1,50 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import AnsibleSelect from '../../src/components/AnsibleSelect';
|
||||
import { _AnsibleSelect } from '../../src/components/AnsibleSelect/AnsibleSelect';
|
||||
|
||||
const label = 'test select';
|
||||
const mockData = ['/venv/baz/', '/venv/ansible/'];
|
||||
describe('<AnsibleSelect />', () => {
|
||||
test('initially renders succesfully', async () => {
|
||||
mountWithContexts(
|
||||
<AnsibleSelect
|
||||
value="foo"
|
||||
name="bar"
|
||||
onChange={() => { }}
|
||||
label={label}
|
||||
data={mockData}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
test('calls "onSelectChange" on dropdown select change', () => {
|
||||
const spy = jest.spyOn(_AnsibleSelect.prototype, 'onSelectChange');
|
||||
const wrapper = mountWithContexts(
|
||||
<AnsibleSelect
|
||||
value="foo"
|
||||
name="bar"
|
||||
onChange={() => { }}
|
||||
label={label}
|
||||
data={mockData}
|
||||
/>
|
||||
);
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
wrapper.find('select').simulate('change');
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('Returns correct select options if defaultSelected props is passed', () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<AnsibleSelect
|
||||
value="foo"
|
||||
name="bar"
|
||||
onChange={() => { }}
|
||||
label={label}
|
||||
data={mockData}
|
||||
defaultSelected={mockData[1]}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find('FormSelect')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
@@ -1,13 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
|
||||
import Background from '../../src/components/Background';
|
||||
|
||||
describe('Background', () => {
|
||||
test('renders the expected content', () => {
|
||||
const wrapper = mount(<Background><div id="test" /></Background>);
|
||||
expect(wrapper).toHaveLength(1);
|
||||
expect(wrapper.find('BackgroundImage')).toHaveLength(1);
|
||||
expect(wrapper.find('#test')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
@@ -1,24 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import BrandLogo from '../../src/components/BrandLogo';
|
||||
|
||||
let logoWrapper;
|
||||
let brandLogoElem;
|
||||
let svgElem;
|
||||
|
||||
const findChildren = () => {
|
||||
brandLogoElem = logoWrapper.find('BrandLogo');
|
||||
svgElem = logoWrapper.find('svg');
|
||||
};
|
||||
|
||||
describe('<BrandLogo />', () => {
|
||||
test('initially renders without crashing', () => {
|
||||
logoWrapper = mountWithContexts(
|
||||
<BrandLogo />
|
||||
);
|
||||
findChildren();
|
||||
expect(logoWrapper.length).toBe(1);
|
||||
expect(brandLogoElem.length).toBe(1);
|
||||
expect(svgElem.length).toBe(1);
|
||||
});
|
||||
});
|
||||
@@ -1,68 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import Breadcrumbs from '../../src/components/Breadcrumbs/Breadcrumbs';
|
||||
|
||||
describe('<Breadcrumb />', () => {
|
||||
let breadcrumbWrapper;
|
||||
let breadcrumb;
|
||||
let breadcrumbItem;
|
||||
let breadcrumbHeading;
|
||||
|
||||
const config = {
|
||||
'/foo': 'Foo',
|
||||
'/foo/1': 'One',
|
||||
'/foo/1/bar': 'Bar',
|
||||
'/foo/1/bar/fiz': 'Fiz'
|
||||
};
|
||||
|
||||
const findChildren = () => {
|
||||
breadcrumb = breadcrumbWrapper.find('Breadcrumb');
|
||||
breadcrumbItem = breadcrumbWrapper.find('BreadcrumbItem');
|
||||
breadcrumbHeading = breadcrumbWrapper.find('BreadcrumbHeading');
|
||||
};
|
||||
|
||||
test('initially renders succesfully', () => {
|
||||
breadcrumbWrapper = mount(
|
||||
<MemoryRouter initialEntries={['/foo/1/bar']} initialIndex={0}>
|
||||
<Breadcrumbs
|
||||
breadcrumbConfig={config}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
findChildren();
|
||||
|
||||
expect(breadcrumb).toHaveLength(1);
|
||||
expect(breadcrumbItem).toHaveLength(2);
|
||||
expect(breadcrumbHeading).toHaveLength(1);
|
||||
expect(breadcrumbItem.first().text()).toBe('Foo');
|
||||
expect(breadcrumbItem.last().text()).toBe('One');
|
||||
expect(breadcrumbHeading.text()).toBe('Bar');
|
||||
breadcrumbWrapper.unmount();
|
||||
});
|
||||
|
||||
test('renders breadcrumb items defined in breadcrumbConfig', () => {
|
||||
const routes = [
|
||||
['/fo', 0],
|
||||
['/foo', 0],
|
||||
['/foo/1', 1],
|
||||
['/foo/baz', 1],
|
||||
['/foo/1/bar', 2],
|
||||
['/foo/1/bar/fiz', 3],
|
||||
];
|
||||
|
||||
routes.forEach(([location, crumbLength]) => {
|
||||
breadcrumbWrapper = mount(
|
||||
<MemoryRouter initialEntries={[location]}>
|
||||
<Breadcrumbs
|
||||
breadcrumbConfig={config}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
expect(breadcrumbWrapper.find('BreadcrumbItem')).toHaveLength(crumbLength);
|
||||
breadcrumbWrapper.unmount();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,23 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import CardCloseButton from '../../src/components/CardCloseButton';
|
||||
|
||||
describe('<CardCloseButton>', () => {
|
||||
test('should render close button', () => {
|
||||
const wrapper = mountWithContexts(<CardCloseButton />);
|
||||
const button = wrapper.find('Button');
|
||||
expect(button).toHaveLength(1);
|
||||
expect(button.prop('variant')).toBe('plain');
|
||||
expect(button.prop('aria-label')).toBe('Close');
|
||||
expect(wrapper.find('Link')).toHaveLength(0);
|
||||
});
|
||||
|
||||
test('should render close link when `linkTo` prop provided', () => {
|
||||
const wrapper = mountWithContexts(<CardCloseButton linkTo="/foo" />);
|
||||
expect(wrapper.find('Button')).toHaveLength(0);
|
||||
const link = wrapper.find('Link');
|
||||
expect(link).toHaveLength(1);
|
||||
expect(link.prop('to')).toEqual('/foo');
|
||||
expect(link.prop('aria-label')).toEqual('Close');
|
||||
});
|
||||
});
|
||||
@@ -1,16 +0,0 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import CheckboxCard from '../../src/components/AddRole/CheckboxCard';
|
||||
|
||||
describe('<CheckboxCard />', () => {
|
||||
let wrapper;
|
||||
test('initially renders without crashing', () => {
|
||||
wrapper = shallow(
|
||||
<CheckboxCard
|
||||
name="Foobar"
|
||||
itemId={5}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.length).toBe(1);
|
||||
});
|
||||
});
|
||||
@@ -1,69 +0,0 @@
|
||||
import React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { mountWithContexts } from '../../enzymeHelpers';
|
||||
import { ChipGroup, Chip } from '../../../src/components/Chip';
|
||||
|
||||
describe('<ChipGroup />', () => {
|
||||
test('should render all chips', () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<ChipGroup>
|
||||
<Chip>One</Chip>
|
||||
<Chip>Two</Chip>
|
||||
<Chip>Three</Chip>
|
||||
<Chip>Four</Chip>
|
||||
<Chip>Five</Chip>
|
||||
<Chip>Six</Chip>
|
||||
</ChipGroup>
|
||||
);
|
||||
expect(wrapper.find(Chip)).toHaveLength(6);
|
||||
expect(wrapper.find('li')).toHaveLength(6);
|
||||
});
|
||||
|
||||
test('should render show more toggle', () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<ChipGroup showOverflowAfter={5}>
|
||||
<Chip>One</Chip>
|
||||
<Chip>Two</Chip>
|
||||
<Chip>Three</Chip>
|
||||
<Chip>Four</Chip>
|
||||
<Chip>Five</Chip>
|
||||
<Chip>Six</Chip>
|
||||
<Chip>Seven</Chip>
|
||||
</ChipGroup>
|
||||
);
|
||||
expect(wrapper.find(Chip)).toHaveLength(6);
|
||||
const toggle = wrapper.find(Chip).at(5);
|
||||
expect(toggle.prop('isOverflowChip')).toBe(true);
|
||||
expect(toggle.text()).toEqual('2 more');
|
||||
});
|
||||
|
||||
test('should render show less toggle', () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<ChipGroup showOverflowAfter={5}>
|
||||
<Chip>One</Chip>
|
||||
<Chip>Two</Chip>
|
||||
<Chip>Three</Chip>
|
||||
<Chip>Four</Chip>
|
||||
<Chip>Five</Chip>
|
||||
<Chip>Six</Chip>
|
||||
<Chip>Seven</Chip>
|
||||
</ChipGroup>
|
||||
);
|
||||
expect(wrapper.find(Chip)).toHaveLength(6);
|
||||
const toggle = wrapper.find(Chip).at(5);
|
||||
expect(toggle.prop('isOverflowChip')).toBe(true);
|
||||
act(() => {
|
||||
toggle.prop('onClick')();
|
||||
});
|
||||
wrapper.update();
|
||||
expect(wrapper.find(Chip)).toHaveLength(8);
|
||||
expect(wrapper.find(Chip).at(7).text()).toEqual('Show Less');
|
||||
act(() => {
|
||||
const toggle2 = wrapper.find(Chip).at(7);
|
||||
expect(toggle2.prop('isOverflowChip')).toBe(true);
|
||||
toggle2.prop('onClick')();
|
||||
});
|
||||
wrapper.update();
|
||||
expect(wrapper.find(Chip)).toHaveLength(6);
|
||||
});
|
||||
});
|
||||
@@ -1,199 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import DataListToolbar from '../../src/components/DataListToolbar';
|
||||
|
||||
describe('<DataListToolbar />', () => {
|
||||
let toolbar;
|
||||
|
||||
afterEach(() => {
|
||||
if (toolbar) {
|
||||
toolbar.unmount();
|
||||
toolbar = null;
|
||||
}
|
||||
});
|
||||
|
||||
test('it triggers the expected callbacks', () => {
|
||||
const columns = [{ name: 'Name', key: 'name', isSortable: true }];
|
||||
|
||||
const search = 'button[aria-label="Search"]';
|
||||
const searchTextInput = 'input[aria-label="Search text input"]';
|
||||
const selectAll = 'input[aria-label="Select all"]';
|
||||
const sort = 'button[aria-label="Sort"]';
|
||||
|
||||
const onSearch = jest.fn();
|
||||
const onSort = jest.fn();
|
||||
const onSelectAll = jest.fn();
|
||||
|
||||
toolbar = mountWithContexts(
|
||||
<DataListToolbar
|
||||
isAllSelected={false}
|
||||
showExpandCollapse
|
||||
sortedColumnKey="name"
|
||||
sortOrder="ascending"
|
||||
columns={columns}
|
||||
onSearch={onSearch}
|
||||
onSort={onSort}
|
||||
onSelectAll={onSelectAll}
|
||||
showSelectAll
|
||||
/>
|
||||
);
|
||||
|
||||
toolbar.find(sort).simulate('click');
|
||||
toolbar.find(selectAll).simulate('change', { target: { checked: false } });
|
||||
|
||||
expect(onSelectAll).toHaveBeenCalledTimes(1);
|
||||
expect(onSort).toHaveBeenCalledTimes(1);
|
||||
expect(onSort).toBeCalledWith('name', 'descending');
|
||||
|
||||
expect(onSelectAll).toHaveBeenCalledTimes(1);
|
||||
expect(onSelectAll.mock.calls[0][0]).toBe(false);
|
||||
|
||||
toolbar.find(searchTextInput).instance().value = 'test-321';
|
||||
toolbar.find(searchTextInput).simulate('change');
|
||||
toolbar.find(search).simulate('click');
|
||||
|
||||
expect(onSearch).toHaveBeenCalledTimes(1);
|
||||
expect(onSearch).toBeCalledWith('test-321');
|
||||
});
|
||||
|
||||
test('dropdown items sortable columns work', () => {
|
||||
const sortDropdownToggleSelector = 'button[id="awx-sort"]';
|
||||
const searchDropdownToggleSelector = 'button[id="awx-search"]';
|
||||
const dropdownMenuItems = 'DropdownMenu > ul';
|
||||
|
||||
const multipleColumns = [
|
||||
{ name: 'Foo', key: 'foo', isSortable: true },
|
||||
{ name: 'Bar', key: 'bar', isSortable: true },
|
||||
{ name: 'Bakery', key: 'bakery', isSortable: true },
|
||||
{ name: 'Baz', key: 'baz' }
|
||||
];
|
||||
|
||||
const onSort = jest.fn();
|
||||
|
||||
toolbar = mountWithContexts(
|
||||
<DataListToolbar
|
||||
sortedColumnKey="foo"
|
||||
sortOrder="ascending"
|
||||
columns={multipleColumns}
|
||||
onSort={onSort}
|
||||
/>
|
||||
);
|
||||
const sortDropdownToggle = toolbar.find(sortDropdownToggleSelector);
|
||||
expect(sortDropdownToggle.length).toBe(1);
|
||||
sortDropdownToggle.simulate('click');
|
||||
toolbar.update();
|
||||
const sortDropdownItems = toolbar.find(dropdownMenuItems).children();
|
||||
expect(sortDropdownItems.length).toBe(2);
|
||||
|
||||
const mockedSortEvent = { target: { innerText: 'Bar' } };
|
||||
sortDropdownItems.at(0).simulate('click', mockedSortEvent);
|
||||
toolbar = mountWithContexts(
|
||||
<DataListToolbar
|
||||
sortedColumnKey="foo"
|
||||
sortOrder="descending"
|
||||
columns={multipleColumns}
|
||||
onSort={onSort}
|
||||
/>
|
||||
);
|
||||
toolbar.update();
|
||||
|
||||
const sortDropdownToggleDescending = toolbar.find(sortDropdownToggleSelector);
|
||||
expect(sortDropdownToggleDescending.length).toBe(1);
|
||||
sortDropdownToggleDescending.simulate('click');
|
||||
toolbar.update();
|
||||
|
||||
const sortDropdownItemsDescending = toolbar.find(dropdownMenuItems).children();
|
||||
expect(sortDropdownItemsDescending.length).toBe(2);
|
||||
sortDropdownToggleDescending.simulate('click'); // toggle close the sort dropdown
|
||||
|
||||
const mockedSortEventDescending = { target: { innerText: 'Bar' } };
|
||||
sortDropdownItems.at(0).simulate('click', mockedSortEventDescending);
|
||||
toolbar.update();
|
||||
|
||||
const searchDropdownToggle = toolbar.find(searchDropdownToggleSelector);
|
||||
expect(searchDropdownToggle.length).toBe(1);
|
||||
searchDropdownToggle.simulate('click');
|
||||
toolbar.update();
|
||||
|
||||
const searchDropdownItems = toolbar.find(dropdownMenuItems).children();
|
||||
expect(searchDropdownItems.length).toBe(3);
|
||||
|
||||
const mockedSearchEvent = { target: { innerText: 'Bar' } };
|
||||
searchDropdownItems.at(0).simulate('click', mockedSearchEvent);
|
||||
});
|
||||
|
||||
test('it displays correct sort icon', () => {
|
||||
const downNumericIconSelector = 'SortNumericDownIcon';
|
||||
const upNumericIconSelector = 'SortNumericUpIcon';
|
||||
const downAlphaIconSelector = 'SortAlphaDownIcon';
|
||||
const upAlphaIconSelector = 'SortAlphaUpIcon';
|
||||
|
||||
const numericColumns = [{ name: 'ID', key: 'id', isSortable: true, isNumeric: true }];
|
||||
const alphaColumns = [{ name: 'Name', key: 'name', isSortable: true, isNumeric: false }];
|
||||
|
||||
toolbar = mountWithContexts(
|
||||
<DataListToolbar
|
||||
sortedColumnKey="id"
|
||||
sortOrder="descending"
|
||||
columns={numericColumns}
|
||||
/>
|
||||
);
|
||||
|
||||
const downNumericIcon = toolbar.find(downNumericIconSelector);
|
||||
expect(downNumericIcon.length).toBe(1);
|
||||
|
||||
toolbar = mountWithContexts(
|
||||
<DataListToolbar
|
||||
sortedColumnKey="id"
|
||||
sortOrder="ascending"
|
||||
columns={numericColumns}
|
||||
/>
|
||||
);
|
||||
|
||||
const upNumericIcon = toolbar.find(upNumericIconSelector);
|
||||
expect(upNumericIcon.length).toBe(1);
|
||||
|
||||
toolbar = mountWithContexts(
|
||||
<DataListToolbar
|
||||
sortedColumnKey="name"
|
||||
sortOrder="descending"
|
||||
columns={alphaColumns}
|
||||
/>
|
||||
);
|
||||
|
||||
const downAlphaIcon = toolbar.find(downAlphaIconSelector);
|
||||
expect(downAlphaIcon.length).toBe(1);
|
||||
|
||||
toolbar = mountWithContexts(
|
||||
<DataListToolbar
|
||||
sortedColumnKey="name"
|
||||
sortOrder="ascending"
|
||||
columns={alphaColumns}
|
||||
/>
|
||||
);
|
||||
|
||||
const upAlphaIcon = toolbar.find(upAlphaIconSelector);
|
||||
expect(upAlphaIcon.length).toBe(1);
|
||||
});
|
||||
|
||||
test('should render additionalControls', () => {
|
||||
const columns = [{ name: 'Name', key: 'name', isSortable: true }];
|
||||
const onSearch = jest.fn();
|
||||
const onSort = jest.fn();
|
||||
const onSelectAll = jest.fn();
|
||||
|
||||
toolbar = mountWithContexts(
|
||||
<DataListToolbar
|
||||
columns={columns}
|
||||
onSearch={onSearch}
|
||||
onSort={onSort}
|
||||
onSelectAll={onSelectAll}
|
||||
additionalControls={[<button key="1" id="test" type="button">click</button>]}
|
||||
/>
|
||||
);
|
||||
|
||||
const button = toolbar.find('#test');
|
||||
expect(button).toHaveLength(1);
|
||||
expect(button.text()).toEqual('click');
|
||||
});
|
||||
});
|
||||
@@ -1,20 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import ExpandCollapse from '../../src/components/ExpandCollapse';
|
||||
|
||||
describe('<ExpandCollapse />', () => {
|
||||
const onCompact = jest.fn();
|
||||
const onExpand = jest.fn();
|
||||
const isCompact = false;
|
||||
test('initially renders without crashing', () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<ExpandCollapse
|
||||
onCompact={onCompact}
|
||||
onExpand={onExpand}
|
||||
isCompact={isCompact}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.length).toBe(1);
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
@@ -1,228 +0,0 @@
|
||||
import React from 'react';
|
||||
import { createMemoryHistory } from 'history';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import Lookup from '../../src/components/Lookup';
|
||||
import { _Lookup } from '../../src/components/Lookup/Lookup';
|
||||
|
||||
let mockData = [{ name: 'foo', id: 1, isChecked: false }];
|
||||
const mockColumns = [
|
||||
{ name: 'Name', key: 'name', isSortable: true }
|
||||
];
|
||||
describe('<Lookup />', () => {
|
||||
test('initially renders succesfully', () => {
|
||||
mountWithContexts(
|
||||
<Lookup
|
||||
lookupHeader="Foo Bar"
|
||||
name="fooBar"
|
||||
value={mockData}
|
||||
onLookupSave={() => { }}
|
||||
getItems={() => { }}
|
||||
columns={mockColumns}
|
||||
sortedColumnKey="name"
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
test('API response is formatted properly', (done) => {
|
||||
const wrapper = mountWithContexts(
|
||||
<Lookup
|
||||
lookupHeader="Foo Bar"
|
||||
name="fooBar"
|
||||
value={mockData}
|
||||
onLookupSave={() => { }}
|
||||
getItems={() => ({ data: { results: [{ name: 'test instance', id: 1 }] } })}
|
||||
columns={mockColumns}
|
||||
sortedColumnKey="name"
|
||||
/>
|
||||
).find('Lookup');
|
||||
|
||||
setImmediate(() => {
|
||||
expect(wrapper.state().results).toEqual([{ id: 1, name: 'test instance' }]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('Opens modal when search icon is clicked', () => {
|
||||
const spy = jest.spyOn(_Lookup.prototype, 'handleModalToggle');
|
||||
const mockSelected = [{ name: 'foo', id: 1 }];
|
||||
const wrapper = mountWithContexts(
|
||||
<Lookup
|
||||
id="search"
|
||||
lookupHeader="Foo Bar"
|
||||
name="fooBar"
|
||||
value={mockSelected}
|
||||
onLookupSave={() => { }}
|
||||
getItems={() => { }}
|
||||
columns={mockColumns}
|
||||
sortedColumnKey="name"
|
||||
/>
|
||||
).find('Lookup');
|
||||
expect(spy).not.toHaveBeenCalled();
|
||||
expect(wrapper.state('lookupSelectedItems')).toEqual(mockSelected);
|
||||
const searchItem = wrapper.find('button[aria-label="Search"]');
|
||||
searchItem.first().simulate('click');
|
||||
expect(spy).toHaveBeenCalled();
|
||||
expect(wrapper.state('lookupSelectedItems')).toEqual([{
|
||||
id: 1,
|
||||
name: 'foo'
|
||||
}]);
|
||||
expect(wrapper.state('isModalOpen')).toEqual(true);
|
||||
});
|
||||
|
||||
test('calls "toggleSelected" when a user changes a checkbox', (done) => {
|
||||
const spy = jest.spyOn(_Lookup.prototype, 'toggleSelected');
|
||||
const mockSelected = [{ name: 'foo', id: 1 }];
|
||||
const data = {
|
||||
results: [
|
||||
{ name: 'test instance', id: 1, url: '/foo' }
|
||||
],
|
||||
count: 1,
|
||||
};
|
||||
const wrapper = mountWithContexts(
|
||||
<Lookup
|
||||
id="search"
|
||||
lookupHeader="Foo Bar"
|
||||
name="fooBar"
|
||||
value={mockSelected}
|
||||
onLookupSave={() => { }}
|
||||
getItems={() => ({ data })}
|
||||
columns={mockColumns}
|
||||
sortedColumnKey="name"
|
||||
/>
|
||||
);
|
||||
setImmediate(() => {
|
||||
const searchItem = wrapper.find('button[aria-label="Search"]');
|
||||
searchItem.first().simulate('click');
|
||||
wrapper.find('input[type="checkbox"]').simulate('change');
|
||||
expect(spy).toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('calls "toggleSelected" when remove icon is clicked', () => {
|
||||
const spy = jest.spyOn(_Lookup.prototype, 'toggleSelected');
|
||||
mockData = [{ name: 'foo', id: 1 }, { name: 'bar', id: 2 }];
|
||||
const data = {
|
||||
results: [
|
||||
{ name: 'test instance', id: 1, url: '/foo' }
|
||||
],
|
||||
count: 1,
|
||||
};
|
||||
const wrapper = mountWithContexts(
|
||||
<Lookup
|
||||
id="search"
|
||||
lookupHeader="Foo Bar"
|
||||
name="fooBar"
|
||||
value={mockData}
|
||||
onLookupSave={() => { }}
|
||||
getItems={() => ({ data })}
|
||||
columns={mockColumns}
|
||||
sortedColumnKey="name"
|
||||
/>
|
||||
);
|
||||
const removeIcon = wrapper.find('button[aria-label="close"]').first();
|
||||
removeIcon.simulate('click');
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('renders chips from prop value', () => {
|
||||
mockData = [{ name: 'foo', id: 0 }, { name: 'bar', id: 1 }];
|
||||
const wrapper = mountWithContexts(
|
||||
<Lookup
|
||||
lookupHeader="Foo Bar"
|
||||
onLookupSave={() => { }}
|
||||
value={mockData}
|
||||
selected={[]}
|
||||
getItems={() => { }}
|
||||
columns={mockColumns}
|
||||
sortedColumnKey="name"
|
||||
/>
|
||||
).find('Lookup');
|
||||
const chip = wrapper.find('.pf-c-chip');
|
||||
expect(chip).toHaveLength(2);
|
||||
});
|
||||
|
||||
test('toggleSelected successfully adds/removes row from lookupSelectedItems state', () => {
|
||||
mockData = [];
|
||||
const wrapper = mountWithContexts(
|
||||
<Lookup
|
||||
lookupHeader="Foo Bar"
|
||||
onLookupSave={() => { }}
|
||||
value={mockData}
|
||||
getItems={() => { }}
|
||||
columns={mockColumns}
|
||||
sortedColumnKey="name"
|
||||
/>
|
||||
).find('Lookup');
|
||||
wrapper.instance().toggleSelected({
|
||||
id: 1,
|
||||
name: 'foo'
|
||||
});
|
||||
expect(wrapper.state('lookupSelectedItems')).toEqual([{
|
||||
id: 1,
|
||||
name: 'foo'
|
||||
}]);
|
||||
wrapper.instance().toggleSelected({
|
||||
id: 1,
|
||||
name: 'foo'
|
||||
});
|
||||
expect(wrapper.state('lookupSelectedItems')).toEqual([]);
|
||||
});
|
||||
|
||||
test('saveModal calls callback with selected items', () => {
|
||||
mockData = [];
|
||||
const onLookupSaveFn = jest.fn();
|
||||
const wrapper = mountWithContexts(
|
||||
<Lookup
|
||||
lookupHeader="Foo Bar"
|
||||
name="fooBar"
|
||||
value={mockData}
|
||||
onLookupSave={onLookupSaveFn}
|
||||
getItems={() => { }}
|
||||
sortedColumnKey="name"
|
||||
/>
|
||||
).find('Lookup');
|
||||
wrapper.instance().toggleSelected({
|
||||
id: 1,
|
||||
name: 'foo'
|
||||
});
|
||||
expect(wrapper.state('lookupSelectedItems')).toEqual([{
|
||||
id: 1,
|
||||
name: 'foo'
|
||||
}]);
|
||||
wrapper.instance().saveModal();
|
||||
expect(onLookupSaveFn).toHaveBeenCalledWith([{
|
||||
id: 1,
|
||||
name: 'foo'
|
||||
}], 'fooBar');
|
||||
});
|
||||
|
||||
test('should re-fetch data when URL params change', async () => {
|
||||
const history = createMemoryHistory({
|
||||
initialEntries: ['/organizations/add'],
|
||||
});
|
||||
const getItems = jest.fn();
|
||||
const wrapper = mountWithContexts(
|
||||
<_Lookup
|
||||
lookupHeader="Foo Bar"
|
||||
onLookupSave={() => { }}
|
||||
value={mockData}
|
||||
selected={[]}
|
||||
columns={mockColumns}
|
||||
sortedColumnKey="name"
|
||||
getItems={getItems}
|
||||
handleHttpError={() => {}}
|
||||
location={{ history }}
|
||||
i18n={{ _: val => val.toString() }}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(getItems).toHaveBeenCalledTimes(1);
|
||||
history.push('organizations/add?page=2');
|
||||
wrapper.setProps({
|
||||
location: { history },
|
||||
});
|
||||
wrapper.update();
|
||||
expect(getItems).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
@@ -1,63 +0,0 @@
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { mount } from 'enzyme';
|
||||
|
||||
import { Nav } from '@patternfly/react-core';
|
||||
import NavExpandableGroup from '../../src/components/NavExpandableGroup';
|
||||
|
||||
describe('NavExpandableGroup', () => {
|
||||
test('initialization and render', () => {
|
||||
const component = mount(
|
||||
<MemoryRouter initialEntries={['/foo']}>
|
||||
<Nav aria-label="Test Navigation">
|
||||
<NavExpandableGroup
|
||||
groupId="test"
|
||||
groupTitle="Test"
|
||||
routes={[
|
||||
{ path: '/foo', title: 'Foo' },
|
||||
{ path: '/bar', title: 'Bar' },
|
||||
{ path: '/fiz', title: 'Fiz' },
|
||||
]}
|
||||
/>
|
||||
</Nav>
|
||||
</MemoryRouter>
|
||||
).find('NavExpandableGroup').instance();
|
||||
|
||||
expect(component.navItemPaths).toEqual(['/foo', '/bar', '/fiz']);
|
||||
expect(component.isActiveGroup()).toEqual(true);
|
||||
});
|
||||
|
||||
describe('isActivePath', () => {
|
||||
const params = [
|
||||
['/fo', '/foo', false],
|
||||
['/foo', '/foo', true],
|
||||
['/foo/1/bar/fiz', '/foo', true],
|
||||
['/foo/1/bar/fiz', 'foo', false],
|
||||
['/foo/1/bar/fiz', 'foo/', false],
|
||||
['/foo/1/bar/fiz', '/bar', false],
|
||||
['/foo/1/bar/fiz', '/fiz', false],
|
||||
];
|
||||
|
||||
params.forEach(([location, path, expected]) => {
|
||||
test(`when location is ${location}, isActivePath('${path}') returns ${expected} `, () => {
|
||||
const component = mount(
|
||||
<MemoryRouter initialEntries={[location]}>
|
||||
<Nav aria-label="Test Navigation">
|
||||
<NavExpandableGroup
|
||||
groupId="test"
|
||||
groupTitle="Test"
|
||||
routes={[
|
||||
{ path: '/foo', title: 'Foo' },
|
||||
{ path: '/bar', title: 'Bar' },
|
||||
{ path: '/fiz', title: 'Fiz' },
|
||||
]}
|
||||
/>
|
||||
</Nav>
|
||||
</MemoryRouter>
|
||||
).find('NavExpandableGroup').instance();
|
||||
|
||||
expect(component.isActivePath(path)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,108 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import NotificationListItem from '../../src/components/NotificationsList/NotificationListItem';
|
||||
|
||||
describe('<NotificationListItem canToggleNotifications />', () => {
|
||||
let wrapper;
|
||||
let toggleNotification;
|
||||
|
||||
beforeEach(() => {
|
||||
toggleNotification = jest.fn();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (wrapper) {
|
||||
wrapper.unmount();
|
||||
wrapper = null;
|
||||
}
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('initially renders succesfully', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<NotificationListItem
|
||||
notification={{
|
||||
id: 9000,
|
||||
name: 'Foo',
|
||||
notification_type: 'slack',
|
||||
}}
|
||||
toggleNotification={toggleNotification}
|
||||
detailUrl="/foo"
|
||||
canToggleNotifications
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find('NotificationListItem')).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('handles success click when toggle is on', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<NotificationListItem
|
||||
notification={{
|
||||
id: 9000,
|
||||
name: 'Foo',
|
||||
notification_type: 'slack',
|
||||
}}
|
||||
successTurnedOn
|
||||
toggleNotification={toggleNotification}
|
||||
detailUrl="/foo"
|
||||
canToggleNotifications
|
||||
/>
|
||||
);
|
||||
wrapper.find('Switch').first().find('input').simulate('change');
|
||||
expect(toggleNotification).toHaveBeenCalledWith(9000, true, 'success');
|
||||
});
|
||||
|
||||
test('handles success click when toggle is off', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<NotificationListItem
|
||||
notification={{
|
||||
id: 9000,
|
||||
name: 'Foo',
|
||||
notification_type: 'slack',
|
||||
}}
|
||||
successTurnedOn={false}
|
||||
toggleNotification={toggleNotification}
|
||||
detailUrl="/foo"
|
||||
canToggleNotifications
|
||||
/>
|
||||
);
|
||||
wrapper.find('Switch').first().find('input').simulate('change');
|
||||
expect(toggleNotification).toHaveBeenCalledWith(9000, false, 'success');
|
||||
});
|
||||
|
||||
test('handles error click when toggle is on', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<NotificationListItem
|
||||
notification={{
|
||||
id: 9000,
|
||||
name: 'Foo',
|
||||
notification_type: 'slack',
|
||||
}}
|
||||
errorTurnedOn
|
||||
toggleNotification={toggleNotification}
|
||||
detailUrl="/foo"
|
||||
canToggleNotifications
|
||||
/>
|
||||
);
|
||||
wrapper.find('Switch').at(1).find('input').simulate('change');
|
||||
expect(toggleNotification).toHaveBeenCalledWith(9000, true, 'error');
|
||||
});
|
||||
|
||||
test('handles error click when toggle is off', () => {
|
||||
wrapper = mountWithContexts(
|
||||
<NotificationListItem
|
||||
notification={{
|
||||
id: 9000,
|
||||
name: 'Foo',
|
||||
notification_type: 'slack',
|
||||
}}
|
||||
errorTurnedOn={false}
|
||||
toggleNotification={toggleNotification}
|
||||
detailUrl="/foo"
|
||||
canToggleNotifications
|
||||
/>
|
||||
);
|
||||
wrapper.find('Switch').at(1).find('input').simulate('change');
|
||||
expect(toggleNotification).toHaveBeenCalledWith(9000, false, 'error');
|
||||
});
|
||||
});
|
||||
@@ -1,46 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import PageHeaderToolbar from '../../src/components/PageHeaderToolbar';
|
||||
|
||||
describe('PageHeaderToolbar', () => {
|
||||
const pageHelpDropdownSelector = 'Dropdown QuestionCircleIcon';
|
||||
const pageUserDropdownSelector = 'Dropdown UserIcon';
|
||||
const onAboutClick = jest.fn();
|
||||
const onLogoutClick = jest.fn();
|
||||
|
||||
test('expected content is rendered on initialization', () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<PageHeaderToolbar
|
||||
onAboutClick={onAboutClick}
|
||||
onLogoutClick={onLogoutClick}
|
||||
/>
|
||||
);
|
||||
|
||||
expect(wrapper.find(pageHelpDropdownSelector)).toHaveLength(1);
|
||||
expect(wrapper.find(pageUserDropdownSelector)).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('dropdowns have expected items and callbacks', () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<PageHeaderToolbar
|
||||
onAboutClick={onAboutClick}
|
||||
onLogoutClick={onLogoutClick}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find('DropdownItem')).toHaveLength(0);
|
||||
wrapper.find(pageHelpDropdownSelector).simulate('click');
|
||||
expect(wrapper.find('DropdownItem')).toHaveLength(2);
|
||||
|
||||
const about = wrapper.find('DropdownItem li button');
|
||||
about.simulate('click');
|
||||
expect(onAboutClick).toHaveBeenCalled();
|
||||
|
||||
expect(wrapper.find('DropdownItem')).toHaveLength(0);
|
||||
wrapper.find(pageUserDropdownSelector).simulate('click');
|
||||
expect(wrapper.find('DropdownItem')).toHaveLength(2);
|
||||
|
||||
const logout = wrapper.find('DropdownItem li button');
|
||||
logout.simulate('click');
|
||||
expect(onLogoutClick).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -1,76 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../../enzymeHelpers';
|
||||
import { ToolbarDeleteButton } from '../../../src/components/PaginatedDataList';
|
||||
|
||||
const itemA = {
|
||||
id: 1,
|
||||
name: 'Foo',
|
||||
summary_fields: { user_capabilities: { delete: true } },
|
||||
};
|
||||
const itemB = {
|
||||
id: 1,
|
||||
name: 'Foo',
|
||||
summary_fields: { user_capabilities: { delete: false } },
|
||||
};
|
||||
|
||||
describe('<ToolbarDeleteButton />', () => {
|
||||
test('should render button', () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<ToolbarDeleteButton
|
||||
onDelete={() => {}}
|
||||
itemsToDelete={[]}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find('button')).toHaveLength(1);
|
||||
expect(wrapper.find('ToolbarDeleteButton')).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should open confirmation modal', () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<ToolbarDeleteButton
|
||||
onDelete={() => {}}
|
||||
itemsToDelete={[itemA]}
|
||||
/>
|
||||
);
|
||||
wrapper.find('button').simulate('click');
|
||||
expect(wrapper.find('ToolbarDeleteButton').state('isModalOpen'))
|
||||
.toBe(true);
|
||||
wrapper.update();
|
||||
expect(wrapper.find('Modal')).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('should invoke onDelete prop', () => {
|
||||
const onDelete = jest.fn();
|
||||
const wrapper = mountWithContexts(
|
||||
<ToolbarDeleteButton
|
||||
onDelete={onDelete}
|
||||
itemsToDelete={[itemA]}
|
||||
/>
|
||||
);
|
||||
wrapper.find('ToolbarDeleteButton').setState({ isModalOpen: true });
|
||||
wrapper.find('button.pf-m-danger').simulate('click');
|
||||
expect(onDelete).toHaveBeenCalled();
|
||||
expect(wrapper.find('ToolbarDeleteButton').state('isModalOpen')).toBe(false);
|
||||
});
|
||||
|
||||
test('should disable button when no delete permissions', () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<ToolbarDeleteButton
|
||||
onDelete={() => {}}
|
||||
itemsToDelete={[itemB]}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find('button[disabled]')).toHaveLength(1);
|
||||
});
|
||||
|
||||
test('should render tooltip', () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<ToolbarDeleteButton
|
||||
onDelete={() => {}}
|
||||
itemsToDelete={[itemA]}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find('Tooltip')).toHaveLength(1);
|
||||
expect(wrapper.find('Tooltip').prop('content')).toEqual('Delete');
|
||||
});
|
||||
});
|
||||
@@ -1,123 +0,0 @@
|
||||
import React from 'react';
|
||||
import { createMemoryHistory } from 'history';
|
||||
import { mountWithContexts } from '../../enzymeHelpers';
|
||||
import { sleep } from '../../testUtils';
|
||||
import PaginatedDataList from '../../../src/components/PaginatedDataList';
|
||||
|
||||
const mockData = [
|
||||
{ id: 1, name: 'one', url: '/org/team/1' },
|
||||
{ id: 2, name: 'two', url: '/org/team/2' },
|
||||
{ id: 3, name: 'three', url: '/org/team/3' },
|
||||
{ id: 4, name: 'four', url: '/org/team/4' },
|
||||
{ id: 5, name: 'five', url: '/org/team/5' },
|
||||
];
|
||||
|
||||
const qsConfig = {
|
||||
namespace: 'item',
|
||||
defaultParams: { page: 1, page_size: 5 },
|
||||
integerFields: [],
|
||||
};
|
||||
|
||||
describe('<PaginatedDataList />', () => {
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
test('initially renders succesfully', () => {
|
||||
mountWithContexts(
|
||||
<PaginatedDataList
|
||||
items={mockData}
|
||||
itemCount={7}
|
||||
queryParams={{
|
||||
page: 1,
|
||||
page_size: 5,
|
||||
order_by: 'name',
|
||||
}}
|
||||
qsConfig={qsConfig}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
test('should navigate when DataListToolbar calls onSort prop', async () => {
|
||||
const history = createMemoryHistory({
|
||||
initialEntries: ['/organizations/1/teams'],
|
||||
});
|
||||
const wrapper = mountWithContexts(
|
||||
<PaginatedDataList
|
||||
items={mockData}
|
||||
itemCount={7}
|
||||
queryParams={{
|
||||
page: 1,
|
||||
page_size: 5,
|
||||
order_by: 'name',
|
||||
}}
|
||||
qsConfig={qsConfig}
|
||||
/>, { context: { router: { history } } }
|
||||
);
|
||||
|
||||
const toolbar = wrapper.find('DataListToolbar');
|
||||
expect(toolbar.prop('sortedColumnKey')).toEqual('name');
|
||||
expect(toolbar.prop('sortOrder')).toEqual('ascending');
|
||||
toolbar.prop('onSort')('name', 'descending');
|
||||
expect(history.location.search).toEqual('?item.order_by=-name');
|
||||
await sleep(0);
|
||||
wrapper.update();
|
||||
|
||||
expect(toolbar.prop('sortedColumnKey')).toEqual('name');
|
||||
// TODO: this assertion required updating queryParams prop. Consider
|
||||
// fixing after #147 is done:
|
||||
// expect(toolbar.prop('sortOrder')).toEqual('descending');
|
||||
toolbar.prop('onSort')('name', 'ascending');
|
||||
expect(history.location.search).toEqual('?item.order_by=name');
|
||||
});
|
||||
|
||||
test('should navigate to page when Pagination calls onSetPage prop', () => {
|
||||
const history = createMemoryHistory({
|
||||
initialEntries: ['/organizations/1/teams'],
|
||||
});
|
||||
const wrapper = mountWithContexts(
|
||||
<PaginatedDataList
|
||||
items={mockData}
|
||||
itemCount={7}
|
||||
queryParams={{
|
||||
page: 1,
|
||||
page_size: 5,
|
||||
order_by: 'name',
|
||||
}}
|
||||
qsConfig={qsConfig}
|
||||
/>, { context: { router: { history } } }
|
||||
);
|
||||
|
||||
const pagination = wrapper.find('Pagination');
|
||||
pagination.prop('onSetPage')(null, 2);
|
||||
expect(history.location.search).toEqual('?item.page=2');
|
||||
wrapper.update();
|
||||
pagination.prop('onSetPage')(null, 1);
|
||||
expect(history.location.search).toEqual('?item.page=1');
|
||||
});
|
||||
|
||||
test('should navigate to page when Pagination calls onPerPageSelect prop', () => {
|
||||
const history = createMemoryHistory({
|
||||
initialEntries: ['/organizations/1/teams'],
|
||||
});
|
||||
const wrapper = mountWithContexts(
|
||||
<PaginatedDataList
|
||||
items={mockData}
|
||||
itemCount={7}
|
||||
queryParams={{
|
||||
page: 1,
|
||||
page_size: 5,
|
||||
order_by: 'name',
|
||||
}}
|
||||
qsConfig={qsConfig}
|
||||
/>, { context: { router: { history } } }
|
||||
);
|
||||
|
||||
const pagination = wrapper.find('Pagination');
|
||||
pagination.prop('onPerPageSelect')(null, 5);
|
||||
expect(history.location.search).toEqual('?item.page_size=5');
|
||||
wrapper.update();
|
||||
pagination.prop('onPerPageSelect')(null, 25);
|
||||
expect(history.location.search).toEqual('?item.page_size=25');
|
||||
});
|
||||
});
|
||||
@@ -1,25 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../../enzymeHelpers';
|
||||
import { ToolbarAddButton } from '../../../src/components/PaginatedDataList';
|
||||
|
||||
describe('<ToolbarAddButton />', () => {
|
||||
test('should render button', () => {
|
||||
const onClick = jest.fn();
|
||||
const wrapper = mountWithContexts(
|
||||
<ToolbarAddButton onClick={onClick} />
|
||||
);
|
||||
const button = wrapper.find('button');
|
||||
expect(button).toHaveLength(1);
|
||||
button.simulate('click');
|
||||
expect(onClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should render link', () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<ToolbarAddButton linkTo="/foo" />
|
||||
);
|
||||
const link = wrapper.find('Link');
|
||||
expect(link).toHaveLength(1);
|
||||
expect(link.prop('to')).toBe('/foo');
|
||||
});
|
||||
});
|
||||
@@ -1,202 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<ToolbarDeleteButton /> should render button 1`] = `
|
||||
<ToolbarDeleteButton
|
||||
i18n={"/i18n/"}
|
||||
itemName="item"
|
||||
itemsToDelete={Array []}
|
||||
onDelete={[Function]}
|
||||
>
|
||||
<Tooltip
|
||||
appendTo={[Function]}
|
||||
className={null}
|
||||
content="Select a row to delete"
|
||||
enableFlip={true}
|
||||
entryDelay={500}
|
||||
exitDelay={500}
|
||||
maxWidth="18.75rem"
|
||||
position="top"
|
||||
trigger="mouseenter focus"
|
||||
zIndex={9999}
|
||||
>
|
||||
<Tippy
|
||||
animateFill={false}
|
||||
appendTo={[Function]}
|
||||
content={
|
||||
<div
|
||||
className="pf-c-tooltip"
|
||||
role="tooltip"
|
||||
>
|
||||
<TooltipArrow
|
||||
className={null}
|
||||
/>
|
||||
<TooltipContent
|
||||
className={null}
|
||||
>
|
||||
Select a row to delete
|
||||
</TooltipContent>
|
||||
</div>
|
||||
}
|
||||
delay={
|
||||
Array [
|
||||
500,
|
||||
500,
|
||||
]
|
||||
}
|
||||
distance={15}
|
||||
flip={true}
|
||||
lazy={true}
|
||||
maxWidth="18.75rem"
|
||||
onCreate={[Function]}
|
||||
performance={true}
|
||||
placement="top"
|
||||
popperOptions={
|
||||
Object {
|
||||
"modifiers": Object {
|
||||
"hide": Object {
|
||||
"enabled": true,
|
||||
},
|
||||
"preventOverflow": Object {
|
||||
"enabled": true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
theme="pf-tippy"
|
||||
trigger="mouseenter focus"
|
||||
zIndex={9999}
|
||||
>
|
||||
<div>
|
||||
<ToolbarDeleteButton__DeleteButton
|
||||
aria-label="Delete"
|
||||
isDisabled={true}
|
||||
onClick={[Function]}
|
||||
variant="plain"
|
||||
>
|
||||
<StyledComponent
|
||||
aria-label="Delete"
|
||||
forwardedComponent={
|
||||
Object {
|
||||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "ToolbarDeleteButton__DeleteButton-sc-1e3r0eg-0",
|
||||
"isStatic": true,
|
||||
"lastClassName": "bQjfFG",
|
||||
"rules": Array [
|
||||
"padding:5px 8px;&:hover{background-color:#d9534f;color:white;}&[disabled]{color:var(--pf-c-button--m-plain--Color);pointer-events:initial;cursor:not-allowed;}",
|
||||
],
|
||||
},
|
||||
"displayName": "ToolbarDeleteButton__DeleteButton",
|
||||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"styledComponentId": "ToolbarDeleteButton__DeleteButton-sc-1e3r0eg-0",
|
||||
"target": [Function],
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
"withComponent": [Function],
|
||||
}
|
||||
}
|
||||
forwardedRef={null}
|
||||
isDisabled={true}
|
||||
onClick={[Function]}
|
||||
variant="plain"
|
||||
>
|
||||
<Button
|
||||
aria-label="Delete"
|
||||
className="ToolbarDeleteButton__DeleteButton-sc-1e3r0eg-0 bQjfFG"
|
||||
component="button"
|
||||
isActive={false}
|
||||
isBlock={false}
|
||||
isDisabled={true}
|
||||
isFocus={false}
|
||||
isHover={false}
|
||||
isInline={false}
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
variant="plain"
|
||||
>
|
||||
<button
|
||||
aria-disabled={null}
|
||||
aria-label="Delete"
|
||||
className="pf-c-button pf-m-plain pf-m-disabled ToolbarDeleteButton__DeleteButton-sc-1e3r0eg-0 bQjfFG"
|
||||
disabled={true}
|
||||
onClick={[Function]}
|
||||
tabIndex={null}
|
||||
type="button"
|
||||
>
|
||||
<TrashAltIcon
|
||||
color="currentColor"
|
||||
size="sm"
|
||||
title={null}
|
||||
>
|
||||
<svg
|
||||
aria-hidden={true}
|
||||
aria-labelledby={null}
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
role="img"
|
||||
style={
|
||||
Object {
|
||||
"verticalAlign": "-0.125em",
|
||||
}
|
||||
}
|
||||
viewBox="0 0 448 512"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M32 464a48 48 0 0 0 48 48h288a48 48 0 0 0 48-48V128H32zm272-256a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zM432 32H312l-9.4-18.7A24 24 0 0 0 281.1 0H166.8a23.72 23.72 0 0 0-21.4 13.3L136 32H16A16 16 0 0 0 0 48v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16z"
|
||||
transform=""
|
||||
/>
|
||||
</svg>
|
||||
</TrashAltIcon>
|
||||
</button>
|
||||
</Button>
|
||||
</StyledComponent>
|
||||
</ToolbarDeleteButton__DeleteButton>
|
||||
</div>
|
||||
<Portal
|
||||
containerInfo={
|
||||
<div>
|
||||
<div
|
||||
class="pf-c-tooltip"
|
||||
role="tooltip"
|
||||
>
|
||||
<div
|
||||
class="pf-c-tooltip__arrow"
|
||||
/>
|
||||
<div
|
||||
class="pf-c-tooltip__content"
|
||||
>
|
||||
Select a row to delete
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div
|
||||
className="pf-c-tooltip"
|
||||
role="tooltip"
|
||||
>
|
||||
<TooltipArrow
|
||||
className={null}
|
||||
>
|
||||
<div
|
||||
className="pf-c-tooltip__arrow"
|
||||
/>
|
||||
</TooltipArrow>
|
||||
<TooltipContent
|
||||
className={null}
|
||||
>
|
||||
<div
|
||||
className="pf-c-tooltip__content"
|
||||
>
|
||||
Select a row to delete
|
||||
</div>
|
||||
</TooltipContent>
|
||||
</div>
|
||||
</Portal>
|
||||
</Tippy>
|
||||
</Tooltip>
|
||||
</ToolbarDeleteButton>
|
||||
`;
|
||||
@@ -1,63 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mount, shallow } from 'enzyme';
|
||||
import { Router } from 'react-router-dom';
|
||||
import { createMemoryHistory } from 'history';
|
||||
import { Tab } from '@patternfly/react-core';
|
||||
import RoutedTabs, { _RoutedTabs } from '../../src/components/Tabs/RoutedTabs';
|
||||
|
||||
let wrapper;
|
||||
let history;
|
||||
|
||||
const tabs = [
|
||||
{ name: 'Details', link: '/organizations/19/details', id: 1 },
|
||||
{ name: 'Access', link: '/organizations/19/access', id: 2 },
|
||||
{ name: 'Teams', link: '/organizations/19/teams', id: 3 },
|
||||
{ name: 'Notification', link: '/organizations/19/notification', id: 4 }
|
||||
];
|
||||
|
||||
describe('<RoutedTabs />', () => {
|
||||
beforeEach(() => {
|
||||
history = createMemoryHistory({
|
||||
initialEntries: ['/organizations/19/teams'],
|
||||
});
|
||||
});
|
||||
|
||||
test('RoutedTabs renders successfully', () => {
|
||||
wrapper = shallow(
|
||||
<_RoutedTabs
|
||||
tabsArray={tabs}
|
||||
history={history}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find(Tab)).toHaveLength(4);
|
||||
});
|
||||
|
||||
test('Given a URL the correct tab is active', async () => {
|
||||
wrapper = mount(
|
||||
<Router history={history}>
|
||||
<RoutedTabs
|
||||
tabsArray={tabs}
|
||||
/>
|
||||
</Router>
|
||||
);
|
||||
|
||||
expect(history.location.pathname).toEqual('/organizations/19/teams');
|
||||
expect(wrapper.find('Tabs').prop('activeKey')).toBe(3);
|
||||
});
|
||||
|
||||
test('should update history when new tab selected', async () => {
|
||||
wrapper = mount(
|
||||
<Router history={history}>
|
||||
<RoutedTabs
|
||||
tabsArray={tabs}
|
||||
/>
|
||||
</Router>
|
||||
);
|
||||
|
||||
wrapper.find('Tabs').prop('onSelect')({}, 2);
|
||||
wrapper.update();
|
||||
|
||||
expect(history.location.pathname).toEqual('/organizations/19/access');
|
||||
expect(wrapper.find('Tabs').prop('activeKey')).toBe(2);
|
||||
});
|
||||
});
|
||||
@@ -1,70 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import Search from '../../src/components/Search';
|
||||
|
||||
describe('<Search />', () => {
|
||||
let search;
|
||||
|
||||
afterEach(() => {
|
||||
if (search) {
|
||||
search = null;
|
||||
}
|
||||
});
|
||||
|
||||
test('it triggers the expected callbacks', () => {
|
||||
const columns = [{ name: 'Name', key: 'name', isSortable: true }];
|
||||
|
||||
const searchBtn = 'button[aria-label="Search"]';
|
||||
const searchTextInput = 'input[aria-label="Search text input"]';
|
||||
|
||||
const onSearch = jest.fn();
|
||||
|
||||
search = mountWithContexts(
|
||||
<Search
|
||||
sortedColumnKey="name"
|
||||
columns={columns}
|
||||
onSearch={onSearch}
|
||||
/>
|
||||
);
|
||||
|
||||
search.find(searchTextInput).instance().value = 'test-321';
|
||||
search.find(searchTextInput).simulate('change');
|
||||
search.find(searchBtn).simulate('click');
|
||||
|
||||
expect(onSearch).toHaveBeenCalledTimes(1);
|
||||
expect(onSearch).toBeCalledWith('test-321');
|
||||
});
|
||||
|
||||
test('handleDropdownToggle properly updates state', async () => {
|
||||
const columns = [{ name: 'Name', key: 'name', isSortable: true }];
|
||||
const onSearch = jest.fn();
|
||||
const wrapper = mountWithContexts(
|
||||
<Search
|
||||
sortedColumnKey="name"
|
||||
columns={columns}
|
||||
onSearch={onSearch}
|
||||
/>
|
||||
).find('Search');
|
||||
expect(wrapper.state('isSearchDropdownOpen')).toEqual(false);
|
||||
wrapper.instance().handleDropdownToggle(true);
|
||||
expect(wrapper.state('isSearchDropdownOpen')).toEqual(true);
|
||||
});
|
||||
|
||||
test('handleDropdownSelect properly updates state', async () => {
|
||||
const columns = [
|
||||
{ name: 'Name', key: 'name', isSortable: true },
|
||||
{ name: 'Description', key: 'description', isSortable: true }
|
||||
];
|
||||
const onSearch = jest.fn();
|
||||
const wrapper = mountWithContexts(
|
||||
<Search
|
||||
sortedColumnKey="name"
|
||||
columns={columns}
|
||||
onSearch={onSearch}
|
||||
/>
|
||||
).find('Search');
|
||||
expect(wrapper.state('searchKey')).toEqual('name');
|
||||
wrapper.instance().handleDropdownSelect({ target: { innerText: 'Description' } });
|
||||
expect(wrapper.state('searchKey')).toEqual('description');
|
||||
});
|
||||
});
|
||||
@@ -1,118 +0,0 @@
|
||||
import React from 'react';
|
||||
import { createMemoryHistory } from 'history';
|
||||
import { shallow } from 'enzyme';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import { sleep } from '../testUtils';
|
||||
import SelectResourceStep from '../../src/components/AddRole/SelectResourceStep';
|
||||
|
||||
describe('<SelectResourceStep />', () => {
|
||||
const columns = [
|
||||
{ name: 'Username', key: 'username', isSortable: true }
|
||||
];
|
||||
afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
test('initially renders without crashing', () => {
|
||||
shallow(
|
||||
<SelectResourceStep
|
||||
columns={columns}
|
||||
displayKey="username"
|
||||
onRowClick={() => {}}
|
||||
onSearch={() => {}}
|
||||
sortedColumnKey="username"
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
test('fetches resources on mount', async () => {
|
||||
const handleSearch = jest.fn().mockResolvedValue({
|
||||
data: {
|
||||
count: 2,
|
||||
results: [
|
||||
{ id: 1, username: 'foo', url: 'item/1' },
|
||||
{ id: 2, username: 'bar', url: 'item/2' }
|
||||
]
|
||||
}
|
||||
});
|
||||
mountWithContexts(
|
||||
<SelectResourceStep
|
||||
columns={columns}
|
||||
displayKey="username"
|
||||
onRowClick={() => {}}
|
||||
onSearch={handleSearch}
|
||||
sortedColumnKey="username"
|
||||
/>
|
||||
);
|
||||
expect(handleSearch).toHaveBeenCalledWith({
|
||||
order_by: 'username',
|
||||
page: 1,
|
||||
page_size: 5
|
||||
});
|
||||
});
|
||||
|
||||
test('readResourceList properly adds rows to state', async () => {
|
||||
const selectedResourceRows = [
|
||||
{ id: 1, username: 'foo', url: 'item/1' }
|
||||
];
|
||||
const handleSearch = jest.fn().mockResolvedValue({
|
||||
data: {
|
||||
count: 2,
|
||||
results: [
|
||||
{ id: 1, username: 'foo', url: 'item/1' },
|
||||
{ id: 2, username: 'bar', url: 'item/2' }
|
||||
]
|
||||
}
|
||||
});
|
||||
const history = createMemoryHistory({
|
||||
initialEntries: ['/organizations/1/access?resource.page=1&resource.order_by=-username'],
|
||||
});
|
||||
const wrapper = await mountWithContexts(
|
||||
<SelectResourceStep
|
||||
columns={columns}
|
||||
displayKey="username"
|
||||
onRowClick={() => {}}
|
||||
onSearch={handleSearch}
|
||||
selectedResourceRows={selectedResourceRows}
|
||||
sortedColumnKey="username"
|
||||
/>, { context: { router: { history, route: { location: history.location } } } }
|
||||
).find('SelectResourceStep');
|
||||
await wrapper.instance().readResourceList();
|
||||
expect(handleSearch).toHaveBeenCalledWith({
|
||||
order_by: '-username',
|
||||
page: 1,
|
||||
page_size: 5,
|
||||
});
|
||||
expect(wrapper.state('resources')).toEqual([
|
||||
{ id: 1, username: 'foo', url: 'item/1' },
|
||||
{ id: 2, username: 'bar', url: 'item/2' }
|
||||
]);
|
||||
});
|
||||
|
||||
test('clicking on row fires callback with correct params', async () => {
|
||||
const handleRowClick = jest.fn();
|
||||
const data = {
|
||||
count: 2,
|
||||
results: [
|
||||
{ id: 1, username: 'foo', url: 'item/1' },
|
||||
{ id: 2, username: 'bar', url: 'item/2' }
|
||||
]
|
||||
};
|
||||
const wrapper = mountWithContexts(
|
||||
<SelectResourceStep
|
||||
columns={columns}
|
||||
displayKey="username"
|
||||
onRowClick={handleRowClick}
|
||||
onSearch={() => ({ data })}
|
||||
selectedResourceRows={[]}
|
||||
sortedColumnKey="username"
|
||||
/>
|
||||
);
|
||||
await sleep(0);
|
||||
wrapper.update();
|
||||
const checkboxListItemWrapper = wrapper.find('CheckboxListItem');
|
||||
expect(checkboxListItemWrapper.length).toBe(2);
|
||||
checkboxListItemWrapper.first().find('input[type="checkbox"]')
|
||||
.simulate('change', { target: { checked: true } });
|
||||
expect(handleRowClick).toHaveBeenCalledWith(data.results[0]);
|
||||
});
|
||||
});
|
||||
@@ -1,64 +0,0 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import SelectRoleStep from '../../src/components/AddRole/SelectRoleStep';
|
||||
|
||||
describe('<SelectRoleStep />', () => {
|
||||
let wrapper;
|
||||
const roles = {
|
||||
project_admin_role: {
|
||||
id: 1,
|
||||
name: 'Project Admin',
|
||||
description: 'Can manage all projects of the organization'
|
||||
},
|
||||
execute_role: {
|
||||
id: 2,
|
||||
name: 'Execute',
|
||||
description: 'May run any executable resources in the organization'
|
||||
}
|
||||
};
|
||||
const selectedRoles = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Project Admin',
|
||||
description: 'Can manage all projects of the organization'
|
||||
}
|
||||
];
|
||||
const selectedResourceRows = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'foo'
|
||||
}
|
||||
];
|
||||
test('initially renders without crashing', () => {
|
||||
wrapper = shallow(
|
||||
<SelectRoleStep
|
||||
roles={roles}
|
||||
selectedResourceRows={selectedResourceRows}
|
||||
selectedRoleRows={selectedRoles}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.length).toBe(1);
|
||||
wrapper.unmount();
|
||||
});
|
||||
test('clicking role fires onRolesClick callback', () => {
|
||||
const onRolesClick = jest.fn();
|
||||
wrapper = mountWithContexts(
|
||||
<SelectRoleStep
|
||||
onRolesClick={onRolesClick}
|
||||
roles={roles}
|
||||
selectedResourceRows={selectedResourceRows}
|
||||
selectedRoleRows={selectedRoles}
|
||||
/>
|
||||
);
|
||||
const CheckboxCards = wrapper.find('CheckboxCard');
|
||||
expect(CheckboxCards.length).toBe(2);
|
||||
CheckboxCards.first().prop('onSelect')();
|
||||
expect(onRolesClick).toBeCalledWith({
|
||||
id: 1,
|
||||
name: 'Project Admin',
|
||||
description: 'Can manage all projects of the organization'
|
||||
});
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
@@ -1,27 +0,0 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import SelectableCard from '../../src/components/AddRole/SelectableCard';
|
||||
|
||||
describe('<SelectableCard />', () => {
|
||||
let wrapper;
|
||||
const onClick = jest.fn();
|
||||
test('initially renders without crashing when not selected', () => {
|
||||
wrapper = shallow(
|
||||
<SelectableCard
|
||||
onClick={onClick}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.length).toBe(1);
|
||||
wrapper.unmount();
|
||||
});
|
||||
test('initially renders without crashing when selected', () => {
|
||||
wrapper = shallow(
|
||||
<SelectableCard
|
||||
isSelected
|
||||
onClick={onClick}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.length).toBe(1);
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
@@ -1,63 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import SelectedList from '../../src/components/SelectedList';
|
||||
import { ChipGroup } from '../../src/components/Chip';
|
||||
|
||||
describe('<SelectedList />', () => {
|
||||
test('initially renders succesfully', () => {
|
||||
const mockSelected = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'foo'
|
||||
}, {
|
||||
id: 2,
|
||||
name: 'bar'
|
||||
}
|
||||
];
|
||||
mount(
|
||||
<SelectedList
|
||||
label="Selected"
|
||||
selected={mockSelected}
|
||||
showOverflowAfter={5}
|
||||
onRemove={() => {}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
test('showOverflow should set showOverflow on ChipGroup', () => {
|
||||
const wrapper = mount(
|
||||
<SelectedList
|
||||
label="Selected"
|
||||
selected={[]}
|
||||
showOverflowAfter={5}
|
||||
onRemove={() => {}}
|
||||
/>
|
||||
);
|
||||
const chipGroup = wrapper.find(ChipGroup);
|
||||
expect(chipGroup).toHaveLength(1);
|
||||
expect(chipGroup.prop('showOverflowAfter')).toEqual(5);
|
||||
});
|
||||
|
||||
test('Clicking remove on chip calls onRemove callback prop with correct params', () => {
|
||||
const onRemove = jest.fn();
|
||||
const mockSelected = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'foo'
|
||||
}
|
||||
];
|
||||
const wrapper = mount(
|
||||
<SelectedList
|
||||
label="Selected"
|
||||
selected={mockSelected}
|
||||
showOverflowAfter={3}
|
||||
onRemove={onRemove}
|
||||
/>
|
||||
);
|
||||
wrapper.find('.pf-c-chip button').first().simulate('click');
|
||||
expect(onRemove).toBeCalledWith({
|
||||
id: 1,
|
||||
name: 'foo'
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,188 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import Sort from '../../src/components/Sort';
|
||||
|
||||
describe('<Sort />', () => {
|
||||
let sort;
|
||||
|
||||
afterEach(() => {
|
||||
if (sort) {
|
||||
sort = null;
|
||||
}
|
||||
});
|
||||
|
||||
test('it triggers the expected callbacks', () => {
|
||||
const columns = [{ name: 'Name', key: 'name', isSortable: true }];
|
||||
|
||||
const sortBtn = 'button[aria-label="Sort"]';
|
||||
|
||||
const onSort = jest.fn();
|
||||
|
||||
const wrapper = mountWithContexts(
|
||||
<Sort
|
||||
sortedColumnKey="name"
|
||||
sortOrder="ascending"
|
||||
columns={columns}
|
||||
onSort={onSort}
|
||||
/>
|
||||
).find('Sort');
|
||||
|
||||
wrapper.find(sortBtn).simulate('click');
|
||||
|
||||
expect(onSort).toHaveBeenCalledTimes(1);
|
||||
expect(onSort).toBeCalledWith('name', 'descending');
|
||||
});
|
||||
|
||||
test('onSort properly passes back descending when ascending was passed as prop', () => {
|
||||
const multipleColumns = [
|
||||
{ name: 'Foo', key: 'foo', isSortable: true },
|
||||
{ name: 'Bar', key: 'bar', isSortable: true },
|
||||
{ name: 'Bakery', key: 'bakery', isSortable: true },
|
||||
{ name: 'Baz', key: 'baz' }
|
||||
];
|
||||
|
||||
const onSort = jest.fn();
|
||||
|
||||
const wrapper = mountWithContexts(
|
||||
<Sort
|
||||
sortedColumnKey="foo"
|
||||
sortOrder="ascending"
|
||||
columns={multipleColumns}
|
||||
onSort={onSort}
|
||||
/>
|
||||
).find('Sort');
|
||||
const sortDropdownToggle = wrapper.find('Button');
|
||||
expect(sortDropdownToggle.length).toBe(1);
|
||||
sortDropdownToggle.simulate('click');
|
||||
expect(onSort).toHaveBeenCalledWith('foo', 'descending');
|
||||
});
|
||||
|
||||
test('onSort properly passes back ascending when descending was passed as prop', () => {
|
||||
const multipleColumns = [
|
||||
{ name: 'Foo', key: 'foo', isSortable: true },
|
||||
{ name: 'Bar', key: 'bar', isSortable: true },
|
||||
{ name: 'Bakery', key: 'bakery', isSortable: true },
|
||||
{ name: 'Baz', key: 'baz' }
|
||||
];
|
||||
|
||||
const onSort = jest.fn();
|
||||
|
||||
const wrapper = mountWithContexts(
|
||||
<Sort
|
||||
sortedColumnKey="foo"
|
||||
sortOrder="descending"
|
||||
columns={multipleColumns}
|
||||
onSort={onSort}
|
||||
/>
|
||||
).find('Sort');
|
||||
const sortDropdownToggle = wrapper.find('Button');
|
||||
expect(sortDropdownToggle.length).toBe(1);
|
||||
sortDropdownToggle.simulate('click');
|
||||
expect(onSort).toHaveBeenCalledWith('foo', 'ascending');
|
||||
});
|
||||
|
||||
test('Changing dropdown correctly passes back new sort key', () => {
|
||||
const multipleColumns = [
|
||||
{ name: 'Foo', key: 'foo', isSortable: true },
|
||||
{ name: 'Bar', key: 'bar', isSortable: true },
|
||||
{ name: 'Bakery', key: 'bakery', isSortable: true },
|
||||
{ name: 'Baz', key: 'baz' }
|
||||
];
|
||||
|
||||
const onSort = jest.fn();
|
||||
|
||||
const wrapper = mountWithContexts(
|
||||
<Sort
|
||||
sortedColumnKey="foo"
|
||||
sortOrder="ascending"
|
||||
columns={multipleColumns}
|
||||
onSort={onSort}
|
||||
/>
|
||||
).find('Sort');
|
||||
|
||||
wrapper.instance().handleDropdownSelect({ target: { innerText: 'Bar' } });
|
||||
expect(onSort).toBeCalledWith('bar', 'ascending');
|
||||
});
|
||||
|
||||
test('Opening dropdown correctly updates state', () => {
|
||||
const multipleColumns = [
|
||||
{ name: 'Foo', key: 'foo', isSortable: true },
|
||||
{ name: 'Bar', key: 'bar', isSortable: true },
|
||||
{ name: 'Bakery', key: 'bakery', isSortable: true },
|
||||
{ name: 'Baz', key: 'baz' }
|
||||
];
|
||||
|
||||
const onSort = jest.fn();
|
||||
|
||||
const wrapper = mountWithContexts(
|
||||
<Sort
|
||||
sortedColumnKey="foo"
|
||||
sortOrder="ascending"
|
||||
columns={multipleColumns}
|
||||
onSort={onSort}
|
||||
/>
|
||||
).find('Sort');
|
||||
expect(wrapper.state('isSortDropdownOpen')).toEqual(false);
|
||||
wrapper.instance().handleDropdownToggle(true);
|
||||
expect(wrapper.state('isSortDropdownOpen')).toEqual(true);
|
||||
});
|
||||
|
||||
test('It displays correct sort icon', () => {
|
||||
const downNumericIconSelector = 'SortNumericDownIcon';
|
||||
const upNumericIconSelector = 'SortNumericUpIcon';
|
||||
const downAlphaIconSelector = 'SortAlphaDownIcon';
|
||||
const upAlphaIconSelector = 'SortAlphaUpIcon';
|
||||
|
||||
const numericColumns = [{ name: 'ID', key: 'id', isSortable: true, isNumeric: true }];
|
||||
const alphaColumns = [{ name: 'Name', key: 'name', isSortable: true, isNumeric: false }];
|
||||
const onSort = jest.fn();
|
||||
|
||||
sort = mountWithContexts(
|
||||
<Sort
|
||||
sortedColumnKey="id"
|
||||
sortOrder="descending"
|
||||
columns={numericColumns}
|
||||
onSort={onSort}
|
||||
/>
|
||||
);
|
||||
|
||||
const downNumericIcon = sort.find(downNumericIconSelector);
|
||||
expect(downNumericIcon.length).toBe(1);
|
||||
|
||||
sort = mountWithContexts(
|
||||
<Sort
|
||||
sortedColumnKey="id"
|
||||
sortOrder="ascending"
|
||||
columns={numericColumns}
|
||||
onSort={onSort}
|
||||
/>
|
||||
);
|
||||
|
||||
const upNumericIcon = sort.find(upNumericIconSelector);
|
||||
expect(upNumericIcon.length).toBe(1);
|
||||
|
||||
sort = mountWithContexts(
|
||||
<Sort
|
||||
sortedColumnKey="name"
|
||||
sortOrder="descending"
|
||||
columns={alphaColumns}
|
||||
onSort={onSort}
|
||||
/>
|
||||
);
|
||||
|
||||
const downAlphaIcon = sort.find(downAlphaIconSelector);
|
||||
expect(downAlphaIcon.length).toBe(1);
|
||||
|
||||
sort = mountWithContexts(
|
||||
<Sort
|
||||
sortedColumnKey="name"
|
||||
sortOrder="ascending"
|
||||
columns={alphaColumns}
|
||||
onSort={onSort}
|
||||
/>
|
||||
);
|
||||
|
||||
const upAlphaIcon = sort.find(upAlphaIconSelector);
|
||||
expect(upAlphaIcon.length).toBe(1);
|
||||
});
|
||||
});
|
||||
@@ -1,11 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
|
||||
import VerticalSeparator from '../../src/components/VerticalSeparator';
|
||||
|
||||
describe('VerticalSeparator', () => {
|
||||
test('renders the expected content', () => {
|
||||
const wrapper = mount(<VerticalSeparator />);
|
||||
expect(wrapper).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
@@ -1,456 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<NotificationListItem canToggleNotifications /> initially renders succesfully 1`] = `
|
||||
<NotificationListItem
|
||||
canToggleNotifications={true}
|
||||
detailUrl="/foo"
|
||||
errorTurnedOn={false}
|
||||
i18n={"/i18n/"}
|
||||
notification={
|
||||
Object {
|
||||
"id": 9000,
|
||||
"name": "Foo",
|
||||
"notification_type": "slack",
|
||||
}
|
||||
}
|
||||
successTurnedOn={false}
|
||||
toggleNotification={[MockFunction]}
|
||||
>
|
||||
<DataListItem
|
||||
aria-labelledby="items-list-item-9000"
|
||||
className=""
|
||||
isExpanded={false}
|
||||
key="9000"
|
||||
>
|
||||
<li
|
||||
aria-labelledby="items-list-item-9000"
|
||||
className="pf-c-data-list__item"
|
||||
>
|
||||
<DataListItemRow
|
||||
className=""
|
||||
key=".0"
|
||||
rowid="items-list-item-9000"
|
||||
>
|
||||
<div
|
||||
className="pf-c-data-list__item-row"
|
||||
>
|
||||
<DataListItemCells
|
||||
className=""
|
||||
dataListCells={
|
||||
Array [
|
||||
<ForwardRef>
|
||||
<ForwardRef
|
||||
to={
|
||||
Object {
|
||||
"pathname": "/foo",
|
||||
}
|
||||
}
|
||||
>
|
||||
<b
|
||||
id="items-list-item-9000"
|
||||
>
|
||||
Foo
|
||||
</b>
|
||||
</ForwardRef>
|
||||
<ForwardRef
|
||||
isRead={true}
|
||||
>
|
||||
slack
|
||||
</ForwardRef>
|
||||
</ForwardRef>,
|
||||
<ForwardRef
|
||||
righthalf="true"
|
||||
>
|
||||
<ForwardRef
|
||||
aria-label="Toggle notification success"
|
||||
id="notification-9000-success-toggle"
|
||||
isChecked={false}
|
||||
isDisabled={false}
|
||||
label="Successful"
|
||||
onChange={[Function]}
|
||||
/>
|
||||
<ForwardRef
|
||||
aria-label="Toggle notification failure"
|
||||
id="notification-9000-error-toggle"
|
||||
isChecked={false}
|
||||
isDisabled={false}
|
||||
label="Failure"
|
||||
onChange={[Function]}
|
||||
/>
|
||||
</ForwardRef>,
|
||||
]
|
||||
}
|
||||
key=".0"
|
||||
rowid="items-list-item-9000"
|
||||
>
|
||||
<div
|
||||
className="pf-c-data-list__item-content"
|
||||
>
|
||||
<NotificationListItem__DataListCell
|
||||
key="name"
|
||||
>
|
||||
<StyledComponent
|
||||
forwardedComponent={
|
||||
Object {
|
||||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "NotificationListItem__DataListCell-j7c411-0",
|
||||
"isStatic": false,
|
||||
"lastClassName": "hoXOpW",
|
||||
"rules": Array [
|
||||
"display:flex;justify-content:",
|
||||
[Function],
|
||||
";padding-bottom:",
|
||||
[Function],
|
||||
";@media screen and (min-width:768px){justify-content:",
|
||||
[Function],
|
||||
";padding-bottom:0;}",
|
||||
],
|
||||
},
|
||||
"displayName": "NotificationListItem__DataListCell",
|
||||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"styledComponentId": "NotificationListItem__DataListCell-j7c411-0",
|
||||
"target": [Function],
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
"withComponent": [Function],
|
||||
}
|
||||
}
|
||||
forwardedRef={null}
|
||||
>
|
||||
<DataListCell
|
||||
alignRight={false}
|
||||
className="NotificationListItem__DataListCell-j7c411-0 kIdLtz"
|
||||
isFilled={true}
|
||||
isIcon={false}
|
||||
width={1}
|
||||
>
|
||||
<div
|
||||
className="pf-c-data-list__cell NotificationListItem__DataListCell-j7c411-0 kIdLtz"
|
||||
>
|
||||
<Styled(Link)
|
||||
to={
|
||||
Object {
|
||||
"pathname": "/foo",
|
||||
}
|
||||
}
|
||||
>
|
||||
<StyledComponent
|
||||
forwardedComponent={
|
||||
Object {
|
||||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "sc-bdVaJa",
|
||||
"isStatic": true,
|
||||
"lastClassName": "eBseNd",
|
||||
"rules": Array [
|
||||
"margin-right: 1.5em;",
|
||||
],
|
||||
},
|
||||
"displayName": "Styled(Link)",
|
||||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"styledComponentId": "sc-bdVaJa",
|
||||
"target": [Function],
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
"withComponent": [Function],
|
||||
}
|
||||
}
|
||||
forwardedRef={null}
|
||||
to={
|
||||
Object {
|
||||
"pathname": "/foo",
|
||||
}
|
||||
}
|
||||
>
|
||||
<Link
|
||||
className="sc-bdVaJa eBseNd"
|
||||
replace={false}
|
||||
to={
|
||||
Object {
|
||||
"pathname": "/foo",
|
||||
}
|
||||
}
|
||||
>
|
||||
<a
|
||||
className="sc-bdVaJa eBseNd"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<b
|
||||
id="items-list-item-9000"
|
||||
>
|
||||
Foo
|
||||
</b>
|
||||
</a>
|
||||
</Link>
|
||||
</StyledComponent>
|
||||
</Styled(Link)>
|
||||
<Styled(Badge)
|
||||
isRead={true}
|
||||
>
|
||||
<StyledComponent
|
||||
forwardedComponent={
|
||||
Object {
|
||||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "sc-bwzfXH",
|
||||
"isStatic": true,
|
||||
"lastClassName": "chTbOZ",
|
||||
"rules": Array [
|
||||
"text-transform: capitalize;",
|
||||
],
|
||||
},
|
||||
"displayName": "Styled(Badge)",
|
||||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"styledComponentId": "sc-bwzfXH",
|
||||
"target": [Function],
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
"withComponent": [Function],
|
||||
}
|
||||
}
|
||||
forwardedRef={null}
|
||||
isRead={true}
|
||||
>
|
||||
<Badge
|
||||
className="sc-bwzfXH chTbOZ"
|
||||
isRead={true}
|
||||
>
|
||||
<span
|
||||
className="pf-c-badge pf-m-read sc-bwzfXH chTbOZ"
|
||||
>
|
||||
slack
|
||||
</span>
|
||||
</Badge>
|
||||
</StyledComponent>
|
||||
</Styled(Badge)>
|
||||
</div>
|
||||
</DataListCell>
|
||||
</StyledComponent>
|
||||
</NotificationListItem__DataListCell>
|
||||
<NotificationListItem__DataListCell
|
||||
key="toggles"
|
||||
righthalf="true"
|
||||
>
|
||||
<StyledComponent
|
||||
forwardedComponent={
|
||||
Object {
|
||||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "NotificationListItem__DataListCell-j7c411-0",
|
||||
"isStatic": false,
|
||||
"lastClassName": "hoXOpW",
|
||||
"rules": Array [
|
||||
"display:flex;justify-content:",
|
||||
[Function],
|
||||
";padding-bottom:",
|
||||
[Function],
|
||||
";@media screen and (min-width:768px){justify-content:",
|
||||
[Function],
|
||||
";padding-bottom:0;}",
|
||||
],
|
||||
},
|
||||
"displayName": "NotificationListItem__DataListCell",
|
||||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"styledComponentId": "NotificationListItem__DataListCell-j7c411-0",
|
||||
"target": [Function],
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
"withComponent": [Function],
|
||||
}
|
||||
}
|
||||
forwardedRef={null}
|
||||
righthalf="true"
|
||||
>
|
||||
<DataListCell
|
||||
alignRight={false}
|
||||
className="NotificationListItem__DataListCell-j7c411-0 hoXOpW"
|
||||
isFilled={true}
|
||||
isIcon={false}
|
||||
righthalf="true"
|
||||
width={1}
|
||||
>
|
||||
<div
|
||||
className="pf-c-data-list__cell NotificationListItem__DataListCell-j7c411-0 hoXOpW"
|
||||
righthalf="true"
|
||||
>
|
||||
<NotificationListItem__Switch
|
||||
aria-label="Toggle notification success"
|
||||
id="notification-9000-success-toggle"
|
||||
isChecked={false}
|
||||
isDisabled={false}
|
||||
label="Successful"
|
||||
onChange={[Function]}
|
||||
>
|
||||
<StyledComponent
|
||||
aria-label="Toggle notification success"
|
||||
forwardedComponent={
|
||||
Object {
|
||||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "NotificationListItem__Switch-j7c411-1",
|
||||
"isStatic": true,
|
||||
"lastClassName": "ceuHGn",
|
||||
"rules": Array [
|
||||
"display:flex;flex-wrap:no-wrap;",
|
||||
],
|
||||
},
|
||||
"displayName": "NotificationListItem__Switch",
|
||||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"styledComponentId": "NotificationListItem__Switch-j7c411-1",
|
||||
"target": [Function],
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
"withComponent": [Function],
|
||||
}
|
||||
}
|
||||
forwardedRef={null}
|
||||
id="notification-9000-success-toggle"
|
||||
isChecked={false}
|
||||
isDisabled={false}
|
||||
label="Successful"
|
||||
onChange={[Function]}
|
||||
>
|
||||
<Switch
|
||||
aria-label="Toggle notification success"
|
||||
className="NotificationListItem__Switch-j7c411-1 ceuHGn"
|
||||
id="notification-9000-success-toggle"
|
||||
isChecked={false}
|
||||
isDisabled={false}
|
||||
label="Successful"
|
||||
onChange={[Function]}
|
||||
>
|
||||
<label
|
||||
className="pf-c-switch NotificationListItem__Switch-j7c411-1 ceuHGn"
|
||||
htmlFor="notification-9000-success-toggle"
|
||||
>
|
||||
<input
|
||||
aria-label="Toggle notification success"
|
||||
checked={false}
|
||||
className="pf-c-switch__input"
|
||||
disabled={false}
|
||||
id="notification-9000-success-toggle"
|
||||
onChange={[Function]}
|
||||
type="checkbox"
|
||||
/>
|
||||
<span
|
||||
className="pf-c-switch__toggle"
|
||||
/>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="pf-c-switch__label pf-m-on"
|
||||
>
|
||||
Successful
|
||||
</span>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="pf-c-switch__label pf-m-off"
|
||||
>
|
||||
Successful
|
||||
</span>
|
||||
</label>
|
||||
</Switch>
|
||||
</StyledComponent>
|
||||
</NotificationListItem__Switch>
|
||||
<NotificationListItem__Switch
|
||||
aria-label="Toggle notification failure"
|
||||
id="notification-9000-error-toggle"
|
||||
isChecked={false}
|
||||
isDisabled={false}
|
||||
label="Failure"
|
||||
onChange={[Function]}
|
||||
>
|
||||
<StyledComponent
|
||||
aria-label="Toggle notification failure"
|
||||
forwardedComponent={
|
||||
Object {
|
||||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "NotificationListItem__Switch-j7c411-1",
|
||||
"isStatic": true,
|
||||
"lastClassName": "ceuHGn",
|
||||
"rules": Array [
|
||||
"display:flex;flex-wrap:no-wrap;",
|
||||
],
|
||||
},
|
||||
"displayName": "NotificationListItem__Switch",
|
||||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"styledComponentId": "NotificationListItem__Switch-j7c411-1",
|
||||
"target": [Function],
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
"withComponent": [Function],
|
||||
}
|
||||
}
|
||||
forwardedRef={null}
|
||||
id="notification-9000-error-toggle"
|
||||
isChecked={false}
|
||||
isDisabled={false}
|
||||
label="Failure"
|
||||
onChange={[Function]}
|
||||
>
|
||||
<Switch
|
||||
aria-label="Toggle notification failure"
|
||||
className="NotificationListItem__Switch-j7c411-1 ceuHGn"
|
||||
id="notification-9000-error-toggle"
|
||||
isChecked={false}
|
||||
isDisabled={false}
|
||||
label="Failure"
|
||||
onChange={[Function]}
|
||||
>
|
||||
<label
|
||||
className="pf-c-switch NotificationListItem__Switch-j7c411-1 ceuHGn"
|
||||
htmlFor="notification-9000-error-toggle"
|
||||
>
|
||||
<input
|
||||
aria-label="Toggle notification failure"
|
||||
checked={false}
|
||||
className="pf-c-switch__input"
|
||||
disabled={false}
|
||||
id="notification-9000-error-toggle"
|
||||
onChange={[Function]}
|
||||
type="checkbox"
|
||||
/>
|
||||
<span
|
||||
className="pf-c-switch__toggle"
|
||||
/>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="pf-c-switch__label pf-m-on"
|
||||
>
|
||||
Failure
|
||||
</span>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className="pf-c-switch__label pf-m-off"
|
||||
>
|
||||
Failure
|
||||
</span>
|
||||
</label>
|
||||
</Switch>
|
||||
</StyledComponent>
|
||||
</NotificationListItem__Switch>
|
||||
</div>
|
||||
</DataListCell>
|
||||
</StyledComponent>
|
||||
</NotificationListItem__DataListCell>
|
||||
</div>
|
||||
</DataListItemCells>
|
||||
</div>
|
||||
</DataListItemRow>
|
||||
</li>
|
||||
</DataListItem>
|
||||
</NotificationListItem>
|
||||
`;
|
||||
@@ -1,156 +0,0 @@
|
||||
/*
|
||||
* Enzyme helpers for injecting top-level contexts
|
||||
* derived from https://lingui.js.org/guides/testing.html
|
||||
*/
|
||||
import React from 'react';
|
||||
import { shape, object, string, arrayOf } from 'prop-types';
|
||||
import { mount, shallow } from 'enzyme';
|
||||
import { I18nProvider } from '@lingui/react';
|
||||
import { ConfigProvider } from '../src/contexts/Config';
|
||||
|
||||
const language = 'en-US';
|
||||
const intlProvider = new I18nProvider(
|
||||
{
|
||||
language,
|
||||
catalogs: {
|
||||
[language]: {}
|
||||
}
|
||||
},
|
||||
{}
|
||||
);
|
||||
const {
|
||||
linguiPublisher: { i18n: originalI18n }
|
||||
} = intlProvider.getChildContext();
|
||||
|
||||
const defaultContexts = {
|
||||
linguiPublisher: {
|
||||
i18n: {
|
||||
...originalI18n,
|
||||
_: key => key.id, // provide _ macro, for just passing down the key
|
||||
toJSON: () => '/i18n/',
|
||||
},
|
||||
},
|
||||
config: {
|
||||
ansible_version: null,
|
||||
custom_virtualenvs: [],
|
||||
version: null,
|
||||
toJSON: () => '/config/'
|
||||
},
|
||||
router: {
|
||||
history: {
|
||||
push: () => {},
|
||||
replace: () => {},
|
||||
createHref: () => {},
|
||||
location: {
|
||||
hash: '',
|
||||
pathname: '',
|
||||
search: '',
|
||||
state: '',
|
||||
},
|
||||
toJSON: () => '/history/',
|
||||
},
|
||||
route: {
|
||||
location: {
|
||||
hash: '',
|
||||
pathname: '',
|
||||
search: '',
|
||||
state: '',
|
||||
},
|
||||
match: {
|
||||
params: {},
|
||||
isExact: false,
|
||||
path: '',
|
||||
url: '',
|
||||
}
|
||||
},
|
||||
toJSON: () => '/router/',
|
||||
},
|
||||
};
|
||||
|
||||
function wrapContexts (node, context) {
|
||||
const { config } = context;
|
||||
class Wrap extends React.Component {
|
||||
render () {
|
||||
// eslint-disable-next-line react/no-this-in-sfc
|
||||
const { children, ...props } = this.props;
|
||||
const component = React.cloneElement(children, props);
|
||||
return (
|
||||
<ConfigProvider value={config}>
|
||||
{component}
|
||||
</ConfigProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Wrap>{node}</Wrap>
|
||||
);
|
||||
}
|
||||
|
||||
function applyDefaultContexts (context) {
|
||||
if (!context) {
|
||||
return defaultContexts;
|
||||
}
|
||||
const newContext = {};
|
||||
Object.keys(defaultContexts).forEach(key => {
|
||||
newContext[key] = {
|
||||
...defaultContexts[key],
|
||||
...context[key],
|
||||
};
|
||||
});
|
||||
return newContext;
|
||||
}
|
||||
|
||||
export function shallowWithContexts (node, options = {}) {
|
||||
const context = applyDefaultContexts(options.context);
|
||||
return shallow(wrapContexts(node, context));
|
||||
}
|
||||
|
||||
export function mountWithContexts (node, options = {}) {
|
||||
const context = applyDefaultContexts(options.context);
|
||||
const childContextTypes = {
|
||||
linguiPublisher: shape({
|
||||
i18n: object.isRequired
|
||||
}).isRequired,
|
||||
config: shape({
|
||||
ansible_version: string,
|
||||
custom_virtualenvs: arrayOf(string),
|
||||
version: string,
|
||||
}),
|
||||
router: shape({
|
||||
route: shape({
|
||||
location: shape({}),
|
||||
match: shape({}),
|
||||
}).isRequired,
|
||||
history: shape({}).isRequired,
|
||||
}),
|
||||
...options.childContextTypes
|
||||
};
|
||||
return mount(wrapContexts(node, context), { context, childContextTypes });
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for element(s) to achieve a desired state.
|
||||
*
|
||||
* @param[wrapper] - A ReactWrapper instance
|
||||
* @param[selector] - The selector of the element(s) to wait for.
|
||||
* @param[callback] - Callback to poll - by default this checks for a node count of 1.
|
||||
*/
|
||||
export function waitForElement (wrapper, selector, callback = el => el.length === 1) {
|
||||
const interval = 100;
|
||||
return new Promise((resolve, reject) => {
|
||||
let attempts = 30;
|
||||
(function pollElement () {
|
||||
wrapper.update();
|
||||
const el = wrapper.find(selector);
|
||||
if (callback(el)) {
|
||||
return resolve(el);
|
||||
}
|
||||
if (--attempts <= 0) {
|
||||
const message = `Expected condition for <${selector}> not met: ${callback.toString()}`;
|
||||
return reject(new Error(message));
|
||||
}
|
||||
return setTimeout(pollElement, interval);
|
||||
}());
|
||||
});
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { withI18n } from '@lingui/react';
|
||||
import { t } from '@lingui/macro';
|
||||
import { mountWithContexts, waitForElement } from './enzymeHelpers';
|
||||
import { Config } from '../src/contexts/Config';
|
||||
|
||||
describe('mountWithContexts', () => {
|
||||
describe('injected I18nProvider', () => {
|
||||
test('should mount and render', () => {
|
||||
const Child = withI18n()(({ i18n }) => (
|
||||
<div>
|
||||
<span>{i18n._(t`Text content`)}</span>
|
||||
</div>
|
||||
));
|
||||
const wrapper = mountWithContexts(<Child />);
|
||||
expect(wrapper.find('div')).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should mount and render deeply nested consumer', () => {
|
||||
const Child = withI18n()(({ i18n }) => (
|
||||
<div>{i18n._(t`Text content`)}</div>
|
||||
));
|
||||
const Parent = () => (<Child />);
|
||||
const wrapper = mountWithContexts(<Parent />);
|
||||
expect(wrapper.find('Parent')).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('injected Router', () => {
|
||||
it('should mount and render', () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<div>
|
||||
<Link to="/">home</Link>
|
||||
</div>
|
||||
);
|
||||
|
||||
expect(wrapper.find('div')).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should mount and render with stubbed context', () => {
|
||||
const context = {
|
||||
router: {
|
||||
history: {
|
||||
push: jest.fn(),
|
||||
replace: jest.fn(),
|
||||
createHref: jest.fn(),
|
||||
},
|
||||
route: {
|
||||
location: {},
|
||||
match: {}
|
||||
}
|
||||
}
|
||||
};
|
||||
const wrapper = mountWithContexts(
|
||||
(
|
||||
<div>
|
||||
<Link to="/">home</Link>
|
||||
</div>
|
||||
),
|
||||
{ context }
|
||||
);
|
||||
|
||||
const link = wrapper.find('Link');
|
||||
expect(link).toHaveLength(1);
|
||||
link.simulate('click', { button: 0 });
|
||||
wrapper.update();
|
||||
|
||||
expect(context.router.history.push).toHaveBeenCalledWith('/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('injected ConfigProvider', () => {
|
||||
it('should mount and render with default values', () => {
|
||||
const Foo = () => (
|
||||
<Config>
|
||||
{value => (
|
||||
<div>
|
||||
{value.custom_virtualenvs[0]}
|
||||
{value.version}
|
||||
</div>
|
||||
)}
|
||||
</Config>
|
||||
);
|
||||
const wrapper = mountWithContexts(<Foo />);
|
||||
expect(wrapper.find('Foo')).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should mount and render with custom Config value', () => {
|
||||
const config = {
|
||||
custom_virtualenvs: ['Fizz', 'Buzz'],
|
||||
version: '1.1',
|
||||
};
|
||||
const Foo = () => (
|
||||
<Config>
|
||||
{value => (
|
||||
<div>
|
||||
{value.custom_virtualenvs[0]}
|
||||
{value.version}
|
||||
</div>
|
||||
)}
|
||||
</Config>
|
||||
);
|
||||
const wrapper = mountWithContexts(
|
||||
<Foo />,
|
||||
{ context: { config } }
|
||||
);
|
||||
expect(wrapper.find('Foo')).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* This is a fixture for testing async components. It renders a div
|
||||
* after a short amount of time.
|
||||
*/
|
||||
class TestAsyncComponent extends Component {
|
||||
constructor (props) {
|
||||
super(props);
|
||||
this.state = { displayElement: false };
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
setTimeout(() => this.setState({ displayElement: true }), 500);
|
||||
}
|
||||
|
||||
render () {
|
||||
const { displayElement } = this.state;
|
||||
if (displayElement) {
|
||||
return (<div id="test-async-component" />);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
describe('waitForElement', () => {
|
||||
it('waits for the element and returns it', async (done) => {
|
||||
const selector = '#test-async-component';
|
||||
const wrapper = mountWithContexts(<TestAsyncComponent />);
|
||||
expect(wrapper.exists(selector)).toEqual(false);
|
||||
|
||||
const elem = await waitForElement(wrapper, selector);
|
||||
expect(elem.props().id).toEqual('test-async-component');
|
||||
expect(wrapper.exists(selector)).toEqual(true);
|
||||
done();
|
||||
});
|
||||
|
||||
it('eventually throws an error for elements that don\'t exist', async (done) => {
|
||||
const wrapper = mountWithContexts(<div />);
|
||||
|
||||
let error;
|
||||
try {
|
||||
await waitForElement(wrapper, '#does-not-exist');
|
||||
} catch (err) {
|
||||
error = err;
|
||||
} finally {
|
||||
expect(error).toEqual(new Error('Expected condition for <#does-not-exist> not met: el => el.length === 1'));
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,17 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { main } from '../src/index';
|
||||
|
||||
const render = template => mount(
|
||||
<MemoryRouter>
|
||||
{template}
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
describe('index.jsx', () => {
|
||||
test('index.jsx loads without issue', () => {
|
||||
const wrapper = main(render);
|
||||
expect(wrapper.find('RootProvider')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import Applications from '../../src/pages/Applications';
|
||||
|
||||
describe('<Applications />', () => {
|
||||
let pageWrapper;
|
||||
let pageSections;
|
||||
let title;
|
||||
|
||||
beforeEach(() => {
|
||||
pageWrapper = mountWithContexts(<Applications />);
|
||||
pageSections = pageWrapper.find('PageSection');
|
||||
title = pageWrapper.find('Title');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
pageWrapper.unmount();
|
||||
});
|
||||
|
||||
test('initially renders without crashing', () => {
|
||||
expect(pageWrapper.length).toBe(1);
|
||||
expect(pageSections.length).toBe(2);
|
||||
expect(title.length).toBe(1);
|
||||
expect(title.props().size).toBe('2xl');
|
||||
pageSections.forEach(section => {
|
||||
expect(section.props().variant).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import AuthSettings from '../../src/pages/AuthSettings';
|
||||
|
||||
describe('<AuthSettings />', () => {
|
||||
let pageWrapper;
|
||||
let pageSections;
|
||||
let title;
|
||||
|
||||
beforeEach(() => {
|
||||
pageWrapper = mountWithContexts(<AuthSettings />);
|
||||
pageSections = pageWrapper.find('PageSection');
|
||||
title = pageWrapper.find('Title');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
pageWrapper.unmount();
|
||||
});
|
||||
|
||||
test('initially renders without crashing', () => {
|
||||
expect(pageWrapper.length).toBe(1);
|
||||
expect(pageSections.length).toBe(2);
|
||||
expect(title.length).toBe(1);
|
||||
expect(title.props().size).toBe('2xl');
|
||||
pageSections.forEach(section => {
|
||||
expect(section.props().variant).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import CredentialTypes from '../../src/pages/CredentialTypes';
|
||||
|
||||
describe('<CredentialTypes />', () => {
|
||||
let pageWrapper;
|
||||
let pageSections;
|
||||
let title;
|
||||
|
||||
beforeEach(() => {
|
||||
pageWrapper = mountWithContexts(<CredentialTypes />);
|
||||
pageSections = pageWrapper.find('PageSection');
|
||||
title = pageWrapper.find('Title');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
pageWrapper.unmount();
|
||||
});
|
||||
|
||||
test('initially renders without crashing', () => {
|
||||
expect(pageWrapper.length).toBe(1);
|
||||
expect(pageSections.length).toBe(2);
|
||||
expect(title.length).toBe(1);
|
||||
expect(title.props().size).toBe('2xl');
|
||||
pageSections.forEach(section => {
|
||||
expect(section.props().variant).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import Credentials from '../../src/pages/Credentials';
|
||||
|
||||
describe('<Credentials />', () => {
|
||||
let pageWrapper;
|
||||
let pageSections;
|
||||
let title;
|
||||
|
||||
beforeEach(() => {
|
||||
pageWrapper = mountWithContexts(<Credentials />);
|
||||
pageSections = pageWrapper.find('PageSection');
|
||||
title = pageWrapper.find('Title');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
pageWrapper.unmount();
|
||||
});
|
||||
|
||||
test('initially renders without crashing', () => {
|
||||
expect(pageWrapper.length).toBe(1);
|
||||
expect(pageSections.length).toBe(2);
|
||||
expect(title.length).toBe(1);
|
||||
expect(title.props().size).toBe('2xl');
|
||||
pageSections.forEach(section => {
|
||||
expect(section.props().variant).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import Dashboard from '../../src/pages/Dashboard';
|
||||
|
||||
describe('<Dashboard />', () => {
|
||||
let pageWrapper;
|
||||
let pageSections;
|
||||
let title;
|
||||
|
||||
beforeEach(() => {
|
||||
pageWrapper = mountWithContexts(<Dashboard />);
|
||||
pageSections = pageWrapper.find('PageSection');
|
||||
title = pageWrapper.find('Title');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
pageWrapper.unmount();
|
||||
});
|
||||
|
||||
test('initially renders without crashing', () => {
|
||||
expect(pageWrapper.length).toBe(1);
|
||||
expect(pageSections.length).toBe(2);
|
||||
expect(title.length).toBe(1);
|
||||
expect(title.props().size).toBe('2xl');
|
||||
pageSections.forEach(section => {
|
||||
expect(section.props().variant).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import InstanceGroups from '../../src/pages/InstanceGroups';
|
||||
|
||||
describe('<InstanceGroups />', () => {
|
||||
let pageWrapper;
|
||||
let pageSections;
|
||||
let title;
|
||||
|
||||
beforeEach(() => {
|
||||
pageWrapper = mountWithContexts(<InstanceGroups />);
|
||||
pageSections = pageWrapper.find('PageSection');
|
||||
title = pageWrapper.find('Title');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
pageWrapper.unmount();
|
||||
});
|
||||
|
||||
test('initially renders without crashing', () => {
|
||||
expect(pageWrapper.length).toBe(1);
|
||||
expect(pageSections.length).toBe(2);
|
||||
expect(title.length).toBe(1);
|
||||
expect(title.props().size).toBe('2xl');
|
||||
pageSections.forEach(section => {
|
||||
expect(section.props().variant).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import Inventories from '../../src/pages/Inventories';
|
||||
|
||||
describe('<Inventories />', () => {
|
||||
let pageWrapper;
|
||||
let pageSections;
|
||||
let title;
|
||||
|
||||
beforeEach(() => {
|
||||
pageWrapper = mountWithContexts(<Inventories />);
|
||||
pageSections = pageWrapper.find('PageSection');
|
||||
title = pageWrapper.find('Title');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
pageWrapper.unmount();
|
||||
});
|
||||
|
||||
test('initially renders without crashing', () => {
|
||||
expect(pageWrapper.length).toBe(1);
|
||||
expect(pageSections.length).toBe(2);
|
||||
expect(title.length).toBe(1);
|
||||
expect(title.props().size).toBe('2xl');
|
||||
pageSections.forEach(section => {
|
||||
expect(section.props().variant).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import InventoryScripts from '../../src/pages/InventoryScripts';
|
||||
|
||||
describe('<InventoryScripts />', () => {
|
||||
let pageWrapper;
|
||||
let pageSections;
|
||||
let title;
|
||||
|
||||
beforeEach(() => {
|
||||
pageWrapper = mountWithContexts(<InventoryScripts />);
|
||||
pageSections = pageWrapper.find('PageSection');
|
||||
title = pageWrapper.find('Title');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
pageWrapper.unmount();
|
||||
});
|
||||
|
||||
test('initially renders without crashing', () => {
|
||||
expect(pageWrapper.length).toBe(1);
|
||||
expect(pageSections.length).toBe(2);
|
||||
expect(title.length).toBe(1);
|
||||
expect(title.props().size).toBe('2xl');
|
||||
pageSections.forEach(section => {
|
||||
expect(section.props().variant).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,36 +0,0 @@
|
||||
import React from 'react';
|
||||
import { createMemoryHistory } from 'history';
|
||||
import { mountWithContexts } from '../../enzymeHelpers';
|
||||
import Jobs from '../../../src/pages/Jobs';
|
||||
|
||||
describe('<Jobs />', () => {
|
||||
test('initially renders succesfully', () => {
|
||||
mountWithContexts(
|
||||
<Jobs />
|
||||
);
|
||||
});
|
||||
|
||||
test('should display a breadcrumb heading', () => {
|
||||
const history = createMemoryHistory({
|
||||
initialEntries: ['/jobs'],
|
||||
});
|
||||
const match = { path: '/jobs', url: '/jobs', isExact: true };
|
||||
|
||||
const wrapper = mountWithContexts(
|
||||
<Jobs />,
|
||||
{
|
||||
context: {
|
||||
router: {
|
||||
history,
|
||||
route: {
|
||||
location: history.location,
|
||||
match
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
expect(wrapper.find('BreadcrumbHeading').length).toBe(1);
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
@@ -1,9 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../../../../enzymeHelpers';
|
||||
import { Job } from '../../../../../src/pages/Jobs';
|
||||
|
||||
describe('<Job />', () => {
|
||||
test('initially renders succesfully', () => {
|
||||
mountWithContexts(<Job />);
|
||||
});
|
||||
});
|
||||
@@ -1,24 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../../../../enzymeHelpers';
|
||||
import JobDetail from '../../../../../src/pages/Jobs/JobDetail';
|
||||
|
||||
describe('<JobDetail />', () => {
|
||||
const mockDetails = {
|
||||
name: 'Foo'
|
||||
};
|
||||
|
||||
test('initially renders succesfully', () => {
|
||||
mountWithContexts(
|
||||
<JobDetail job={mockDetails} />
|
||||
);
|
||||
});
|
||||
|
||||
test('should display a Close button', () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<JobDetail job={mockDetails} />
|
||||
);
|
||||
|
||||
expect(wrapper.find('Button[aria-label="close"]').length).toBe(1);
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
@@ -1,15 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../../../../enzymeHelpers';
|
||||
import JobOutput from '../../../../../src/pages/Jobs/JobOutput';
|
||||
|
||||
describe('<JobOutput />', () => {
|
||||
const mockDetails = {
|
||||
name: 'Foo'
|
||||
};
|
||||
|
||||
test('initially renders succesfully', () => {
|
||||
mountWithContexts(
|
||||
<JobOutput job={mockDetails} />
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import JobsSettings from '../../src/pages/JobsSettings';
|
||||
|
||||
describe('<JobsSettings />', () => {
|
||||
let pageWrapper;
|
||||
let pageSections;
|
||||
let title;
|
||||
|
||||
beforeEach(() => {
|
||||
pageWrapper = mountWithContexts(<JobsSettings />);
|
||||
pageSections = pageWrapper.find('PageSection');
|
||||
title = pageWrapper.find('Title');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
pageWrapper.unmount();
|
||||
});
|
||||
|
||||
test('initially renders without crashing', () => {
|
||||
expect(pageWrapper.length).toBe(1);
|
||||
expect(pageSections.length).toBe(2);
|
||||
expect(title.length).toBe(1);
|
||||
expect(title.props().size).toBe('2xl');
|
||||
pageSections.forEach(section => {
|
||||
expect(section.props().variant).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import License from '../../src/pages/License';
|
||||
|
||||
describe('<License />', () => {
|
||||
let pageWrapper;
|
||||
let pageSections;
|
||||
let title;
|
||||
|
||||
beforeEach(() => {
|
||||
pageWrapper = mountWithContexts(<License />);
|
||||
pageSections = pageWrapper.find('PageSection');
|
||||
title = pageWrapper.find('Title');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
pageWrapper.unmount();
|
||||
});
|
||||
|
||||
test('initially renders without crashing', () => {
|
||||
expect(pageWrapper.length).toBe(1);
|
||||
expect(pageSections.length).toBe(2);
|
||||
expect(title.length).toBe(1);
|
||||
expect(title.props().size).toBe('2xl');
|
||||
pageSections.forEach(section => {
|
||||
expect(section.props().variant).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,215 +0,0 @@
|
||||
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();
|
||||
});
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import ManagementJobs from '../../src/pages/ManagementJobs';
|
||||
|
||||
describe('<ManagementJobs />', () => {
|
||||
let pageWrapper;
|
||||
let pageSections;
|
||||
let title;
|
||||
|
||||
beforeEach(() => {
|
||||
pageWrapper = mountWithContexts(<ManagementJobs />);
|
||||
pageSections = pageWrapper.find('PageSection');
|
||||
title = pageWrapper.find('Title');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
pageWrapper.unmount();
|
||||
});
|
||||
|
||||
test('initially renders without crashing', () => {
|
||||
expect(pageWrapper.length).toBe(1);
|
||||
expect(pageSections.length).toBe(2);
|
||||
expect(title.length).toBe(1);
|
||||
expect(title.props().size).toBe('2xl');
|
||||
pageSections.forEach(section => {
|
||||
expect(section.props().variant).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import NotificationTemplates from '../../src/pages/NotificationTemplates';
|
||||
|
||||
describe('<NotificationTemplates />', () => {
|
||||
let pageWrapper;
|
||||
let pageSections;
|
||||
let title;
|
||||
|
||||
beforeEach(() => {
|
||||
pageWrapper = mountWithContexts(<NotificationTemplates />);
|
||||
pageSections = pageWrapper.find('PageSection');
|
||||
title = pageWrapper.find('Title');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
pageWrapper.unmount();
|
||||
});
|
||||
|
||||
test('initially renders without crashing', () => {
|
||||
expect(pageWrapper.length).toBe(1);
|
||||
expect(pageSections.length).toBe(2);
|
||||
expect(title.length).toBe(1);
|
||||
expect(title.props().size).toBe('2xl');
|
||||
pageSections.forEach(section => {
|
||||
expect(section.props().variant).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,16 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../../enzymeHelpers';
|
||||
import Organizations from '../../../src/pages/Organizations/Organizations';
|
||||
|
||||
jest.mock('../../../src/api');
|
||||
|
||||
describe('<Organizations />', () => {
|
||||
test('initially renders succesfully', () => {
|
||||
mountWithContexts(
|
||||
<Organizations
|
||||
match={{ path: '/organizations', url: '/organizations' }}
|
||||
location={{ search: '', pathname: '/organizations' }}
|
||||
/>
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,27 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../../../enzymeHelpers';
|
||||
import DeleteRoleConfirmationModal from '../../../../src/pages/Organizations/components/DeleteRoleConfirmationModal';
|
||||
|
||||
const role = {
|
||||
id: 3,
|
||||
name: 'Member',
|
||||
resource_name: 'Org',
|
||||
resource_type: 'organization',
|
||||
team_id: 5,
|
||||
team_name: 'The Team',
|
||||
};
|
||||
|
||||
describe('<DeleteRoleConfirmationModal />', () => {
|
||||
test('should render initially', () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<DeleteRoleConfirmationModal
|
||||
role={role}
|
||||
username="jane"
|
||||
onCancel={() => {}}
|
||||
onConfirm={() => {}}
|
||||
/>
|
||||
);
|
||||
wrapper.update();
|
||||
expect(wrapper.find('DeleteRoleConfirmationModal')).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -1,37 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../../../enzymeHelpers';
|
||||
import OrganizationAccessItem from '../../../../src/pages/Organizations/components/OrganizationAccessItem';
|
||||
|
||||
const accessRecord = {
|
||||
id: 2,
|
||||
username: 'jane',
|
||||
url: '/bar',
|
||||
first_name: 'jane',
|
||||
last_name: 'brown',
|
||||
summary_fields: {
|
||||
direct_access: [{
|
||||
role: {
|
||||
id: 3,
|
||||
name: 'Member',
|
||||
resource_name: 'Org',
|
||||
resource_type: 'organization',
|
||||
team_id: 5,
|
||||
team_name: 'The Team',
|
||||
user_capabilities: { unattach: true },
|
||||
}
|
||||
}],
|
||||
indirect_access: [],
|
||||
}
|
||||
};
|
||||
|
||||
describe('<OrganizationAccessItem />', () => {
|
||||
test('initially renders succesfully', () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<OrganizationAccessItem
|
||||
accessRecord={accessRecord}
|
||||
onRoleDelete={() => {}}
|
||||
/>
|
||||
);
|
||||
expect(wrapper.find('OrganizationAccessItem')).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -1,307 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../../../enzymeHelpers';
|
||||
import { sleep } from '../../../testUtils';
|
||||
import OrganizationForm from '../../../../src/pages/Organizations/components/OrganizationForm';
|
||||
import { OrganizationsAPI } from '../../../../src/api';
|
||||
|
||||
jest.mock('../../../../src/api');
|
||||
|
||||
describe('<OrganizationForm />', () => {
|
||||
const network = {};
|
||||
const meConfig = {
|
||||
me: {
|
||||
is_superuser: false
|
||||
}
|
||||
};
|
||||
const mockData = {
|
||||
id: 1,
|
||||
name: 'Foo',
|
||||
description: 'Bar',
|
||||
max_hosts: 1,
|
||||
custom_virtualenv: 'Fizz',
|
||||
related: {
|
||||
instance_groups: '/api/v2/organizations/1/instance_groups'
|
||||
}
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('should request related instance groups from api', () => {
|
||||
mountWithContexts(
|
||||
(
|
||||
<OrganizationForm
|
||||
organization={mockData}
|
||||
handleSubmit={jest.fn()}
|
||||
handleCancel={jest.fn()}
|
||||
me={meConfig.me}
|
||||
/>
|
||||
), {
|
||||
context: { network },
|
||||
}
|
||||
);
|
||||
|
||||
expect(OrganizationsAPI.readInstanceGroups).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('componentDidMount should set instanceGroups to state', async () => {
|
||||
const mockInstanceGroups = [
|
||||
{ name: 'One', id: 1 },
|
||||
{ name: 'Two', id: 2 }
|
||||
];
|
||||
OrganizationsAPI.readInstanceGroups.mockReturnValue({
|
||||
data: {
|
||||
results: mockInstanceGroups
|
||||
}
|
||||
});
|
||||
const wrapper = mountWithContexts(
|
||||
(
|
||||
<OrganizationForm
|
||||
organization={mockData}
|
||||
handleSubmit={jest.fn()}
|
||||
handleCancel={jest.fn()}
|
||||
me={meConfig.me}
|
||||
/>
|
||||
), {
|
||||
context: { network },
|
||||
}
|
||||
);
|
||||
|
||||
await sleep(0);
|
||||
expect(OrganizationsAPI.readInstanceGroups).toHaveBeenCalled();
|
||||
expect(wrapper.find('OrganizationForm').state().instanceGroups).toEqual(mockInstanceGroups);
|
||||
});
|
||||
|
||||
test('changing instance group successfully sets instanceGroups state', () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<OrganizationForm
|
||||
organization={mockData}
|
||||
handleSubmit={jest.fn()}
|
||||
handleCancel={jest.fn()}
|
||||
me={meConfig.me}
|
||||
/>
|
||||
);
|
||||
|
||||
const lookup = wrapper.find('InstanceGroupsLookup');
|
||||
expect(lookup.length).toBe(1);
|
||||
|
||||
lookup.prop('onChange')([
|
||||
{
|
||||
id: 1,
|
||||
name: 'foo'
|
||||
}
|
||||
], 'instanceGroups');
|
||||
expect(wrapper.find('OrganizationForm').state().instanceGroups).toEqual([
|
||||
{
|
||||
id: 1,
|
||||
name: 'foo'
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
test('changing inputs should update form values', () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<OrganizationForm
|
||||
organization={mockData}
|
||||
handleSubmit={jest.fn()}
|
||||
handleCancel={jest.fn()}
|
||||
me={meConfig.me}
|
||||
/>
|
||||
);
|
||||
|
||||
const form = wrapper.find('Formik');
|
||||
wrapper.find('input#org-name').simulate('change', {
|
||||
target: { value: 'new foo', name: 'name' }
|
||||
});
|
||||
expect(form.state('values').name).toEqual('new foo');
|
||||
wrapper.find('input#org-description').simulate('change', {
|
||||
target: { value: 'new bar', name: 'description' }
|
||||
});
|
||||
expect(form.state('values').description).toEqual('new bar');
|
||||
wrapper.find('input#org-max_hosts').simulate('change', {
|
||||
target: { value: '134', name: 'max_hosts' }
|
||||
});
|
||||
expect(form.state('values').max_hosts).toEqual('134');
|
||||
});
|
||||
|
||||
test('AnsibleSelect component renders if there are virtual environments', () => {
|
||||
const config = {
|
||||
custom_virtualenvs: ['foo', 'bar'],
|
||||
};
|
||||
const wrapper = mountWithContexts(
|
||||
(
|
||||
<OrganizationForm
|
||||
organization={mockData}
|
||||
handleSubmit={jest.fn()}
|
||||
handleCancel={jest.fn()}
|
||||
me={meConfig.me}
|
||||
/>
|
||||
), {
|
||||
context: { config },
|
||||
}
|
||||
);
|
||||
expect(wrapper.find('FormSelect')).toHaveLength(1);
|
||||
expect(wrapper.find('FormSelectOption')).toHaveLength(2);
|
||||
});
|
||||
|
||||
test('calls handleSubmit when form submitted', async () => {
|
||||
const handleSubmit = jest.fn();
|
||||
const wrapper = mountWithContexts(
|
||||
<OrganizationForm
|
||||
organization={mockData}
|
||||
handleSubmit={handleSubmit}
|
||||
handleCancel={jest.fn()}
|
||||
me={meConfig.me}
|
||||
/>
|
||||
);
|
||||
expect(handleSubmit).not.toHaveBeenCalled();
|
||||
wrapper.find('button[aria-label="Save"]').simulate('click');
|
||||
await sleep(1);
|
||||
expect(handleSubmit).toHaveBeenCalledWith({
|
||||
name: 'Foo',
|
||||
description: 'Bar',
|
||||
max_hosts: 1,
|
||||
custom_virtualenv: 'Fizz',
|
||||
}, [], []);
|
||||
});
|
||||
|
||||
test('handleSubmit associates and disassociates instance groups', async () => {
|
||||
const mockInstanceGroups = [
|
||||
{ name: 'One', id: 1 },
|
||||
{ name: 'Two', id: 2 }
|
||||
];
|
||||
OrganizationsAPI.readInstanceGroups.mockReturnValue({
|
||||
data: {
|
||||
results: mockInstanceGroups
|
||||
}
|
||||
});
|
||||
const mockDataForm = {
|
||||
name: 'Foo',
|
||||
description: 'Bar',
|
||||
max_hosts: 1,
|
||||
custom_virtualenv: 'Fizz',
|
||||
};
|
||||
const handleSubmit = jest.fn();
|
||||
OrganizationsAPI.update.mockResolvedValue(1, mockDataForm);
|
||||
OrganizationsAPI.associateInstanceGroup.mockResolvedValue('done');
|
||||
OrganizationsAPI.disassociateInstanceGroup.mockResolvedValue('done');
|
||||
const wrapper = mountWithContexts(
|
||||
(
|
||||
<OrganizationForm
|
||||
organization={mockData}
|
||||
handleSubmit={handleSubmit}
|
||||
handleCancel={jest.fn()}
|
||||
me={meConfig.me}
|
||||
/>
|
||||
), {
|
||||
context: { network }
|
||||
}
|
||||
);
|
||||
await sleep(0);
|
||||
wrapper.find('InstanceGroupsLookup').prop('onChange')([
|
||||
{ name: 'One', id: 1 },
|
||||
{ name: 'Three', id: 3 }
|
||||
], 'instanceGroups');
|
||||
|
||||
wrapper.find('button[aria-label="Save"]').simulate('click');
|
||||
await sleep(0);
|
||||
expect(handleSubmit).toHaveBeenCalledWith(mockDataForm, [3], [2]);
|
||||
});
|
||||
|
||||
test('handleSubmit is called with max_hosts value if it is in range', async () => {
|
||||
const handleSubmit = jest.fn();
|
||||
|
||||
// normal mount
|
||||
const wrapper = mountWithContexts(
|
||||
<OrganizationForm
|
||||
organization={mockData}
|
||||
handleSubmit={handleSubmit}
|
||||
handleCancel={jest.fn()}
|
||||
me={meConfig.me}
|
||||
/>
|
||||
);
|
||||
wrapper.find('button[aria-label="Save"]').simulate('click');
|
||||
await sleep(0);
|
||||
expect(handleSubmit).toHaveBeenCalledWith({
|
||||
name: 'Foo',
|
||||
description: 'Bar',
|
||||
max_hosts: 1,
|
||||
custom_virtualenv: 'Fizz',
|
||||
}, [], []);
|
||||
});
|
||||
|
||||
test('handleSubmit does not get called if max_hosts value is out of range', async () => {
|
||||
const handleSubmit = jest.fn();
|
||||
|
||||
// not mount with Negative value
|
||||
const mockDataNegative = JSON.parse(JSON.stringify(mockData));
|
||||
mockDataNegative.max_hosts = -5;
|
||||
const wrapper1 = mountWithContexts(
|
||||
<OrganizationForm
|
||||
organization={mockDataNegative}
|
||||
handleSubmit={handleSubmit}
|
||||
handleCancel={jest.fn()}
|
||||
me={meConfig.me}
|
||||
/>
|
||||
);
|
||||
wrapper1.find('button[aria-label="Save"]').simulate('click');
|
||||
await sleep(0);
|
||||
expect(handleSubmit).not.toHaveBeenCalled();
|
||||
|
||||
// not mount with Out of Range value
|
||||
const mockDataOoR = JSON.parse(JSON.stringify(mockData));
|
||||
mockDataOoR.max_hosts = 999999999999;
|
||||
const wrapper2 = mountWithContexts(
|
||||
<OrganizationForm
|
||||
organization={mockDataOoR}
|
||||
handleSubmit={handleSubmit}
|
||||
handleCancel={jest.fn()}
|
||||
me={meConfig.me}
|
||||
/>
|
||||
);
|
||||
wrapper2.find('button[aria-label="Save"]').simulate('click');
|
||||
await sleep(0);
|
||||
expect(handleSubmit).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('handleSubmit is called and max_hosts value defaults to 0 if input is not a number', async () => {
|
||||
const handleSubmit = jest.fn();
|
||||
|
||||
// mount with String value (default to zero)
|
||||
const mockDataString = JSON.parse(JSON.stringify(mockData));
|
||||
mockDataString.max_hosts = 'Bee';
|
||||
const wrapper = mountWithContexts(
|
||||
<OrganizationForm
|
||||
organization={mockDataString}
|
||||
handleSubmit={handleSubmit}
|
||||
handleCancel={jest.fn()}
|
||||
me={meConfig.me}
|
||||
/>
|
||||
);
|
||||
wrapper.find('button[aria-label="Save"]').simulate('click');
|
||||
await sleep(0);
|
||||
expect(handleSubmit).toHaveBeenCalledWith({
|
||||
name: 'Foo',
|
||||
description: 'Bar',
|
||||
max_hosts: 0,
|
||||
custom_virtualenv: 'Fizz',
|
||||
}, [], []);
|
||||
});
|
||||
|
||||
test('calls "handleCancel" when Cancel button is clicked', () => {
|
||||
const handleCancel = jest.fn();
|
||||
|
||||
const wrapper = mountWithContexts(
|
||||
<OrganizationForm
|
||||
organization={mockData}
|
||||
handleSubmit={jest.fn()}
|
||||
handleCancel={handleCancel}
|
||||
me={meConfig.me}
|
||||
/>
|
||||
);
|
||||
expect(handleCancel).not.toHaveBeenCalled();
|
||||
wrapper.find('button[aria-label="Cancel"]').prop('onClick')();
|
||||
expect(handleCancel).toBeCalled();
|
||||
});
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
import React from 'react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { I18nProvider } from '@lingui/react';
|
||||
import { mountWithContexts } from '../../../enzymeHelpers';
|
||||
import OrganizationListItem from '../../../../src/pages/Organizations/components/OrganizationListItem';
|
||||
|
||||
describe('<OrganizationListItem />', () => {
|
||||
test('initially renders succesfully', () => {
|
||||
mountWithContexts(
|
||||
<I18nProvider>
|
||||
<MemoryRouter initialEntries={['/organizations']} initialIndex={0}>
|
||||
<OrganizationListItem
|
||||
organization={{
|
||||
id: 1,
|
||||
name: 'Org',
|
||||
summary_fields: { related_field_counts: {
|
||||
users: 1,
|
||||
teams: 1,
|
||||
} }
|
||||
}}
|
||||
detailUrl="/organization/1"
|
||||
isSelected
|
||||
onSelect={() => {}}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
</I18nProvider>
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,483 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
|
||||
<DeleteRoleConfirmationModal
|
||||
i18n={"/i18n/"}
|
||||
onCancel={[Function]}
|
||||
onConfirm={[Function]}
|
||||
role={
|
||||
Object {
|
||||
"id": 3,
|
||||
"name": "Member",
|
||||
"resource_name": "Org",
|
||||
"resource_type": "organization",
|
||||
"team_id": 5,
|
||||
"team_name": "The Team",
|
||||
}
|
||||
}
|
||||
username="jane"
|
||||
>
|
||||
<_default
|
||||
actions={
|
||||
Array [
|
||||
<Button
|
||||
aria-label="Confirm delete"
|
||||
className=""
|
||||
component="button"
|
||||
isActive={false}
|
||||
isBlock={false}
|
||||
isDisabled={false}
|
||||
isFocus={false}
|
||||
isHover={false}
|
||||
isInline={false}
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
variant="danger"
|
||||
>
|
||||
Delete
|
||||
</Button>,
|
||||
<Button
|
||||
aria-label={null}
|
||||
className=""
|
||||
component="button"
|
||||
isActive={false}
|
||||
isBlock={false}
|
||||
isDisabled={false}
|
||||
isFocus={false}
|
||||
isHover={false}
|
||||
isInline={false}
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
variant="secondary"
|
||||
>
|
||||
Cancel
|
||||
</Button>,
|
||||
]
|
||||
}
|
||||
isOpen={true}
|
||||
onClose={[Function]}
|
||||
title="Remove {0} Access"
|
||||
variant="danger"
|
||||
>
|
||||
<Modal
|
||||
actions={
|
||||
Array [
|
||||
<Button
|
||||
aria-label="Confirm delete"
|
||||
className=""
|
||||
component="button"
|
||||
isActive={false}
|
||||
isBlock={false}
|
||||
isDisabled={false}
|
||||
isFocus={false}
|
||||
isHover={false}
|
||||
isInline={false}
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
variant="danger"
|
||||
>
|
||||
Delete
|
||||
</Button>,
|
||||
<Button
|
||||
aria-label={null}
|
||||
className=""
|
||||
component="button"
|
||||
isActive={false}
|
||||
isBlock={false}
|
||||
isDisabled={false}
|
||||
isFocus={false}
|
||||
isHover={false}
|
||||
isInline={false}
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
variant="secondary"
|
||||
>
|
||||
Cancel
|
||||
</Button>,
|
||||
]
|
||||
}
|
||||
ariaDescribedById=""
|
||||
className="awx-c-modal at-c-alertModal at-c-alertModal--danger"
|
||||
hideTitle={false}
|
||||
isLarge={false}
|
||||
isOpen={true}
|
||||
isSmall={false}
|
||||
onClose={[Function]}
|
||||
title="Remove {0} Access"
|
||||
width={null}
|
||||
>
|
||||
<Portal
|
||||
containerInfo={
|
||||
<div>
|
||||
<div
|
||||
class="pf-c-backdrop"
|
||||
>
|
||||
<div
|
||||
class="pf-l-bullseye"
|
||||
>
|
||||
<div
|
||||
aria-describedby="pf-modal-0"
|
||||
aria-label="Remove {0} Access"
|
||||
aria-modal="true"
|
||||
class="pf-c-modal-box awx-c-modal at-c-alertModal at-c-alertModal--danger"
|
||||
role="dialog"
|
||||
>
|
||||
<button
|
||||
aria-label="Close"
|
||||
class="pf-c-button pf-m-plain"
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
role="img"
|
||||
style="vertical-align: -0.125em;"
|
||||
viewBox="0 0 352 512"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"
|
||||
transform=""
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<h3
|
||||
class="pf-c-title pf-m-2xl"
|
||||
>
|
||||
|
||||
Remove {0} Access
|
||||
|
||||
</h3>
|
||||
<div
|
||||
class="pf-c-modal-box__body"
|
||||
id="pf-modal-0"
|
||||
>
|
||||
Are you sure you want to remove {0} access from {1}? Doing so affects all members of the team.
|
||||
<br />
|
||||
<br />
|
||||
If you {0} want to remove access for this particular user, please remove them from the team.
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="at-c-alertModal__icon"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
role="img"
|
||||
style="vertical-align: -0.125em;"
|
||||
viewBox="0 0 512 512"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"
|
||||
transform=""
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
class="pf-c-modal-box__footer"
|
||||
>
|
||||
|
||||
<button
|
||||
aria-label="Confirm delete"
|
||||
class="pf-c-button pf-m-danger"
|
||||
type="button"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
<button
|
||||
class="pf-c-button pf-m-secondary"
|
||||
type="button"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<ModalContent
|
||||
actions={
|
||||
Array [
|
||||
<Button
|
||||
aria-label="Confirm delete"
|
||||
className=""
|
||||
component="button"
|
||||
isActive={false}
|
||||
isBlock={false}
|
||||
isDisabled={false}
|
||||
isFocus={false}
|
||||
isHover={false}
|
||||
isInline={false}
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
variant="danger"
|
||||
>
|
||||
Delete
|
||||
</Button>,
|
||||
<Button
|
||||
aria-label={null}
|
||||
className=""
|
||||
component="button"
|
||||
isActive={false}
|
||||
isBlock={false}
|
||||
isDisabled={false}
|
||||
isFocus={false}
|
||||
isHover={false}
|
||||
isInline={false}
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
variant="secondary"
|
||||
>
|
||||
Cancel
|
||||
</Button>,
|
||||
]
|
||||
}
|
||||
ariaDescribedById=""
|
||||
className="awx-c-modal at-c-alertModal at-c-alertModal--danger"
|
||||
hideTitle={false}
|
||||
id="pf-modal-0"
|
||||
isLarge={false}
|
||||
isOpen={true}
|
||||
isSmall={false}
|
||||
onClose={[Function]}
|
||||
title="Remove {0} Access"
|
||||
width={null}
|
||||
>
|
||||
<Backdrop
|
||||
className=""
|
||||
>
|
||||
<div
|
||||
className="pf-c-backdrop"
|
||||
>
|
||||
<FocusTrap
|
||||
_createFocusTrap={[Function]}
|
||||
active={true}
|
||||
className="pf-l-bullseye"
|
||||
focusTrapOptions={
|
||||
Object {
|
||||
"clickOutsideDeactivates": true,
|
||||
}
|
||||
}
|
||||
paused={false}
|
||||
tag="div"
|
||||
>
|
||||
<div
|
||||
className="pf-l-bullseye"
|
||||
>
|
||||
<ModalBox
|
||||
className="awx-c-modal at-c-alertModal at-c-alertModal--danger"
|
||||
id="pf-modal-0"
|
||||
isLarge={false}
|
||||
isSmall={false}
|
||||
style={
|
||||
Object {
|
||||
"width": null,
|
||||
}
|
||||
}
|
||||
title="Remove {0} Access"
|
||||
>
|
||||
<div
|
||||
aria-describedby="pf-modal-0"
|
||||
aria-label="Remove {0} Access"
|
||||
aria-modal="true"
|
||||
className="pf-c-modal-box awx-c-modal at-c-alertModal at-c-alertModal--danger"
|
||||
role="dialog"
|
||||
style={
|
||||
Object {
|
||||
"width": null,
|
||||
}
|
||||
}
|
||||
>
|
||||
<ModalBoxCloseButton
|
||||
className=""
|
||||
onClose={[Function]}
|
||||
>
|
||||
<Button
|
||||
aria-label="Close"
|
||||
className=""
|
||||
component="button"
|
||||
isActive={false}
|
||||
isBlock={false}
|
||||
isDisabled={false}
|
||||
isFocus={false}
|
||||
isHover={false}
|
||||
isInline={false}
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
variant="plain"
|
||||
>
|
||||
<button
|
||||
aria-disabled={null}
|
||||
aria-label="Close"
|
||||
className="pf-c-button pf-m-plain"
|
||||
disabled={false}
|
||||
onClick={[Function]}
|
||||
tabIndex={null}
|
||||
type="button"
|
||||
>
|
||||
<TimesIcon
|
||||
color="currentColor"
|
||||
size="sm"
|
||||
title={null}
|
||||
>
|
||||
<svg
|
||||
aria-hidden={true}
|
||||
aria-labelledby={null}
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
role="img"
|
||||
style={
|
||||
Object {
|
||||
"verticalAlign": "-0.125em",
|
||||
}
|
||||
}
|
||||
viewBox="0 0 352 512"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z"
|
||||
transform=""
|
||||
/>
|
||||
</svg>
|
||||
</TimesIcon>
|
||||
</button>
|
||||
</Button>
|
||||
</ModalBoxCloseButton>
|
||||
<ModalBoxHeader
|
||||
className=""
|
||||
hideTitle={false}
|
||||
>
|
||||
<Title
|
||||
className=""
|
||||
headingLevel="h3"
|
||||
size="2xl"
|
||||
>
|
||||
<h3
|
||||
className="pf-c-title pf-m-2xl"
|
||||
>
|
||||
|
||||
Remove {0} Access
|
||||
|
||||
</h3>
|
||||
</Title>
|
||||
</ModalBoxHeader>
|
||||
<ModalBoxBody
|
||||
className=""
|
||||
id="pf-modal-0"
|
||||
>
|
||||
<div
|
||||
className="pf-c-modal-box__body"
|
||||
id="pf-modal-0"
|
||||
>
|
||||
Are you sure you want to remove {0} access from {1}? Doing so affects all members of the team.
|
||||
<br />
|
||||
<br />
|
||||
If you {0} want to remove access for this particular user, please remove them from the team.
|
||||
<ExclamationCircleIcon
|
||||
className="at-c-alertModal__icon"
|
||||
color="currentColor"
|
||||
size="sm"
|
||||
title={null}
|
||||
>
|
||||
<svg
|
||||
aria-hidden={true}
|
||||
aria-labelledby={null}
|
||||
className="at-c-alertModal__icon"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
role="img"
|
||||
style={
|
||||
Object {
|
||||
"verticalAlign": "-0.125em",
|
||||
}
|
||||
}
|
||||
viewBox="0 0 512 512"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"
|
||||
transform=""
|
||||
/>
|
||||
</svg>
|
||||
</ExclamationCircleIcon>
|
||||
</div>
|
||||
</ModalBoxBody>
|
||||
<ModalBoxFooter
|
||||
className=""
|
||||
>
|
||||
<div
|
||||
className="pf-c-modal-box__footer"
|
||||
>
|
||||
|
||||
<Button
|
||||
aria-label="Confirm delete"
|
||||
className=""
|
||||
component="button"
|
||||
isActive={false}
|
||||
isBlock={false}
|
||||
isDisabled={false}
|
||||
isFocus={false}
|
||||
isHover={false}
|
||||
isInline={false}
|
||||
key="delete"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
variant="danger"
|
||||
>
|
||||
<button
|
||||
aria-disabled={null}
|
||||
aria-label="Confirm delete"
|
||||
className="pf-c-button pf-m-danger"
|
||||
disabled={false}
|
||||
onClick={[Function]}
|
||||
tabIndex={null}
|
||||
type="button"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</Button>
|
||||
<Button
|
||||
aria-label={null}
|
||||
className=""
|
||||
component="button"
|
||||
isActive={false}
|
||||
isBlock={false}
|
||||
isDisabled={false}
|
||||
isFocus={false}
|
||||
isHover={false}
|
||||
isInline={false}
|
||||
key="cancel"
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
variant="secondary"
|
||||
>
|
||||
<button
|
||||
aria-disabled={null}
|
||||
aria-label={null}
|
||||
className="pf-c-button pf-m-secondary"
|
||||
disabled={false}
|
||||
onClick={[Function]}
|
||||
tabIndex={null}
|
||||
type="button"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</Button>
|
||||
|
||||
</div>
|
||||
</ModalBoxFooter>
|
||||
</div>
|
||||
</ModalBox>
|
||||
</div>
|
||||
</FocusTrap>
|
||||
</div>
|
||||
</Backdrop>
|
||||
</ModalContent>
|
||||
</Portal>
|
||||
</Modal>
|
||||
</_default>
|
||||
</DeleteRoleConfirmationModal>
|
||||
`;
|
||||
@@ -1,872 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<OrganizationAccessItem /> initially renders succesfully 1`] = `
|
||||
<OrganizationAccessItem
|
||||
accessRecord={
|
||||
Object {
|
||||
"first_name": "jane",
|
||||
"id": 2,
|
||||
"last_name": "brown",
|
||||
"summary_fields": Object {
|
||||
"direct_access": Array [
|
||||
Object {
|
||||
"role": Object {
|
||||
"id": 3,
|
||||
"name": "Member",
|
||||
"resource_name": "Org",
|
||||
"resource_type": "organization",
|
||||
"team_id": 5,
|
||||
"team_name": "The Team",
|
||||
"user_capabilities": Object {
|
||||
"unattach": true,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
"indirect_access": Array [],
|
||||
},
|
||||
"url": "/bar",
|
||||
"username": "jane",
|
||||
}
|
||||
}
|
||||
i18n={"/i18n/"}
|
||||
onRoleDelete={[Function]}
|
||||
>
|
||||
<DataListItem
|
||||
aria-labelledby="access-list-item"
|
||||
className=""
|
||||
isExpanded={false}
|
||||
key="2"
|
||||
>
|
||||
<li
|
||||
aria-labelledby="access-list-item"
|
||||
className="pf-c-data-list__item"
|
||||
>
|
||||
<DataListItemRow
|
||||
className=""
|
||||
key=".0"
|
||||
rowid="access-list-item"
|
||||
>
|
||||
<div
|
||||
className="pf-c-data-list__item-row"
|
||||
>
|
||||
<OrganizationAccessItem__DataListItemCells
|
||||
dataListCells={
|
||||
Array [
|
||||
<DataListCell
|
||||
alignRight={false}
|
||||
className=""
|
||||
isFilled={true}
|
||||
isIcon={false}
|
||||
width={1}
|
||||
>
|
||||
<TextContent
|
||||
className=""
|
||||
>
|
||||
<Text
|
||||
className=""
|
||||
component="h6"
|
||||
>
|
||||
<ForwardRef
|
||||
to={
|
||||
Object {
|
||||
"pathname": "/bar",
|
||||
}
|
||||
}
|
||||
>
|
||||
jane
|
||||
</ForwardRef>
|
||||
</Text>
|
||||
</TextContent>
|
||||
<ForwardRef
|
||||
stacked={true}
|
||||
>
|
||||
<Detail
|
||||
fullWidth={false}
|
||||
label="Name"
|
||||
value="jane brown"
|
||||
/>
|
||||
</ForwardRef>
|
||||
</DataListCell>,
|
||||
<DataListCell
|
||||
alignRight={false}
|
||||
className=""
|
||||
isFilled={true}
|
||||
isIcon={false}
|
||||
width={1}
|
||||
>
|
||||
<ForwardRef
|
||||
stacked={true}
|
||||
>
|
||||
<Detail
|
||||
fullWidth={false}
|
||||
label="Team Roles"
|
||||
value={
|
||||
<ForwardRef>
|
||||
<ForwardRef
|
||||
isReadOnly={false}
|
||||
onClick={[Function]}
|
||||
>
|
||||
Member
|
||||
</ForwardRef>
|
||||
</ForwardRef>
|
||||
}
|
||||
/>
|
||||
</ForwardRef>
|
||||
</DataListCell>,
|
||||
]
|
||||
}
|
||||
key=".0"
|
||||
rowid="access-list-item"
|
||||
>
|
||||
<StyledComponent
|
||||
dataListCells={
|
||||
Array [
|
||||
<DataListCell
|
||||
alignRight={false}
|
||||
className=""
|
||||
isFilled={true}
|
||||
isIcon={false}
|
||||
width={1}
|
||||
>
|
||||
<TextContent
|
||||
className=""
|
||||
>
|
||||
<Text
|
||||
className=""
|
||||
component="h6"
|
||||
>
|
||||
<ForwardRef
|
||||
to={
|
||||
Object {
|
||||
"pathname": "/bar",
|
||||
}
|
||||
}
|
||||
>
|
||||
jane
|
||||
</ForwardRef>
|
||||
</Text>
|
||||
</TextContent>
|
||||
<ForwardRef
|
||||
stacked={true}
|
||||
>
|
||||
<Detail
|
||||
fullWidth={false}
|
||||
label="Name"
|
||||
value="jane brown"
|
||||
/>
|
||||
</ForwardRef>
|
||||
</DataListCell>,
|
||||
<DataListCell
|
||||
alignRight={false}
|
||||
className=""
|
||||
isFilled={true}
|
||||
isIcon={false}
|
||||
width={1}
|
||||
>
|
||||
<ForwardRef
|
||||
stacked={true}
|
||||
>
|
||||
<Detail
|
||||
fullWidth={false}
|
||||
label="Team Roles"
|
||||
value={
|
||||
<ForwardRef>
|
||||
<ForwardRef
|
||||
isReadOnly={false}
|
||||
onClick={[Function]}
|
||||
>
|
||||
Member
|
||||
</ForwardRef>
|
||||
</ForwardRef>
|
||||
}
|
||||
/>
|
||||
</ForwardRef>
|
||||
</DataListCell>,
|
||||
]
|
||||
}
|
||||
forwardedComponent={
|
||||
Object {
|
||||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "OrganizationAccessItem__DataListItemCells-sc-1yema4k-0",
|
||||
"isStatic": true,
|
||||
"lastClassName": "OJmEc",
|
||||
"rules": Array [
|
||||
"align-items:start;",
|
||||
],
|
||||
},
|
||||
"displayName": "OrganizationAccessItem__DataListItemCells",
|
||||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"styledComponentId": "OrganizationAccessItem__DataListItemCells-sc-1yema4k-0",
|
||||
"target": [Function],
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
"withComponent": [Function],
|
||||
}
|
||||
}
|
||||
forwardedRef={null}
|
||||
rowid="access-list-item"
|
||||
>
|
||||
<DataListItemCells
|
||||
className="OrganizationAccessItem__DataListItemCells-sc-1yema4k-0 OJmEc"
|
||||
dataListCells={
|
||||
Array [
|
||||
<DataListCell
|
||||
alignRight={false}
|
||||
className=""
|
||||
isFilled={true}
|
||||
isIcon={false}
|
||||
width={1}
|
||||
>
|
||||
<TextContent
|
||||
className=""
|
||||
>
|
||||
<Text
|
||||
className=""
|
||||
component="h6"
|
||||
>
|
||||
<ForwardRef
|
||||
to={
|
||||
Object {
|
||||
"pathname": "/bar",
|
||||
}
|
||||
}
|
||||
>
|
||||
jane
|
||||
</ForwardRef>
|
||||
</Text>
|
||||
</TextContent>
|
||||
<ForwardRef
|
||||
stacked={true}
|
||||
>
|
||||
<Detail
|
||||
fullWidth={false}
|
||||
label="Name"
|
||||
value="jane brown"
|
||||
/>
|
||||
</ForwardRef>
|
||||
</DataListCell>,
|
||||
<DataListCell
|
||||
alignRight={false}
|
||||
className=""
|
||||
isFilled={true}
|
||||
isIcon={false}
|
||||
width={1}
|
||||
>
|
||||
<ForwardRef
|
||||
stacked={true}
|
||||
>
|
||||
<Detail
|
||||
fullWidth={false}
|
||||
label="Team Roles"
|
||||
value={
|
||||
<ForwardRef>
|
||||
<ForwardRef
|
||||
isReadOnly={false}
|
||||
onClick={[Function]}
|
||||
>
|
||||
Member
|
||||
</ForwardRef>
|
||||
</ForwardRef>
|
||||
}
|
||||
/>
|
||||
</ForwardRef>
|
||||
</DataListCell>,
|
||||
]
|
||||
}
|
||||
rowid="access-list-item"
|
||||
>
|
||||
<div
|
||||
className="pf-c-data-list__item-content OrganizationAccessItem__DataListItemCells-sc-1yema4k-0 OJmEc"
|
||||
>
|
||||
<DataListCell
|
||||
alignRight={false}
|
||||
className=""
|
||||
isFilled={true}
|
||||
isIcon={false}
|
||||
key="name"
|
||||
width={1}
|
||||
>
|
||||
<div
|
||||
className="pf-c-data-list__cell"
|
||||
>
|
||||
<TextContent
|
||||
className=""
|
||||
>
|
||||
<div
|
||||
className="pf-c-content"
|
||||
>
|
||||
<Text
|
||||
className=""
|
||||
component="h6"
|
||||
>
|
||||
<h6
|
||||
className=""
|
||||
data-pf-content={true}
|
||||
>
|
||||
<Styled(Link)
|
||||
to={
|
||||
Object {
|
||||
"pathname": "/bar",
|
||||
}
|
||||
}
|
||||
>
|
||||
<StyledComponent
|
||||
forwardedComponent={
|
||||
Object {
|
||||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "sc-bdVaJa",
|
||||
"isStatic": true,
|
||||
"lastClassName": "fqQVUT",
|
||||
"rules": Array [
|
||||
"font-weight: bold",
|
||||
],
|
||||
},
|
||||
"displayName": "Styled(Link)",
|
||||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"styledComponentId": "sc-bdVaJa",
|
||||
"target": [Function],
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
"withComponent": [Function],
|
||||
}
|
||||
}
|
||||
forwardedRef={null}
|
||||
to={
|
||||
Object {
|
||||
"pathname": "/bar",
|
||||
}
|
||||
}
|
||||
>
|
||||
<Link
|
||||
className="sc-bdVaJa fqQVUT"
|
||||
replace={false}
|
||||
to={
|
||||
Object {
|
||||
"pathname": "/bar",
|
||||
}
|
||||
}
|
||||
>
|
||||
<a
|
||||
className="sc-bdVaJa fqQVUT"
|
||||
onClick={[Function]}
|
||||
>
|
||||
jane
|
||||
</a>
|
||||
</Link>
|
||||
</StyledComponent>
|
||||
</Styled(Link)>
|
||||
</h6>
|
||||
</Text>
|
||||
</div>
|
||||
</TextContent>
|
||||
<DetailList
|
||||
stacked={true}
|
||||
>
|
||||
<StyledComponent
|
||||
forwardedComponent={
|
||||
Object {
|
||||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "DetailList-sc-12g7m4-0",
|
||||
"isStatic": false,
|
||||
"lastClassName": "hndBXy",
|
||||
"rules": Array [
|
||||
"display:grid;grid-gap:20px;",
|
||||
[Function],
|
||||
],
|
||||
},
|
||||
"displayName": "DetailList",
|
||||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"styledComponentId": "DetailList-sc-12g7m4-0",
|
||||
"target": [Function],
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
"withComponent": [Function],
|
||||
}
|
||||
}
|
||||
forwardedRef={null}
|
||||
stacked={true}
|
||||
>
|
||||
<DetailList
|
||||
className="DetailList-sc-12g7m4-0 hndBXy"
|
||||
stacked={true}
|
||||
>
|
||||
<TextList
|
||||
className="DetailList-sc-12g7m4-0 hndBXy"
|
||||
component="dl"
|
||||
>
|
||||
<dl
|
||||
className="DetailList-sc-12g7m4-0 hndBXy"
|
||||
data-pf-content={true}
|
||||
>
|
||||
<Detail
|
||||
fullWidth={false}
|
||||
label="Name"
|
||||
value="jane brown"
|
||||
>
|
||||
<Detail__DetailName
|
||||
component="dt"
|
||||
fullWidth={false}
|
||||
>
|
||||
<StyledComponent
|
||||
component="dt"
|
||||
forwardedComponent={
|
||||
Object {
|
||||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "Detail__DetailName-sc-16ypsyv-0",
|
||||
"isStatic": false,
|
||||
"lastClassName": "gRioSK",
|
||||
"rules": Array [
|
||||
"font-weight:var(--pf-global--FontWeight--bold);text-align:right;",
|
||||
[Function],
|
||||
],
|
||||
},
|
||||
"displayName": "Detail__DetailName",
|
||||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"styledComponentId": "Detail__DetailName-sc-16ypsyv-0",
|
||||
"target": [Function],
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
"withComponent": [Function],
|
||||
}
|
||||
}
|
||||
forwardedRef={null}
|
||||
fullWidth={false}
|
||||
>
|
||||
<Component
|
||||
className="Detail__DetailName-sc-16ypsyv-0 gRioSK"
|
||||
component="dt"
|
||||
fullWidth={false}
|
||||
>
|
||||
<TextListItem
|
||||
className="Detail__DetailName-sc-16ypsyv-0 gRioSK"
|
||||
component="dt"
|
||||
>
|
||||
<dt
|
||||
className="Detail__DetailName-sc-16ypsyv-0 gRioSK"
|
||||
data-pf-content={true}
|
||||
>
|
||||
Name
|
||||
</dt>
|
||||
</TextListItem>
|
||||
</Component>
|
||||
</StyledComponent>
|
||||
</Detail__DetailName>
|
||||
<Detail__DetailValue
|
||||
component="dd"
|
||||
fullWidth={false}
|
||||
>
|
||||
<StyledComponent
|
||||
component="dd"
|
||||
forwardedComponent={
|
||||
Object {
|
||||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "Detail__DetailValue-sc-16ypsyv-1",
|
||||
"isStatic": false,
|
||||
"lastClassName": "yHlYM",
|
||||
"rules": Array [
|
||||
"word-break:break-all;",
|
||||
[Function],
|
||||
],
|
||||
},
|
||||
"displayName": "Detail__DetailValue",
|
||||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"styledComponentId": "Detail__DetailValue-sc-16ypsyv-1",
|
||||
"target": [Function],
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
"withComponent": [Function],
|
||||
}
|
||||
}
|
||||
forwardedRef={null}
|
||||
fullWidth={false}
|
||||
>
|
||||
<Component
|
||||
className="Detail__DetailValue-sc-16ypsyv-1 yHlYM"
|
||||
component="dd"
|
||||
fullWidth={false}
|
||||
>
|
||||
<TextListItem
|
||||
className="Detail__DetailValue-sc-16ypsyv-1 yHlYM"
|
||||
component="dd"
|
||||
>
|
||||
<dd
|
||||
className="Detail__DetailValue-sc-16ypsyv-1 yHlYM"
|
||||
data-pf-content={true}
|
||||
>
|
||||
jane brown
|
||||
</dd>
|
||||
</TextListItem>
|
||||
</Component>
|
||||
</StyledComponent>
|
||||
</Detail__DetailValue>
|
||||
</Detail>
|
||||
</dl>
|
||||
</TextList>
|
||||
</DetailList>
|
||||
</StyledComponent>
|
||||
</DetailList>
|
||||
</div>
|
||||
</DataListCell>
|
||||
<DataListCell
|
||||
alignRight={false}
|
||||
className=""
|
||||
isFilled={true}
|
||||
isIcon={false}
|
||||
key="roles"
|
||||
width={1}
|
||||
>
|
||||
<div
|
||||
className="pf-c-data-list__cell"
|
||||
>
|
||||
<DetailList
|
||||
stacked={true}
|
||||
>
|
||||
<StyledComponent
|
||||
forwardedComponent={
|
||||
Object {
|
||||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "DetailList-sc-12g7m4-0",
|
||||
"isStatic": false,
|
||||
"lastClassName": "hndBXy",
|
||||
"rules": Array [
|
||||
"display:grid;grid-gap:20px;",
|
||||
[Function],
|
||||
],
|
||||
},
|
||||
"displayName": "DetailList",
|
||||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"styledComponentId": "DetailList-sc-12g7m4-0",
|
||||
"target": [Function],
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
"withComponent": [Function],
|
||||
}
|
||||
}
|
||||
forwardedRef={null}
|
||||
stacked={true}
|
||||
>
|
||||
<DetailList
|
||||
className="DetailList-sc-12g7m4-0 hndBXy"
|
||||
stacked={true}
|
||||
>
|
||||
<TextList
|
||||
className="DetailList-sc-12g7m4-0 hndBXy"
|
||||
component="dl"
|
||||
>
|
||||
<dl
|
||||
className="DetailList-sc-12g7m4-0 hndBXy"
|
||||
data-pf-content={true}
|
||||
>
|
||||
<Detail
|
||||
fullWidth={false}
|
||||
label="Team Roles"
|
||||
value={
|
||||
<ForwardRef>
|
||||
<ForwardRef
|
||||
isReadOnly={false}
|
||||
onClick={[Function]}
|
||||
>
|
||||
Member
|
||||
</ForwardRef>
|
||||
</ForwardRef>
|
||||
}
|
||||
>
|
||||
<Detail__DetailName
|
||||
component="dt"
|
||||
fullWidth={false}
|
||||
>
|
||||
<StyledComponent
|
||||
component="dt"
|
||||
forwardedComponent={
|
||||
Object {
|
||||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "Detail__DetailName-sc-16ypsyv-0",
|
||||
"isStatic": false,
|
||||
"lastClassName": "gRioSK",
|
||||
"rules": Array [
|
||||
"font-weight:var(--pf-global--FontWeight--bold);text-align:right;",
|
||||
[Function],
|
||||
],
|
||||
},
|
||||
"displayName": "Detail__DetailName",
|
||||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"styledComponentId": "Detail__DetailName-sc-16ypsyv-0",
|
||||
"target": [Function],
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
"withComponent": [Function],
|
||||
}
|
||||
}
|
||||
forwardedRef={null}
|
||||
fullWidth={false}
|
||||
>
|
||||
<Component
|
||||
className="Detail__DetailName-sc-16ypsyv-0 gRioSK"
|
||||
component="dt"
|
||||
fullWidth={false}
|
||||
>
|
||||
<TextListItem
|
||||
className="Detail__DetailName-sc-16ypsyv-0 gRioSK"
|
||||
component="dt"
|
||||
>
|
||||
<dt
|
||||
className="Detail__DetailName-sc-16ypsyv-0 gRioSK"
|
||||
data-pf-content={true}
|
||||
>
|
||||
Team Roles
|
||||
</dt>
|
||||
</TextListItem>
|
||||
</Component>
|
||||
</StyledComponent>
|
||||
</Detail__DetailName>
|
||||
<Detail__DetailValue
|
||||
component="dd"
|
||||
fullWidth={false}
|
||||
>
|
||||
<StyledComponent
|
||||
component="dd"
|
||||
forwardedComponent={
|
||||
Object {
|
||||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "Detail__DetailValue-sc-16ypsyv-1",
|
||||
"isStatic": false,
|
||||
"lastClassName": "yHlYM",
|
||||
"rules": Array [
|
||||
"word-break:break-all;",
|
||||
[Function],
|
||||
],
|
||||
},
|
||||
"displayName": "Detail__DetailValue",
|
||||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"styledComponentId": "Detail__DetailValue-sc-16ypsyv-1",
|
||||
"target": [Function],
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
"withComponent": [Function],
|
||||
}
|
||||
}
|
||||
forwardedRef={null}
|
||||
fullWidth={false}
|
||||
>
|
||||
<Component
|
||||
className="Detail__DetailValue-sc-16ypsyv-1 yHlYM"
|
||||
component="dd"
|
||||
fullWidth={false}
|
||||
>
|
||||
<TextListItem
|
||||
className="Detail__DetailValue-sc-16ypsyv-1 yHlYM"
|
||||
component="dd"
|
||||
>
|
||||
<dd
|
||||
className="Detail__DetailValue-sc-16ypsyv-1 yHlYM"
|
||||
data-pf-content={true}
|
||||
>
|
||||
<ChipGroup>
|
||||
<StyledComponent
|
||||
forwardedComponent={
|
||||
Object {
|
||||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "ChipGroup-sc-10zu8t0-0",
|
||||
"isStatic": true,
|
||||
"lastClassName": "vIGxT",
|
||||
"rules": Array [
|
||||
"--pf-c-chip-group--c-chip--MarginRight:10px;--pf-c-chip-group--c-chip--MarginBottom:10px;",
|
||||
],
|
||||
},
|
||||
"displayName": "ChipGroup",
|
||||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"styledComponentId": "ChipGroup-sc-10zu8t0-0",
|
||||
"target": [Function],
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
"withComponent": [Function],
|
||||
}
|
||||
}
|
||||
forwardedRef={null}
|
||||
>
|
||||
<ChipGroup
|
||||
className="ChipGroup-sc-10zu8t0-0 vIGxT"
|
||||
showOverflowAfter={null}
|
||||
>
|
||||
<ul
|
||||
className="pf-c-chip-group ChipGroup-sc-10zu8t0-0 vIGxT"
|
||||
>
|
||||
<Chip
|
||||
component="li"
|
||||
isReadOnly={false}
|
||||
key=".$3"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<StyledComponent
|
||||
component="li"
|
||||
forwardedComponent={
|
||||
Object {
|
||||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "Chip-sc-1rzr8oo-0",
|
||||
"isStatic": false,
|
||||
"lastClassName": "dgUGLg",
|
||||
"rules": Array [
|
||||
"--pf-c-chip--m-read-only--PaddingTop:3px;--pf-c-chip--m-read-only--PaddingRight:8px;--pf-c-chip--m-read-only--PaddingBottom:3px;--pf-c-chip--m-read-only--PaddingLeft:8px;& > .pf-c-button{padding:3px 8px;}",
|
||||
[Function],
|
||||
],
|
||||
},
|
||||
"displayName": "Chip",
|
||||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"styledComponentId": "Chip-sc-1rzr8oo-0",
|
||||
"target": [Function],
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
"withComponent": [Function],
|
||||
}
|
||||
}
|
||||
forwardedRef={null}
|
||||
isReadOnly={false}
|
||||
onClick={[Function]}
|
||||
>
|
||||
<Chip
|
||||
className="Chip-sc-1rzr8oo-0 dgUGLg"
|
||||
closeBtnAriaLabel="close"
|
||||
component="li"
|
||||
isOverflowChip={false}
|
||||
isReadOnly={false}
|
||||
onClick={[Function]}
|
||||
tooltipPosition="top"
|
||||
>
|
||||
<GenerateId
|
||||
prefix="pf-random-id-"
|
||||
>
|
||||
<li
|
||||
className="pf-c-chip Chip-sc-1rzr8oo-0 dgUGLg"
|
||||
>
|
||||
<span
|
||||
className="pf-c-chip__text"
|
||||
id="pf-random-id-0"
|
||||
>
|
||||
Member
|
||||
</span>
|
||||
<ChipButton
|
||||
aria-labelledby="remove_pf-random-id-0 pf-random-id-0"
|
||||
ariaLabel="close"
|
||||
className=""
|
||||
id="remove_pf-random-id-0"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<Button
|
||||
aria-label="close"
|
||||
aria-labelledby="remove_pf-random-id-0 pf-random-id-0"
|
||||
className=""
|
||||
component="button"
|
||||
id="remove_pf-random-id-0"
|
||||
isActive={false}
|
||||
isBlock={false}
|
||||
isDisabled={false}
|
||||
isFocus={false}
|
||||
isHover={false}
|
||||
isInline={false}
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
variant="plain"
|
||||
>
|
||||
<button
|
||||
aria-disabled={null}
|
||||
aria-label="close"
|
||||
aria-labelledby="remove_pf-random-id-0 pf-random-id-0"
|
||||
className="pf-c-button pf-m-plain"
|
||||
disabled={false}
|
||||
id="remove_pf-random-id-0"
|
||||
onClick={[Function]}
|
||||
tabIndex={null}
|
||||
type="button"
|
||||
>
|
||||
<TimesCircleIcon
|
||||
aria-hidden="true"
|
||||
color="currentColor"
|
||||
size="sm"
|
||||
title={null}
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
aria-labelledby={null}
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
role="img"
|
||||
style={
|
||||
Object {
|
||||
"verticalAlign": "-0.125em",
|
||||
}
|
||||
}
|
||||
viewBox="0 0 512 512"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm121.6 313.1c4.7 4.7 4.7 12.3 0 17L338 377.6c-4.7 4.7-12.3 4.7-17 0L256 312l-65.1 65.6c-4.7 4.7-12.3 4.7-17 0L134.4 338c-4.7-4.7-4.7-12.3 0-17l65.6-65-65.6-65.1c-4.7-4.7-4.7-12.3 0-17l39.6-39.6c4.7-4.7 12.3-4.7 17 0l65 65.7 65.1-65.6c4.7-4.7 12.3-4.7 17 0l39.6 39.6c4.7 4.7 4.7 12.3 0 17L312 256l65.6 65.1z"
|
||||
transform=""
|
||||
/>
|
||||
</svg>
|
||||
</TimesCircleIcon>
|
||||
</button>
|
||||
</Button>
|
||||
</ChipButton>
|
||||
</li>
|
||||
</GenerateId>
|
||||
</Chip>
|
||||
</StyledComponent>
|
||||
</Chip>
|
||||
</ul>
|
||||
</ChipGroup>
|
||||
</StyledComponent>
|
||||
</ChipGroup>
|
||||
</dd>
|
||||
</TextListItem>
|
||||
</Component>
|
||||
</StyledComponent>
|
||||
</Detail__DetailValue>
|
||||
</Detail>
|
||||
</dl>
|
||||
</TextList>
|
||||
</DetailList>
|
||||
</StyledComponent>
|
||||
</DetailList>
|
||||
</div>
|
||||
</DataListCell>
|
||||
</div>
|
||||
</DataListItemCells>
|
||||
</StyledComponent>
|
||||
</OrganizationAccessItem__DataListItemCells>
|
||||
</div>
|
||||
</DataListItemRow>
|
||||
</li>
|
||||
</DataListItem>
|
||||
</OrganizationAccessItem>
|
||||
`;
|
||||
@@ -1,232 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts, waitForElement } from '../../../../enzymeHelpers';
|
||||
import Organization from '../../../../../src/pages/Organizations/screens/Organization/Organization';
|
||||
import { OrganizationsAPI } from '../../../../../src/api';
|
||||
|
||||
jest.mock('../../../../../src/api');
|
||||
|
||||
const mockMe = {
|
||||
is_super_user: true,
|
||||
is_system_auditor: false
|
||||
};
|
||||
|
||||
const mockNoResults = {
|
||||
count: 0,
|
||||
next: null,
|
||||
previous: null,
|
||||
data: { results: [] }
|
||||
};
|
||||
|
||||
const mockDetails = {
|
||||
data: {
|
||||
id: 1,
|
||||
type: 'organization',
|
||||
url: '/api/v2/organizations/1/',
|
||||
related: {
|
||||
notification_templates: '/api/v2/organizations/1/notification_templates/',
|
||||
notification_templates_any: '/api/v2/organizations/1/notification_templates_any/',
|
||||
notification_templates_success: '/api/v2/organizations/1/notification_templates_success/',
|
||||
notification_templates_error: '/api/v2/organizations/1/notification_templates_error/',
|
||||
object_roles: '/api/v2/organizations/1/object_roles/',
|
||||
access_list: '/api/v2/organizations/1/access_list/',
|
||||
instance_groups: '/api/v2/organizations/1/instance_groups/'
|
||||
},
|
||||
summary_fields: {
|
||||
created_by: {
|
||||
id: 1,
|
||||
username: 'admin',
|
||||
first_name: 'Super',
|
||||
last_name: 'User'
|
||||
},
|
||||
modified_by: {
|
||||
id: 1,
|
||||
username: 'admin',
|
||||
first_name: 'Super',
|
||||
last_name: 'User'
|
||||
},
|
||||
object_roles: {
|
||||
admin_role: {
|
||||
description: 'Can manage all aspects of the organization',
|
||||
name: 'Admin',
|
||||
id: 42
|
||||
},
|
||||
notification_admin_role: {
|
||||
description: 'Can manage all notifications of the organization',
|
||||
name: 'Notification Admin',
|
||||
id: 1683
|
||||
},
|
||||
auditor_role: {
|
||||
description: 'Can view all aspects of the organization',
|
||||
name: 'Auditor',
|
||||
id: 41
|
||||
},
|
||||
},
|
||||
user_capabilities: {
|
||||
edit: true,
|
||||
delete: true
|
||||
},
|
||||
related_field_counts: {
|
||||
users: 51,
|
||||
admins: 19,
|
||||
inventories: 23,
|
||||
teams: 12,
|
||||
projects: 33,
|
||||
job_templates: 30
|
||||
}
|
||||
},
|
||||
created: '2015-07-07T17:21:26.429745Z',
|
||||
modified: '2017-09-05T19:23:15.418808Z',
|
||||
name: 'Sarif Industries',
|
||||
description: '',
|
||||
max_hosts: 0,
|
||||
custom_virtualenv: null
|
||||
}
|
||||
};
|
||||
|
||||
const adminOrganization = {
|
||||
id: 1,
|
||||
type: 'organization',
|
||||
url: '/api/v2/organizations/1/',
|
||||
related: {
|
||||
instance_groups: '/api/v2/organizations/1/instance_groups/',
|
||||
object_roles: '/api/v2/organizations/1/object_roles/',
|
||||
access_list: '/api/v2/organizations/1/access_list/',
|
||||
},
|
||||
summary_fields: {
|
||||
created_by: {
|
||||
id: 1,
|
||||
username: 'admin',
|
||||
first_name: 'Super',
|
||||
last_name: 'User'
|
||||
},
|
||||
modified_by: {
|
||||
id: 1,
|
||||
username: 'admin',
|
||||
first_name: 'Super',
|
||||
last_name: 'User'
|
||||
},
|
||||
},
|
||||
created: '2015-07-07T17:21:26.429745Z',
|
||||
modified: '2017-09-05T19:23:15.418808Z',
|
||||
name: 'Sarif Industries',
|
||||
description: '',
|
||||
max_hosts: 0,
|
||||
custom_virtualenv: null
|
||||
};
|
||||
|
||||
const auditorOrganization = {
|
||||
id: 2,
|
||||
type: 'organization',
|
||||
url: '/api/v2/organizations/2/',
|
||||
related: {
|
||||
instance_groups: '/api/v2/organizations/2/instance_groups/',
|
||||
object_roles: '/api/v2/organizations/2/object_roles/',
|
||||
access_list: '/api/v2/organizations/2/access_list/',
|
||||
},
|
||||
summary_fields: {
|
||||
created_by: {
|
||||
id: 2,
|
||||
username: 'admin',
|
||||
first_name: 'Super',
|
||||
last_name: 'User'
|
||||
},
|
||||
modified_by: {
|
||||
id: 2,
|
||||
username: 'admin',
|
||||
first_name: 'Super',
|
||||
last_name: 'User'
|
||||
},
|
||||
},
|
||||
created: '2015-07-07T17:21:26.429745Z',
|
||||
modified: '2017-09-05T19:23:15.418808Z',
|
||||
name: 'Autobots',
|
||||
description: '',
|
||||
max_hosts: 0,
|
||||
custom_virtualenv: null
|
||||
};
|
||||
|
||||
const notificationAdminOrganization = {
|
||||
id: 3,
|
||||
type: 'organization',
|
||||
url: '/api/v2/organizations/3/',
|
||||
related: {
|
||||
instance_groups: '/api/v2/organizations/3/instance_groups/',
|
||||
object_roles: '/api/v2/organizations/3/object_roles/',
|
||||
access_list: '/api/v2/organizations/3/access_list/',
|
||||
},
|
||||
summary_fields: {
|
||||
created_by: {
|
||||
id: 1,
|
||||
username: 'admin',
|
||||
first_name: 'Super',
|
||||
last_name: 'User'
|
||||
},
|
||||
modified_by: {
|
||||
id: 1,
|
||||
username: 'admin',
|
||||
first_name: 'Super',
|
||||
last_name: 'User'
|
||||
},
|
||||
},
|
||||
created: '2015-07-07T17:21:26.429745Z',
|
||||
modified: '2017-09-05T19:23:15.418808Z',
|
||||
name: 'Decepticons',
|
||||
description: '',
|
||||
max_hosts: 0,
|
||||
custom_virtualenv: null
|
||||
};
|
||||
|
||||
const allOrganizations = [
|
||||
adminOrganization,
|
||||
auditorOrganization,
|
||||
notificationAdminOrganization
|
||||
];
|
||||
|
||||
async function getOrganizations (params) {
|
||||
let results = allOrganizations;
|
||||
if (params && params.role_level) {
|
||||
if (params.role_level === 'admin_role') {
|
||||
results = [adminOrganization];
|
||||
}
|
||||
if (params.role_level === 'auditor_role') {
|
||||
results = [auditorOrganization];
|
||||
}
|
||||
if (params.role_level === 'notification_admin_role') {
|
||||
results = [notificationAdminOrganization];
|
||||
}
|
||||
}
|
||||
return {
|
||||
count: results.length,
|
||||
next: null,
|
||||
previous: null,
|
||||
data: { results }
|
||||
};
|
||||
}
|
||||
|
||||
describe.only('<Organization />', () => {
|
||||
test('initially renders succesfully', () => {
|
||||
OrganizationsAPI.readDetail.mockResolvedValue(mockDetails);
|
||||
OrganizationsAPI.read.mockImplementation(getOrganizations);
|
||||
mountWithContexts(<Organization setBreadcrumb={() => {}} me={mockMe} />);
|
||||
});
|
||||
|
||||
test('notifications tab shown for admins', async (done) => {
|
||||
OrganizationsAPI.readDetail.mockResolvedValue(mockDetails);
|
||||
OrganizationsAPI.read.mockImplementation(getOrganizations);
|
||||
|
||||
const wrapper = mountWithContexts(<Organization setBreadcrumb={() => {}} me={mockMe} />);
|
||||
const tabs = await waitForElement(wrapper, '.pf-c-tabs__item', el => el.length === 4);
|
||||
expect(tabs.last().text()).toEqual('Notifications');
|
||||
done();
|
||||
});
|
||||
|
||||
test('notifications tab hidden with reduced permissions', async (done) => {
|
||||
OrganizationsAPI.readDetail.mockResolvedValue(mockDetails);
|
||||
OrganizationsAPI.read.mockResolvedValue(mockNoResults);
|
||||
|
||||
const wrapper = mountWithContexts(<Organization setBreadcrumb={() => {}} me={mockMe} />);
|
||||
const tabs = await waitForElement(wrapper, '.pf-c-tabs__item', el => el.length === 3);
|
||||
tabs.forEach(tab => expect(tab.text()).not.toEqual('Notifications'));
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -1,162 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts, waitForElement } from '../../../../enzymeHelpers';
|
||||
import OrganizationAccess from '../../../../../src/pages/Organizations/screens/Organization/OrganizationAccess';
|
||||
import { sleep } from '../../../../testUtils';
|
||||
import { OrganizationsAPI, TeamsAPI, UsersAPI } from '../../../../../src/api';
|
||||
|
||||
jest.mock('../../../../../src/api');
|
||||
|
||||
describe('<OrganizationAccess />', () => {
|
||||
const organization = {
|
||||
id: 1,
|
||||
name: 'Default',
|
||||
summary_fields: {
|
||||
object_roles: {},
|
||||
user_capabilities: {
|
||||
edit: true
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const data = {
|
||||
count: 2,
|
||||
results: [{
|
||||
id: 1,
|
||||
username: 'joe',
|
||||
url: '/foo',
|
||||
first_name: 'joe',
|
||||
last_name: 'smith',
|
||||
summary_fields: {
|
||||
direct_access: [{
|
||||
role: {
|
||||
id: 1,
|
||||
name: 'Member',
|
||||
resource_name: 'Org',
|
||||
resource_type: 'organization',
|
||||
user_capabilities: { unattach: true },
|
||||
}
|
||||
}],
|
||||
indirect_access: [],
|
||||
}
|
||||
}, {
|
||||
id: 2,
|
||||
username: 'jane',
|
||||
url: '/bar',
|
||||
first_name: 'jane',
|
||||
last_name: 'brown',
|
||||
summary_fields: {
|
||||
direct_access: [{
|
||||
role: {
|
||||
id: 3,
|
||||
name: 'Member',
|
||||
resource_name: 'Org',
|
||||
resource_type: 'organization',
|
||||
team_id: 5,
|
||||
team_name: 'The Team',
|
||||
user_capabilities: { unattach: true },
|
||||
}
|
||||
}],
|
||||
indirect_access: [],
|
||||
}
|
||||
}]
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
OrganizationsAPI.readAccessList.mockResolvedValue({ data });
|
||||
TeamsAPI.disassociateRole.mockResolvedValue({});
|
||||
UsersAPI.disassociateRole.mockResolvedValue({});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('initially renders succesfully', () => {
|
||||
const wrapper = mountWithContexts(<OrganizationAccess organization={organization} />);
|
||||
expect(wrapper.find('OrganizationAccess')).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should fetch and display access records on mount', async (done) => {
|
||||
const wrapper = mountWithContexts(<OrganizationAccess organization={organization} />);
|
||||
await waitForElement(wrapper, 'OrganizationAccessItem', el => el.length === 2);
|
||||
expect(wrapper.find('PaginatedDataList').prop('items')).toEqual(data.results);
|
||||
expect(wrapper.find('OrganizationAccess').state('contentLoading')).toBe(false);
|
||||
expect(wrapper.find('OrganizationAccess').state('contentError')).toBe(false);
|
||||
done();
|
||||
});
|
||||
|
||||
test('should open confirmation dialog when deleting role', async (done) => {
|
||||
const wrapper = mountWithContexts(<OrganizationAccess organization={organization} />);
|
||||
await sleep(0);
|
||||
wrapper.update();
|
||||
|
||||
const button = wrapper.find('ChipButton').at(0);
|
||||
button.prop('onClick')();
|
||||
wrapper.update();
|
||||
|
||||
const component = wrapper.find('OrganizationAccess');
|
||||
expect(component.state('deletionRole'))
|
||||
.toEqual(data.results[0].summary_fields.direct_access[0].role);
|
||||
expect(component.state('deletionRecord'))
|
||||
.toEqual(data.results[0]);
|
||||
expect(component.find('DeleteRoleConfirmationModal')).toHaveLength(1);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should close dialog when cancel button clicked', async (done) => {
|
||||
const wrapper = mountWithContexts(<OrganizationAccess organization={organization} />);
|
||||
await sleep(0);
|
||||
wrapper.update();
|
||||
const button = wrapper.find('ChipButton').at(0);
|
||||
button.prop('onClick')();
|
||||
wrapper.update();
|
||||
|
||||
wrapper.find('DeleteRoleConfirmationModal').prop('onCancel')();
|
||||
const component = wrapper.find('OrganizationAccess');
|
||||
expect(component.state('deletionRole')).toBeNull();
|
||||
expect(component.state('deletionRecord')).toBeNull();
|
||||
expect(TeamsAPI.disassociateRole).not.toHaveBeenCalled();
|
||||
expect(UsersAPI.disassociateRole).not.toHaveBeenCalled();
|
||||
done();
|
||||
});
|
||||
|
||||
it('should delete user role', async (done) => {
|
||||
const wrapper = mountWithContexts(<OrganizationAccess organization={organization} />);
|
||||
const button = await waitForElement(wrapper, 'ChipButton', el => el.length === 2);
|
||||
button.at(0).prop('onClick')();
|
||||
|
||||
const confirmation = await waitForElement(wrapper, 'DeleteRoleConfirmationModal');
|
||||
confirmation.prop('onConfirm')();
|
||||
await waitForElement(wrapper, 'DeleteRoleConfirmationModal', el => el.length === 0);
|
||||
|
||||
await sleep(0);
|
||||
wrapper.update();
|
||||
const component = wrapper.find('OrganizationAccess');
|
||||
expect(component.state('deletionRole')).toBeNull();
|
||||
expect(component.state('deletionRecord')).toBeNull();
|
||||
expect(TeamsAPI.disassociateRole).not.toHaveBeenCalled();
|
||||
expect(UsersAPI.disassociateRole).toHaveBeenCalledWith(1, 1);
|
||||
expect(OrganizationsAPI.readAccessList).toHaveBeenCalledTimes(2);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should delete team role', async (done) => {
|
||||
const wrapper = mountWithContexts(<OrganizationAccess organization={organization} />);
|
||||
const button = await waitForElement(wrapper, 'ChipButton', el => el.length === 2);
|
||||
button.at(1).prop('onClick')();
|
||||
|
||||
const confirmation = await waitForElement(wrapper, 'DeleteRoleConfirmationModal');
|
||||
confirmation.prop('onConfirm')();
|
||||
await waitForElement(wrapper, 'DeleteRoleConfirmationModal', el => el.length === 0);
|
||||
|
||||
await sleep(0);
|
||||
wrapper.update();
|
||||
const component = wrapper.find('OrganizationAccess');
|
||||
expect(component.state('deletionRole')).toBeNull();
|
||||
expect(component.state('deletionRecord')).toBeNull();
|
||||
expect(TeamsAPI.disassociateRole).toHaveBeenCalledWith(5, 3);
|
||||
expect(UsersAPI.disassociateRole).not.toHaveBeenCalled();
|
||||
expect(OrganizationsAPI.readAccessList).toHaveBeenCalledTimes(2);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -1,93 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts, waitForElement } from '../../../../enzymeHelpers';
|
||||
import OrganizationDetail from '../../../../../src/pages/Organizations/screens/Organization/OrganizationDetail';
|
||||
import { OrganizationsAPI } from '../../../../../src/api';
|
||||
|
||||
jest.mock('../../../../../src/api');
|
||||
|
||||
describe('<OrganizationDetail />', () => {
|
||||
const mockOrganization = {
|
||||
name: 'Foo',
|
||||
description: 'Bar',
|
||||
custom_virtualenv: 'Fizz',
|
||||
max_hosts: '0',
|
||||
created: 'Bat',
|
||||
modified: 'Boo',
|
||||
summary_fields: {
|
||||
user_capabilities: {
|
||||
edit: true
|
||||
}
|
||||
}
|
||||
};
|
||||
const mockInstanceGroups = {
|
||||
data: {
|
||||
results: [
|
||||
{ name: 'One', id: 1 },
|
||||
{ name: 'Two', id: 2 }
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
OrganizationsAPI.readInstanceGroups.mockResolvedValue(mockInstanceGroups);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('initially renders succesfully', () => {
|
||||
mountWithContexts(<OrganizationDetail organization={mockOrganization} />);
|
||||
});
|
||||
|
||||
test('should request instance groups from api', () => {
|
||||
mountWithContexts(<OrganizationDetail organization={mockOrganization} />);
|
||||
expect(OrganizationsAPI.readInstanceGroups).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('should handle setting instance groups to state', async (done) => {
|
||||
const wrapper = mountWithContexts(
|
||||
<OrganizationDetail organization={mockOrganization} />
|
||||
);
|
||||
const component = await waitForElement(wrapper, 'OrganizationDetail');
|
||||
expect(component.state().instanceGroups).toEqual(mockInstanceGroups.data.results);
|
||||
done();
|
||||
});
|
||||
|
||||
test('should render Details', async (done) => {
|
||||
const wrapper = mountWithContexts(<OrganizationDetail organization={mockOrganization} />);
|
||||
const testParams = [
|
||||
{ label: 'Name', value: 'Foo' },
|
||||
{ label: 'Description', value: 'Bar' },
|
||||
{ label: 'Ansible Environment', value: 'Fizz' },
|
||||
{ label: 'Created', value: 'Bat' },
|
||||
{ label: 'Last Modified', value: 'Boo' },
|
||||
{ label: 'Max Hosts', value: '0' },
|
||||
];
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const { label, value } of testParams) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const detail = await waitForElement(wrapper, `Detail[label="${label}"]`);
|
||||
expect(detail.find('dt').text()).toBe(label);
|
||||
expect(detail.find('dd').text()).toBe(value);
|
||||
}
|
||||
done();
|
||||
});
|
||||
|
||||
test('should show edit button for users with edit permission', async (done) => {
|
||||
const wrapper = mountWithContexts(<OrganizationDetail organization={mockOrganization} />);
|
||||
const editButton = await waitForElement(wrapper, 'OrganizationDetail Button');
|
||||
expect(editButton.text()).toEqual('Edit');
|
||||
expect(editButton.prop('to')).toBe('/organizations/undefined/edit');
|
||||
done();
|
||||
});
|
||||
|
||||
test('should hide edit button for users without edit permission', async (done) => {
|
||||
const readOnlyOrg = { ...mockOrganization };
|
||||
readOnlyOrg.summary_fields.user_capabilities.edit = false;
|
||||
const wrapper = mountWithContexts(<OrganizationDetail organization={readOnlyOrg} />);
|
||||
await waitForElement(wrapper, 'OrganizationDetail');
|
||||
expect(wrapper.find('OrganizationDetail Button').length).toBe(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -1,95 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../../../../enzymeHelpers';
|
||||
|
||||
import OrganizationEdit from '../../../../../src/pages/Organizations/screens/Organization/OrganizationEdit';
|
||||
|
||||
import { OrganizationsAPI } from '../../../../../src/api';
|
||||
|
||||
jest.mock('../../../../../src/api');
|
||||
|
||||
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
||||
|
||||
describe('<OrganizationEdit />', () => {
|
||||
let api;
|
||||
|
||||
const mockData = {
|
||||
name: 'Foo',
|
||||
description: 'Bar',
|
||||
custom_virtualenv: 'Fizz',
|
||||
id: 1,
|
||||
related: {
|
||||
instance_groups: '/api/v2/organizations/1/instance_groups'
|
||||
}
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
api = {
|
||||
getInstanceGroups: jest.fn(),
|
||||
updateOrganizationDetails: jest.fn(),
|
||||
associateInstanceGroup: jest.fn(),
|
||||
disassociate: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
test('handleSubmit should call api update', () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<OrganizationEdit
|
||||
organization={mockData}
|
||||
/>, { context: { network: {
|
||||
api,
|
||||
} } }
|
||||
);
|
||||
|
||||
const updatedOrgData = {
|
||||
name: 'new name',
|
||||
description: 'new description',
|
||||
custom_virtualenv: 'Buzz',
|
||||
};
|
||||
wrapper.find('OrganizationForm').prop('handleSubmit')(updatedOrgData, [], []);
|
||||
|
||||
expect(OrganizationsAPI.update).toHaveBeenCalledWith(1, updatedOrgData);
|
||||
});
|
||||
|
||||
test('handleSubmit associates and disassociates instance groups', async () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<OrganizationEdit
|
||||
organization={mockData}
|
||||
/>, { context: { network: {
|
||||
api,
|
||||
} } }
|
||||
);
|
||||
|
||||
const updatedOrgData = {
|
||||
name: 'new name',
|
||||
description: 'new description',
|
||||
custom_virtualenv: 'Buzz',
|
||||
};
|
||||
wrapper.find('OrganizationForm').prop('handleSubmit')(updatedOrgData, [3, 4], [2]);
|
||||
await sleep(1);
|
||||
|
||||
expect(OrganizationsAPI.associateInstanceGroup).toHaveBeenCalledWith(1, 3);
|
||||
expect(OrganizationsAPI.associateInstanceGroup).toHaveBeenCalledWith(1, 4);
|
||||
expect(OrganizationsAPI.disassociateInstanceGroup).toHaveBeenCalledWith(1, 2);
|
||||
});
|
||||
|
||||
test('should navigate to organization detail when cancel is clicked', () => {
|
||||
const history = {
|
||||
push: jest.fn(),
|
||||
};
|
||||
const wrapper = mountWithContexts(
|
||||
<OrganizationEdit
|
||||
organization={mockData}
|
||||
/>, { context: {
|
||||
network: {
|
||||
api: { api },
|
||||
},
|
||||
router: { history }
|
||||
} }
|
||||
);
|
||||
|
||||
expect(history.push).not.toHaveBeenCalled();
|
||||
wrapper.find('button[aria-label="Cancel"]').prop('onClick')();
|
||||
|
||||
expect(history.push).toHaveBeenCalledWith('/organizations/1');
|
||||
});
|
||||
});
|
||||
@@ -1,146 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../../../../enzymeHelpers';
|
||||
import OrganizationNotifications from '../../../../../src/pages/Organizations/screens/Organization/OrganizationNotifications';
|
||||
import { sleep } from '../../../../testUtils';
|
||||
import { OrganizationsAPI } from '../../../../../src/api';
|
||||
|
||||
jest.mock('../../../../../src/api');
|
||||
|
||||
describe('<OrganizationNotifications />', () => {
|
||||
let data;
|
||||
|
||||
beforeEach(() => {
|
||||
data = {
|
||||
count: 2,
|
||||
results: [{
|
||||
id: 1,
|
||||
name: 'Notification one',
|
||||
url: '/api/v2/notification_templates/1/',
|
||||
notification_type: 'email',
|
||||
}, {
|
||||
id: 2,
|
||||
name: 'Notification two',
|
||||
url: '/api/v2/notification_templates/2/',
|
||||
notification_type: 'email',
|
||||
}]
|
||||
};
|
||||
OrganizationsAPI.readNotificationTemplates.mockReturnValue({ data });
|
||||
OrganizationsAPI.readNotificationTemplatesSuccess.mockReturnValue({
|
||||
data: { results: [{ id: 1 }] },
|
||||
});
|
||||
OrganizationsAPI.readNotificationTemplatesError.mockReturnValue({
|
||||
data: { results: [{ id: 2 }] },
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('initially renders succesfully', async () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<OrganizationNotifications id={1} canToggleNotifications />
|
||||
);
|
||||
await sleep(0);
|
||||
wrapper.update();
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should render list fetched of items', async () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<OrganizationNotifications id={1} canToggleNotifications />
|
||||
);
|
||||
await sleep(0);
|
||||
wrapper.update();
|
||||
|
||||
expect(OrganizationsAPI.readNotificationTemplates).toHaveBeenCalled();
|
||||
expect(wrapper.find('OrganizationNotifications').state('notifications'))
|
||||
.toEqual(data.results);
|
||||
const items = wrapper.find('NotificationListItem');
|
||||
expect(items).toHaveLength(2);
|
||||
expect(items.at(0).prop('successTurnedOn')).toEqual(true);
|
||||
expect(items.at(0).prop('errorTurnedOn')).toEqual(false);
|
||||
expect(items.at(1).prop('successTurnedOn')).toEqual(false);
|
||||
expect(items.at(1).prop('errorTurnedOn')).toEqual(true);
|
||||
});
|
||||
|
||||
test('should enable success notification', async () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<OrganizationNotifications id={1} canToggleNotifications />
|
||||
);
|
||||
await sleep(0);
|
||||
wrapper.update();
|
||||
|
||||
expect(
|
||||
wrapper.find('OrganizationNotifications').state('successTemplateIds')
|
||||
).toEqual([1]);
|
||||
const items = wrapper.find('NotificationListItem');
|
||||
items.at(1).find('Switch').at(0).prop('onChange')();
|
||||
expect(OrganizationsAPI.updateNotificationTemplateAssociation).toHaveBeenCalledWith(1, 2, 'success', true);
|
||||
await sleep(0);
|
||||
wrapper.update();
|
||||
expect(
|
||||
wrapper.find('OrganizationNotifications').state('successTemplateIds')
|
||||
).toEqual([1, 2]);
|
||||
});
|
||||
|
||||
test('should enable error notification', async () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<OrganizationNotifications id={1} canToggleNotifications />
|
||||
);
|
||||
await sleep(0);
|
||||
wrapper.update();
|
||||
|
||||
expect(
|
||||
wrapper.find('OrganizationNotifications').state('errorTemplateIds')
|
||||
).toEqual([2]);
|
||||
const items = wrapper.find('NotificationListItem');
|
||||
items.at(0).find('Switch').at(1).prop('onChange')();
|
||||
expect(OrganizationsAPI.updateNotificationTemplateAssociation).toHaveBeenCalledWith(1, 1, 'error', true);
|
||||
await sleep(0);
|
||||
wrapper.update();
|
||||
expect(
|
||||
wrapper.find('OrganizationNotifications').state('errorTemplateIds')
|
||||
).toEqual([2, 1]);
|
||||
});
|
||||
|
||||
test('should disable success notification', async () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<OrganizationNotifications id={1} canToggleNotifications />
|
||||
);
|
||||
await sleep(0);
|
||||
wrapper.update();
|
||||
|
||||
expect(
|
||||
wrapper.find('OrganizationNotifications').state('successTemplateIds')
|
||||
).toEqual([1]);
|
||||
const items = wrapper.find('NotificationListItem');
|
||||
items.at(0).find('Switch').at(0).prop('onChange')();
|
||||
expect(OrganizationsAPI.updateNotificationTemplateAssociation).toHaveBeenCalledWith(1, 1, 'success', false);
|
||||
await sleep(0);
|
||||
wrapper.update();
|
||||
expect(
|
||||
wrapper.find('OrganizationNotifications').state('successTemplateIds')
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
test('should disable error notification', async () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<OrganizationNotifications id={1} canToggleNotifications />
|
||||
);
|
||||
await sleep(0);
|
||||
wrapper.update();
|
||||
|
||||
expect(
|
||||
wrapper.find('OrganizationNotifications').state('errorTemplateIds')
|
||||
).toEqual([2]);
|
||||
const items = wrapper.find('NotificationListItem');
|
||||
items.at(1).find('Switch').at(1).prop('onChange')();
|
||||
expect(OrganizationsAPI.updateNotificationTemplateAssociation).toHaveBeenCalledWith(1, 2, 'error', false);
|
||||
await sleep(0);
|
||||
wrapper.update();
|
||||
expect(
|
||||
wrapper.find('OrganizationNotifications').state('errorTemplateIds')
|
||||
).toEqual([]);
|
||||
});
|
||||
});
|
||||
@@ -1,80 +0,0 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { mountWithContexts } from '../../../../enzymeHelpers';
|
||||
import { sleep } from '../../../../testUtils';
|
||||
import OrganizationTeams, { _OrganizationTeams } from '../../../../../src/pages/Organizations/screens/Organization/OrganizationTeams';
|
||||
import { OrganizationsAPI } from '../../../../../src/api';
|
||||
|
||||
jest.mock('../../../../../src/api');
|
||||
|
||||
const listData = {
|
||||
data: {
|
||||
count: 7,
|
||||
results: [
|
||||
{ id: 1, name: 'one', url: '/org/team/1' },
|
||||
{ id: 2, name: 'two', url: '/org/team/2' },
|
||||
{ id: 3, name: 'three', url: '/org/team/3' },
|
||||
{ id: 4, name: 'four', url: '/org/team/4' },
|
||||
{ id: 5, name: 'five', url: '/org/team/5' },
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
describe('<OrganizationTeams />', () => {
|
||||
beforeEach(() => {
|
||||
OrganizationsAPI.readTeams.mockResolvedValue(listData);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('renders succesfully', () => {
|
||||
shallow(
|
||||
<_OrganizationTeams
|
||||
id={1}
|
||||
searchString=""
|
||||
location={{ search: '', pathname: '/organizations/1/teams' }}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
test('should load teams on mount', () => {
|
||||
mountWithContexts(
|
||||
<OrganizationTeams
|
||||
id={1}
|
||||
searchString=""
|
||||
/>
|
||||
).find('OrganizationTeams');
|
||||
expect(OrganizationsAPI.readTeams).toHaveBeenCalledWith(1, {
|
||||
page: 1,
|
||||
page_size: 5,
|
||||
order_by: 'name',
|
||||
});
|
||||
});
|
||||
|
||||
test('should pass fetched teams to PaginatedDatalist', async () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<OrganizationTeams
|
||||
id={1}
|
||||
searchString=""
|
||||
/>
|
||||
);
|
||||
|
||||
await sleep(0);
|
||||
wrapper.update();
|
||||
|
||||
const list = wrapper.find('PaginatedDataList');
|
||||
expect(list.prop('items')).toEqual(listData.data.results);
|
||||
expect(list.prop('itemCount')).toEqual(listData.data.count);
|
||||
expect(list.prop('qsConfig')).toEqual({
|
||||
namespace: 'team',
|
||||
defaultParams: {
|
||||
page: 1,
|
||||
page_size: 5,
|
||||
order_by: 'name',
|
||||
},
|
||||
integerFields: ['page', 'page_size'],
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,260 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`<OrganizationAccess /> initially renders succesfully 1`] = `
|
||||
<OrganizationAccess
|
||||
history={"/history/"}
|
||||
i18n={"/i18n/"}
|
||||
location={
|
||||
Object {
|
||||
"hash": "",
|
||||
"pathname": "",
|
||||
"search": "",
|
||||
"state": "",
|
||||
}
|
||||
}
|
||||
match={
|
||||
Object {
|
||||
"isExact": false,
|
||||
"params": Object {},
|
||||
"path": "",
|
||||
"url": "",
|
||||
}
|
||||
}
|
||||
organization={
|
||||
Object {
|
||||
"id": 1,
|
||||
"name": "Default",
|
||||
"summary_fields": Object {
|
||||
"object_roles": Object {},
|
||||
"user_capabilities": Object {
|
||||
"edit": true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<WithI18n
|
||||
contentError={false}
|
||||
contentLoading={true}
|
||||
itemCount={0}
|
||||
itemName="role"
|
||||
items={Array []}
|
||||
qsConfig={
|
||||
Object {
|
||||
"defaultParams": Object {
|
||||
"order_by": "first_name",
|
||||
"page": 1,
|
||||
"page_size": 5,
|
||||
},
|
||||
"integerFields": Array [
|
||||
"page",
|
||||
"page_size",
|
||||
],
|
||||
"namespace": "access",
|
||||
}
|
||||
}
|
||||
renderItem={[Function]}
|
||||
renderToolbar={[Function]}
|
||||
toolbarColumns={
|
||||
Array [
|
||||
Object {
|
||||
"isSortable": true,
|
||||
"key": "first_name",
|
||||
"name": "Name",
|
||||
},
|
||||
Object {
|
||||
"isSortable": true,
|
||||
"key": "username",
|
||||
"name": "Username",
|
||||
},
|
||||
Object {
|
||||
"isSortable": true,
|
||||
"key": "last_name",
|
||||
"name": "Last Name",
|
||||
},
|
||||
]
|
||||
}
|
||||
>
|
||||
<I18n
|
||||
update={true}
|
||||
withHash={true}
|
||||
>
|
||||
<withRouter(PaginatedDataList)
|
||||
contentError={false}
|
||||
contentLoading={true}
|
||||
i18n={"/i18n/"}
|
||||
itemCount={0}
|
||||
itemName="role"
|
||||
items={Array []}
|
||||
qsConfig={
|
||||
Object {
|
||||
"defaultParams": Object {
|
||||
"order_by": "first_name",
|
||||
"page": 1,
|
||||
"page_size": 5,
|
||||
},
|
||||
"integerFields": Array [
|
||||
"page",
|
||||
"page_size",
|
||||
],
|
||||
"namespace": "access",
|
||||
}
|
||||
}
|
||||
renderItem={[Function]}
|
||||
renderToolbar={[Function]}
|
||||
toolbarColumns={
|
||||
Array [
|
||||
Object {
|
||||
"isSortable": true,
|
||||
"key": "first_name",
|
||||
"name": "Name",
|
||||
},
|
||||
Object {
|
||||
"isSortable": true,
|
||||
"key": "username",
|
||||
"name": "Username",
|
||||
},
|
||||
Object {
|
||||
"isSortable": true,
|
||||
"key": "last_name",
|
||||
"name": "Last Name",
|
||||
},
|
||||
]
|
||||
}
|
||||
>
|
||||
<Route>
|
||||
<PaginatedDataList
|
||||
contentError={false}
|
||||
contentLoading={true}
|
||||
history={"/history/"}
|
||||
i18n={"/i18n/"}
|
||||
itemCount={0}
|
||||
itemName="role"
|
||||
itemNamePlural=""
|
||||
items={Array []}
|
||||
location={
|
||||
Object {
|
||||
"hash": "",
|
||||
"pathname": "",
|
||||
"search": "",
|
||||
"state": "",
|
||||
}
|
||||
}
|
||||
match={
|
||||
Object {
|
||||
"isExact": false,
|
||||
"params": Object {},
|
||||
"path": "",
|
||||
"url": "",
|
||||
}
|
||||
}
|
||||
qsConfig={
|
||||
Object {
|
||||
"defaultParams": Object {
|
||||
"order_by": "first_name",
|
||||
"page": 1,
|
||||
"page_size": 5,
|
||||
},
|
||||
"integerFields": Array [
|
||||
"page",
|
||||
"page_size",
|
||||
],
|
||||
"namespace": "access",
|
||||
}
|
||||
}
|
||||
renderItem={[Function]}
|
||||
renderToolbar={[Function]}
|
||||
showPageSizeOptions={true}
|
||||
toolbarColumns={
|
||||
Array [
|
||||
Object {
|
||||
"isSortable": true,
|
||||
"key": "first_name",
|
||||
"name": "Name",
|
||||
},
|
||||
Object {
|
||||
"isSortable": true,
|
||||
"key": "username",
|
||||
"name": "Username",
|
||||
},
|
||||
Object {
|
||||
"isSortable": true,
|
||||
"key": "last_name",
|
||||
"name": "Last Name",
|
||||
},
|
||||
]
|
||||
}
|
||||
>
|
||||
<WithI18n>
|
||||
<I18n
|
||||
update={true}
|
||||
withHash={true}
|
||||
>
|
||||
<ContentLoading
|
||||
i18n={"/i18n/"}
|
||||
>
|
||||
<EmptyState
|
||||
className=""
|
||||
variant="large"
|
||||
>
|
||||
<div
|
||||
className="pf-c-empty-state pf-m-lg"
|
||||
>
|
||||
<EmptyStateBody
|
||||
className=""
|
||||
>
|
||||
<p
|
||||
className="pf-c-empty-state__body"
|
||||
>
|
||||
Loading...
|
||||
</p>
|
||||
</EmptyStateBody>
|
||||
</div>
|
||||
</EmptyState>
|
||||
</ContentLoading>
|
||||
</I18n>
|
||||
</WithI18n>
|
||||
</PaginatedDataList>
|
||||
</Route>
|
||||
</withRouter(PaginatedDataList)>
|
||||
</I18n>
|
||||
</WithI18n>
|
||||
<_default
|
||||
isOpen={false}
|
||||
onClose={[Function]}
|
||||
title="Error!"
|
||||
variant="danger"
|
||||
>
|
||||
<Modal
|
||||
actions={Array []}
|
||||
ariaDescribedById=""
|
||||
className="awx-c-modal at-c-alertModal at-c-alertModal--danger"
|
||||
hideTitle={false}
|
||||
isLarge={false}
|
||||
isOpen={false}
|
||||
isSmall={false}
|
||||
onClose={[Function]}
|
||||
title="Error!"
|
||||
width={null}
|
||||
>
|
||||
<Portal
|
||||
containerInfo={<div />}
|
||||
>
|
||||
<ModalContent
|
||||
actions={Array []}
|
||||
ariaDescribedById=""
|
||||
className="awx-c-modal at-c-alertModal at-c-alertModal--danger"
|
||||
hideTitle={false}
|
||||
id="pf-modal-0"
|
||||
isLarge={false}
|
||||
isOpen={false}
|
||||
isSmall={false}
|
||||
onClose={[Function]}
|
||||
title="Error!"
|
||||
width={null}
|
||||
/>
|
||||
</Portal>
|
||||
</Modal>
|
||||
</_default>
|
||||
</OrganizationAccess>
|
||||
`;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,121 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import { mountWithContexts, waitForElement } from '../../../enzymeHelpers';
|
||||
|
||||
import OrganizationAdd from '../../../../src/pages/Organizations/screens/OrganizationAdd';
|
||||
import { OrganizationsAPI } from '../../../../src/api';
|
||||
|
||||
jest.mock('../../../../src/api');
|
||||
|
||||
describe('<OrganizationAdd />', () => {
|
||||
test('handleSubmit should post to api', () => {
|
||||
const wrapper = mountWithContexts(<OrganizationAdd />);
|
||||
const updatedOrgData = {
|
||||
name: 'new name',
|
||||
description: 'new description',
|
||||
custom_virtualenv: 'Buzz',
|
||||
};
|
||||
wrapper.find('OrganizationForm').prop('handleSubmit')(updatedOrgData, [], []);
|
||||
expect(OrganizationsAPI.create).toHaveBeenCalledWith(updatedOrgData);
|
||||
});
|
||||
|
||||
test('should navigate to organizations list when cancel is clicked', () => {
|
||||
const history = {
|
||||
push: jest.fn(),
|
||||
};
|
||||
const wrapper = mountWithContexts(
|
||||
<OrganizationAdd />,
|
||||
{ context: { router: { history } } }
|
||||
);
|
||||
expect(history.push).not.toHaveBeenCalled();
|
||||
wrapper.find('button[aria-label="Cancel"]').prop('onClick')();
|
||||
expect(history.push).toHaveBeenCalledWith('/organizations');
|
||||
});
|
||||
|
||||
test('should navigate to organizations list when close (x) is clicked', () => {
|
||||
const history = {
|
||||
push: jest.fn(),
|
||||
};
|
||||
const wrapper = mountWithContexts(
|
||||
<OrganizationAdd />,
|
||||
{ context: { router: { history } } }
|
||||
);
|
||||
expect(history.push).not.toHaveBeenCalled();
|
||||
wrapper.find('button[aria-label="Close"]').prop('onClick')();
|
||||
expect(history.push).toHaveBeenCalledWith('/organizations');
|
||||
});
|
||||
|
||||
test('successful form submission should trigger redirect', async (done) => {
|
||||
const history = {
|
||||
push: jest.fn(),
|
||||
};
|
||||
const orgData = {
|
||||
name: 'new name',
|
||||
description: 'new description',
|
||||
custom_virtualenv: 'Buzz',
|
||||
};
|
||||
OrganizationsAPI.create.mockResolvedValueOnce({
|
||||
data: {
|
||||
id: 5,
|
||||
related: {
|
||||
instance_groups: '/bar',
|
||||
},
|
||||
...orgData,
|
||||
}
|
||||
});
|
||||
const wrapper = mountWithContexts(
|
||||
<OrganizationAdd />,
|
||||
{ context: { router: { history } } }
|
||||
);
|
||||
await waitForElement(wrapper, 'button[aria-label="Save"]');
|
||||
await wrapper.find('OrganizationForm').prop('handleSubmit')(orgData, [3], []);
|
||||
expect(history.push).toHaveBeenCalledWith('/organizations/5');
|
||||
done();
|
||||
});
|
||||
|
||||
test('handleSubmit should post instance groups', async (done) => {
|
||||
const orgData = {
|
||||
name: 'new name',
|
||||
description: 'new description',
|
||||
custom_virtualenv: 'Buzz',
|
||||
};
|
||||
OrganizationsAPI.create.mockResolvedValueOnce({
|
||||
data: {
|
||||
id: 5,
|
||||
related: {
|
||||
instance_groups: '/api/v2/organizations/5/instance_groups',
|
||||
},
|
||||
...orgData,
|
||||
}
|
||||
});
|
||||
const wrapper = mountWithContexts(<OrganizationAdd />);
|
||||
await waitForElement(wrapper, 'button[aria-label="Save"]');
|
||||
await wrapper.find('OrganizationForm').prop('handleSubmit')(orgData, [3], []);
|
||||
expect(OrganizationsAPI.associateInstanceGroup)
|
||||
.toHaveBeenCalledWith(5, 3);
|
||||
done();
|
||||
});
|
||||
|
||||
test('AnsibleSelect component renders if there are virtual environments', () => {
|
||||
const config = {
|
||||
custom_virtualenvs: ['foo', 'bar'],
|
||||
};
|
||||
const wrapper = mountWithContexts(
|
||||
<OrganizationAdd />,
|
||||
{ context: { config } }
|
||||
).find('AnsibleSelect');
|
||||
expect(wrapper.find('FormSelect')).toHaveLength(1);
|
||||
expect(wrapper.find('FormSelectOption')).toHaveLength(2);
|
||||
});
|
||||
|
||||
test('AnsibleSelect component does not render if there are 0 virtual environments', () => {
|
||||
const config = {
|
||||
custom_virtualenvs: [],
|
||||
};
|
||||
const wrapper = mountWithContexts(
|
||||
<OrganizationAdd />,
|
||||
{ context: { config } }
|
||||
).find('AnsibleSelect');
|
||||
expect(wrapper.find('FormSelect')).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
@@ -1,136 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts, waitForElement } from '../../../enzymeHelpers';
|
||||
import OrganizationsList, { _OrganizationsList } from '../../../../src/pages/Organizations/screens/OrganizationsList';
|
||||
import { OrganizationsAPI } from '../../../../src/api';
|
||||
|
||||
jest.mock('../../../../src/api');
|
||||
|
||||
const mockAPIOrgsList = {
|
||||
data: {
|
||||
count: 3,
|
||||
results: [{
|
||||
name: 'Organization 0',
|
||||
id: 1,
|
||||
url: '/organizations/1',
|
||||
summary_fields: {
|
||||
related_field_counts: {
|
||||
teams: 3,
|
||||
users: 4
|
||||
},
|
||||
user_capabilities: {
|
||||
delete: true
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Organization 1',
|
||||
id: 2,
|
||||
url: '/organizations/2',
|
||||
summary_fields: {
|
||||
related_field_counts: {
|
||||
teams: 2,
|
||||
users: 5
|
||||
},
|
||||
user_capabilities: {
|
||||
delete: true
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'Organization 2',
|
||||
id: 3,
|
||||
url: '/organizations/3',
|
||||
summary_fields: {
|
||||
related_field_counts: {
|
||||
teams: 5,
|
||||
users: 6
|
||||
},
|
||||
user_capabilities: {
|
||||
delete: true
|
||||
}
|
||||
},
|
||||
}]
|
||||
},
|
||||
isModalOpen: false,
|
||||
warningTitle: 'title',
|
||||
warningMsg: 'message'
|
||||
};
|
||||
|
||||
describe('<OrganizationsList />', () => {
|
||||
let wrapper;
|
||||
|
||||
test('initially renders succesfully', () => {
|
||||
mountWithContexts(<OrganizationsList />);
|
||||
});
|
||||
|
||||
test('Puts 1 selected Org in state when handleSelect is called.', () => {
|
||||
wrapper = mountWithContexts(<OrganizationsList />).find('OrganizationsList');
|
||||
|
||||
wrapper.setState({
|
||||
organizations: mockAPIOrgsList.data.results,
|
||||
itemCount: 3,
|
||||
isInitialized: true
|
||||
});
|
||||
wrapper.update();
|
||||
expect(wrapper.state('selected').length).toBe(0);
|
||||
wrapper.instance().handleSelect(mockAPIOrgsList.data.results.slice(0, 1));
|
||||
expect(wrapper.state('selected').length).toBe(1);
|
||||
});
|
||||
|
||||
test('Puts all Orgs in state when handleSelectAll is called.', () => {
|
||||
wrapper = mountWithContexts(<OrganizationsList />);
|
||||
const list = wrapper.find('OrganizationsList');
|
||||
list.setState({
|
||||
organizations: mockAPIOrgsList.data.results,
|
||||
itemCount: 3,
|
||||
isInitialized: true
|
||||
});
|
||||
expect(list.state('selected').length).toBe(0);
|
||||
list.instance().handleSelectAll(true);
|
||||
wrapper.update();
|
||||
expect(list.state('selected').length)
|
||||
.toEqual(list.state('organizations').length);
|
||||
});
|
||||
|
||||
test('api is called to delete Orgs for each org in selected.', () => {
|
||||
wrapper = mountWithContexts(<OrganizationsList />);
|
||||
const component = wrapper.find('OrganizationsList');
|
||||
wrapper.find('OrganizationsList').setState({
|
||||
organizations: mockAPIOrgsList.data.results,
|
||||
itemCount: 3,
|
||||
isInitialized: true,
|
||||
isModalOpen: mockAPIOrgsList.isModalOpen,
|
||||
selected: mockAPIOrgsList.data.results
|
||||
});
|
||||
wrapper.find('ToolbarDeleteButton').prop('onDelete')();
|
||||
expect(OrganizationsAPI.destroy).toHaveBeenCalledTimes(component.state('selected').length);
|
||||
});
|
||||
|
||||
test('call loadOrganizations after org(s) have been deleted', () => {
|
||||
const fetchOrgs = jest.spyOn(_OrganizationsList.prototype, 'loadOrganizations');
|
||||
const event = { preventDefault: () => { } };
|
||||
wrapper = mountWithContexts(<OrganizationsList />);
|
||||
wrapper.find('OrganizationsList').setState({
|
||||
organizations: mockAPIOrgsList.data.results,
|
||||
itemCount: 3,
|
||||
isInitialized: true,
|
||||
selected: mockAPIOrgsList.data.results.slice(0, 1)
|
||||
});
|
||||
const component = wrapper.find('OrganizationsList');
|
||||
component.instance().handleOrgDelete(event);
|
||||
expect(fetchOrgs).toBeCalled();
|
||||
});
|
||||
|
||||
test('error is shown when org not successfully deleted from api', async () => {
|
||||
OrganizationsAPI.destroy = () => Promise.reject();
|
||||
wrapper = mountWithContexts(<OrganizationsList />);
|
||||
wrapper.find('OrganizationsList').setState({
|
||||
organizations: mockAPIOrgsList.data.results,
|
||||
itemCount: 3,
|
||||
isInitialized: true,
|
||||
selected: mockAPIOrgsList.data.results.slice(0, 1)
|
||||
});
|
||||
wrapper.find('ToolbarDeleteButton').prop('onDelete')();
|
||||
await waitForElement(wrapper, 'Modal', (el) => el.props().isOpen === true && el.props().title === 'Error!');
|
||||
});
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import Portal from '../../src/pages/Portal';
|
||||
|
||||
describe('<Portal />', () => {
|
||||
let pageWrapper;
|
||||
let pageSections;
|
||||
let title;
|
||||
|
||||
beforeEach(() => {
|
||||
pageWrapper = mountWithContexts(<Portal />);
|
||||
pageSections = pageWrapper.find('PageSection');
|
||||
title = pageWrapper.find('Title');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
pageWrapper.unmount();
|
||||
});
|
||||
|
||||
test('initially renders without crashing', () => {
|
||||
expect(pageWrapper.length).toBe(1);
|
||||
expect(pageSections.length).toBe(2);
|
||||
expect(title.length).toBe(1);
|
||||
expect(title.props().size).toBe('2xl');
|
||||
pageSections.forEach(section => {
|
||||
expect(section.props().variant).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import Projects from '../../src/pages/Projects';
|
||||
|
||||
describe('<Projects />', () => {
|
||||
let pageWrapper;
|
||||
let pageSections;
|
||||
let title;
|
||||
|
||||
beforeEach(() => {
|
||||
pageWrapper = mountWithContexts(<Projects />);
|
||||
pageSections = pageWrapper.find('PageSection');
|
||||
title = pageWrapper.find('Title');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
pageWrapper.unmount();
|
||||
});
|
||||
|
||||
test('initially renders without crashing', () => {
|
||||
expect(pageWrapper.length).toBe(1);
|
||||
expect(pageSections.length).toBe(2);
|
||||
expect(title.length).toBe(1);
|
||||
expect(title.props().size).toBe('2xl');
|
||||
pageSections.forEach(section => {
|
||||
expect(section.props().variant).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import Schedules from '../../src/pages/Schedules';
|
||||
|
||||
describe('<Schedules />', () => {
|
||||
let pageWrapper;
|
||||
let pageSections;
|
||||
let title;
|
||||
|
||||
beforeEach(() => {
|
||||
pageWrapper = mountWithContexts(<Schedules />);
|
||||
pageSections = pageWrapper.find('PageSection');
|
||||
title = pageWrapper.find('Title');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
pageWrapper.unmount();
|
||||
});
|
||||
|
||||
test('initially renders without crashing', () => {
|
||||
expect(pageWrapper.length).toBe(1);
|
||||
expect(pageSections.length).toBe(2);
|
||||
expect(title.length).toBe(1);
|
||||
expect(title.props().size).toBe('2xl');
|
||||
pageSections.forEach(section => {
|
||||
expect(section.props().variant).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import SystemSettings from '../../src/pages/SystemSettings';
|
||||
|
||||
describe('<SystemSettings />', () => {
|
||||
let pageWrapper;
|
||||
let pageSections;
|
||||
let title;
|
||||
|
||||
beforeEach(() => {
|
||||
pageWrapper = mountWithContexts(<SystemSettings />);
|
||||
pageSections = pageWrapper.find('PageSection');
|
||||
title = pageWrapper.find('Title');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
pageWrapper.unmount();
|
||||
});
|
||||
|
||||
test('initially renders without crashing', () => {
|
||||
expect(pageWrapper.length).toBe(1);
|
||||
expect(pageSections.length).toBe(2);
|
||||
expect(title.length).toBe(1);
|
||||
expect(title.props().size).toBe('2xl');
|
||||
pageSections.forEach(section => {
|
||||
expect(section.props().variant).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import Teams from '../../src/pages/Teams';
|
||||
|
||||
describe('<Teams />', () => {
|
||||
let pageWrapper;
|
||||
let pageSections;
|
||||
let title;
|
||||
|
||||
beforeEach(() => {
|
||||
pageWrapper = mountWithContexts(<Teams />);
|
||||
pageSections = pageWrapper.find('PageSection');
|
||||
title = pageWrapper.find('Title');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
pageWrapper.unmount();
|
||||
});
|
||||
|
||||
test('initially renders without crashing', () => {
|
||||
expect(pageWrapper.length).toBe(1);
|
||||
expect(pageSections.length).toBe(2);
|
||||
expect(title.length).toBe(1);
|
||||
expect(title.props().size).toBe('2xl');
|
||||
pageSections.forEach(section => {
|
||||
expect(section.props().variant).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
import React from 'react';
|
||||
import Templates from '../../src/pages/Templates/Templates';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
|
||||
describe('<Templates />', () => {
|
||||
let pageWrapper;
|
||||
|
||||
beforeEach(() => {
|
||||
pageWrapper = mountWithContexts(<Templates />);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
pageWrapper.unmount();
|
||||
});
|
||||
|
||||
test('initially renders without crashing', () => {
|
||||
expect(pageWrapper.length).toBe(1);
|
||||
});
|
||||
});
|
||||
@@ -1,11 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../../enzymeHelpers';
|
||||
import Templates from '../../../src/pages/Templates/Templates';
|
||||
|
||||
describe('<Templates />', () => {
|
||||
test('initially renders succesfully', () => {
|
||||
mountWithContexts(
|
||||
<Templates />
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,161 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts, waitForElement } from '../../enzymeHelpers';
|
||||
import TemplatesList, { _TemplatesList } from '../../../src/pages/Templates/TemplatesList';
|
||||
import { JobTemplatesAPI, UnifiedJobTemplatesAPI, WorkflowJobTemplatesAPI } from '../../../src/api';
|
||||
|
||||
jest.mock('../../../src/api');
|
||||
|
||||
const mockTemplates = [{
|
||||
id: 1,
|
||||
name: 'Job Template 1',
|
||||
url: '/templates/job_template/1',
|
||||
type: 'job_template',
|
||||
summary_fields: {
|
||||
user_capabilities: {
|
||||
delete: true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Job Template 2',
|
||||
url: '/templates/job_template/2',
|
||||
type: 'job_template',
|
||||
summary_fields: {
|
||||
user_capabilities: {
|
||||
delete: true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Job Template 3',
|
||||
url: '/templates/job_template/3',
|
||||
type: 'job_template',
|
||||
summary_fields: {
|
||||
user_capabilities: {
|
||||
delete: true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Workflow Job Template 1',
|
||||
url: '/templates/workflow_job_template/4',
|
||||
type: 'workflow_job_template',
|
||||
summary_fields: {
|
||||
user_capabilities: {
|
||||
delete: true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'Workflow Job Template 2',
|
||||
url: '/templates/workflow_job_template/5',
|
||||
type: 'workflow_job_template',
|
||||
summary_fields: {
|
||||
user_capabilities: {
|
||||
delete: false
|
||||
}
|
||||
}
|
||||
}];
|
||||
|
||||
describe('<TemplatesList />', () => {
|
||||
beforeEach(() => {
|
||||
UnifiedJobTemplatesAPI.read.mockResolvedValue({
|
||||
data: {
|
||||
count: mockTemplates.length,
|
||||
results: mockTemplates
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('initially renders succesfully', () => {
|
||||
mountWithContexts(
|
||||
<TemplatesList
|
||||
match={{ path: '/templates', url: '/templates' }}
|
||||
location={{ search: '', pathname: '/templates' }}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
test('Templates are retrieved from the api and the components finishes loading', async (done) => {
|
||||
const loadTemplates = jest.spyOn(_TemplatesList.prototype, 'loadTemplates');
|
||||
const wrapper = mountWithContexts(<TemplatesList />);
|
||||
await waitForElement(wrapper, 'TemplatesList', (el) => el.state('contentLoading') === true);
|
||||
expect(loadTemplates).toHaveBeenCalled();
|
||||
await waitForElement(wrapper, 'TemplatesList', (el) => el.state('contentLoading') === false);
|
||||
done();
|
||||
});
|
||||
|
||||
test('handleSelect is called when a template list item is selected', async (done) => {
|
||||
const handleSelect = jest.spyOn(_TemplatesList.prototype, 'handleSelect');
|
||||
const wrapper = mountWithContexts(<TemplatesList />);
|
||||
await waitForElement(wrapper, 'TemplatesList', (el) => el.state('contentLoading') === false);
|
||||
wrapper.find('DataListCheck#select-jobTemplate-1').props().onChange();
|
||||
expect(handleSelect).toBeCalled();
|
||||
await waitForElement(wrapper, 'TemplatesList', (el) => el.state('selected').length === 1);
|
||||
done();
|
||||
});
|
||||
|
||||
test('handleSelectAll is called when a template list item is selected', async (done) => {
|
||||
const handleSelectAll = jest.spyOn(_TemplatesList.prototype, 'handleSelectAll');
|
||||
const wrapper = mountWithContexts(<TemplatesList />);
|
||||
await waitForElement(wrapper, 'TemplatesList', (el) => el.state('contentLoading') === false);
|
||||
wrapper.find('Checkbox#select-all').props().onChange(true);
|
||||
expect(handleSelectAll).toBeCalled();
|
||||
await waitForElement(wrapper, 'TemplatesList', (el) => el.state('selected').length === 5);
|
||||
done();
|
||||
});
|
||||
|
||||
test('delete button is disabled if user does not have delete capabilities on a selected template', async (done) => {
|
||||
const wrapper = mountWithContexts(<TemplatesList />);
|
||||
wrapper.find('TemplatesList').setState({
|
||||
templates: mockTemplates,
|
||||
itemCount: 5,
|
||||
isInitialized: true,
|
||||
selected: mockTemplates.slice(0, 4)
|
||||
});
|
||||
await waitForElement(wrapper, 'ToolbarDeleteButton * button', (el) => el.getDOMNode().disabled === false);
|
||||
wrapper.find('TemplatesList').setState({
|
||||
selected: mockTemplates
|
||||
});
|
||||
await waitForElement(wrapper, 'ToolbarDeleteButton * button', (el) => el.getDOMNode().disabled === true);
|
||||
done();
|
||||
});
|
||||
|
||||
test('api is called to delete templates for each selected template.', () => {
|
||||
JobTemplatesAPI.destroy = jest.fn();
|
||||
WorkflowJobTemplatesAPI.destroy = jest.fn();
|
||||
const wrapper = mountWithContexts(<TemplatesList />);
|
||||
wrapper.find('TemplatesList').setState({
|
||||
templates: mockTemplates,
|
||||
itemCount: 5,
|
||||
isInitialized: true,
|
||||
isModalOpen: true,
|
||||
selected: mockTemplates.slice(0, 4)
|
||||
});
|
||||
wrapper.find('ToolbarDeleteButton').prop('onDelete')();
|
||||
expect(JobTemplatesAPI.destroy).toHaveBeenCalledTimes(3);
|
||||
expect(WorkflowJobTemplatesAPI.destroy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('error is shown when template not successfully deleted from api', async () => {
|
||||
JobTemplatesAPI.destroy = () => Promise.reject();
|
||||
const wrapper = mountWithContexts(<TemplatesList />);
|
||||
wrapper.find('TemplatesList').setState({
|
||||
templates: mockTemplates,
|
||||
itemCount: 1,
|
||||
isInitialized: true,
|
||||
isModalOpen: true,
|
||||
selected: mockTemplates.slice(0, 1)
|
||||
});
|
||||
wrapper.find('ToolbarDeleteButton').prop('onDelete')();
|
||||
await waitForElement(wrapper, 'Modal', (el) => el.props().isOpen === true && el.props().title === 'Error!');
|
||||
});
|
||||
});
|
||||
@@ -1,16 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../../../enzymeHelpers';
|
||||
import TemplatesListItem from '../../../../src/pages/Templates/components/TemplateListItem';
|
||||
|
||||
describe('<TemplatesListItem />', () => {
|
||||
test('initially render successfully', () => {
|
||||
mountWithContexts(<TemplatesListItem
|
||||
template={{
|
||||
id: 1,
|
||||
name: 'Template 1',
|
||||
url: '/templates/job_template/1',
|
||||
type: 'job_template'
|
||||
}}
|
||||
/>);
|
||||
});
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import UISettings from '../../src/pages/UISettings';
|
||||
|
||||
describe('<UISettings />', () => {
|
||||
let pageWrapper;
|
||||
let pageSections;
|
||||
let title;
|
||||
|
||||
beforeEach(() => {
|
||||
pageWrapper = mountWithContexts(<UISettings />);
|
||||
pageSections = pageWrapper.find('PageSection');
|
||||
title = pageWrapper.find('Title');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
pageWrapper.unmount();
|
||||
});
|
||||
|
||||
test('initially renders without crashing', () => {
|
||||
expect(pageWrapper.length).toBe(1);
|
||||
expect(pageSections.length).toBe(2);
|
||||
expect(title.length).toBe(1);
|
||||
expect(title.props().size).toBe('2xl');
|
||||
pageSections.forEach(section => {
|
||||
expect(section.props().variant).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,29 +0,0 @@
|
||||
import React from 'react';
|
||||
import { mountWithContexts } from '../enzymeHelpers';
|
||||
import Users from '../../src/pages/Users';
|
||||
|
||||
describe('<Users />', () => {
|
||||
let pageWrapper;
|
||||
let pageSections;
|
||||
let title;
|
||||
|
||||
beforeEach(() => {
|
||||
pageWrapper = mountWithContexts(<Users />);
|
||||
pageSections = pageWrapper.find('PageSection');
|
||||
title = pageWrapper.find('Title');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
pageWrapper.unmount();
|
||||
});
|
||||
|
||||
test('initially renders without crashing', () => {
|
||||
expect(pageWrapper.length).toBe(1);
|
||||
expect(pageSections.length).toBe(2);
|
||||
expect(title.length).toBe(1);
|
||||
expect(title.props().size).toBe('2xl');
|
||||
pageSections.forEach(section => {
|
||||
expect(section.props().variant).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,4 +0,0 @@
|
||||
|
||||
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms));
|
||||
/* eslint-disable-next-line import/prefer-default-export */
|
||||
export { sleep };
|
||||
@@ -1,19 +0,0 @@
|
||||
import { isAuthenticated } from '../../src/util/auth';
|
||||
|
||||
const invalidCookie = 'invalid';
|
||||
const validLoggedOutCookie = 'current_user=%7B%22id%22%3A1%2C%22type%22%3A%22user%22%2C%22url%22%3A%22%2Fapi%2Fv2%2Fusers%2F1%2F%22%2C%22related%22%3A%7B%22admin_of_organizations%22%3A%22%2Fapi%2Fv2%2Fusers%2F1%2Fadmin_of_organizations%2F%22%2C%22authorized_tokens%22%3A%22%2Fapi%2Fv2%2Fusers%2F1%2Fauthorized_tokens%2F%22%2C%22roles%22%3A%22%2Fapi%2Fv2%2Fusers%2F1%2Froles%2F%22%2C%22organizations%22%3A%22%2Fapi%2Fv2%2Fusers%2F1%2Forganizations%2F%22%2C%22access_list%22%3A%22%2Fapi%2Fv2%2Fusers%2F1%2Faccess_list%2F%22%2C%22teams%22%3A%22%2Fapi%2Fv2%2Fusers%2F1%2Fteams%2F%22%2C%22tokens%22%3A%22%2Fapi%2Fv2%2Fusers%2F1%2Ftokens%2F%22%2C%22personal_tokens%22%3A%22%2Fapi%2Fv2%2Fusers%2F1%2Fpersonal_tokens%2F%22%2C%22credentials%22%3A%22%2Fapi%2Fv2%2Fusers%2F1%2Fcredentials%2F%22%2C%22activity_stream%22%3A%22%2Fapi%2Fv2%2Fusers%2F1%2Factivity_stream%2F%22%2C%22projects%22%3A%22%2Fapi%2Fv2%2Fusers%2F1%2Fprojects%2F%22%7D%2C%22summary_fields%22%3A%7B%7D%2C%22created%22%3A%222018-10-19T16%3A30%3A59.141963Z%22%2C%22username%22%3A%22admin%22%2C%22first_name%22%3A%22%22%2C%22last_name%22%3A%22%22%2C%22email%22%3A%22%22%2C%22is_superuser%22%3Atrue%2C%22is_system_auditor%22%3Afalse%2C%22ldap_dn%22%3A%22%22%2C%22external_account%22%3Anull%2C%22auth%22%3A%5B%5D%7D; userLoggedIn=false; csrftoken=lhOHpLQUFHlIVqx8CCZmEpdEZAz79GIRBIT3asBzTbPE7HS7wizt7WBsgJClz8Ge';
|
||||
const validLoggedInCookie = 'current_user=%7B%22id%22%3A1%2C%22type%22%3A%22user%22%2C%22url%22%3A%22%2Fapi%2Fv2%2Fusers%2F1%2F%22%2C%22related%22%3A%7B%22admin_of_organizations%22%3A%22%2Fapi%2Fv2%2Fusers%2F1%2Fadmin_of_organizations%2F%22%2C%22authorized_tokens%22%3A%22%2Fapi%2Fv2%2Fusers%2F1%2Fauthorized_tokens%2F%22%2C%22roles%22%3A%22%2Fapi%2Fv2%2Fusers%2F1%2Froles%2F%22%2C%22organizations%22%3A%22%2Fapi%2Fv2%2Fusers%2F1%2Forganizations%2F%22%2C%22access_list%22%3A%22%2Fapi%2Fv2%2Fusers%2F1%2Faccess_list%2F%22%2C%22teams%22%3A%22%2Fapi%2Fv2%2Fusers%2F1%2Fteams%2F%22%2C%22tokens%22%3A%22%2Fapi%2Fv2%2Fusers%2F1%2Ftokens%2F%22%2C%22personal_tokens%22%3A%22%2Fapi%2Fv2%2Fusers%2F1%2Fpersonal_tokens%2F%22%2C%22credentials%22%3A%22%2Fapi%2Fv2%2Fusers%2F1%2Fcredentials%2F%22%2C%22activity_stream%22%3A%22%2Fapi%2Fv2%2Fusers%2F1%2Factivity_stream%2F%22%2C%22projects%22%3A%22%2Fapi%2Fv2%2Fusers%2F1%2Fprojects%2F%22%7D%2C%22summary_fields%22%3A%7B%7D%2C%22created%22%3A%222018-10-19T16%3A30%3A59.141963Z%22%2C%22username%22%3A%22admin%22%2C%22first_name%22%3A%22%22%2C%22last_name%22%3A%22%22%2C%22email%22%3A%22%22%2C%22is_superuser%22%3Atrue%2C%22is_system_auditor%22%3Afalse%2C%22ldap_dn%22%3A%22%22%2C%22external_account%22%3Anull%2C%22auth%22%3A%5B%5D%7D; userLoggedIn=true; csrftoken=lhOHpLQUFHlIVqx8CCZmEpdEZAz79GIRBIT3asBzTbPE7HS7wizt7WBsgJClz8Ge';
|
||||
|
||||
describe('isAuthenticated', () => {
|
||||
test('returns false for invalid cookie', () => {
|
||||
expect(isAuthenticated(invalidCookie)).toEqual(false);
|
||||
});
|
||||
|
||||
test('returns false for expired cookie', () => {
|
||||
expect(isAuthenticated(validLoggedOutCookie)).toEqual(false);
|
||||
});
|
||||
|
||||
test('returns true for valid authenticated cookie', () => {
|
||||
expect(isAuthenticated(validLoggedInCookie)).toEqual(true);
|
||||
});
|
||||
});
|
||||
@@ -1,213 +0,0 @@
|
||||
import {
|
||||
encodeQueryString,
|
||||
parseQueryString,
|
||||
getQSConfig,
|
||||
parseNamespacedQueryString,
|
||||
encodeNamespacedQueryString,
|
||||
updateNamespacedQueryString,
|
||||
} from '../../src/util/qs';
|
||||
|
||||
describe('qs (qs.js)', () => {
|
||||
test('encodeQueryString returns the expected queryString', () => {
|
||||
[
|
||||
[null, ''],
|
||||
[{}, ''],
|
||||
[{ order_by: 'name', page: 1, page_size: 5 }, 'order_by=name&page=1&page_size=5'],
|
||||
[{ '-order_by': 'name', page: '1', page_size: 5 }, '-order_by=name&page=1&page_size=5'],
|
||||
]
|
||||
.forEach(([params, expectedQueryString]) => {
|
||||
const actualQueryString = encodeQueryString(params);
|
||||
|
||||
expect(actualQueryString).toEqual(expectedQueryString);
|
||||
});
|
||||
});
|
||||
|
||||
test('encodeQueryString omits null values', () => {
|
||||
const vals = {
|
||||
order_by: 'name',
|
||||
page: null,
|
||||
};
|
||||
expect(encodeQueryString(vals)).toEqual('order_by=name');
|
||||
});
|
||||
|
||||
describe('parseQueryString', () => {
|
||||
test('parseQueryString returns the expected queryParams', () => {
|
||||
[
|
||||
['order_by=name&page=1&page_size=5', ['page', 'page_size'], { order_by: 'name', page: 1, page_size: 5 }],
|
||||
['order_by=name&page=1&page_size=5', ['page_size'], { order_by: 'name', page: '1', page_size: 5 }],
|
||||
]
|
||||
.forEach(([queryString, integerFields, expectedQueryParams]) => {
|
||||
const actualQueryParams = parseQueryString(queryString, integerFields);
|
||||
|
||||
expect(actualQueryParams).toEqual(expectedQueryParams);
|
||||
});
|
||||
});
|
||||
|
||||
test('parseQueryString should strip leading "?"', () => {
|
||||
expect(parseQueryString('?foo=bar&order_by=win')).toEqual({
|
||||
foo: 'bar',
|
||||
order_by: 'win',
|
||||
});
|
||||
|
||||
expect(parseQueryString('foo=bar&order_by=?win')).toEqual({
|
||||
foo: 'bar',
|
||||
order_by: '?win',
|
||||
});
|
||||
});
|
||||
|
||||
test('should return empty object if no values', () => {
|
||||
expect(parseQueryString('')).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
test('should get default QS config object', () => {
|
||||
expect(getQSConfig('organization')).toEqual({
|
||||
namespace: 'organization',
|
||||
defaultParams: { page: 1, page_size: 5, order_by: 'name' },
|
||||
integerFields: ['page', 'page_size'],
|
||||
});
|
||||
});
|
||||
|
||||
test('should throw if no namespace given', () => {
|
||||
expect(() => getQSConfig()).toThrow();
|
||||
});
|
||||
|
||||
test('should build configured QS config object', () => {
|
||||
const defaults = {
|
||||
page: 1,
|
||||
page_size: 15,
|
||||
};
|
||||
expect(getQSConfig('inventory', defaults)).toEqual({
|
||||
namespace: 'inventory',
|
||||
defaultParams: { page: 1, page_size: 15 },
|
||||
integerFields: ['page', 'page_size'],
|
||||
});
|
||||
});
|
||||
|
||||
describe('parseNamespacedQueryString', () => {
|
||||
test('should get query params', () => {
|
||||
const config = {
|
||||
namespace: null,
|
||||
defaultParams: { page: 1, page_size: 15 },
|
||||
integerFields: ['page', 'page_size'],
|
||||
};
|
||||
const query = '?foo=bar&page=3';
|
||||
expect(parseNamespacedQueryString(config, query)).toEqual({
|
||||
foo: 'bar',
|
||||
page: 3,
|
||||
page_size: 15,
|
||||
});
|
||||
});
|
||||
|
||||
test('should get query params with correct integer fields', () => {
|
||||
const config = {
|
||||
namespace: null,
|
||||
defaultParams: {},
|
||||
integerFields: ['page', 'foo'],
|
||||
};
|
||||
const query = '?foo=4&bar=5';
|
||||
expect(parseNamespacedQueryString(config, query)).toEqual({
|
||||
foo: 4,
|
||||
bar: '5',
|
||||
});
|
||||
});
|
||||
|
||||
test('should get namespaced query params', () => {
|
||||
const config = {
|
||||
namespace: 'inventory',
|
||||
defaultParams: { page: 1, page_size: 5 },
|
||||
integerFields: ['page', 'page_size'],
|
||||
};
|
||||
const query = '?inventory.page=2&inventory.order_by=name&other=15';
|
||||
expect(parseNamespacedQueryString(config, query)).toEqual({
|
||||
page: 2,
|
||||
order_by: 'name',
|
||||
page_size: 5,
|
||||
});
|
||||
});
|
||||
|
||||
test('should exclude other namespaced query params', () => {
|
||||
const config = {
|
||||
namespace: 'inventory',
|
||||
defaultParams: { page: 1, page_size: 5 },
|
||||
integerFields: ['page', 'page_size'],
|
||||
};
|
||||
const query = '?inventory.page=2&inventory.order_by=name&foo.other=15';
|
||||
expect(parseNamespacedQueryString(config, query)).toEqual({
|
||||
page: 2,
|
||||
order_by: 'name',
|
||||
page_size: 5,
|
||||
});
|
||||
});
|
||||
|
||||
test('should exclude defaults if includeDefaults is false', () => {
|
||||
const config = {
|
||||
namespace: null,
|
||||
defaultParams: { page: 1, page_size: 15 },
|
||||
integerFields: ['page', 'page_size'],
|
||||
};
|
||||
const query = '?foo=bar&page=3';
|
||||
expect(parseNamespacedQueryString(config, query, false)).toEqual({
|
||||
foo: 'bar',
|
||||
page: 3,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('encodeNamespacedQueryString', () => {
|
||||
test('should encode params without namespace', () => {
|
||||
const config = {
|
||||
namespace: null,
|
||||
defaultParams: { page: 1, page_size: 5 },
|
||||
integerFields: ['page', 'page_size'],
|
||||
};
|
||||
const params = {
|
||||
page: 1,
|
||||
order_by: 'name',
|
||||
};
|
||||
const qs = 'order_by=name&page=1';
|
||||
expect(encodeNamespacedQueryString(config, params)).toEqual(qs);
|
||||
});
|
||||
|
||||
test('should encode params with namespace', () => {
|
||||
const config = {
|
||||
namespace: 'inventory',
|
||||
defaultParams: { page: 1, page_size: 5 },
|
||||
integerFields: ['page', 'page_size'],
|
||||
};
|
||||
const params = {
|
||||
page: 1,
|
||||
order_by: 'name',
|
||||
};
|
||||
const qs = 'inventory.order_by=name&inventory.page=1';
|
||||
expect(encodeNamespacedQueryString(config, params)).toEqual(qs);
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateNamespacedQueryString', () => {
|
||||
test('should return current values', () => {
|
||||
const qs = '?foo=bar&inventory.page=1';
|
||||
const updated = updateNamespacedQueryString({}, qs, {});
|
||||
expect(updated).toEqual('foo=bar&inventory.page=1');
|
||||
});
|
||||
|
||||
test('should update new values', () => {
|
||||
const qs = '?foo=bar&inventory.page=1';
|
||||
const updated = updateNamespacedQueryString({}, qs, { foo: 'baz' });
|
||||
expect(updated).toEqual('foo=baz&inventory.page=1');
|
||||
});
|
||||
|
||||
test('should add new values', () => {
|
||||
const qs = '?foo=bar&inventory.page=1';
|
||||
const updated = updateNamespacedQueryString({}, qs, { page: 5 });
|
||||
expect(updated).toEqual('foo=bar&inventory.page=1&page=5');
|
||||
});
|
||||
|
||||
test('should update namespaced values', () => {
|
||||
const qs = '?foo=bar&inventory.page=1';
|
||||
const config = { namespace: 'inventory' };
|
||||
const updated = updateNamespacedQueryString(config, qs, { page: 2 });
|
||||
expect(updated).toEqual('foo=bar&inventory.page=2');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,34 +0,0 @@
|
||||
import { pluralize, getArticle, ucFirst } from '../../src/util/strings';
|
||||
|
||||
describe('string utils', () => {
|
||||
describe('pluralize', () => {
|
||||
test('should add an "s"', () => {
|
||||
expect(pluralize('team')).toEqual('teams');
|
||||
});
|
||||
|
||||
test('should add an "es"', () => {
|
||||
expect(pluralize('class')).toEqual('classes');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getArticle', () => {
|
||||
test('should return "a"', () => {
|
||||
expect(getArticle('team')).toEqual('a');
|
||||
expect(getArticle('notification')).toEqual('a');
|
||||
});
|
||||
|
||||
test('should return "an"', () => {
|
||||
expect(getArticle('aardvark')).toEqual('an');
|
||||
expect(getArticle('ear')).toEqual('an');
|
||||
expect(getArticle('interest')).toEqual('an');
|
||||
expect(getArticle('ogre')).toEqual('an');
|
||||
expect(getArticle('umbrella')).toEqual('an');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ucFirst', () => {
|
||||
test('should capitalize first character', () => {
|
||||
expect(ucFirst('team')).toEqual('Team');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,36 +0,0 @@
|
||||
import { required, maxLength } from '../../src/util/validators';
|
||||
|
||||
const i18n = { _: val => val };
|
||||
|
||||
describe('validators', () => {
|
||||
test('required returns undefined if value given', () => {
|
||||
expect(required(null, i18n)('some value')).toBeUndefined();
|
||||
expect(required('oops', i18n)('some value')).toBeUndefined();
|
||||
});
|
||||
|
||||
test('required returns default message if value missing', () => {
|
||||
expect(required(null, i18n)('')).toEqual({ id: 'This field must not be blank' });
|
||||
});
|
||||
|
||||
test('required returns custom message if value missing', () => {
|
||||
expect(required('oops', i18n)('')).toEqual('oops');
|
||||
});
|
||||
|
||||
test('required interprets white space as empty value', () => {
|
||||
expect(required(null, i18n)(' ')).toEqual({ id: 'This field must not be blank' });
|
||||
expect(required(null, i18n)('\t')).toEqual({ id: 'This field must not be blank' });
|
||||
});
|
||||
|
||||
test('maxLength accepts value below max', () => {
|
||||
expect(maxLength(10, i18n)('snazzy')).toBeUndefined();
|
||||
});
|
||||
|
||||
test('maxLength accepts value equal to max', () => {
|
||||
expect(maxLength(10, i18n)('abracadbra')).toBeUndefined();
|
||||
});
|
||||
|
||||
test('maxLength rejects value above max', () => {
|
||||
expect(maxLength(8, i18n)('abracadbra'))
|
||||
.toEqual({ id: 'This field must not exceed {max} characters', values: { max: 8 } });
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user