Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 19 additions & 8 deletions awx/ui/src/components/About/About.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import { mountWithContexts } from '../../../testUtils/enzymeHelpers';
import { screen } from '@testing-library/react';
import { renderWithContexts } from '../../../testUtils/rtlContexts';
import About from './About';

jest.mock('../../hooks/useBrandName', () => ({
Expand All @@ -8,14 +9,24 @@ jest.mock('../../hooks/useBrandName', () => ({
}));

describe('<About />', () => {
test('should render AboutModal', () => {
test('should render AboutModal with product name and version', () => {
const onClose = jest.fn();
const wrapper = mountWithContexts(<About isOpen onClose={onClose} />);
renderWithContexts(<About isOpen onClose={onClose} version="1.2.3" />);

const modal = wrapper.find('AboutModal');
expect(modal).toHaveLength(1);
expect(modal.prop('onClose')).toEqual(onClose);
expect(modal.prop('productName')).toEqual('AWX');
expect(modal.prop('isOpen')).toEqual(true);
// AboutModal renders into a body portal; the product name surfaces as the
// dialog's accessible name.
const dialog = screen.getByRole('dialog');
expect(dialog).toBeInTheDocument();
expect(screen.getByText('AWX')).toBeInTheDocument();

// The version is rendered inside the speech-bubble <pre>.
const pre = dialog.querySelector('pre');
expect(pre.textContent).toContain('AWX 1.2.3');
});

test('should not render when isOpen is false', () => {
const onClose = jest.fn();
renderWithContexts(<About onClose={onClose} version="1.2.3" />);
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
});
});
38 changes: 22 additions & 16 deletions awx/ui/src/components/AddDropDownButton/AddDropDownButton.test.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,42 @@
import React from 'react';
import { screen, waitFor } from '@testing-library/react';
import { DropdownItem } from '@patternfly/react-core';
import { mountWithContexts } from '../../../testUtils/enzymeHelpers';
import { renderWithContexts } from '../../../testUtils/rtlContexts';
import AddDropDownButton from './AddDropDownButton';

describe('<AddDropDownButton />', () => {
const dropdownItems = [
<DropdownItem key="add">Add</DropdownItem>,
<DropdownItem key="route">Route</DropdownItem>,
];

test('should be closed initially', () => {
const wrapper = mountWithContexts(
<AddDropDownButton dropdownItems={dropdownItems} />
);
expect(wrapper.find('Dropdown').prop('isOpen')).toEqual(false);
renderWithContexts(<AddDropDownButton dropdownItems={dropdownItems} />);
expect(screen.queryByRole('menuitem')).not.toBeInTheDocument();
});

test('should render two links', () => {
const wrapper = mountWithContexts(
test('should render the dropdown items when opened', async () => {
const { user } = renderWithContexts(
<AddDropDownButton dropdownItems={dropdownItems} />
);
wrapper.find('button').simulate('click');
expect(wrapper.find('Dropdown').prop('isOpen')).toEqual(true);
expect(wrapper.find('DropdownItem')).toHaveLength(dropdownItems.length);
await user.click(screen.getByRole('button', { name: 'Add' }));
await waitFor(() =>
expect(screen.getAllByRole('menuitem')).toHaveLength(dropdownItems.length)
);
});

test('should close when button re-clicked', () => {
const wrapper = mountWithContexts(
test('should close when button re-clicked', async () => {
const { user } = renderWithContexts(
<AddDropDownButton dropdownItems={dropdownItems} />
);
wrapper.find('button').simulate('click');
expect(wrapper.find('Dropdown').prop('isOpen')).toEqual(true);
wrapper.find('button').simulate('click');
expect(wrapper.find('Dropdown').prop('isOpen')).toEqual(false);
const toggle = screen.getByRole('button', { name: 'Add' });
await user.click(toggle);
await waitFor(() =>
expect(screen.getAllByRole('menuitem')).toHaveLength(dropdownItems.length)
);
await user.click(toggle);
await waitFor(() =>
expect(screen.queryByRole('menuitem')).not.toBeInTheDocument()
);
});
});
32 changes: 21 additions & 11 deletions awx/ui/src/components/AnsibleSelect/AnsibleSelect.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import { mountWithContexts } from '../../../testUtils/enzymeHelpers';
import { screen } from '@testing-library/react';
import { renderWithContexts } from '../../../testUtils/rtlContexts';
import AnsibleSelect from './AnsibleSelect';

const mockData = [
Expand All @@ -16,9 +17,8 @@ const mockData = [
];

describe('<AnsibleSelect />', () => {
const onChange = jest.fn();
test('initially renders successfully', async () => {
mountWithContexts(
test('initially renders successfully', () => {
renderWithContexts(
<AnsibleSelect
id="bar"
value="foo"
Expand All @@ -27,25 +27,33 @@ describe('<AnsibleSelect />', () => {
data={mockData}
/>
);
expect(screen.getByRole('combobox')).toBeInTheDocument();
});

test('calls "onSelectChange" on dropdown select change', () => {
const wrapper = mountWithContexts(
test('calls "onChange" on dropdown select change', async () => {
const onChange = jest.fn();
const { user } = renderWithContexts(
<AnsibleSelect
id="bar"
value="foo"
value="/var/lib/awx/venv/baz/"
name="bar"
onChange={onChange}
data={mockData}
/>
);
expect(onChange).not.toHaveBeenCalled();
wrapper.find('select').simulate('change');
await user.selectOptions(
screen.getByRole('combobox'),
'/var/lib/awx/venv/ansible/'
);
expect(onChange).toHaveBeenCalled();
// onSelectChange forwards (event, value); the selected value is the option.
const [, value] = onChange.mock.calls[0];
expect(value).toEqual('/var/lib/awx/venv/ansible/');
});

test('Returns correct select options', () => {
const wrapper = mountWithContexts(
renderWithContexts(
<AnsibleSelect
id="bar"
value="foo"
Expand All @@ -55,7 +63,9 @@ describe('<AnsibleSelect />', () => {
/>
);

expect(wrapper.find('FormSelect')).toHaveLength(1);
expect(wrapper.find('FormSelectOption')).toHaveLength(2);
expect(screen.getByRole('combobox')).toBeInTheDocument();
const options = screen.getAllByRole('option');
expect(options).toHaveLength(2);
expect(options.map((o) => o.textContent)).toEqual(['Baz', 'Default']);
});
});
96 changes: 54 additions & 42 deletions awx/ui/src/components/AssociateModal/AssociateModal.test.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
import React from 'react';
import { act } from 'react-dom/test-utils';

import {
mountWithContexts,
waitForElement,
} from '../../../testUtils/enzymeHelpers';
import { screen, waitFor, within } from '@testing-library/react';
import { renderWithContexts } from '../../../testUtils/rtlContexts';
import AssociateModal from './AssociateModal';
import mockHosts from './data.hosts.json';

jest.mock('../../api');

describe('<AssociateModal />', () => {
let wrapper;
let onClose;
let onAssociate;
let fetchRequest;
let optionsRequest;

beforeEach(async () => {
beforeEach(() => {
onClose = jest.fn();
onAssociate = jest.fn().mockResolvedValue();
fetchRequest = jest.fn().mockReturnValue({ data: { ...mockHosts } });
Expand All @@ -30,55 +25,72 @@ describe('<AssociateModal />', () => {
related_search_fields: [],
},
});
await act(async () => {
wrapper = mountWithContexts(
<AssociateModal
onClose={onClose}
onAssociate={onAssociate}
fetchRequest={fetchRequest}
optionsRequest={optionsRequest}
isModalOpen
/>
);
});
await waitForElement(wrapper, 'ContentLoading', (el) => el.length === 0);
});

afterEach(() => {
jest.clearAllMocks();
});

test('should render successfully', () => {
expect(wrapper.find('AssociateModal').length).toBe(1);
});
async function setup() {
const result = renderWithContexts(
<AssociateModal
onClose={onClose}
onAssociate={onAssociate}
fetchRequest={fetchRequest}
optionsRequest={optionsRequest}
isModalOpen
/>
);
// wait for the loading state to clear and rows to render
await waitFor(() =>
expect(screen.queryByRole('progressbar')).not.toBeInTheDocument()
);
return result;
}

test('should fetch and render list items', () => {
test('should fetch and render list items', async () => {
await setup();
expect(fetchRequest).toHaveBeenCalledTimes(1);
expect(optionsRequest).toHaveBeenCalledTimes(1);
expect(wrapper.find('CheckboxListItem').length).toBe(3);
// three hosts in the mock fixture, each rendered as a selectable row
expect(screen.getAllByRole('checkbox')).toHaveLength(mockHosts.count);
});

test('should update selected list chips when items are selected', () => {
expect(wrapper.find('SelectedList Chip')).toHaveLength(0);
act(() => {
wrapper.find('CheckboxListItem').first().invoke('onSelect')();
});
wrapper.update();
expect(wrapper.find('SelectedList Chip')).toHaveLength(1);
wrapper.find('SelectedList Chip button').simulate('click');
expect(wrapper.find('SelectedList Chip')).toHaveLength(0);
test('should update selected list chips when items are selected', async () => {
const { user } = await setup();
const dialog = screen.getByRole('dialog');
// no chips initially
expect(within(dialog).queryByText('Selected')).not.toBeInTheDocument();

const [firstCheckbox] = screen.getAllByRole('checkbox');
await user.click(firstCheckbox);

await waitFor(() =>
expect(within(dialog).getByText('Selected')).toBeInTheDocument()
);
// the selected host name appears as a chip
const firstName = mockHosts.results[0].name;
expect(screen.getAllByText(firstName).length).toBeGreaterThanOrEqual(1);
});

test('save button should call onAssociate', () => {
act(() => {
wrapper.find('CheckboxListItem').first().invoke('onSelect')();
});
wrapper.find('button[aria-label="Save"]').simulate('click');
expect(onAssociate).toHaveBeenCalledTimes(1);
test('save button should call onAssociate', async () => {
const { user } = await setup();
const [firstCheckbox] = screen.getAllByRole('checkbox');
await user.click(firstCheckbox);

const saveButton = screen.getByRole('button', { name: 'Save' });
await waitFor(() => expect(saveButton).toBeEnabled());
await user.click(saveButton);

await waitFor(() => expect(onAssociate).toHaveBeenCalledTimes(1));
expect(onAssociate).toHaveBeenCalledWith([
expect.objectContaining({ id: mockHosts.results[0].id }),
]);
});

test('cancel button should call onClose', () => {
wrapper.find('button[aria-label="Cancel"]').simulate('click');
test('cancel button should call onClose', async () => {
const { user } = await setup();
await user.click(screen.getByRole('button', { name: 'Cancel' }));
expect(onClose).toHaveBeenCalledTimes(1);
});
});
Loading