Merge pull request #4469 from jakemcdermott/lookup-tests

refactor lookup tests

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
This commit is contained in:
softwarefactory-project-zuul[bot] 2019-08-13 17:46:02 +00:00 committed by GitHub
commit 8fbda8a773
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,285 +1,362 @@
/* eslint-disable react/jsx-pascal-case */
import React from 'react';
import { createMemoryHistory } from 'history';
import { mountWithContexts } from '../../../testUtils/enzymeHelpers';
import { mountWithContexts, waitForElement } from '@testUtils/enzymeHelpers';
import Lookup, { _Lookup } from './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"
multiple
/>
);
/**
* Check that an element is present on the document body
* @param {selector} query selector
*/
function checkRootElementPresent(selector) {
const queryResult = global.document.querySelector(selector);
expect(queryResult).not.toEqual(null);
}
/**
* Check that an element isn't present on the document body
* @param {selector} query selector
*/
function checkRootElementNotPresent(selector) {
const queryResult = global.document.querySelector(selector);
expect(queryResult).toEqual(null);
}
/**
* Check lookup input group tags for expected values
* @param {wrapper} enzyme wrapper instance
* @param {expected} array of expected tag values
*/
async function checkInputTagValues(wrapper, expected) {
checkRootElementNotPresent('body div[role="dialog"]');
// check input group chip values
const chips = await waitForElement(
wrapper,
'Lookup InputGroup Chip span',
el => el.length === expected.length
);
expect(chips).toHaveLength(expected.length);
chips.forEach((el, index) => {
expect(el.text()).toEqual(expected[index]);
});
}
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"
multiple
/>
).find('Lookup');
setImmediate(() => {
expect(wrapper.state().results).toEqual([
{ id: 1, name: 'test instance' },
]);
done();
});
/**
* Check lookup modal list for expected values
* @param {wrapper} enzyme wrapper instance
* @param {expected} array of [selected, text] pairs describing
* the expected visible state of the modal data list
*/
async function checkModalListValues(wrapper, expected) {
// fail if modal isn't actually visible
checkRootElementPresent('body div[role="dialog"]');
// check list item values
const rows = await waitForElement(
wrapper,
'DataListItemRow',
el => el.length === expected.length
);
expect(rows).toHaveLength(expected.length);
rows.forEach((el, index) => {
const [expectedChecked, expectedText] = expected[index];
expect(expectedText).toEqual(el.text());
expect(expectedChecked).toEqual(el.find('input').props().checked);
});
}
test('Opens modal when search icon is clicked', () => {
const spy = jest.spyOn(_Lookup.prototype, 'handleModalToggle');
const mockSelected = [{ name: 'foo', id: 1 }];
const wrapper = mountWithContexts(
/**
* Check lookup modal selection tags for expected values
* @param {wrapper} enzyme wrapper instance
* @param {expected} array of expected tag values
*/
async function checkModalTagValues(wrapper, expected) {
// fail if modal isn't actually visible
checkRootElementPresent('body div[role="dialog"]');
// check modal chip values
const chips = await waitForElement(
wrapper,
'Modal Chip span',
el => el.length === expected.length
);
expect(chips).toHaveLength(expected.length);
chips.forEach((el, index) => {
expect(el.text()).toEqual(expected[index]);
});
}
describe('<Lookup multiple/>', () => {
let wrapper;
let onChange;
beforeEach(() => {
const mockSelected = [{ name: 'foo', id: 1, url: '/api/v2/item/1' }];
onChange = jest.fn();
document.body.innerHTML = '';
wrapper = mountWithContexts(
<Lookup
id="search"
multiple
lookupHeader="Foo Bar"
name="fooBar"
name="foobar"
value={mockSelected}
onLookupSave={() => {}}
getItems={() => {}}
columns={mockColumns}
sortedColumnKey="name"
multiple
/>
).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"
multiple
/>
);
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"
multiple
/>
);
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"
multiple
/>
).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"
multiple
/>
).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"
multiple
/>
).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 call callback with selected single item', () => {
mockData = { name: 'foo', id: 1, isChecked: false, url: 'https://foo' };
const onLookupSaveFn = jest.fn();
const wrapper = mountWithContexts(
<Lookup
lookupHeader="Foo Bar"
name="fooBar"
value={mockData}
onLookupSave={onLookupSaveFn}
onLookupSave={onChange}
getItems={() => ({
data: {
results: [mockData],
count: 1,
count: 2,
results: [
...mockSelected,
{ name: 'bar', id: 2, url: '/api/v2/item/2' },
],
},
})}
columns={mockColumns}
sortedColumnKey="name"
/>
);
});
test('Initially renders succesfully', () => {
expect(wrapper.find('Lookup')).toHaveLength(1);
});
test('Expected items are shown', async done => {
expect(wrapper.find('Lookup')).toHaveLength(1);
await checkInputTagValues(wrapper, ['foo']);
done();
});
test('Open and close modal', async done => {
checkRootElementNotPresent('body div[role="dialog"]');
wrapper.find('button[aria-label="Search"]').simulate('click');
checkRootElementPresent('body div[role="dialog"]');
// This check couldn't pass unless api response was formatted properly
await checkModalListValues(wrapper, [[true, 'foo'], [false, 'bar']]);
wrapper.find('Modal button[aria-label="Close"]').simulate('click');
checkRootElementNotPresent('body div[role="dialog"]');
wrapper.find('button[aria-label="Search"]').simulate('click');
checkRootElementPresent('body div[role="dialog"]');
wrapper
.find('Lookup')
.instance()
.toggleSelected({
id: 1,
name: 'foo',
});
.find('Modal button')
.findWhere(e => e.text() === 'Cancel')
.first()
.simulate('click');
checkRootElementNotPresent('body div[role="dialog"]');
done();
});
test('Add item with checkbox then save', async done => {
wrapper.find('button[aria-label="Search"]').simulate('click');
await checkModalListValues(wrapper, [[true, 'foo'], [false, 'bar']]);
wrapper
.find('Lookup')
.instance()
.saveModal();
expect(onLookupSaveFn).toHaveBeenCalledWith(
{
id: 1,
name: 'foo',
},
'fooBar'
.find('DataListItemRow')
.findWhere(el => el.text() === 'bar')
.find('input[type="checkbox"]')
.simulate('change');
await checkModalListValues(wrapper, [[true, 'foo'], [true, 'bar']]);
wrapper
.find('Modal button')
.findWhere(e => e.text() === 'Save')
.first()
.simulate('click');
expect(onChange).toHaveBeenCalledTimes(1);
expect(onChange.mock.calls[0][0].map(({ name }) => name)).toEqual([
'foo',
'bar',
]);
done();
});
test('Add item with checkbox then cancel', async done => {
wrapper.find('button[aria-label="Search"]').simulate('click');
await checkModalListValues(wrapper, [[true, 'foo'], [false, 'bar']]);
wrapper
.find('DataListItemRow')
.findWhere(el => el.text() === 'bar')
.find('input[type="checkbox"]')
.simulate('change');
await checkModalListValues(wrapper, [[true, 'foo'], [true, 'bar']]);
wrapper
.find('Modal button')
.findWhere(e => e.text() === 'Cancel')
.first()
.simulate('click');
expect(onChange).toHaveBeenCalledTimes(0);
await checkInputTagValues(wrapper, ['foo']);
done();
});
test('Remove item with checkbox', async done => {
wrapper.find('button[aria-label="Search"]').simulate('click');
await checkModalListValues(wrapper, [[true, 'foo'], [false, 'bar']]);
await checkModalTagValues(wrapper, ['foo']);
wrapper
.find('DataListItemRow')
.findWhere(el => el.text() === 'foo')
.find('input[type="checkbox"]')
.simulate('change');
await checkModalListValues(wrapper, [[false, 'foo'], [false, 'bar']]);
await checkModalTagValues(wrapper, []);
done();
});
test('Remove item with selected icon button', async done => {
wrapper.find('button[aria-label="Search"]').simulate('click');
await checkModalListValues(wrapper, [[true, 'foo'], [false, 'bar']]);
await checkModalTagValues(wrapper, ['foo']);
wrapper
.find('Modal Chip')
.findWhere(el => el.text() === 'foo')
.first()
.find('button')
.simulate('click');
await checkModalListValues(wrapper, [[false, 'foo'], [false, 'bar']]);
await checkModalTagValues(wrapper, []);
done();
});
test('Remove item with input group button', async done => {
await checkInputTagValues(wrapper, ['foo']);
wrapper
.find('Lookup InputGroup Chip')
.findWhere(el => el.text() === 'foo')
.first()
.find('button')
.simulate('click');
expect(onChange).toHaveBeenCalledTimes(1);
expect(onChange).toHaveBeenCalledWith([], 'foobar');
done();
});
});
describe('<Lookup />', () => {
let wrapper;
let onChange;
beforeEach(() => {
const mockSelected = { name: 'foo', id: 1, url: '/api/v2/item/1' };
onChange = jest.fn();
document.body.innerHTML = '';
wrapper = mountWithContexts(
<Lookup
lookupHeader="Foo Bar"
name="foobar"
value={mockSelected}
onLookupSave={onChange}
getItems={() => ({
data: {
count: 2,
results: [
mockSelected,
{ name: 'bar', id: 2, url: '/api/v2/item/2' },
],
},
})}
columns={mockColumns}
sortedColumnKey="name"
/>
);
});
test('should re-fetch data when URL params change', async () => {
test('Initially renders succesfully', () => {
expect(wrapper.find('Lookup')).toHaveLength(1);
});
test('Expected items are shown', async done => {
expect(wrapper.find('Lookup')).toHaveLength(1);
await checkInputTagValues(wrapper, ['foo']);
done();
});
test('Open and close modal', async done => {
checkRootElementNotPresent('body div[role="dialog"]');
wrapper.find('button[aria-label="Search"]').simulate('click');
checkRootElementPresent('body div[role="dialog"]');
// This check couldn't pass unless api response was formatted properly
await checkModalListValues(wrapper, [[true, 'foo'], [false, 'bar']]);
wrapper.find('Modal button[aria-label="Close"]').simulate('click');
checkRootElementNotPresent('body div[role="dialog"]');
wrapper.find('button[aria-label="Search"]').simulate('click');
checkRootElementPresent('body div[role="dialog"]');
wrapper
.find('Modal button')
.findWhere(e => e.text() === 'Cancel')
.first()
.simulate('click');
checkRootElementNotPresent('body div[role="dialog"]');
done();
});
test('Change selected item with radio control then save', async done => {
wrapper.find('button[aria-label="Search"]').simulate('click');
await checkModalListValues(wrapper, [[true, 'foo'], [false, 'bar']]);
await checkModalTagValues(wrapper, ['foo']);
wrapper
.find('DataListItemRow')
.findWhere(el => el.text() === 'bar')
.find('input[type="radio"]')
.simulate('change');
await checkModalListValues(wrapper, [[false, 'foo'], [true, 'bar']]);
await checkModalTagValues(wrapper, ['bar']);
wrapper
.find('Modal button')
.findWhere(e => e.text() === 'Save')
.first()
.simulate('click');
expect(onChange).toHaveBeenCalledTimes(1);
const [[{ name }]] = onChange.mock.calls;
expect(name).toEqual('bar');
done();
});
test('Change selected item with checkbox then cancel', async done => {
wrapper.find('button[aria-label="Search"]').simulate('click');
await checkModalListValues(wrapper, [[true, 'foo'], [false, 'bar']]);
await checkModalTagValues(wrapper, ['foo']);
wrapper
.find('DataListItemRow')
.findWhere(el => el.text() === 'bar')
.find('input[type="radio"]')
.simulate('change');
await checkModalListValues(wrapper, [[false, 'foo'], [true, 'bar']]);
await checkModalTagValues(wrapper, ['bar']);
wrapper
.find('Modal button')
.findWhere(e => e.text() === 'Cancel')
.first()
.simulate('click');
expect(onChange).toHaveBeenCalledTimes(0);
done();
});
test('should re-fetch data when URL params change', async done => {
mockData = [{ name: 'foo', id: 1, isChecked: false }];
const history = createMemoryHistory({
initialEntries: ['/organizations/add'],
});
const getItems = jest.fn();
const wrapper = mountWithContexts(
const LookupWrapper = mountWithContexts(
<_Lookup
multiple
name="foo"
lookupHeader="Foo Bar"
onLookupSave={() => {}}
value={mockData}
selected={[]}
columns={mockColumns}
sortedColumnKey="name"
getItems={getItems}
multiple
handleHttpError={() => {}}
location={{ history }}
i18n={{ _: val => val.toString() }}
/>
);
expect(getItems).toHaveBeenCalledTimes(1);
history.push('organizations/add?page=2');
wrapper.setProps({
LookupWrapper.setProps({
location: { history },
});
wrapper.update();
LookupWrapper.update();
expect(getItems).toHaveBeenCalledTimes(2);
done();
});
});