Upgrade to react 16.0.0 (#15469) (#15530)

* get kibana to start with react 16.0.0

* ensure width and height for dashboard grid

* Update to Enzyme 3.x. (#12)

* Fix tests broken by Enzyme upgrade (#13)

* Update to Enzyme 3.x. (#12)

* Add findTestSubject test helper. Fix KuiCodeEditor tests.

* Fix KuiContextMenu tests.

* Fix KuiConfirmModal tests.

* Fix tests for KuiPager.

* Update KuiConfirmModal tests to use findTestSubject helper.

* Publish test helpers from ui_framework. Fix DashboardCloneModal tests.

* Fix more tests (#14)

* Fix DashboardPanelContainer tests.

* Update KuiColorPicker tests.

* Fix ControlsTab tests.

* Rename vis to input_control_vis. Update and fix InputControlVis tests.

* Fix KuiListingTable tests.

* Fix KuiTextInput tests.

* Update DashboardGrid test snapshots.

* Fix test file names (#15)

* Remove old enzyme setup file.

* Add .test to YesNo and AddDeleteButtons test files.

* needed window.cancelAnimationFrame to accompany requestAnimationFrame

* remove getDOMNode function call from findTestSubject
This commit is contained in:
Nathan Reese 2017-12-11 15:26:47 -07:00 committed by GitHub
parent b58beede63
commit f4e94f70b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 214 additions and 171 deletions

View file

@ -123,7 +123,7 @@
"expose-loader": "0.7.3",
"extract-text-webpack-plugin": "3.0.1",
"file-loader": "1.1.4",
"focus-trap-react": "3.0.3",
"focus-trap-react": "3.0.5",
"font-awesome": "4.4.0",
"glob": "5.0.13",
"glob-all": "3.0.1",
@ -155,28 +155,27 @@
"mkdirp": "0.5.1",
"moment": "2.13.0",
"moment-timezone": "0.5.4",
"ngreact": "0.3.0",
"ngreact": "0.5.1",
"no-ui-slider": "1.2.0",
"node-fetch": "1.3.2",
"pegjs": "0.9.0",
"postcss-loader": "2.0.6",
"prop-types": "15.5.8",
"proxy-from-env": "1.0.0",
"pui-react-overlay-trigger": "7.5.4",
"pui-react-tooltip": "7.5.4",
"pui-react-overlay-trigger": "8.3.3",
"pui-react-tooltip": "8.3.3",
"querystring-browser": "1.0.4",
"raw-loader": "0.5.1",
"react": "15.6.1",
"react": "16.0.0",
"react-ace": "5.2.2",
"react-test-renderer": "15.6.1",
"react-addons-test-utils": "15.6.0",
"react-anything-sortable": "1.6.1",
"react-addons-test-utils": "15.6.2",
"react-anything-sortable": "1.7.3",
"react-color": "2.11.7",
"react-dom": "15.6.1",
"react-dom": "16.0.0",
"react-grid-layout": "0.16.0",
"react-input-autosize": "1.1.0",
"react-input-range": "1.2.1",
"react-markdown": "2.4.2",
"react-markdown": "3.1.0",
"react-redux": "5.0.5",
"react-router": "2.0.0",
"react-router-dom": "4.2.2",
@ -184,8 +183,9 @@
"react-select": "1.0.0-rc.5",
"react-sizeme": "2.3.4",
"react-sortable": "1.1.0",
"react-toggle": "3.0.1",
"reactcss": "1.0.7",
"react-test-renderer": "16.0.0",
"react-toggle": "4.0.2",
"reactcss": "1.2.3",
"redux": "3.7.2",
"redux-actions": "2.2.1",
"redux-thunk": "2.2.0",
@ -228,8 +228,9 @@
"chokidar": "1.6.0",
"chromedriver": "2.33.2",
"classnames": "2.2.5",
"enzyme": "2.9.1",
"enzyme-to-json": "1.4.5",
"enzyme": "3.2.0",
"enzyme-adapter-react-16": "1.1.0",
"enzyme-to-json": "3.1.4",
"eslint": "4.10.0",
"eslint-plugin-babel": "4.1.2",
"eslint-plugin-import": "2.8.0",
@ -260,8 +261,8 @@
"husky": "0.8.1",
"image-diff": "1.6.0",
"istanbul-instrumenter-loader": "3.0.0",
"jest": "21.0.1",
"jest-cli": "21.0.1",
"jest": "21.2.1",
"jest-cli": "21.2.1",
"jsdom": "9.9.1",
"karma": "1.7.0",
"karma-chrome-launcher": "2.1.1",

View file

@ -27,6 +27,7 @@ exports[`renders ControlsTab 1`] = `
handleLabelChange={[Function]}
handleNumberOptionChange={[Function]}
handleRemoveControl={[Function]}
key="1"
moveControl={[Function]}
/>
<ControlEditor
@ -51,6 +52,7 @@ exports[`renders ControlsTab 1`] = `
handleLabelChange={[Function]}
handleNumberOptionChange={[Function]}
handleRemoveControl={[Function]}
key="2"
moveControl={[Function]}
/>
<div

View file

@ -1,7 +1,7 @@
import React from 'react';
import sinon from 'sinon';
import { mount, shallow } from 'enzyme';
import { findTestSubject } from 'ui_framework/test';
import {
ControlsTab,
} from './controls_tab';
@ -84,7 +84,7 @@ test('add control btn', () => {
scope={scopeMock}
stageEditorParams={stageEditorParams}
/>);
component.find('[data-test-subj="inputControlEditorAddBtn"]').simulate('click');
findTestSubject(component, 'inputControlEditorAddBtn').simulate('click');
// Use custom match function since control.id is dynamically generated and never the same.
sinon.assert.calledWith(stageEditorParams, sinon.match((newParams) => {
if (newParams.controls.length !== 3) {
@ -99,7 +99,7 @@ test('remove control btn', () => {
scope={scopeMock}
stageEditorParams={stageEditorParams}
/>);
component.find('[data-test-subj="inputControlEditorRemoveControl0"]').simulate('click');
findTestSubject(component, 'inputControlEditorRemoveControl0').simulate('click');
const expectedParams = {
'controls': [
{
@ -123,7 +123,7 @@ test('move down control btn', () => {
scope={scopeMock}
stageEditorParams={stageEditorParams}
/>);
component.find('[data-test-subj="inputControlEditorMoveDownControl0"]').simulate('click');
findTestSubject(component, 'inputControlEditorMoveDownControl0').simulate('click');
const expectedParams = {
'controls': [
{
@ -159,7 +159,7 @@ test('move up control btn', () => {
scope={scopeMock}
stageEditorParams={stageEditorParams}
/>);
component.find('[data-test-subj="inputControlEditorMoveUpControl1"]').simulate('click');
findTestSubject(component, 'inputControlEditorMoveUpControl1').simulate('click');
const expectedParams = {
'controls': [
{

View file

@ -12,6 +12,7 @@ exports[`Apply and Cancel change btns enabled when there are changes 1`] = `
>
<KuiFlexItem
grow={true}
key="mock-list-control"
style={
Object {
"minWidth": "250px",
@ -106,6 +107,7 @@ exports[`Clear btns enabled when there are values 1`] = `
>
<KuiFlexItem
grow={true}
key="mock-list-control"
style={
Object {
"minWidth": "250px",
@ -200,6 +202,7 @@ exports[`Renders list control 1`] = `
>
<KuiFlexItem
grow={true}
key="mock-list-control"
style={
Object {
"minWidth": "250px",
@ -294,6 +297,7 @@ exports[`Renders range control 1`] = `
>
<KuiFlexItem
grow={true}
key="mock-range-control"
style={
Object {
"minWidth": "250px",

View file

@ -1,10 +1,11 @@
import React from 'react';
import sinon from 'sinon';
import { mount, shallow } from 'enzyme';
import { findTestSubject } from 'ui_framework/test';
import {
InputControlVis,
} from './vis';
} from './input_control_vis';
const mockListControl = {
id: 'mock-list-control',
@ -114,7 +115,7 @@ test('clearControls', () => {
hasChanges={() => { return true; }}
hasValues={() => { return true; }}
/>);
component.find('[data-test-subj="inputControlClearBtn"]').simulate('click');
findTestSubject(component, 'inputControlClearBtn').simulate('click');
sinon.assert.calledOnce(clearControls);
sinon.assert.notCalled(submitFilters);
sinon.assert.notCalled(resetControls);
@ -132,7 +133,7 @@ test('submitFilters', () => {
hasChanges={() => { return true; }}
hasValues={() => { return true; }}
/>);
component.find('[data-test-subj="inputControlSubmitBtn"]').simulate('click');
findTestSubject(component, 'inputControlSubmitBtn').simulate('click');
sinon.assert.calledOnce(submitFilters);
sinon.assert.notCalled(clearControls);
sinon.assert.notCalled(resetControls);
@ -150,7 +151,7 @@ test('resetControls', () => {
hasChanges={() => { return true; }}
hasValues={() => { return true; }}
/>);
component.find('[data-test-subj="inputControlCancelBtn"]').simulate('click');
findTestSubject(component, 'inputControlCancelBtn').simulate('click');
sinon.assert.calledOnce(resetControls);
sinon.assert.notCalled(clearControls);
sinon.assert.notCalled(submitFilters);
@ -168,7 +169,7 @@ test('stageFilter list control', () => {
hasChanges={() => { return true; }}
hasValues={() => { return true; }}
/>);
const reactSelectInput = component.find(`#${mockListControl.id}`);
const reactSelectInput = component.find(`#${mockListControl.id}`).hostNodes();
reactSelectInput.simulate('change', { target: { value: 'choice1' } });
reactSelectInput.simulate('keyDown', { keyCode: 9, key: 'Tab' });
sinon.assert.notCalled(clearControls);

View file

@ -1,6 +1,6 @@
import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { InputControlVis } from './components/vis/vis';
import { InputControlVis } from './components/vis/input_control_vis';
import { controlFactory } from './control/control_factory';
class VisController {

View file

@ -26,6 +26,7 @@ exports[`renders DashboardGrid 1`] = `
>
<div
className=""
key="1"
>
<Connect(DashboardPanel)
embeddableFactory={
@ -45,6 +46,7 @@ exports[`renders DashboardGrid 1`] = `
</div>
<div
className=""
key="2"
>
<Connect(DashboardPanel)
embeddableFactory={

View file

@ -14,7 +14,7 @@ import { getEmbeddableFactoryMock } from '../__tests__/get_embeddable_factories_
import {
takeMountedSnapshot,
} from 'ui_framework/src/test';
} from 'ui_framework/test';
function getProps(props = {}) {
const defaultTestProps = {

View file

@ -35,8 +35,8 @@ test('renders an error when embeddableFactory.render throws an error', (done) =>
});
};
const component = mount(<Provider store={store}><DashboardPanelContainer {...props} /></Provider>);
setTimeout(() => {
component.update();
const panelError = component.find(PanelError);
expect(panelError.length).toBe(1);
done();

View file

@ -16,7 +16,7 @@ import {
import { getEmbeddableFactoryMock } from '../../__tests__/get_embeddable_factories_mock';
import {
TestSubjects,
} from 'ui_framework/src/test';
} from 'ui_framework/test';
function getProps(props = {}) {
const defaultTestProps = {

View file

@ -405,9 +405,13 @@ dashboard-viewport-provider {
}
.dashboard-viewport {
height: 100%;
width: 100%;
background-color: @dashboard-bg;
}
.dashboard-viewport-with-margins {
height: 100%;
width: 100%;
background-color: @dashboard-bg-with-margins;
}

View file

@ -1,6 +1,9 @@
import React from 'react';
import sinon from 'sinon';
import { mount, render } from 'enzyme';
import {
findTestSubject,
} from 'ui_framework/test';
import {
DashboardCloneModal,
@ -32,14 +35,14 @@ test('renders DashboardCloneModal', () => {
test('onClone', () => {
createComponent();
component.find('[data-test-subj="cloneConfirmButton"]').simulate('click');
findTestSubject(component, 'cloneConfirmButton', false).simulate('click');
sinon.assert.calledWith(onClone, 'dash title');
sinon.assert.notCalled(onClose);
});
test('onClose', () => {
createComponent();
component.find('[data-test-subj="cloneCancelButton"]').simulate('click');
findTestSubject(component, 'cloneCancelButton', false).simulate('click');
sinon.assert.calledOnce(onClose);
sinon.assert.notCalled(onClone);
});
@ -48,6 +51,6 @@ test('title', () => {
createComponent();
const event = { target: { value: 'a' } };
component.find('input').simulate('change', event);
component.find('[data-test-subj="cloneConfirmButton"]').simulate('click');
findTestSubject(component, 'cloneConfirmButton', false).simulate('click');
sinon.assert.calledWith(onClone, 'a');
});

View file

@ -2,10 +2,9 @@ import React from 'react';
import { expect } from 'chai';
import { shallow } from 'enzyme';
import sinon from 'sinon';
import AddDeleteButtons from '../add_delete_buttons';
describe('<AddDeleteButtons />', () => {
import AddDeleteButtons from './add_delete_buttons';
describe('AddDeleteButtons', () => {
it('calls onAdd={handleAdd}', () => {
const handleAdd = sinon.spy();
const wrapper = shallow(
@ -61,5 +60,4 @@ describe('<AddDeleteButtons />', () => {
);
expect(wrapper.find({ text: 'Clone' })).to.have.length(0);
});
});

View file

@ -1,4 +1,5 @@
import React, { Component, PropTypes } from 'react';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';
import uuid from 'uuid';
import AggRow from './agg_row';

View file

@ -1,4 +1,5 @@
import React, { Component, PropTypes } from 'react';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import FieldSelect from '../aggs/field_select';
import SeriesEditor from '../series_editor';
import { IndexPattern } from '../index_pattern';

View file

@ -1,4 +1,5 @@
import React, { Component, PropTypes } from 'react';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import uuid from 'uuid';
import DataFormatPicker from '../../data_format_picker';
import createSelectHandler from '../../lib/create_select_handler';

View file

@ -1,4 +1,5 @@
import React, { PropTypes } from 'react';
import React from 'react';
import PropTypes from 'prop-types';
import AddDeleteButtons from '../../add_delete_buttons';
import SeriesConfig from './config';
import Sortable from 'react-anything-sortable';

View file

@ -1,5 +1,6 @@
import _ from 'lodash';
import React, { Component, PropTypes } from 'react';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import ticFormatter from '../../lib/tick_formatter';
import calculateLabel from '../../../../common/calculate_label';
import { isSortable } from './is_sortable';

View file

@ -2,10 +2,9 @@ import React from 'react';
import { expect } from 'chai';
import { shallow } from 'enzyme';
import sinon from 'sinon';
import YesNo from '../yes_no';
describe('<YesNo />', () => {
import YesNo from './yes_no';
describe('YesNo', () => {
it('call onChange={handleChange} on yes', () => {
const handleChange = sinon.spy();
const wrapper = shallow(
@ -29,5 +28,4 @@ describe('<YesNo />', () => {
test: 0
});
});
});

View file

@ -16,14 +16,15 @@
"moduleNameMapper": {
"^ui_framework/components": "<rootDir>/ui_framework/components",
"^ui_framework/services": "<rootDir>/ui_framework/services",
"^ui_framework/src/test": "<rootDir>/ui_framework/src/test",
"^ui_framework/test": "<rootDir>/ui_framework/test",
"^ui/(.*)": "<rootDir>/src/ui/public/$1",
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/src/dev/jest/mocks/file_mock.js",
"\\.(css|less|scss)$": "<rootDir>/src/dev/jest/mocks/style_mock.js"
},
"setupFiles": [
"<rootDir>/src/dev/jest/setup/babel_polyfill.js",
"<rootDir>/src/dev/jest/setup/request_animation_frame_polyfill.js"
"<rootDir>/src/dev/jest/setup/request_animation_frame_polyfill.js",
"<rootDir>/src/dev/jest/setup/enzyme.js"
],
"coverageDirectory": "<rootDir>/target/jest-coverage",
"coverageReporters": [

View file

@ -0,0 +1,4 @@
import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
configure({ adapter: new Adapter() });

View file

@ -16,3 +16,7 @@ window.requestAnimationFrame = (() => {
}
};
})();
window.cancelAnimationFrame = (id) => {
clearTimeout(id);
};

View file

@ -2,23 +2,21 @@
exports[`KuiCodeEditor behavior hint element should be disabled when the ui ace box gains focus 1`] = `
<div
className="kuiCodeEditorKeyboardHint kuiCodeEditorKeyboardHint-isInactive"
class="kuiCodeEditorKeyboardHint"
data-test-subj="codeEditorHint"
id={42}
onClick={[Function]}
onKeyDown={[Function]}
id="42"
role="button"
tabIndex="0"
tabindex="0"
>
<p
className="kuiText kuiVerticalRhythmSmall"
class="kuiText kuiVerticalRhythmSmall"
>
Press Enter to start
editing
.
</p>
<p
className="kuiText kuiVerticalRhythmSmall"
class="kuiText kuiVerticalRhythmSmall"
>
When youre done, press Escape to stop
editing
@ -29,23 +27,46 @@ exports[`KuiCodeEditor behavior hint element should be disabled when the ui ace
exports[`KuiCodeEditor behavior hint element should be enabled when the ui ace box loses focus 1`] = `
<div
className="kuiCodeEditorKeyboardHint"
class="kuiCodeEditorKeyboardHint"
data-test-subj="codeEditorHint"
id={42}
onClick={[Function]}
onKeyDown={[Function]}
id="42"
role="button"
tabIndex="0"
tabindex="0"
>
<p
className="kuiText kuiVerticalRhythmSmall"
class="kuiText kuiVerticalRhythmSmall"
>
Press Enter to start
editing
.
</p>
<p
className="kuiText kuiVerticalRhythmSmall"
class="kuiText kuiVerticalRhythmSmall"
>
When youre done, press Escape to stop
editing
.
</p>
</div>
`;
exports[`KuiCodeEditor behavior hint element should be tabable 1`] = `
<div
class="kuiCodeEditorKeyboardHint"
data-test-subj="codeEditorHint"
id="42"
role="button"
tabindex="0"
>
<p
class="kuiText kuiVerticalRhythmSmall"
>
Press Enter to start
editing
.
</p>
<p
class="kuiText kuiVerticalRhythmSmall"
>
When youre done, press Escape to stop
editing
@ -68,28 +89,12 @@ exports[`KuiCodeEditor is rendered 1`] = `
<p
class="kuiText kuiVerticalRhythmSmall"
>
<!-- react-text: 4 -->
Press Enter to start
<!-- /react-text -->
<!-- react-text: 5 -->
editing
<!-- /react-text -->
<!-- react-text: 6 -->
.
<!-- /react-text -->
Press Enter to start editing.
</p>
<p
class="kuiText kuiVerticalRhythmSmall"
>
<!-- react-text: 8 -->
When youre done, press Escape to stop
<!-- /react-text -->
<!-- react-text: 9 -->
editing
<!-- /react-text -->
<!-- react-text: 10 -->
.
<!-- /react-text -->
When youre done, press Escape to stop editing.
</p>
</div>
<div
@ -197,28 +202,12 @@ exports[`KuiCodeEditor props isReadOnly renders alternate hint text 1`] = `
<p
class="kuiText kuiVerticalRhythmSmall"
>
<!-- react-text: 4 -->
Press Enter to start
<!-- /react-text -->
<!-- react-text: 5 -->
interacting with the code
<!-- /react-text -->
<!-- react-text: 6 -->
.
<!-- /react-text -->
Press Enter to start interacting with the code.
</p>
<p
class="kuiText kuiVerticalRhythmSmall"
>
<!-- react-text: 8 -->
When youre done, press Escape to stop
<!-- /react-text -->
<!-- react-text: 9 -->
interacting with the code
<!-- /react-text -->
<!-- react-text: 10 -->
.
<!-- /react-text -->
When youre done, press Escape to stop interacting with the code.
</p>
</div>
<div

View file

@ -4,6 +4,7 @@ import { mount } from 'enzyme';
import { KuiCodeEditor } from './code_editor';
import { keyCodes } from '../../services';
import {
findTestSubject,
requiredProps,
takeMountedSnapshot,
} from '../../test';
@ -37,20 +38,21 @@ describe('KuiCodeEditor', () => {
describe('hint element', () => {
test('should be tabable', () => {
expect(component.find('[data-test-subj="codeEditorHint"]').prop('tabIndex')).toBe('0');
const hint = findTestSubject(component, 'codeEditorHint').getDOMNode();
expect(hint).toMatchSnapshot();
});
test('should be disabled when the ui ace box gains focus', () => {
const hint = component.find('[data-test-subj="codeEditorHint"]');
hint.simulate('keydown', { keyCode: keyCodes.ENTER });
expect(hint).toMatchSnapshot();
const hint = findTestSubject(component, 'codeEditorHint');
hint.simulate('keyup', { keyCode: keyCodes.ENTER });
expect(findTestSubject(component, 'codeEditorHint').getDOMNode()).toMatchSnapshot();
});
test('should be enabled when the ui ace box loses focus', () => {
const hint = component.find('[data-test-subj="codeEditorHint"]');
hint.simulate('keydown', { keyCode: keyCodes.ENTER });
const hint = findTestSubject(component, 'codeEditorHint');
hint.simulate('keyup', { keyCode: keyCodes.ENTER });
component.instance().onBlurAce();
expect(hint).toMatchSnapshot();
expect(findTestSubject(component, 'codeEditorHint').getDOMNode()).toMatchSnapshot();
});
});
@ -66,11 +68,10 @@ describe('KuiCodeEditor', () => {
component.instance().onKeydownAce({
preventDefault: () => {},
stopPropagation: () => {},
keyCode: keyCodes.ESCAPE
keyCode: keyCodes.ESCAPE,
});
expect(
component.find('[data-test-subj="codeEditorHint"]').matchesElement(document.activeElement)
).toBe(true);
const hint = findTestSubject(component, 'codeEditorHint').getDOMNode();
expect(hint).toBe(document.activeElement);
});
});
});

View file

@ -12,7 +12,7 @@ exports[`renders KuiColorPicker 1`] = `
aria-label="aria-label"
class="kuiColorPicker__swatch"
data-test-subj="colorSwatch"
style="background:#ffeedd;"
style="background:#ffeedd"
/>
<div
aria-label="Color selection is #ffeedd"
@ -36,7 +36,7 @@ exports[`renders KuiColorPicker with an empty swatch when color is null 1`] = `
aria-label="aria-label"
class="kuiColorPicker__swatch kuiColorPicker__emptySwatch"
data-test-subj="colorSwatch"
style="background:;"
style="background:"
>
<svg>
<line
@ -69,7 +69,7 @@ exports[`renders KuiColorPicker without a color label when showColorLabel is fal
aria-label="aria-label"
class="kuiColorPicker__swatch"
data-test-subj="colorSwatch"
style="background:#ffffff;"
style="background:#ffffff"
/>
</div>
</div>

View file

@ -102,7 +102,6 @@ test('Setting a new color calls onChange', () => {
const event = { target: { value: '#000000' } };
const inputs = colorPicker.find('input');
expect(inputs.length).toBe(1);
inputs.get(0).value = '';
inputs.simulate('change', event);
sinon.assert.calledOnce(onChange);
sinon.assert.calledWith(onChange, '#000000');

View file

@ -18,6 +18,21 @@ exports[`KuiContextMenuItem is rendered 1`] = `
</button>
`;
exports[`KuiContextMenuItem props disabled is rendered 1`] = `
<button
class="kuiContextMenuItem kuiContextMenuItem-disabled"
disabled=""
>
<span
class="kuiContextMenu__itemLayout"
>
<span
class="kuiContextMenuItem__text"
/>
</span>
</button>
`;
exports[`KuiContextMenuItem props hasPanel is rendered 1`] = `
<button
class="kuiContextMenuItem"

View file

@ -29,6 +29,17 @@ describe('KuiContextMenuItem', () => {
});
});
describe('disabled', () => {
test('is rendered', () => {
const component = render(
<KuiContextMenuItem disabled />
);
expect(component)
.toMatchSnapshot();
});
});
describe('onClick', () => {
test(`isn't called upon instantiation`, () => {
const onClickHandler = sinon.stub();
@ -56,7 +67,7 @@ describe('KuiContextMenuItem', () => {
const onClickHandler = sinon.stub();
const component = mount(
<KuiContextMenuItem disabled={true} onClick={onClickHandler} />
<KuiContextMenuItem disabled onClick={onClickHandler} />
);
component.simulate('click');

View file

@ -1,7 +1,7 @@
import React from 'react';
import { render, shallow, mount } from 'enzyme';
import { render, mount } from 'enzyme';
import sinon from 'sinon';
import { requiredProps } from '../../test/required_props';
import { findTestSubject, requiredProps } from '../../test';
import {
KuiContextMenuPanel,
@ -75,7 +75,7 @@ describe('KuiContextMenuPanel', () => {
test(`isn't called upon instantiation`, () => {
const onCloseHandler = sinon.stub();
shallow(
mount(
<KuiContextMenuPanel title="Title" onClose={onCloseHandler} />
);
@ -85,7 +85,7 @@ describe('KuiContextMenuPanel', () => {
test('is called when the title is clicked', () => {
const onCloseHandler = sinon.stub();
const component = shallow(
const component = mount(
<KuiContextMenuPanel title="Title" onClose={onCloseHandler} />
);
@ -170,9 +170,7 @@ describe('KuiContextMenuPanel', () => {
/>
);
expect(
component.find('[data-test-subj="itemB"]').matchesElement(document.activeElement)
).toBe(true);
expect(findTestSubject(component, 'itemB').getDOMNode()).toBe(document.activeElement);
});
});
@ -278,9 +276,7 @@ describe('KuiContextMenuPanel', () => {
</KuiContextMenuPanel>
);
expect(
component.find('[data-test-subj="button"]').matchesElement(document.activeElement)
).toBe(true);
expect(findTestSubject(component, 'button').getDOMNode()).toBe(document.activeElement);
});
it('is not set on anything if hasFocus is false', () => {
@ -290,9 +286,7 @@ describe('KuiContextMenuPanel', () => {
</KuiContextMenuPanel>
);
expect(
component.find('[data-test-subj="button"]').matchesElement(document.activeElement)
).toBe(true);
expect(findTestSubject(component, 'button').getDOMNode()).not.toBe(document.activeElement);
});
});
@ -314,60 +308,48 @@ describe('KuiContextMenuPanel', () => {
);
});
it(`doesn't focus an item by default`, () => {
expect(component.find('[data-test-subj]').contains(document.activeElement)).toBe(false);
it(`focuses the panel by default`, () => {
expect(component.getDOMNode()).toBe(document.activeElement);
});
it('down arrow key focuses the first menu item', () => {
component.simulate('keydown', { keyCode: keyCodes.DOWN });
expect(
component.find('[data-test-subj="itemA"]').matchesElement(document.activeElement)
).toBe(true);
expect(findTestSubject(component, 'itemA').getDOMNode()).toBe(document.activeElement);
});
it('subsequently, down arrow key focuses the next menu item', () => {
component.simulate('keydown', { keyCode: keyCodes.DOWN });
component.simulate('keydown', { keyCode: keyCodes.DOWN });
expect(
component.find('[data-test-subj="itemB"]').matchesElement(document.activeElement)
).toBe(true);
expect(findTestSubject(component, 'itemB').getDOMNode()).toBe(document.activeElement);
});
it('down arrow key wraps to first menu item', () => {
component.simulate('keydown', { keyCode: keyCodes.UP });
component.simulate('keydown', { keyCode: keyCodes.DOWN });
expect(
component.find('[data-test-subj="itemA"]').matchesElement(document.activeElement)
).toBe(true);
expect(findTestSubject(component, 'itemA').getDOMNode()).toBe(document.activeElement);
});
it('up arrow key focuses the last menu item', () => {
component.simulate('keydown', { keyCode: keyCodes.UP });
expect(
component.find('[data-test-subj="itemC"]').matchesElement(document.activeElement)
).toBe(true);
expect(findTestSubject(component, 'itemC').getDOMNode()).toBe(document.activeElement);
});
it('subsequently, up arrow key focuses the previous menu item', () => {
component.simulate('keydown', { keyCode: keyCodes.UP });
component.simulate('keydown', { keyCode: keyCodes.UP });
expect(
component.find('[data-test-subj="itemB"]').matchesElement(document.activeElement)
).toBe(true);
expect(findTestSubject(component, 'itemB').getDOMNode()).toBe(document.activeElement);
});
it('up arrow key wraps to last menu item', () => {
component.simulate('keydown', { keyCode: keyCodes.DOWN });
component.simulate('keydown', { keyCode: keyCodes.UP });
expect(
component.find('[data-test-subj="itemC"]').matchesElement(document.activeElement)
).toBe(true);
expect(findTestSubject(component, 'itemC').getDOMNode()).toBe(document.activeElement);
});
it(`right arrow key shows next panel with focused item's index`, () => {

View file

@ -1,6 +1,6 @@
import React from 'react';
import { render, shallow, mount } from 'enzyme';
import { requiredProps } from '../../../test/required_props';
import { requiredProps, findTestSubject } from '../../../test';
import sinon from 'sinon';
import {
@ -55,8 +55,8 @@ describe('KuiTextInput', () => {
);
expect(
component.find('[data-test-subj="input"]').matchesElement(document.activeElement)
).toBe(true);
findTestSubject(component, 'input').getDOMNode()
).toBe(document.activeElement);
});
test('does not focus the element by default', () => {
@ -68,8 +68,8 @@ describe('KuiTextInput', () => {
);
expect(
component.find('[data-test-subj="input"]').matchesElement(document.activeElement)
).toBe(false);
findTestSubject(component, 'input').getDOMNode()
).not.toBe(document.activeElement);
});
});

View file

@ -2,7 +2,7 @@ import React from 'react';
import sinon from 'sinon';
import { mount, render } from 'enzyme';
import { requiredProps } from '../../test/required_props';
import { findTestSubject, requiredProps } from '../../test';
import { keyCodes } from '../../services';
import {
@ -42,7 +42,8 @@ test('onConfirm', () => {
confirmButtonText="Confirm Button Text"
/>
);
component.find('[data-test-subj="confirmModalConfirmButton"]').simulate('click');
findTestSubject(component, 'confirmModalConfirmButton').simulate('click');
sinon.assert.calledOnce(onConfirm);
sinon.assert.notCalled(onCancel);
});
@ -57,7 +58,8 @@ describe('onCancel', () => {
confirmButtonText="Confirm Button Text"
/>
);
component.find('[data-test-subj="confirmModalCancelButton"]').simulate('click');
findTestSubject(component, 'confirmModalCancelButton').simulate('click');
sinon.assert.notCalled(onConfirm);
sinon.assert.calledOnce(onCancel);
});
@ -72,7 +74,8 @@ describe('onCancel', () => {
data-test-subj="modal"
/>
);
component.find('[data-test-subj="modal"]').simulate('keydown', { keyCode: keyCodes.ESCAPE });
findTestSubject(component, 'modal').simulate('keydown', { keyCode: keyCodes.ESCAPE });
sinon.assert.notCalled(onConfirm);
sinon.assert.calledOnce(onCancel);
});
@ -83,12 +86,14 @@ describe('defaultFocusedButton', () => {
const component = mount(
<KuiConfirmModal
onCancel={onCancel}
defaultFocusedButton={CANCEL_BUTTON}
onConfirm={onConfirm}
cancelButtonText="Cancel Button Text"
confirmButtonText="Confirm Button Text"
defaultFocusedButton={CANCEL_BUTTON}
/>
);
const button = component.find('[data-test-subj="confirmModalCancelButton"]').getDOMNode();
const button = findTestSubject(component, 'confirmModalCancelButton').getDOMNode();
expect(document.activeElement).toEqual(button);
});
@ -96,12 +101,14 @@ describe('defaultFocusedButton', () => {
const component = mount(
<KuiConfirmModal
onCancel={onCancel}
defaultFocusedButton={CONFIRM_BUTTON}
onConfirm={onConfirm}
cancelButtonText="Cancel Button Text"
confirmButtonText="Confirm Button Text"
defaultFocusedButton={CONFIRM_BUTTON}
/>
);
const button = component.find('[data-test-subj="confirmModalConfirmButton"]').getDOMNode();
const button = findTestSubject(component, 'confirmModalConfirmButton').getDOMNode();
expect(document.activeElement).toEqual(button);
});
@ -109,6 +116,7 @@ describe('defaultFocusedButton', () => {
const component = mount(
<KuiConfirmModal
onCancel={onCancel}
onConfirm={onConfirm}
cancelButtonText="Cancel Button Text"
confirmButtonText="Confirm Button Text"
/>

View file

@ -1,7 +1,7 @@
import React from 'react';
import sinon from 'sinon';
import { render, mount } from 'enzyme';
import { requiredProps } from '../../test/required_props';
import { findTestSubject, requiredProps } from '../../test';
import {
KuiPager,
@ -72,7 +72,7 @@ describe('property', () => {
totalItems={20}
/>);
const pager = mount(component);
pager.find('[data-test-subj="pagerPreviousButton"]').simulate('click');
findTestSubject(pager, 'pagerPreviousButton').simulate('click');
sinon.assert.calledOnce(onPreviousPage);
sinon.assert.notCalled(onNextPage);
});
@ -90,7 +90,7 @@ describe('property', () => {
totalItems={20}
/>);
const pager = mount(component);
pager.find('[data-test-subj="pagerNextButton"]').simulate('click');
findTestSubject(pager, 'pagerNextButton').simulate('click');
sinon.assert.calledOnce(onNextPage);
sinon.assert.notCalled(onPreviousPage);
});

View file

@ -1,7 +1,7 @@
import React from 'react';
import sinon from 'sinon';
import { render, mount } from 'enzyme';
import { requiredProps } from '../../test/required_props';
import { findTestSubject, requiredProps } from '../../test';
import {
KuiPagerButtonGroup,
@ -27,13 +27,12 @@ test('renders KuiPagerButtonGroup', () => {
});
describe('property', () => {
function findPreviousButton(pager) {
return pager.find('[data-test-subj="pagerPreviousButton"]');
return findTestSubject(pager, 'pagerPreviousButton');
}
function findNextButton(pager) {
return pager.find('[data-test-subj="pagerNextButton"]');
return findTestSubject(pager, 'pagerNextButton');
}
test('onNext', () => {

View file

@ -1,9 +1,6 @@
import React from 'react';
import { mount, shallow } from 'enzyme';
import { requiredProps } from '../../../test/required_props';
import {
takeMountedSnapshot,
} from 'ui_framework/src/test';
import { requiredProps, takeMountedSnapshot } from '../../../test';
import {
KuiListingTable,
} from './listing_table';

View file

@ -0,0 +1,13 @@
/**
* Find node which matches a specific test subject selector. Returns ReactWrappers around DOM element,
* https://github.com/airbnb/enzyme/tree/master/docs/api/ReactWrapper.
* Typically call simulate on ReactWrapper or call getDOMNode to get underlying DOM node.
*/
export const findTestSubject = (mountedComponent, testSubjectSelector) => {
const testSubject = mountedComponent.find(`[data-test-subj="${testSubjectSelector}"]`);
// restore enzyme 2 default find behavior of only returning ReactWrappers around DOM element
// where as enzyme 3 returns both 1) ReactWrappers around DOM element and 2) react component.
// https://github.com/airbnb/enzyme/issues/1174
return testSubject.hostNodes();
};

View file

@ -1,5 +1,6 @@
export { requiredProps } from './required_props';
export { takeMountedSnapshot } from './take_mounted_snapshot';
export { findTestSubject } from './find_test_subject';
import * as TestSubjects from './test_subjects';
export { TestSubjects };

View file

@ -0,0 +1 @@
export * from '../src/test';