mirror of
https://github.com/zoriya/react-native-web.git
synced 2026-06-03 10:46:19 +00:00
[fix] Prevent onClick being called when certain roles are disabled
Fix #1779 Close #1780
This commit is contained in:
committed by
Nicolas Gallagher
parent
a2d72ee89c
commit
cea4172efb
@@ -23,37 +23,5 @@ describe('exports/createElement', () => {
|
||||
const { container } = render(createElement(Custom, { accessibilityRole: 'link' }));
|
||||
expect(container.firstChild.nodeName).toBe('DIV');
|
||||
});
|
||||
|
||||
const testRole = ({ accessibilityRole, disabled }) => {
|
||||
[{ key: 'Enter' }, { key: ' ' }].forEach(({ key }) => {
|
||||
test(`"onClick" is ${disabled ? 'not ' : ''}called when "${key}" key is pressed`, () => {
|
||||
const onClick = jest.fn();
|
||||
const { container } = render(
|
||||
createElement('span', { accessibilityRole, disabled, onClick })
|
||||
);
|
||||
const event = document.createEvent('CustomEvent');
|
||||
event.initCustomEvent('keydown', true, true);
|
||||
event.key = key;
|
||||
container.firstChild.dispatchEvent(event);
|
||||
expect(onClick).toHaveBeenCalledTimes(disabled ? 0 : 1);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
describe('value is "button" and disabled is "true"', () => {
|
||||
testRole({ accessibilityRole: 'button', disabled: true });
|
||||
});
|
||||
|
||||
describe('value is "button" and disabled is "false"', () => {
|
||||
testRole({ accessibilityRole: 'button', disabled: false });
|
||||
});
|
||||
|
||||
describe('value is "menuitem" and disabled is "true"', () => {
|
||||
testRole({ accessibilityRole: 'menuitem', disabled: true });
|
||||
});
|
||||
|
||||
describe('value is "menuitem" and disabled is "false"', () => {
|
||||
testRole({ accessibilityRole: 'menuitem', disabled: false });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+100
@@ -140,6 +140,106 @@ describe('modules/createDOMProps', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('prop "onClick"', () => {
|
||||
const callsOnClick = (component, accessibilityRole, disabled = false) => {
|
||||
const onClick = jest.fn();
|
||||
const event = { stopPropagation: jest.fn() };
|
||||
const finalProps = createDOMProps(component, { accessibilityRole, disabled, onClick });
|
||||
finalProps.onClick(event);
|
||||
return onClick.mock.calls.length === 1;
|
||||
};
|
||||
|
||||
test('is called for various roles', () => {
|
||||
expect(callsOnClick('div', 'link')).toBe(true);
|
||||
expect(callsOnClick('div', 'button')).toBe(true);
|
||||
expect(callsOnClick('div', 'textbox')).toBe(true);
|
||||
expect(callsOnClick('div', 'menuitem')).toBe(true);
|
||||
expect(callsOnClick('div', 'bogus')).toBe(true);
|
||||
expect(callsOnClick('a')).toBe(true);
|
||||
expect(callsOnClick('button')).toBe(true);
|
||||
expect(callsOnClick('input')).toBe(true);
|
||||
expect(callsOnClick('select')).toBe(true);
|
||||
expect(callsOnClick('textarea')).toBe(true);
|
||||
expect(callsOnClick('h1')).toBe(true);
|
||||
});
|
||||
|
||||
test('is not called when disabled is true', () => {
|
||||
expect(callsOnClick('div', 'link', true)).toBe(false);
|
||||
expect(callsOnClick('div', 'button', true)).toBe(false);
|
||||
expect(callsOnClick('div', 'menuitem', true)).toBe(false);
|
||||
expect(callsOnClick('a', undefined, true)).toBe(false);
|
||||
expect(callsOnClick('button', undefined, true)).toBe(false);
|
||||
expect(callsOnClick('input', undefined, true)).toBe(false);
|
||||
expect(callsOnClick('select', undefined, true)).toBe(false);
|
||||
expect(callsOnClick('textarea', undefined, true)).toBe(false);
|
||||
|
||||
expect(callsOnClick('div', 'textbox', true)).toBe(true);
|
||||
expect(callsOnClick('div', 'bogus', true)).toBe(true);
|
||||
expect(callsOnClick('h1', undefined, true)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('prop "onKeyDown"', () => {
|
||||
const callsOnClick = key => (component, accessibilityRole, disabled = false) => {
|
||||
const onClick = jest.fn();
|
||||
const onKeyDown = jest.fn();
|
||||
const event = { key, preventDefault: jest.fn() };
|
||||
const finalProps = createDOMProps(component, {
|
||||
accessibilityRole,
|
||||
disabled,
|
||||
onClick,
|
||||
onKeyDown
|
||||
});
|
||||
finalProps.onKeyDown(event);
|
||||
// The original onKeyDown should always be called
|
||||
expect(onKeyDown).toHaveBeenCalled();
|
||||
return onClick.mock.calls.length === 1;
|
||||
};
|
||||
|
||||
const respondsToEnter = callsOnClick('Enter');
|
||||
const respondsToSpace = callsOnClick(' ');
|
||||
|
||||
test('does not emulate "onClick" when disabled', () => {
|
||||
expect(respondsToEnter('div', 'link', true)).toBe(false);
|
||||
expect(respondsToEnter('div', 'button', true)).toBe(false);
|
||||
expect(respondsToEnter('div', 'textbox', true)).toBe(false);
|
||||
expect(respondsToEnter('div', 'menuitem', true)).toBe(false);
|
||||
expect(respondsToEnter('div', 'bogus', true)).toBe(false);
|
||||
});
|
||||
|
||||
test('does not emulate "onClick" for native elements', () => {
|
||||
expect(respondsToEnter('a')).toBe(false);
|
||||
expect(respondsToEnter('button')).toBe(false);
|
||||
expect(respondsToEnter('input')).toBe(false);
|
||||
expect(respondsToEnter('select')).toBe(false);
|
||||
expect(respondsToEnter('textarea')).toBe(false);
|
||||
expect(respondsToEnter('h1')).toBe(false);
|
||||
expect(respondsToEnter('div', 'link')).toBe(false);
|
||||
|
||||
expect(respondsToSpace('a')).toBe(false);
|
||||
expect(respondsToSpace('button')).toBe(false);
|
||||
expect(respondsToSpace('input')).toBe(false);
|
||||
expect(respondsToSpace('select')).toBe(false);
|
||||
expect(respondsToSpace('textarea')).toBe(false);
|
||||
expect(respondsToSpace('h1')).toBe(false);
|
||||
expect(respondsToSpace('div', 'link')).toBe(false);
|
||||
});
|
||||
|
||||
test('emulates "onClick" for "Enter" for certain roles', () => {
|
||||
expect(respondsToEnter('div', 'button')).toBe(true);
|
||||
expect(respondsToEnter('div', 'menuitem')).toBe(true);
|
||||
expect(respondsToEnter('div', 'textbox')).toBe(false);
|
||||
expect(respondsToEnter('div', 'bogus')).toBe(false);
|
||||
});
|
||||
|
||||
test('emulates "onClick" for "Space" for certain roles', () => {
|
||||
expect(respondsToSpace('div', 'button')).toBe(true);
|
||||
expect(respondsToSpace('div', 'menuitem')).toBe(true);
|
||||
expect(respondsToSpace('div', 'textbox')).toBe(false);
|
||||
expect(respondsToSpace('div', 'bogus')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
test('prop "accessibilityLabel" becomes "aria-label"', () => {
|
||||
const accessibilityLabel = 'accessibilityLabel';
|
||||
const props = createProps({ accessibilityLabel });
|
||||
|
||||
@@ -225,7 +225,7 @@ const createDOMProps = (component, props) => {
|
||||
// Keyboard accessibility
|
||||
// Button-like roles should trigger 'onClick' if SPACE key is pressed.
|
||||
// Button-like roles should not trigger 'onClick' if they are disabled.
|
||||
if (domProps['data-focusable']) {
|
||||
if (isNativeInteractiveElement || role === 'button' || role === 'menuitem') {
|
||||
const onClick = domProps.onClick;
|
||||
if (onClick != null) {
|
||||
if (disabled) {
|
||||
|
||||
Reference in New Issue
Block a user