Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 14cf627

Browse files
author
Kerry
authored
Fix: AccessibleButton does not set disabled attribute (PSF-1055) (#8682)
* remove old styles for pin drop buttons Signed-off-by: Kerry Archibald <[email protected]> * fully disable share location button until location is shared Signed-off-by: Kerry Archibald <[email protected]> * set disabled on button Signed-off-by: Kerry Archibald <[email protected]> * test AccessibleButton disabled Signed-off-by: Kerry Archibald <[email protected]> * remove disbaled check in LocationPicker Signed-off-by: Kerry Archibald <[email protected]>
1 parent 0d1bb3b commit 14cf627

File tree

7 files changed

+291
-9
lines changed

7 files changed

+291
-9
lines changed

res/css/components/views/location/_ShareType.scss

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,6 @@ limitations under the License.
6363
&:hover, &:focus {
6464
border-color: $accent;
6565
}
66-
67-
// this style is only during active development
68-
// when lab is enabled but feature not fully implemented
69-
// pin drop option will be disabled
70-
&.mx_AccessibleButton_disabled {
71-
pointer-events: none;
72-
opacity: 0.4;
73-
}
7466
}
7567

7668
.mx_ShareType_option-icon {

src/components/views/elements/AccessibleButton.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ export default function AccessibleButton({
8585
const newProps: IAccessibleButtonProps = restProps;
8686
if (disabled) {
8787
newProps["aria-disabled"] = true;
88+
newProps["disabled"] = true;
8889
} else {
8990
if (triggerOnMouseDown) {
9091
newProps.onMouseDown = onClick;
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
/*
2+
Copyright 2022 The Matrix.org Foundation C.I.C.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
import React from 'react';
18+
import { mount } from 'enzyme';
19+
import { act } from 'react-dom/test-utils';
20+
21+
import AccessibleButton from '../../../../src/components/views/elements/AccessibleButton';
22+
import { Key } from '../../../../src/Keyboard';
23+
import { mockPlatformPeg, unmockPlatformPeg } from '../../../test-utils';
24+
25+
describe('<AccessibleButton />', () => {
26+
const defaultProps = {
27+
onClick: jest.fn(),
28+
children: 'i am a button',
29+
};
30+
const getComponent = (props = {}) =>
31+
mount(<AccessibleButton {...defaultProps} {...props} />);
32+
33+
beforeEach(() => {
34+
mockPlatformPeg();
35+
});
36+
37+
afterAll(() => {
38+
unmockPlatformPeg();
39+
});
40+
41+
const makeKeyboardEvent = (key: string) => ({
42+
key,
43+
stopPropagation: jest.fn(),
44+
preventDefault: jest.fn(),
45+
}) as unknown as KeyboardEvent;
46+
47+
it('renders div with role button by default', () => {
48+
const component = getComponent();
49+
expect(component).toMatchSnapshot();
50+
});
51+
52+
it('renders a button element', () => {
53+
const component = getComponent({ element: 'button' });
54+
expect(component).toMatchSnapshot();
55+
});
56+
57+
it('renders with correct classes when button has kind', () => {
58+
const component = getComponent({
59+
kind: 'primary',
60+
});
61+
expect(component).toMatchSnapshot();
62+
});
63+
64+
it('disables button correctly', () => {
65+
const onClick = jest.fn();
66+
const component = getComponent({
67+
onClick,
68+
disabled: true,
69+
});
70+
expect(component.find('.mx_AccessibleButton').props().disabled).toBeTruthy();
71+
expect(component.find('.mx_AccessibleButton').props()['aria-disabled']).toBeTruthy();
72+
73+
act(() => {
74+
component.simulate('click');
75+
});
76+
77+
expect(onClick).not.toHaveBeenCalled();
78+
79+
act(() => {
80+
const keydownEvent = makeKeyboardEvent(Key.ENTER);
81+
component.simulate('keydown', keydownEvent);
82+
});
83+
84+
expect(onClick).not.toHaveBeenCalled();
85+
});
86+
87+
it('calls onClick handler on button click', () => {
88+
const onClick = jest.fn();
89+
const component = getComponent({
90+
onClick,
91+
});
92+
93+
act(() => {
94+
component.simulate('click');
95+
});
96+
97+
expect(onClick).toHaveBeenCalled();
98+
});
99+
100+
it('calls onClick handler on button mousedown when triggerOnMousedown is passed', () => {
101+
const onClick = jest.fn();
102+
const component = getComponent({
103+
onClick,
104+
triggerOnMouseDown: true,
105+
});
106+
107+
act(() => {
108+
component.simulate('mousedown');
109+
});
110+
111+
expect(onClick).toHaveBeenCalled();
112+
});
113+
114+
describe('handling keyboard events', () => {
115+
it('calls onClick handler on enter keydown', () => {
116+
const onClick = jest.fn();
117+
const component = getComponent({
118+
onClick,
119+
});
120+
121+
const keyboardEvent = makeKeyboardEvent(Key.ENTER);
122+
act(() => {
123+
component.simulate('keydown', keyboardEvent);
124+
});
125+
126+
expect(onClick).toHaveBeenCalled();
127+
128+
act(() => {
129+
component.simulate('keyup', keyboardEvent);
130+
});
131+
132+
// handler only called once on keydown
133+
expect(onClick).toHaveBeenCalledTimes(1);
134+
// called for both keyup and keydown
135+
expect(keyboardEvent.stopPropagation).toHaveBeenCalledTimes(2);
136+
expect(keyboardEvent.preventDefault).toHaveBeenCalledTimes(2);
137+
});
138+
139+
it('calls onClick handler on space keyup', () => {
140+
const onClick = jest.fn();
141+
const component = getComponent({
142+
onClick,
143+
});
144+
145+
const keyboardEvent = makeKeyboardEvent(Key.SPACE);
146+
act(() => {
147+
component.simulate('keydown', keyboardEvent);
148+
});
149+
150+
expect(onClick).not.toHaveBeenCalled();
151+
152+
act(() => {
153+
component.simulate('keyup', keyboardEvent);
154+
});
155+
156+
// handler only called once on keyup
157+
expect(onClick).toHaveBeenCalledTimes(1);
158+
// called for both keyup and keydown
159+
expect(keyboardEvent.stopPropagation).toHaveBeenCalledTimes(2);
160+
expect(keyboardEvent.preventDefault).toHaveBeenCalledTimes(2);
161+
});
162+
163+
it('calls onKeydown/onKeyUp handlers for keys other than space and enter', () => {
164+
const onClick = jest.fn();
165+
const onKeyDown = jest.fn();
166+
const onKeyUp = jest.fn();
167+
const component = getComponent({
168+
onClick,
169+
onKeyDown,
170+
onKeyUp,
171+
});
172+
173+
const keyboardEvent = makeKeyboardEvent(Key.K);
174+
act(() => {
175+
component.simulate('keydown', keyboardEvent);
176+
component.simulate('keyup', keyboardEvent);
177+
});
178+
179+
expect(onClick).not.toHaveBeenCalled();
180+
expect(onKeyDown).toHaveBeenCalled();
181+
expect(onKeyUp).toHaveBeenCalled();
182+
expect(keyboardEvent.stopPropagation).not.toHaveBeenCalled();
183+
expect(keyboardEvent.preventDefault).not.toHaveBeenCalled();
184+
});
185+
186+
it('does nothing on non space/enter key presses when no onKeydown/onKeyUp handlers provided', () => {
187+
const onClick = jest.fn();
188+
const component = getComponent({
189+
onClick,
190+
});
191+
192+
const keyboardEvent = makeKeyboardEvent(Key.K);
193+
act(() => {
194+
component.simulate('keydown', keyboardEvent);
195+
component.simulate('keyup', keyboardEvent);
196+
});
197+
198+
// no onClick call, no problems
199+
expect(onClick).not.toHaveBeenCalled();
200+
expect(keyboardEvent.stopPropagation).not.toHaveBeenCalled();
201+
expect(keyboardEvent.preventDefault).not.toHaveBeenCalled();
202+
});
203+
});
204+
});
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`<AccessibleButton /> renders a button element 1`] = `
4+
<AccessibleButton
5+
element="button"
6+
onClick={[MockFunction]}
7+
role="button"
8+
tabIndex={0}
9+
>
10+
<button
11+
className="mx_AccessibleButton"
12+
onClick={[MockFunction]}
13+
onKeyDown={[Function]}
14+
onKeyUp={[Function]}
15+
role="button"
16+
tabIndex={0}
17+
>
18+
i am a button
19+
</button>
20+
</AccessibleButton>
21+
`;
22+
23+
exports[`<AccessibleButton /> renders div with role button by default 1`] = `
24+
<AccessibleButton
25+
element="div"
26+
onClick={[MockFunction]}
27+
role="button"
28+
tabIndex={0}
29+
>
30+
<div
31+
className="mx_AccessibleButton"
32+
onClick={[MockFunction]}
33+
onKeyDown={[Function]}
34+
onKeyUp={[Function]}
35+
role="button"
36+
tabIndex={0}
37+
>
38+
i am a button
39+
</div>
40+
</AccessibleButton>
41+
`;
42+
43+
exports[`<AccessibleButton /> renders with correct classes when button has kind 1`] = `
44+
<AccessibleButton
45+
element="div"
46+
kind="primary"
47+
onClick={[MockFunction]}
48+
role="button"
49+
tabIndex={0}
50+
>
51+
<div
52+
className="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
53+
onClick={[MockFunction]}
54+
onKeyDown={[Function]}
55+
onKeyUp={[Function]}
56+
role="button"
57+
tabIndex={0}
58+
>
59+
i am a button
60+
</div>
61+
</AccessibleButton>
62+
`;

test/components/views/elements/__snapshots__/PollCreateDialog-test.tsx.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3-
exports[`PollCreateDialog renders a blank poll 1`] = `"<div data-focus-guard=\\"true\\" tabindex=\\"0\\" style=\\"width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;\\"></div><div data-focus-lock-disabled=\\"false\\" role=\\"dialog\\" aria-labelledby=\\"mx_CompoundDialog_title\\" aria-describedby=\\"mx_CompoundDialog_content\\" class=\\"mx_CompoundDialog mx_ScrollableBaseDialog\\"><div class=\\"mx_CompoundDialog_header\\"><h1>Create poll</h1><div aria-label=\\"Close dialog\\" role=\\"button\\" tabindex=\\"0\\" class=\\"mx_AccessibleButton mx_CompoundDialog_cancelButton\\"></div></div><form><div class=\\"mx_CompoundDialog_content\\"><div class=\\"mx_PollCreateDialog\\"><h2>Poll type</h2><div class=\\"mx_Field mx_Field_select\\"><select type=\\"text\\" id=\\"mx_Field_1\\"><option value=\\"org.matrix.msc3381.poll.disclosed\\">Open poll</option><option value=\\"org.matrix.msc3381.poll.undisclosed\\">Closed poll</option></select><label for=\\"mx_Field_1\\"></label></div><p>Voters see results as soon as they have voted</p><h2>What is your poll question or topic?</h2><div class=\\"mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint\\"><input id=\\"poll-topic-input\\" maxlength=\\"340\\" label=\\"Question or topic\\" placeholder=\\"Write something...\\" type=\\"text\\" value=\\"\\"><label for=\\"poll-topic-input\\">Question or topic</label></div><h2>Create options</h2><div class=\\"mx_PollCreateDialog_option\\"><div class=\\"mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint\\"><input id=\\"pollcreate_option_0\\" maxlength=\\"340\\" label=\\"Option 1\\" placeholder=\\"Write an option\\" type=\\"text\\" value=\\"\\"><label for=\\"pollcreate_option_0\\">Option 1</label></div><div role=\\"button\\" tabindex=\\"0\\" class=\\"mx_AccessibleButton mx_PollCreateDialog_removeOption\\"></div></div><div class=\\"mx_PollCreateDialog_option\\"><div class=\\"mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint\\"><input id=\\"pollcreate_option_1\\" maxlength=\\"340\\" label=\\"Option 2\\" placeholder=\\"Write an option\\" type=\\"text\\" value=\\"\\"><label for=\\"pollcreate_option_1\\">Option 2</label></div><div role=\\"button\\" tabindex=\\"0\\" class=\\"mx_AccessibleButton mx_PollCreateDialog_removeOption\\"></div></div><div role=\\"button\\" tabindex=\\"0\\" class=\\"mx_AccessibleButton mx_PollCreateDialog_addOption mx_AccessibleButton_hasKind mx_AccessibleButton_kind_secondary\\">Add option</div></div></div><div class=\\"mx_CompoundDialog_footer\\"><div role=\\"button\\" tabindex=\\"0\\" class=\\"mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_outline\\">Cancel</div><button type=\\"submit\\" role=\\"button\\" tabindex=\\"0\\" aria-disabled=\\"true\\" class=\\"mx_AccessibleButton mx_Dialog_nonDialogButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary mx_AccessibleButton_disabled\\">Create Poll</button></div></form></div><div data-focus-guard=\\"true\\" tabindex=\\"0\\" style=\\"width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;\\"></div>"`;
3+
exports[`PollCreateDialog renders a blank poll 1`] = `"<div data-focus-guard=\\"true\\" tabindex=\\"0\\" style=\\"width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;\\"></div><div data-focus-lock-disabled=\\"false\\" role=\\"dialog\\" aria-labelledby=\\"mx_CompoundDialog_title\\" aria-describedby=\\"mx_CompoundDialog_content\\" class=\\"mx_CompoundDialog mx_ScrollableBaseDialog\\"><div class=\\"mx_CompoundDialog_header\\"><h1>Create poll</h1><div aria-label=\\"Close dialog\\" role=\\"button\\" tabindex=\\"0\\" class=\\"mx_AccessibleButton mx_CompoundDialog_cancelButton\\"></div></div><form><div class=\\"mx_CompoundDialog_content\\"><div class=\\"mx_PollCreateDialog\\"><h2>Poll type</h2><div class=\\"mx_Field mx_Field_select\\"><select type=\\"text\\" id=\\"mx_Field_1\\"><option value=\\"org.matrix.msc3381.poll.disclosed\\">Open poll</option><option value=\\"org.matrix.msc3381.poll.undisclosed\\">Closed poll</option></select><label for=\\"mx_Field_1\\"></label></div><p>Voters see results as soon as they have voted</p><h2>What is your poll question or topic?</h2><div class=\\"mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint\\"><input id=\\"poll-topic-input\\" maxlength=\\"340\\" label=\\"Question or topic\\" placeholder=\\"Write something...\\" type=\\"text\\" value=\\"\\"><label for=\\"poll-topic-input\\">Question or topic</label></div><h2>Create options</h2><div class=\\"mx_PollCreateDialog_option\\"><div class=\\"mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint\\"><input id=\\"pollcreate_option_0\\" maxlength=\\"340\\" label=\\"Option 1\\" placeholder=\\"Write an option\\" type=\\"text\\" value=\\"\\"><label for=\\"pollcreate_option_0\\">Option 1</label></div><div role=\\"button\\" tabindex=\\"0\\" class=\\"mx_AccessibleButton mx_PollCreateDialog_removeOption\\"></div></div><div class=\\"mx_PollCreateDialog_option\\"><div class=\\"mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint\\"><input id=\\"pollcreate_option_1\\" maxlength=\\"340\\" label=\\"Option 2\\" placeholder=\\"Write an option\\" type=\\"text\\" value=\\"\\"><label for=\\"pollcreate_option_1\\">Option 2</label></div><div role=\\"button\\" tabindex=\\"0\\" class=\\"mx_AccessibleButton mx_PollCreateDialog_removeOption\\"></div></div><div role=\\"button\\" tabindex=\\"0\\" class=\\"mx_AccessibleButton mx_PollCreateDialog_addOption mx_AccessibleButton_hasKind mx_AccessibleButton_kind_secondary\\">Add option</div></div></div><div class=\\"mx_CompoundDialog_footer\\"><div role=\\"button\\" tabindex=\\"0\\" class=\\"mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_outline\\">Cancel</div><button type=\\"submit\\" role=\\"button\\" tabindex=\\"0\\" aria-disabled=\\"true\\" disabled=\\"\\" class=\\"mx_AccessibleButton mx_Dialog_nonDialogButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary mx_AccessibleButton_disabled\\">Create Poll</button></div></form></div><div data-focus-guard=\\"true\\" tabindex=\\"0\\" style=\\"width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;\\"></div>"`;
44

55
exports[`PollCreateDialog renders a question and some options 1`] = `"<div data-focus-guard=\\"true\\" tabindex=\\"0\\" style=\\"width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;\\"></div><div data-focus-lock-disabled=\\"false\\" role=\\"dialog\\" aria-labelledby=\\"mx_CompoundDialog_title\\" aria-describedby=\\"mx_CompoundDialog_content\\" class=\\"mx_CompoundDialog mx_ScrollableBaseDialog\\"><div class=\\"mx_CompoundDialog_header\\"><h1>Create poll</h1><div aria-label=\\"Close dialog\\" role=\\"button\\" tabindex=\\"0\\" class=\\"mx_AccessibleButton mx_CompoundDialog_cancelButton\\"></div></div><form><div class=\\"mx_CompoundDialog_content\\"><div class=\\"mx_PollCreateDialog\\"><h2>Poll type</h2><div class=\\"mx_Field mx_Field_select\\"><select type=\\"text\\" id=\\"mx_Field_4\\"><option value=\\"org.matrix.msc3381.poll.disclosed\\">Open poll</option><option value=\\"org.matrix.msc3381.poll.undisclosed\\">Closed poll</option></select><label for=\\"mx_Field_4\\"></label></div><p>Voters see results as soon as they have voted</p><h2>What is your poll question or topic?</h2><div class=\\"mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint\\"><input id=\\"poll-topic-input\\" maxlength=\\"340\\" label=\\"Question or topic\\" placeholder=\\"Write something...\\" type=\\"text\\" value=\\"How many turnips is the optimal number?\\"><label for=\\"poll-topic-input\\">Question or topic</label></div><h2>Create options</h2><div class=\\"mx_PollCreateDialog_option\\"><div class=\\"mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint\\"><input id=\\"pollcreate_option_0\\" maxlength=\\"340\\" label=\\"Option 1\\" placeholder=\\"Write an option\\" type=\\"text\\" value=\\"As many as my neighbour\\"><label for=\\"pollcreate_option_0\\">Option 1</label></div><div role=\\"button\\" tabindex=\\"0\\" class=\\"mx_AccessibleButton mx_PollCreateDialog_removeOption\\"></div></div><div class=\\"mx_PollCreateDialog_option\\"><div class=\\"mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint\\"><input id=\\"pollcreate_option_1\\" maxlength=\\"340\\" label=\\"Option 2\\" placeholder=\\"Write an option\\" type=\\"text\\" value=\\"The question is meaningless\\"><label for=\\"pollcreate_option_1\\">Option 2</label></div><div role=\\"button\\" tabindex=\\"0\\" class=\\"mx_AccessibleButton mx_PollCreateDialog_removeOption\\"></div></div><div class=\\"mx_PollCreateDialog_option\\"><div class=\\"mx_Field mx_Field_input mx_Field_labelAlwaysTopLeft mx_Field_placeholderIsHint\\"><input id=\\"pollcreate_option_2\\" maxlength=\\"340\\" label=\\"Option 3\\" placeholder=\\"Write an option\\" type=\\"text\\" value=\\"Mu\\"><label for=\\"pollcreate_option_2\\">Option 3</label></div><div role=\\"button\\" tabindex=\\"0\\" class=\\"mx_AccessibleButton mx_PollCreateDialog_removeOption\\"></div></div><div role=\\"button\\" tabindex=\\"0\\" class=\\"mx_AccessibleButton mx_PollCreateDialog_addOption mx_AccessibleButton_hasKind mx_AccessibleButton_kind_secondary\\">Add option</div></div></div><div class=\\"mx_CompoundDialog_footer\\"><div role=\\"button\\" tabindex=\\"0\\" class=\\"mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary_outline\\">Cancel</div><button type=\\"submit\\" role=\\"button\\" tabindex=\\"0\\" class=\\"mx_AccessibleButton mx_Dialog_nonDialogButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary\\">Create Poll</button></div></form></div><div data-focus-guard=\\"true\\" tabindex=\\"0\\" style=\\"width: 1px; height: 0px; padding: 0px; overflow: hidden; position: fixed; top: 1px; left: 1px;\\"></div>"`;
66

0 commit comments

Comments
 (0)