Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ExpansionPanelSummary] Test in StrictMode #17873

Merged
merged 4 commits into from
Oct 15, 2019
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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"@babel/preset-env": "^7.6.0",
"@babel/preset-react": "^7.0.0",
"@babel/register": "^7.6.2",
"@testing-library/dom": "^6.8.1",
"@testing-library/react": "^9.2.0",
"@types/chai": "^4.2.3",
"@types/chai-dom": "^0.0.8",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describe('<SpeedDialAction />', () => {
};

before(() => {
// StrictModeViolation: unknown
// StrictModeViolation: uses Tooltip
mount = createMount({ strict: false });
classes = getClasses(<SpeedDialAction {...defaultProps} />);
});
Expand Down
5 changes: 2 additions & 3 deletions packages/material-ui/src/Button/Button.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@ import ButtonBase from '../ButtonBase';

describe('<Button />', () => {
let mount;
// StrictModeViolation uses ButtonBase
const render = createClientRender({ strict: false });
const render = createClientRender({ strict: true });
let classes;

before(() => {
mount = createMount({ strict: false });
mount = createMount({ strict: true });
classes = getClasses(<Button>Hello World</Button>);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ const ExpansionPanelSummary = React.forwardRef(function ExpansionPanelSummary(pr
onBlur(event);
}
};
// TODO: Remove in v5 and use onClick in ExpansionPanel.js
const handleChange = event => {
if (onChange) {
onChange(event);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,125 +1,119 @@
import React from 'react';
import { assert } from 'chai';
import { expect } from 'chai';
import { spy } from 'sinon';
import { createMount, findOutermostIntrinsic, getClasses } from '@material-ui/core/test-utils';
import { createMount, getClasses } from '@material-ui/core/test-utils';
import describeConformance from '../test-utils/describeConformance';
import { createClientRender, fireEvent } from 'test/utils/createClientRender';
import ExpansionPanelSummary from './ExpansionPanelSummary';
import ButtonBase from '../ButtonBase';

describe('<ExpansionPanelSummary />', () => {
let mount;
let classes;

function findExpandButton(wrapper) {
return wrapper.find('[role="button"]:not([aria-hidden=true])');
}
const render = createClientRender({ strict: true });

before(() => {
// StrictModeViolation: uses simulate
mount = createMount({ strict: false });
mount = createMount({ strict: true });
classes = getClasses(<ExpansionPanelSummary />);
});

after(() => {
mount.cleanUp();
});

describeConformance(<ExpansionPanelSummary />, () => ({
classes,
inheritComponent: ButtonBase,
mount,
refInstanceof: window.HTMLDivElement,
skip: ['componentProp'],
after: () => mount.cleanUp(),
}));

it('should render with the content', () => {
const wrapper = mount(<ExpansionPanelSummary>The Summary</ExpansionPanelSummary>);
const itemsWrap = wrapper.find(`.${classes.content}`);
assert.strictEqual(itemsWrap.text(), 'The Summary');
it('renders the children inside the .content element', () => {
const { container } = render(<ExpansionPanelSummary>The Summary</ExpansionPanelSummary>);

expect(container.querySelector(`.${classes.content}`)).to.have.text('The Summary');
});

it('when disabled should have disabled class', () => {
const wrapper = mount(<ExpansionPanelSummary disabled />);
assert.strictEqual(findExpandButton(wrapper).hasClass(classes.disabled), true);
const { getByRole } = render(<ExpansionPanelSummary disabled />);

expect(getByRole('button')).to.have.class(classes.disabled);
});

it('when expanded should have expanded class', () => {
const wrapper = mount(<ExpansionPanelSummary expanded />);
assert.strictEqual(wrapper.find('[aria-expanded=true]').every(`.${classes.expanded}`), true);
it('when expanded adds the expanded class to any button regardless of a11y', () => {
const { getAllByRole } = render(<ExpansionPanelSummary expanded expandIcon="expand" />);

const buttons = getAllByRole('button', { hidden: true });
expect(buttons).to.have.length(2);
expect(buttons[0]).to.have.class(classes.expanded);
expect(buttons[0]).to.have.attribute('aria-expanded', 'true');
expect(buttons[0]).not.to.be.inaccessible;
expect(buttons[1]).to.have.class(classes.expanded);
expect(buttons[1]).to.be.inaccessible;
});

it('should render with the expand icon and have the expandIcon class', () => {
const wrapper = mount(<ExpansionPanelSummary expandIcon={<div>Icon</div>} />);
const iconWrap = wrapper.find(`.${classes.expandIcon}`).first();
assert.strictEqual(iconWrap.text(), 'Icon');
const { getAllByRole } = render(<ExpansionPanelSummary expandIcon={<div>Icon</div>} />);

const expandButton = getAllByRole('button', { hidden: true })[1];
expect(expandButton).to.have.class(classes.expandIcon);
expect(expandButton).to.have.text('Icon');
expect(expandButton).to.be.inaccessible;
});

it('handleFocusVisible() should set focused state', () => {
const wrapper = mount(<ExpansionPanelSummary />);
wrapper
.find(ButtonBase)
.props()
.onFocusVisible();
wrapper.update();
assert.strictEqual(findExpandButton(wrapper).hasClass(classes.focused), true);
it('focusing adds the `focused` class if focused visible', () => {
// TODO: Rename `focused` -> `focus-visible`
// `focused` is a global state which is applied on focus
// only here do we constrain it to focus-visible. THe name is also not consistent
// with :focus
const { getByRole } = render(<ExpansionPanelSummary />);
fireEvent.mouseDown(document.body); // pointer device

fireEvent.keyDown(document.activeElement, { key: 'Tab' }); // not actually focusing (yet)
getByRole('button').focus();

expect(getByRole('button')).to.be.focused;
expect(getByRole('button')).to.have.class(classes.focused);
});

it('handleBlur() should unset focused state', () => {
const wrapper = mount(<ExpansionPanelSummary />);
wrapper
.find(ButtonBase)
.props()
.onFocusVisible();
wrapper.update();
wrapper
.find(ButtonBase)
.props()
.onBlur();
wrapper.update();
assert.strictEqual(findExpandButton(wrapper).hasClass(classes.focused), false);
it('blur should unset focused state', () => {
const { getByRole } = render(<ExpansionPanelSummary />);
fireEvent.mouseDown(document.body); // pointer device
fireEvent.keyDown(document.activeElement, { key: 'Tab' }); // not actually focusing (yet)
getByRole('button').focus();

getByRole('button').blur();

expect(getByRole('button')).not.to.be.focused;
expect(getByRole('button')).not.to.have.class(classes.focused);
});

describe('event callbacks', () => {
it('should fire event callbacks', () => {
const events = ['onClick', 'onFocusVisible', 'onBlur'];

const handlers = events.reduce((result, n) => {
result[n] = spy();
return result;
}, {});

const wrapper = mount(<ExpansionPanelSummary {...handlers} />);

events.forEach(event => {
wrapper
.find(ButtonBase)
.props()
[event]({ persist: () => {} });
assert.strictEqual(handlers[event].callCount, 1, `should have called the ${event} handler`);
});
});
it('should fire onClick callbacks', () => {
const handleClick = spy();
const { getByRole } = render(<ExpansionPanelSummary onClick={handleClick} />);

getByRole('button').click();

expect(handleClick.callCount).to.equal(1);
});

describe('prop: onChange', () => {
it('fires onChange if the summary control is clicked', () => {
const handleChange = spy();
const wrapper = mount(<ExpansionPanelSummary expanded={false} onChange={handleChange} />);
it('calls onChange when clicking', () => {
const handleChange = spy();
const { getByRole } = render(<ExpansionPanelSummary onChange={handleChange} />);

const control = findOutermostIntrinsic(wrapper);
const eventMock = 'woofExpansionPanelSummary';
control.simulate('click', { eventMock });
getByRole('button').click();

assert.strictEqual(handleChange.callCount, 1);
assert.strictEqual(handleChange.calledWithMatch({ eventMock }), true);
});
expect(handleChange.callCount).to.equal(1);
});

describe('prop: click', () => {
it('should trigger onClick', () => {
const handleClick = spy();
const wrapper = mount(<ExpansionPanelSummary onClick={handleClick} />);
wrapper.simulate('click');
assert.strictEqual(handleClick.callCount, 1);
});
it('calls onFocusVisible if focused visibly', () => {
const handleFocusVisible = spy();
const { getByRole } = render(<ExpansionPanelSummary onFocusVisible={handleFocusVisible} />);
// simulate pointer device
fireEvent.mouseDown(document.body);

// this doesn't actually apply focus like in the browser. we need to move focus manually
fireEvent.keyDown(document.body, { key: 'Tab' });
getByRole('button').focus();

expect(handleFocusVisible.callCount).to.equal(1);
});
});
2 changes: 1 addition & 1 deletion packages/material-ui/src/RadioGroup/RadioGroup.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe('<RadioGroup />', () => {
let mount;

before(() => {
// StrictModeViolation: uses #simulate
// StrictModeViolation: test uses #simulate
mount = createMount({ strict: false });
});

Expand Down
2 changes: 1 addition & 1 deletion packages/material-ui/src/Select/Select.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('<Select />', () => {

before(() => {
classes = getClasses(<Select />);
// StrictModeViolation: test uses MenuItem
// StrictModeViolation: uses Menu
mount = createMount({ strict: false });
});

Expand Down
2 changes: 1 addition & 1 deletion packages/material-ui/src/Tab/Tab.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('<Tab />', () => {

before(() => {
shallow = createShallow({ dive: true });
// StrictModeViolation: uses text()
// StrictModeViolation: test uses text()
mount = createMount({ strict: false });
classes = getClasses(<Tab textColor="inherit" />);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ describe('<TablePagination />', () => {
classes = getClasses(
<TablePagination count={1} onChangePage={() => {}} page={0} rowsPerPage={10} />,
);
// StrictModeViolation: uses #html()
// StrictModeViolation: test uses #html()
mount = createMount({ strict: false });
});

Expand Down
1 change: 1 addition & 0 deletions packages/material-ui/test/integration/Menu.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ describe('<Menu /> integration', () => {
* @type {ReturnType<useFakeTimers>}
*/
let clock;
// StrictModeViolation: uses Popover
const render = createClientRender({ strict: false });

beforeEach(() => {
Expand Down
2 changes: 1 addition & 1 deletion packages/material-ui/test/integration/NestedMenu.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ function NestedMenu(props) {
}

describe('<NestedMenu> integration', () => {
// StrictModeViolation: test uses Popover
// StrictModeViolation: uses Popover
const render = createClientRender({ strict: false });

afterEach(() => {
Expand Down
5 changes: 5 additions & 0 deletions test/utils/init.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,13 @@ declare namespace Chai {
/**
* checks if the element in question is considered aria-hidden
* Does not replace accessibility check as that requires display/visibility/layout
* @deprecated Use `inaccessible` + `visible` instead
*/
ariaHidden: Assertion;
/**
* checks if the element is inaccessible
*/
inaccessible: Assertion;
/**
* checks if the element is focused
*/
Expand Down
13 changes: 13 additions & 0 deletions test/utils/initMatchers.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import chai from 'chai';
import chaiDom from 'chai-dom';
import { isInaccessible } from '@testing-library/dom';
import { prettyDOM } from '@testing-library/react';

chai.use(chaiDom);
Expand Down Expand Up @@ -48,4 +49,16 @@ chai.use((chaiAPI, utils) => {
)} had aria-hidden="true" instead\n${prettyDOM(previousNode)}`,
);
});

chai.Assertion.addProperty('inaccessible', function elementIsAccessible() {
const element = utils.flag(this, 'object');

const inaccessible = isInaccessible(element);

this.assert(
inaccessible === true,
`expected ${utils.elToString(element)} to be inaccessible but it was accessible`,
`expected ${utils.elToString(element)} to be accessible but it was inaccessible`,
);
});
});
Loading