MM-11302 Add accessibility to channel header buttons (#4768)

* Add accessibility to channel header - search & more options buttons

* Add unit tests for channel_nav_bar accessibility

* Update snapshot for settings_drawer_button.js
This commit is contained in:
Soo Hwan Kim 2020-09-17 14:46:43 +09:00 committed by GitHub
parent ee26e051c6
commit e7302fa6cc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 254 additions and 1 deletions

View file

@ -0,0 +1,35 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`SettingDrawerButton should match, full snapshot 1`] = `
<ForwardRef
accessibilityHint="Opens the more options right hand sidebar"
accessibilityLabel="More Options"
accessibilityRole="button"
accessible={true}
onPress={[Function]}
style={
Object {
"width": 44,
}
}
>
<View
style={
Object {
"alignItems": "center",
"flex": 1,
"flexDirection": "column",
"justifyContent": "center",
"marginLeft": 8,
}
}
>
<Icon
allowFontScaling={false}
color="#ffffff"
name="ellipsis-vertical"
size={25}
/>
</View>
</ForwardRef>
`;

View file

@ -126,4 +126,25 @@ describe('ChannelDrawerButton', () => {
expect(setApplicationIconBadgeNumber).toHaveBeenCalledWith(-1);
NotificationsIOS.getBadgesCount((count) => expect(count).toBe(0));
});
test('Should be accessible', () => {
const wrapper = shallowWithIntl(
<ChannelDrawerButton {...baseProps}/>,
);
expect(wrapper.props().accessible).toBeTruthy();
});
test('Should have the correct accessibilityHint', () => {
const wrapper = shallowWithIntl(
<ChannelDrawerButton {...baseProps}/>,
);
expect(wrapper.props().accessibilityHint).toEqual('Opens the channels and teams drawer');
});
test('Should have the correct accessibilityLabel', () => {
const wrapper = shallowWithIntl(
<ChannelDrawerButton {...baseProps}/>,
);
expect(wrapper.props().accessibilityLabel).toEqual('Channels and teams');
});
});

View file

@ -0,0 +1,49 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ChannelSearchButton should match, full snapshot 1`] = `
<View
style={
Object {
"width": 40,
}
}
>
<ForwardRef
accessibilityHint="Opens the channel search modal"
accessibilityLabel="Search"
accessibilityRole="button"
accessible={true}
onPress={[Function]}
style={
Object {
"flex": 1,
}
}
>
<View
style={
Object {
"alignItems": "flex-end",
"flex": 1,
"flexDirection": "column",
"justifyContent": "center",
"position": "relative",
"top": -1,
}
}
>
<Icon
allowFontScaling={false}
name="search"
size={18}
style={
Object {
"backgroundColor": "#1153ab",
"color": "#ffffff",
}
}
/>
</View>
</ForwardRef>
</View>
`;

View file

@ -13,6 +13,8 @@ import AwesomeIcon from 'react-native-vector-icons/FontAwesome';
import {preventDoubleTap} from 'app/utils/tap';
import {makeStyleSheetFromTheme} from 'app/utils/theme';
import {showSearchModal} from 'app/actions/navigation';
import {t} from 'app/utils/i18n';
import {intlShape} from 'react-intl';
export default class ChannelSearchButton extends PureComponent {
static propTypes = {
@ -22,6 +24,10 @@ export default class ChannelSearchButton extends PureComponent {
theme: PropTypes.object,
};
static contextTypes = {
intl: intlShape.isRequired,
};
handlePress = preventDoubleTap(async () => {
const {actions} = this.props;
@ -35,11 +41,31 @@ export default class ChannelSearchButton extends PureComponent {
theme,
} = this.props;
const {formatMessage} = this.context.intl;
const buttonDescriptor = {
id: t('navbar.search.button'),
defaultMessage: 'Search',
description: 'Accessibility helper for search button in channel header.',
};
const accessibilityLabel = formatMessage(buttonDescriptor);
const buttonHint = {
id: t('navbar.search.hint'),
defaultMessage: 'Opens the channel search modal',
description: 'Accessibility helper for explaining what the search button in the channel header will do.',
};
const accessibilityHint = formatMessage(buttonHint);
const style = getStyle(theme);
return (
<View style={style.container}>
<TouchableOpacity
accessible={true}
accessibilityHint={accessibilityHint}
accessibilityLabel={accessibilityLabel}
accessibilityRole='button'
onPress={this.handlePress}
style={style.flex}
>

View file

@ -0,0 +1,47 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import {TouchableOpacity} from 'react-native';
import Preferences from '@mm-redux/constants/preferences';
import ChannelSearchButton from './channel_search_button';
import {shallowWithIntl} from 'test/intl-test-helper';
describe('ChannelSearchButton', () => {
const baseProps = {
actions: {clearSearch: jest.fn()},
theme: Preferences.THEMES.default,
};
test('should match, full snapshot', () => {
const wrapper = shallowWithIntl(
<ChannelSearchButton {...baseProps}/>,
);
expect(wrapper.getElement()).toMatchSnapshot();
expect(wrapper.find(TouchableOpacity).first().exists()).toEqual(true);
});
test('Should be accessible', () => {
const wrapper = shallowWithIntl(
<ChannelSearchButton {...baseProps}/>,
);
expect(wrapper.find(TouchableOpacity).first().props().accessible).toBeTruthy();
});
test('Should have the correct accessibilityHint', () => {
const wrapper = shallowWithIntl(
<ChannelSearchButton {...baseProps}/>,
);
expect(wrapper.find(TouchableOpacity).first().props().accessibilityHint).toEqual('Opens the channel search modal');
});
test('Should have the correct accessibilityLabel', () => {
const wrapper = shallowWithIntl(
<ChannelSearchButton {...baseProps}/>,
);
expect(wrapper.find(TouchableOpacity).first().props().accessibilityLabel).toEqual('Search');
});
});

View file

@ -14,8 +14,10 @@ import Icon from 'react-native-vector-icons/Ionicons';
import {getTheme} from '@mm-redux/selectors/entities/preferences';
import {preventDoubleTap} from 'app/utils/tap';
import {makeStyleSheetFromTheme} from 'app/utils/theme';
import {t} from 'app/utils/i18n';
import {intlShape} from 'react-intl';
class SettingDrawerButton extends PureComponent {
export class SettingDrawerButton extends PureComponent {
static propTypes = {
openSidebar: PropTypes.func.isRequired,
theme: PropTypes.object,
@ -25,12 +27,33 @@ class SettingDrawerButton extends PureComponent {
theme: {},
};
static contextTypes = {
intl: intlShape.isRequired,
};
handlePress = preventDoubleTap(() => {
this.props.openSidebar();
});
render() {
const {theme} = this.props;
const {formatMessage} = this.context.intl;
const buttonDescriptor = {
id: t('navbar.more_options.button'),
defaultMessage: 'More Options',
description: 'Accessibility helper for more options button in channel header.',
};
const accessibilityLabel = formatMessage(buttonDescriptor);
const buttonHint = {
id: t('navbar.more_options.hint'),
defaultMessage: 'Opens the more options right hand sidebar',
description: 'Accessibility helper for explaining what the more options button in the channel header will do.',
};
const accessibilityHint = formatMessage(buttonHint);
const style = getStyleFromTheme(theme);
const icon = (
@ -43,6 +66,10 @@ class SettingDrawerButton extends PureComponent {
return (
<TouchableOpacity
accessible={true}
accessibilityHint={accessibilityHint}
accessibilityLabel={accessibilityLabel}
accessibilityRole='button'
onPress={this.handlePress}
style={style.container}
>

View file

@ -0,0 +1,44 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import Preferences from '@mm-redux/constants/preferences';
import {SettingDrawerButton} from './settings_drawer_button';
import {shallowWithIntl} from 'test/intl-test-helper';
describe('SettingDrawerButton', () => {
const baseProps = {
openSidebar: jest.fn(),
theme: Preferences.THEMES.default,
};
test('should match, full snapshot', () => {
const wrapper = shallowWithIntl(
<SettingDrawerButton {...baseProps}/>,
);
expect(wrapper).toMatchSnapshot();
});
test('Should be accessible', () => {
const wrapper = shallowWithIntl(
<SettingDrawerButton {...baseProps}/>,
);
expect(wrapper.props().accessible).toBeTruthy();
});
test('Should have the correct accessibilityHint', () => {
const wrapper = shallowWithIntl(
<SettingDrawerButton {...baseProps}/>,
);
expect(wrapper.props().accessibilityHint).toEqual('Opens the more options right hand sidebar');
});
test('Should have the correct accessibilityLabel', () => {
const wrapper = shallowWithIntl(
<SettingDrawerButton {...baseProps}/>,
);
expect(wrapper.props().accessibilityLabel).toEqual('More Options');
});
});

View file

@ -545,6 +545,10 @@
"navbar.channel_drawer.button": "Channels and teams",
"navbar.channel_drawer.hint": "Opens the channels and teams drawer",
"navbar.leave": "Leave Channel",
"navbar.more_options.button": "More Options",
"navbar.more_options.hint": "Opens the more options right hand sidebar",
"navbar.search.button": "Channel Search",
"navbar.search.hint": "Opens the channel search modal",
"password_form.title": "Password Reset",
"password_send.checkInbox": "Please check your inbox.",
"password_send.description": "To reset your password, enter the email address you used to sign up",