|
1 | 1 | import React from 'react';
|
2 |
| -import { assert } from 'chai'; |
| 2 | +import { expect } from 'chai'; |
3 | 3 | import { spy } from 'sinon';
|
4 |
| -import { createMount, findOutermostIntrinsic, getClasses } from '@material-ui/core/test-utils'; |
| 4 | +import { createMount, getClasses } from '@material-ui/core/test-utils'; |
5 | 5 | import describeConformance from '../test-utils/describeConformance';
|
| 6 | +import { createClientRender, fireEvent } from 'test/utils/createClientRender'; |
6 | 7 | import ExpansionPanelSummary from './ExpansionPanelSummary';
|
7 | 8 | import ButtonBase from '../ButtonBase';
|
8 | 9 |
|
9 | 10 | describe('<ExpansionPanelSummary />', () => {
|
10 | 11 | let mount;
|
11 | 12 | let classes;
|
12 |
| - |
13 |
| - function findExpandButton(wrapper) { |
14 |
| - return wrapper.find('[role="button"]:not([aria-hidden=true])'); |
15 |
| - } |
| 13 | + const render = createClientRender({ strict: true }); |
16 | 14 |
|
17 | 15 | before(() => {
|
18 |
| - // StrictModeViolation: uses simulate |
19 |
| - mount = createMount({ strict: false }); |
| 16 | + mount = createMount({ strict: true }); |
20 | 17 | classes = getClasses(<ExpansionPanelSummary />);
|
21 | 18 | });
|
22 | 19 |
|
23 |
| - after(() => { |
24 |
| - mount.cleanUp(); |
25 |
| - }); |
26 |
| - |
27 | 20 | describeConformance(<ExpansionPanelSummary />, () => ({
|
28 | 21 | classes,
|
29 | 22 | inheritComponent: ButtonBase,
|
30 | 23 | mount,
|
31 | 24 | refInstanceof: window.HTMLDivElement,
|
32 | 25 | skip: ['componentProp'],
|
| 26 | + after: () => mount.cleanUp(), |
33 | 27 | }));
|
34 | 28 |
|
35 |
| - it('should render with the content', () => { |
36 |
| - const wrapper = mount(<ExpansionPanelSummary>The Summary</ExpansionPanelSummary>); |
37 |
| - const itemsWrap = wrapper.find(`.${classes.content}`); |
38 |
| - assert.strictEqual(itemsWrap.text(), 'The Summary'); |
| 29 | + it('renders the children inside the .content element', () => { |
| 30 | + const { container } = render(<ExpansionPanelSummary>The Summary</ExpansionPanelSummary>); |
| 31 | + |
| 32 | + expect(container.querySelector(`.${classes.content}`)).to.have.text('The Summary'); |
39 | 33 | });
|
40 | 34 |
|
41 | 35 | it('when disabled should have disabled class', () => {
|
42 |
| - const wrapper = mount(<ExpansionPanelSummary disabled />); |
43 |
| - assert.strictEqual(findExpandButton(wrapper).hasClass(classes.disabled), true); |
| 36 | + const { getByRole } = render(<ExpansionPanelSummary disabled />); |
| 37 | + |
| 38 | + expect(getByRole('button')).to.have.class(classes.disabled); |
44 | 39 | });
|
45 | 40 |
|
46 |
| - it('when expanded should have expanded class', () => { |
47 |
| - const wrapper = mount(<ExpansionPanelSummary expanded />); |
48 |
| - assert.strictEqual(wrapper.find('[aria-expanded=true]').every(`.${classes.expanded}`), true); |
| 41 | + it('when expanded adds the expanded class to any button regardless of a11y', () => { |
| 42 | + const { getAllByRole } = render(<ExpansionPanelSummary expanded expandIcon="expand" />); |
| 43 | + |
| 44 | + const buttons = getAllByRole('button', { hidden: true }); |
| 45 | + expect(buttons).to.have.length(2); |
| 46 | + expect(buttons[0]).to.have.class(classes.expanded); |
| 47 | + expect(buttons[0]).to.have.attribute('aria-expanded', 'true'); |
| 48 | + expect(buttons[0]).not.to.be.inaccessible; |
| 49 | + expect(buttons[1]).to.have.class(classes.expanded); |
| 50 | + expect(buttons[1]).to.be.inaccessible; |
49 | 51 | });
|
50 | 52 |
|
51 | 53 | it('should render with the expand icon and have the expandIcon class', () => {
|
52 |
| - const wrapper = mount(<ExpansionPanelSummary expandIcon={<div>Icon</div>} />); |
53 |
| - const iconWrap = wrapper.find(`.${classes.expandIcon}`).first(); |
54 |
| - assert.strictEqual(iconWrap.text(), 'Icon'); |
| 54 | + const { getAllByRole } = render(<ExpansionPanelSummary expandIcon={<div>Icon</div>} />); |
| 55 | + |
| 56 | + const expandButton = getAllByRole('button', { hidden: true })[1]; |
| 57 | + expect(expandButton).to.have.class(classes.expandIcon); |
| 58 | + expect(expandButton).to.have.text('Icon'); |
| 59 | + expect(expandButton).to.be.inaccessible; |
55 | 60 | });
|
56 | 61 |
|
57 |
| - it('handleFocusVisible() should set focused state', () => { |
58 |
| - const wrapper = mount(<ExpansionPanelSummary />); |
59 |
| - wrapper |
60 |
| - .find(ButtonBase) |
61 |
| - .props() |
62 |
| - .onFocusVisible(); |
63 |
| - wrapper.update(); |
64 |
| - assert.strictEqual(findExpandButton(wrapper).hasClass(classes.focused), true); |
| 62 | + it('focusing adds the `focused` class if focused visible', () => { |
| 63 | + // TODO: Rename `focused` -> `focus-visible` |
| 64 | + // `focused` is a global state which is applied on focus |
| 65 | + // only here do we constrain it to focus-visible. THe name is also not consistent |
| 66 | + // with :focus |
| 67 | + const { getByRole } = render(<ExpansionPanelSummary />); |
| 68 | + fireEvent.mouseDown(document.body); // pointer device |
| 69 | + |
| 70 | + fireEvent.keyDown(document.activeElement, { key: 'Tab' }); // not actually focusing (yet) |
| 71 | + getByRole('button').focus(); |
| 72 | + |
| 73 | + expect(getByRole('button')).to.be.focused; |
| 74 | + expect(getByRole('button')).to.have.class(classes.focused); |
65 | 75 | });
|
66 | 76 |
|
67 |
| - it('handleBlur() should unset focused state', () => { |
68 |
| - const wrapper = mount(<ExpansionPanelSummary />); |
69 |
| - wrapper |
70 |
| - .find(ButtonBase) |
71 |
| - .props() |
72 |
| - .onFocusVisible(); |
73 |
| - wrapper.update(); |
74 |
| - wrapper |
75 |
| - .find(ButtonBase) |
76 |
| - .props() |
77 |
| - .onBlur(); |
78 |
| - wrapper.update(); |
79 |
| - assert.strictEqual(findExpandButton(wrapper).hasClass(classes.focused), false); |
| 77 | + it('blur should unset focused state', () => { |
| 78 | + const { getByRole } = render(<ExpansionPanelSummary />); |
| 79 | + fireEvent.mouseDown(document.body); // pointer device |
| 80 | + fireEvent.keyDown(document.activeElement, { key: 'Tab' }); // not actually focusing (yet) |
| 81 | + getByRole('button').focus(); |
| 82 | + |
| 83 | + getByRole('button').blur(); |
| 84 | + |
| 85 | + expect(getByRole('button')).not.to.be.focused; |
| 86 | + expect(getByRole('button')).not.to.have.class(classes.focused); |
80 | 87 | });
|
81 | 88 |
|
82 |
| - describe('event callbacks', () => { |
83 |
| - it('should fire event callbacks', () => { |
84 |
| - const events = ['onClick', 'onFocusVisible', 'onBlur']; |
85 |
| - |
86 |
| - const handlers = events.reduce((result, n) => { |
87 |
| - result[n] = spy(); |
88 |
| - return result; |
89 |
| - }, {}); |
90 |
| - |
91 |
| - const wrapper = mount(<ExpansionPanelSummary {...handlers} />); |
92 |
| - |
93 |
| - events.forEach(event => { |
94 |
| - wrapper |
95 |
| - .find(ButtonBase) |
96 |
| - .props() |
97 |
| - [event]({ persist: () => {} }); |
98 |
| - assert.strictEqual(handlers[event].callCount, 1, `should have called the ${event} handler`); |
99 |
| - }); |
100 |
| - }); |
| 89 | + it('should fire onClick callbacks', () => { |
| 90 | + const handleClick = spy(); |
| 91 | + const { getByRole } = render(<ExpansionPanelSummary onClick={handleClick} />); |
| 92 | + |
| 93 | + getByRole('button').click(); |
| 94 | + |
| 95 | + expect(handleClick.callCount).to.equal(1); |
101 | 96 | });
|
102 | 97 |
|
103 |
| - describe('prop: onChange', () => { |
104 |
| - it('fires onChange if the summary control is clicked', () => { |
105 |
| - const handleChange = spy(); |
106 |
| - const wrapper = mount(<ExpansionPanelSummary expanded={false} onChange={handleChange} />); |
| 98 | + it('calls onChange when clicking', () => { |
| 99 | + const handleChange = spy(); |
| 100 | + const { getByRole } = render(<ExpansionPanelSummary onChange={handleChange} />); |
107 | 101 |
|
108 |
| - const control = findOutermostIntrinsic(wrapper); |
109 |
| - const eventMock = 'woofExpansionPanelSummary'; |
110 |
| - control.simulate('click', { eventMock }); |
| 102 | + getByRole('button').click(); |
111 | 103 |
|
112 |
| - assert.strictEqual(handleChange.callCount, 1); |
113 |
| - assert.strictEqual(handleChange.calledWithMatch({ eventMock }), true); |
114 |
| - }); |
| 104 | + expect(handleChange.callCount).to.equal(1); |
115 | 105 | });
|
116 | 106 |
|
117 |
| - describe('prop: click', () => { |
118 |
| - it('should trigger onClick', () => { |
119 |
| - const handleClick = spy(); |
120 |
| - const wrapper = mount(<ExpansionPanelSummary onClick={handleClick} />); |
121 |
| - wrapper.simulate('click'); |
122 |
| - assert.strictEqual(handleClick.callCount, 1); |
123 |
| - }); |
| 107 | + it('calls onFocusVisible if focused visibly', () => { |
| 108 | + const handleFocusVisible = spy(); |
| 109 | + const { getByRole } = render(<ExpansionPanelSummary onFocusVisible={handleFocusVisible} />); |
| 110 | + // simulate pointer device |
| 111 | + fireEvent.mouseDown(document.body); |
| 112 | + |
| 113 | + // this doesn't actually apply focus like in the browser. we need to move focus manually |
| 114 | + fireEvent.keyDown(document.body, { key: 'Tab' }); |
| 115 | + getByRole('button').focus(); |
| 116 | + |
| 117 | + expect(handleFocusVisible.callCount).to.equal(1); |
124 | 118 | });
|
125 | 119 | });
|
0 commit comments