Bug 1552067 - add checks section for text label audit. r=mtigley,fluent-reviewers,flod

Differential Revision: https://phabricator.services.mozilla.com/D35497

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Yura Zenevich 2019-07-04 03:36:35 +00:00
Родитель 76b7fe4f3e
Коммит a2bb375be2
19 изменённых файлов: 1795 добавлений и 1215 удалений

Просмотреть файл

@ -52,8 +52,9 @@ AccessibilityView.prototype = {
* @param {JSON} supports a collection of flags indicating which accessibility
* panel features are supported by the current serverside
* version.
* @param {Array} fluentBundles array of FluentBundles elements for localization
*/
async initialize(accessibility, walker, supports) {
async initialize(accessibility, walker, supports, fluentBundles) {
// Make sure state is reset every time accessibility panel is initialized.
await this.store.dispatch(reset(accessibility, supports));
const container = document.getElementById("content");
@ -63,7 +64,7 @@ AccessibilityView.prototype = {
return;
}
const mainFrame = MainFrame({ accessibility, walker });
const mainFrame = MainFrame({ accessibility, walker, fluentBundles });
// Render top level component
const provider = createElement(Provider, { store: this.store }, mainFrame);
this.mainFrame = ReactDOM.render(provider, container);

Просмотреть файл

@ -28,6 +28,7 @@
--accessible-label-color: var(--grey-60);
/* Similarly to webconsole, add more padding before the toolbar group. */
--separator-inline-margin: 5px;
--accessibility-code-background: var(--grey-20);
}
:root.theme-dark {
@ -42,6 +43,7 @@
--accessible-label-background-color: var(--grey-80);
--accessible-label-border-color: var(--grey-50);
--accessible-label-color: var(--grey-40);
--accessibility-code-background: var(--grey-70);
}
/* General */
@ -660,8 +662,31 @@ body {
white-space: initial;
}
/* Color Contrast */
.accessibility-color-contrast-check,
/* Checks */
.accessibility-check code {
background-color: var(--accessibility-code-background);
border-radius: 2px;
box-decoration-break: clone;
padding: 0 4px;
}
.accessibility-text-label-check .icon {
display: inline;
-moz-context-properties: fill;
vertical-align: top;
margin-block-start: 2px;
margin-inline-end: 4px;
}
.accessibility-text-label-check .icon.fail {
fill: var(--theme-icon-error-color);
}
.accessibility-text-label-check .icon.WARNING {
fill: var(--theme-icon-warning-color);
}
.accessibility-check,
.accessibility-color-contrast {
position: relative;
display: flex;
@ -669,7 +694,7 @@ body {
height: inherit;
}
.accessibility-color-contrast-check {
.accessibility-check {
flex-direction: column;
padding: 4px var(--accessibility-horizontal-indent);
line-height: 20px;
@ -679,20 +704,21 @@ body {
align-items: baseline;
}
.accessibility-color-contrast-header {
.accessibility-check-header {
margin: 0;
font-weight: bold;
font-size: var(--accessibility-font-size);
line-height: var(--accessibility-toolbar-height);
}
.accessibility-color-contrast-annotation {
.accessibility-check-annotation {
display: inline;
margin: 0;
white-space: normal;
color: var(--accessible-label-color);
}
.accessibility-color-contrast-annotation .link {
.accessibility-check-annotation .link {
color: var(--accessibility-link-color);
cursor: pointer;
outline: 0;
@ -700,16 +726,16 @@ body {
font-style: normal;
}
.accessibility-color-contrast-annotation .link:hover:not(:focus) {
.accessibility-check-annotation .link:hover:not(:focus) {
text-decoration: underline;
}
.accessibility-color-contrast-annotation .link:focus:not(:active) {
.accessibility-check-annotation .link:focus:not(:active) {
box-shadow: 0 0 0 2px var(--accessibility-toolbar-focus), 0 0 0 4px var(--accessibility-toolbar-focus-alpha30);
border-radius: 2px;
}
.accessibility-color-contrast-annotation .link:active {
.accessibility-check-annotation .link:active {
color: var(--accessibility-link-color-active);
text-decoration: underline;
}

Просмотреть файл

@ -12,6 +12,7 @@ const { div } = require("devtools/client/shared/vendor/react-dom-factories");
const List = createFactory(require("devtools/client/shared/components/List").List);
const ColorContrastCheck =
createFactory(require("./ColorContrastAccessibility").ColorContrastCheck);
const TextLabelCheck = createFactory(require("./TextLabelCheck"));
const { L10N } = require("../utils/l10n");
const { accessibility: { AUDIT_TYPE } } = require("devtools/shared/constants");
@ -39,6 +40,10 @@ class Checks extends Component {
return ColorContrastCheck(contrastRatio);
}
[AUDIT_TYPE.TEXT_LABEL](textLabelCheck) {
return TextLabelCheck(textLabelCheck);
}
render() {
const { audit, labelledby } = this.props;
if (!audit) {

Просмотреть файл

@ -152,7 +152,7 @@ class ContrastAnnotationClass extends Component {
return (
LearnMoreLink(
{
className: "accessibility-color-contrast-annotation",
className: "accessibility-check-annotation",
href: A11Y_CONTRAST_LEARN_MORE_LINK,
learnMoreStringKey: "accessibility.learnMore",
l10n: L10N,
@ -178,10 +178,10 @@ class ColorContrastCheck extends Component {
return (
div({
role: "presentation",
className: "accessibility-color-contrast-check",
className: "accessibility-check",
},
h3({
className: "accessibility-color-contrast-header",
className: "accessibility-check-header",
}, L10N.getStr("accessibility.contrast.header")),
ColorContrastAccessibility(this.props),
!error && ContrastAnnotation(this.props)

Просмотреть файл

@ -12,6 +12,10 @@ const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const { reset } = require("../actions/ui");
// Localization
const FluentReact = require("devtools/client/shared/vendor/fluent-react");
const LocalizationProvider = createFactory(FluentReact.LocalizationProvider);
// Constants
const { SIDEBAR_WIDTH, PORTRAIT_MODE_WIDTH } = require("../constants");
@ -31,6 +35,7 @@ class MainFrame extends Component {
static get propTypes() {
return {
accessibility: PropTypes.object.isRequired,
fluentBundles: PropTypes.array.isRequired,
walker: PropTypes.object.isRequired,
enabled: PropTypes.bool.isRequired,
dispatch: PropTypes.func.isRequired,
@ -91,7 +96,7 @@ class MainFrame extends Component {
* Render Accessibility panel content
*/
render() {
const { accessibility, walker, enabled, auditing } = this.props;
const { accessibility, walker, fluentBundles, enabled, auditing } = this.props;
if (!enabled) {
return Description({ accessibility });
@ -100,7 +105,7 @@ class MainFrame extends Component {
// Audit is currently running.
const isAuditing = auditing.length > 0;
return (
return LocalizationProvider({ messages: fluentBundles },
div({ className: "mainFrame", role: "presentation" },
Toolbar({ accessibility, walker }),
isAuditing && AuditProgressOverlay(),
@ -122,8 +127,10 @@ class MainFrame extends Component {
}, AccessibilityTree({ walker })),
endPanel: RightSidebar({ walker }),
vert: this.useLandscapeMode,
})),
));
})
),
)
);
}
}

Просмотреть файл

@ -0,0 +1,335 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// React
const { Component, createFactory } = require("devtools/client/shared/vendor/react");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const ReactDOM = require("devtools/client/shared/vendor/react-dom-factories");
const FluentReact = require("devtools/client/shared/vendor/fluent-react");
const Localized = createFactory(FluentReact.Localized);
const { openDocLink } = require("devtools/client/shared/link");
const { A11Y_TEXT_LABEL_LINKS } = require("../constants");
const {
accessibility: {
AUDIT_TYPE: { TEXT_LABEL },
ISSUE_TYPE: {
[TEXT_LABEL]: {
AREA_NO_NAME_FROM_ALT,
DIALOG_NO_NAME,
DOCUMENT_NO_TITLE,
EMBED_NO_NAME,
FIGURE_NO_NAME,
FORM_FIELDSET_NO_NAME,
FORM_FIELDSET_NO_NAME_FROM_LEGEND,
FORM_NO_NAME,
FORM_NO_VISIBLE_NAME,
FORM_OPTGROUP_NO_NAME,
FORM_OPTGROUP_NO_NAME_FROM_LABEL,
FRAME_NO_NAME,
HEADING_NO_CONTENT,
HEADING_NO_NAME,
IFRAME_NO_NAME_FROM_TITLE,
IMAGE_NO_NAME,
INTERACTIVE_NO_NAME,
MATHML_GLYPH_NO_NAME,
TOOLBAR_NO_NAME,
},
},
SCORES: { BEST_PRACTICES, FAIL, WARNING },
},
} = require("devtools/shared/constants");
/**
* A map from text label issues to annotation component properties.
*/
const ISSUE_TO_ANNOTATION_MAP = {
[AREA_NO_NAME_FROM_ALT]: {
href: A11Y_TEXT_LABEL_LINKS.AREA_NO_NAME_FROM_ALT,
l10nId: "accessibility-text-label-issue-area",
args: {
get code() {
return ReactDOM.code({}, "alt");
},
// Note: there is no way right now to use custom elements in privileged
// content. We have to use something like <div> since we can't provide
// three args with the same name.
get div() {
return ReactDOM.code({}, "area");
},
// Note: there is no way right now to use custom elements in privileged
// content. We have to use something like <span> since we can't provide
// three args with the same name.
get span() {
return ReactDOM.code({}, "href");
},
},
},
[DIALOG_NO_NAME]: {
href: A11Y_TEXT_LABEL_LINKS.DIALOG_NO_NAME,
l10nId: "accessibility-text-label-issue-dialog",
},
[DOCUMENT_NO_TITLE]: {
href: A11Y_TEXT_LABEL_LINKS.DOCUMENT_NO_TITLE,
l10nId: "accessibility-text-label-issue-document-title",
args: {
get code() {
return ReactDOM.code({}, "title");
},
},
},
[EMBED_NO_NAME]: {
href: A11Y_TEXT_LABEL_LINKS.EMBED_NO_NAME,
l10nId: "accessibility-text-label-issue-embed",
},
[FIGURE_NO_NAME]: {
href: A11Y_TEXT_LABEL_LINKS.FIGURE_NO_NAME,
l10nId: "accessibility-text-label-issue-figure",
},
[FORM_FIELDSET_NO_NAME]: {
href: A11Y_TEXT_LABEL_LINKS.FORM_FIELDSET_NO_NAME,
l10nId: "accessibility-text-label-issue-fieldset",
args: {
get code() {
return ReactDOM.code({}, "fieldset");
},
},
},
[FORM_FIELDSET_NO_NAME_FROM_LEGEND]: {
href: A11Y_TEXT_LABEL_LINKS.FORM_FIELDSET_NO_NAME_FROM_LEGEND,
l10nId: "accessibility-text-label-issue-fieldset-legend",
args: {
get code() {
return ReactDOM.code({}, "legend");
},
// Note: there is no way right now to use custom elements in privileged
// content. We have to use something like <span> since we can't provide
// two args with the same name.
get span() {
return ReactDOM.code({}, "fieldset");
},
},
},
[FORM_NO_NAME]: {
href: A11Y_TEXT_LABEL_LINKS.FORM_NO_NAME,
l10nId: "accessibility-text-label-issue-form",
},
[FORM_NO_VISIBLE_NAME]: {
href: A11Y_TEXT_LABEL_LINKS.FORM_NO_VISIBLE_NAME,
l10nId: "accessibility-text-label-issue-form-visible",
},
[FORM_OPTGROUP_NO_NAME]: {
href: A11Y_TEXT_LABEL_LINKS.FORM_OPTGROUP_NO_NAME,
l10nId: "accessibility-text-label-issue-optgroup",
args: {
get code() {
return ReactDOM.code({}, "optgroup");
},
},
},
[FORM_OPTGROUP_NO_NAME_FROM_LABEL]: {
href: A11Y_TEXT_LABEL_LINKS.FORM_OPTGROUP_NO_NAME_FROM_LABEL,
l10nId: "accessibility-text-label-issue-optgroup-label",
args: {
get code() {
return ReactDOM.code({}, "label");
},
// Note: there is no way right now to use custom elements in privileged
// content. We have to use something like <span> since we can't provide
// two args with the same name.
get span() {
return ReactDOM.code({}, "optgroup");
},
},
},
[FRAME_NO_NAME]: {
href: A11Y_TEXT_LABEL_LINKS.FRAME_NO_NAME,
l10nId: "accessibility-text-label-issue-frame",
args: {
get code() {
return ReactDOM.code({}, "frame");
},
},
},
[HEADING_NO_CONTENT]: {
href: A11Y_TEXT_LABEL_LINKS.HEADING_NO_CONTENT,
l10nId: "accessibility-text-label-issue-heading-content",
},
[HEADING_NO_NAME]: {
href: A11Y_TEXT_LABEL_LINKS.HEADING_NO_NAME,
l10nId: "accessibility-text-label-issue-heading",
},
[IFRAME_NO_NAME_FROM_TITLE]: {
href: A11Y_TEXT_LABEL_LINKS.IFRAME_NO_NAME_FROM_TITLE,
l10nId: "accessibility-text-label-issue-iframe",
args: {
get code() {
return ReactDOM.code({}, "title");
},
// Note: there is no way right now to use custom elements in privileged
// content. We have to use something like <span> since we can't provide
// two args with the same name.
get span() {
return ReactDOM.code({}, "iframe");
},
},
},
[IMAGE_NO_NAME]: {
href: A11Y_TEXT_LABEL_LINKS.IMAGE_NO_NAME,
l10nId: "accessibility-text-label-issue-image",
},
[INTERACTIVE_NO_NAME]: {
href: A11Y_TEXT_LABEL_LINKS.INTERACTIVE_NO_NAME,
l10nId: "accessibility-text-label-issue-interactive",
},
[MATHML_GLYPH_NO_NAME]: {
href: A11Y_TEXT_LABEL_LINKS.MATHML_GLYPH_NO_NAME,
l10nId: "accessibility-text-label-issue-glyph",
args: {
get code() {
return ReactDOM.code({}, "alt");
},
// Note: there is no way right now to use custom elements in privileged
// content. We have to use something like <span> since we can't provide
// two args with the same name.
get span() {
return ReactDOM.code({}, "mglyph");
},
},
},
[TOOLBAR_NO_NAME]: {
href: A11Y_TEXT_LABEL_LINKS.TOOLBAR_NO_NAME,
l10nId: "accessibility-text-label-issue-toolbar",
},
};
/**
* A map of accessibility scores to the text descriptions of check icons.
*/
const SCORE_TO_ICON_MAP = {
[BEST_PRACTICES]: {
l10nId: "accessibility-best-practices",
src: "chrome://devtools/skin/images/info.svg",
},
[FAIL]: {
l10nId: "accessibility-fail",
src: "chrome://devtools/skin/images/error.svg",
},
[WARNING]: {
l10nId: "accessibility-warning",
src: "chrome://devtools/skin/images/alert.svg",
},
};
/**
* Localized "Learn more" link that opens a new tab with relevant documentation.
*/
class LearnMoreClass extends Component {
static get propTypes() {
return {
href: PropTypes.string,
l10nId: PropTypes.string.isRequired,
onClick: PropTypes.func,
};
}
static get defaultProps() {
return {
href: "#",
l10nId: null,
onClick: LearnMoreClass.openDocOnClick,
};
}
static openDocOnClick(event) {
event.preventDefault();
openDocLink(event.target.href);
}
render() {
const { href, l10nId, onClick } = this.props;
const className = "link";
return Localized({ id: l10nId }, ReactDOM.a({ className, href, onClick }));
}
}
const LearnMore = createFactory(LearnMoreClass);
/**
* Renders icon with text description for the text label accessibility check.
*
* @param {Object}
* Options:
* - score: value from SCORES from "devtools/shared/constants"
*/
function Icon({ score }) {
const { l10nId, src } = SCORE_TO_ICON_MAP[score];
return Localized({ id: l10nId, attrs: { alt: true } },
ReactDOM.img({ src, className: `icon ${score}` })
);
}
/**
* Renders text description of the text label accessibility check.
*
* @param {Object}
* Options:
* - issue: value from ISSUE_TYPE[AUDIT_TYPE.TEXT_LABEL] from
* "devtools/shared/constants"
*/
function Annotation({ issue }) {
const { args, href, l10nId } = ISSUE_TO_ANNOTATION_MAP[issue];
return Localized({
id: l10nId,
a: LearnMore({ l10nId: "accessibility-learn-more", href }),
...args,
},
ReactDOM.p({ className: "accessibility-check-annotation" })
);
}
/**
* Component for rendering a check for text label accessibliity check failures,
* warnings and best practices suggestions association with a given
* accessibility object in the accessibility tree.
*/
class TextLabelCheck extends Component {
static get propTypes() {
return {
issue: PropTypes.string.isRequired,
score: PropTypes.string.isRequired,
};
}
render() {
const { issue, score } = this.props;
return ReactDOM.div({
role: "presentation",
className: "accessibility-check",
},
Localized({
id: "accessibility-text-label-header",
},
ReactDOM.h3({ className: "accessibility-check-header" })),
ReactDOM.div({
role: "presentation",
className: "accessibility-text-label-check",
},
Icon({ score }),
Annotation({ issue })
)
);
}
}
module.exports = TextLabelCheck;

Просмотреть файл

@ -22,5 +22,6 @@ DevToolsModules(
'MainFrame.js',
'RightSidebar.js',
'TextLabelBadge.js',
'TextLabelCheck.js',
'Toolbar.js'
)

Просмотреть файл

@ -3,7 +3,34 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { accessibility: { AUDIT_TYPE } } = require("devtools/shared/constants");
const {
accessibility: {
AUDIT_TYPE,
ISSUE_TYPE: {
[AUDIT_TYPE.TEXT_LABEL]: {
AREA_NO_NAME_FROM_ALT,
DIALOG_NO_NAME,
DOCUMENT_NO_TITLE,
EMBED_NO_NAME,
FIGURE_NO_NAME,
FORM_FIELDSET_NO_NAME,
FORM_FIELDSET_NO_NAME_FROM_LEGEND,
FORM_NO_NAME,
FORM_NO_VISIBLE_NAME,
FORM_OPTGROUP_NO_NAME,
FORM_OPTGROUP_NO_NAME_FROM_LABEL,
FRAME_NO_NAME,
HEADING_NO_CONTENT,
HEADING_NO_NAME,
IFRAME_NO_NAME_FROM_TITLE,
IMAGE_NO_NAME,
INTERACTIVE_NO_NAME,
MATHML_GLYPH_NO_NAME,
TOOLBAR_NO_NAME,
},
},
},
} = require("devtools/shared/constants");
// Used in accessible component for properties tree rendering.
exports.TREE_ROW_HEIGHT = 21;
@ -84,3 +111,41 @@ exports.A11Y_LEARN_MORE_LINK =
exports.A11Y_CONTRAST_LEARN_MORE_LINK =
"https://developer.mozilla.org/docs/Web/Accessibility/Understanding_WCAG/Perceivable/" +
"Color_contrast?utm_source=devtools&utm_medium=a11y-panel-checks-color-contrast";
const A11Y_TEXT_LABEL_LINK_BASE =
"https://developer.mozilla.org/docs/Web/Accessibility/Understanding_WCAG/Text_labels_and_names" +
"?utm_source=devtools&utm_medium=a11y-panel-checks-text-label";
const A11Y_TEXT_LABEL_LINK_IDS = {
[AREA_NO_NAME_FROM_ALT]:
"Use_alt_attribute_to_provide_a_name_for_areas_that_have_the_href_attribute",
[DIALOG_NO_NAME]: "Dialogs_should_have_a_name",
[DOCUMENT_NO_TITLE]: "Documents_must_have_a_title",
[EMBED_NO_NAME]: "Embedded_content_must_have_a_name",
[FIGURE_NO_NAME]: "Figures_with_optional_captions_should_have_a_name",
[FORM_FIELDSET_NO_NAME]: "Form_element_groups_must_have_a_name",
[FORM_FIELDSET_NO_NAME_FROM_LEGEND]:
"Use_legend_element_to_provide_a_name_for_form_element_groups",
[FORM_NO_NAME]: "Form_elements_must_have_a_name",
[FORM_NO_VISIBLE_NAME]: "Form_elements_should_have_a_visible_text_label",
[FORM_OPTGROUP_NO_NAME]: "Groupings_of_options_must_have_a_name",
[FORM_OPTGROUP_NO_NAME_FROM_LABEL]:
"Use_label_attribute_to_provide_a_name_for_groupings_of_options",
[FRAME_NO_NAME]: "Frames_must_have_a_name",
[HEADING_NO_NAME]: "Headings_must_have_a_name",
[HEADING_NO_CONTENT]: "Headings_must_have_visible_text_content",
[IFRAME_NO_NAME_FROM_TITLE]: "Use_title_attribute_to_describe_iframe_content",
[IMAGE_NO_NAME]: "Content_with_images_must_have_a_name",
[INTERACTIVE_NO_NAME]: "Interactive_elements_must_have_a_name",
[MATHML_GLYPH_NO_NAME]:
"Use_alt_attribute_to_provide_a_name_for_MathML_glyphs",
[TOOLBAR_NO_NAME]:
"Toolbars_must_have_a_name_when_there_is_more_than_one_toolbar",
};
const A11Y_TEXT_LABEL_LINKS = {};
for (const key in A11Y_TEXT_LABEL_LINK_IDS) {
A11Y_TEXT_LABEL_LINKS[key] =
`${A11Y_TEXT_LABEL_LINK_BASE}#${A11Y_TEXT_LABEL_LINK_IDS[key]}`;
}
exports.A11Y_TEXT_LABEL_LINKS = A11Y_TEXT_LABEL_LINKS;

Просмотреть файл

@ -3,6 +3,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const Services = require("Services");
const { L10nRegistry } = require("resource://gre/modules/L10nRegistry.jsm");
const EventEmitter = require("devtools/shared/event-emitter");
const Telemetry = require("devtools/client/shared/telemetry");
@ -81,6 +84,8 @@ AccessibilityPanel.prototype = {
this.picker = new Picker(this);
}
this.fluentBundles = await this.createFluentBundles();
this.updateA11YServiceDurationTimer();
this.front.on("init", this.updateA11YServiceDurationTimer);
this.front.on("shutdown", this.updateA11YServiceDurationTimer);
@ -94,6 +99,25 @@ AccessibilityPanel.prototype = {
return this._opening;
},
/**
* Retrieve message contexts for the current locales, and return them as an
* array of FluentBundles elements.
*/
async createFluentBundles() {
const locales = Services.locale.appLocalesAsBCP47;
const generator =
L10nRegistry.generateBundles(locales, ["devtools/accessibility.ftl"]);
// Return value of generateBundles is a generator and should be converted to
// a sync iterable before using it with React.
const contexts = [];
for await (const message of generator) {
contexts.push(message);
}
return contexts;
},
onNewAccessibleFrontSelected(selected) {
this.emit("new-accessible-front-selected", selected);
},
@ -133,7 +157,8 @@ AccessibilityPanel.prototype = {
}
// Alright reset the flag we are about to refresh the panel.
this.shouldRefresh = false;
this.postContentMessage("initialize", this.front, this.walker, this.supports);
this.postContentMessage("initialize", this.front, this.walker, this.supports,
this.fluentBundles);
},
updateA11YServiceDurationTimer() {

Просмотреть файл

@ -0,0 +1,9 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
module.exports = {
"plugins": ["@babel/plugin-proposal-async-generator-functions"],
};

Просмотреть файл

@ -4,10 +4,10 @@ exports[`AuditController component: audit filter filtered contrast checks fail 1
exports[`AuditController component: audit filter filtered contrast checks fail range 1`] = `"<span></span>"`;
exports[`AuditController component: audit filter filtered contrast checks success 1`] = `null`;
exports[`AuditController component: audit filter filtered contrast checks success 1`] = `""`;
exports[`AuditController component: audit filter filtered no checks 1`] = `null`;
exports[`AuditController component: audit filter filtered no checks 1`] = `""`;
exports[`AuditController component: audit filter filtered unknown checks 1`] = `null`;
exports[`AuditController component: audit filter filtered unknown checks 1`] = `""`;
exports[`AuditController component: audit filter not filtered 1`] = `"<span></span>"`;

Просмотреть файл

@ -10,4 +10,4 @@ exports[`AuditProgressOverlay component: render auditing progress 2`] = `"<span
exports[`AuditProgressOverlay component: render auditing progress 3`] = `"<span id=\\"audit-progress-container\\">accessibility.progress.progressbar<progress max=\\"100\\" value=\\"75\\" class=\\"audit-progress-progressbar\\" aria-labelledby=\\"audit-progress-container\\"></progress></span>"`;
exports[`AuditProgressOverlay component: render not auditing 1`] = `null`;
exports[`AuditProgressOverlay component: render not auditing 1`] = `""`;

Просмотреть файл

@ -6,10 +6,10 @@ exports[`Badges component: contrast ratio fail render 1`] = `"<span class=\\"bad
exports[`Badges component: contrast ratio success render 1`] = `"<span class=\\"badges\\" role=\\"group\\" aria-label=\\"accessibility.badges\\"></span>"`;
exports[`Badges component: empty checks render 1`] = `null`;
exports[`Badges component: empty checks render 1`] = `""`;
exports[`Badges component: no props render 1`] = `null`;
exports[`Badges component: no props render 1`] = `""`;
exports[`Badges component: null checks render 1`] = `null`;
exports[`Badges component: null checks render 1`] = `""`;
exports[`Badges component: unsupported checks render 1`] = `null`;
exports[`Badges component: unsupported checks render 1`] = `""`;

Просмотреть файл

@ -0,0 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`TextLabelCheck component: BEST_PRACTICES render 1`] = `"<div role=\\"presentation\\" class=\\"accessibility-check\\"><h3 class=\\"accessibility-check-header\\"></h3><div role=\\"presentation\\" class=\\"accessibility-text-label-check\\"><img src=\\"chrome://devtools/skin/images/info.svg\\" class=\\"icon BEST_PRACTICES\\"><p class=\\"accessibility-check-annotation\\"></p></div></div>"`;
exports[`TextLabelCheck component: WARNING render 1`] = `"<div role=\\"presentation\\" class=\\"accessibility-check\\"><h3 class=\\"accessibility-check-header\\"></h3><div role=\\"presentation\\" class=\\"accessibility-text-label-check\\"><img src=\\"chrome://devtools/skin/images/alert.svg\\" class=\\"icon WARNING\\"><p class=\\"accessibility-check-annotation\\"></p></div></div>"`;
exports[`TextLabelCheck component: fail render 1`] = `"<div role=\\"presentation\\" class=\\"accessibility-check\\"><h3 class=\\"accessibility-check-header\\"></h3><div role=\\"presentation\\" class=\\"accessibility-text-label-check\\"><img src=\\"chrome://devtools/skin/images/error.svg\\" class=\\"icon fail\\"><p class=\\"accessibility-check-annotation\\"></p></div></div>"`;

Просмотреть файл

@ -0,0 +1,69 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const { mount } = require("enzyme");
const { createFactory } = require("devtools/client/shared/vendor/react");
const TextLabelCheckClass = require("devtools/client/accessibility/components/TextLabelCheck");
const TextLabelCheck = createFactory(TextLabelCheckClass);
const FluentReact = require("devtools/client/shared/vendor/fluent-react");
const LocalizationProvider = createFactory(FluentReact.LocalizationProvider);
const {
accessibility: {
AUDIT_TYPE: { TEXT_LABEL },
ISSUE_TYPE: {
[TEXT_LABEL]: {
AREA_NO_NAME_FROM_ALT,
DIALOG_NO_NAME,
FORM_NO_VISIBLE_NAME,
},
},
SCORES: { BEST_PRACTICES, FAIL, WARNING },
},
} = require("devtools/shared/constants");
function testTextLabelCheck(wrapper, props) {
expect(wrapper.html()).toMatchSnapshot();
expect(wrapper.children().length).toBe(1);
const container = wrapper.childAt(0);
expect(container.hasClass("accessibility-check")).toBe(true);
expect(container.prop("role")).toBe("presentation");
expect(wrapper.props()).toMatchObject(props);
const localized = wrapper.find(FluentReact.Localized);
expect(localized.length).toBe(3);
const heading = localized.at(0).childAt(0);
expect(heading.type()).toBe("h3");
expect(heading.hasClass("accessibility-check-header")).toBe(true);
const icon = localized.at(1).childAt(0);
expect(icon.type()).toBe("img");
expect(icon.hasClass(props.score === FAIL ? "fail" : props.score)).toBe(true);
const annotation = localized.at(2).childAt(0);
expect(annotation.type()).toBe("p");
expect(annotation.hasClass("accessibility-check-annotation")).toBe(true);
}
describe("TextLabelCheck component:", () => {
const testProps = [
{ issue: AREA_NO_NAME_FROM_ALT, score: FAIL },
{ issue: FORM_NO_VISIBLE_NAME, score: WARNING },
{ issue: DIALOG_NO_NAME, score: BEST_PRACTICES },
];
for (const props of testProps) {
it(`${props.score} render`, () => {
const wrapper = mount(LocalizationProvider({ messages: []},
TextLabelCheck(props)));
const textLabelCheck = wrapper.find(TextLabelCheckClass);
testTextLabelCheck(textLabelCheck, props);
});
}
});

Просмотреть файл

@ -10,12 +10,13 @@
"test-ci": "jest --json"
},
"dependencies": {
"jest": "^23.0.0",
"@babel/plugin-proposal-async-generator-functions": "^7.2.0",
"jest": "^24.6.0",
"react-test-renderer": "16.4.1",
"react": "16.4.1",
"react-dom": "16.4.1",
"enzyme": "^3.3.0",
"enzyme-to-json": "3.3.4",
"enzyme-adapter-react-16": "^1.1.1"
"enzyme": "^3.9.0",
"enzyme-to-json": "^3.3.5",
"enzyme-adapter-react-16": "^1.13.2"
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -8,13 +8,13 @@ window._snapshots = {
"type": "div",
"props": {
"role": "presentation",
"className": "accessibility-color-contrast-check",
"className": "accessibility-check",
},
"children": [
{
"type": "h3",
"props": {
"className": "accessibility-color-contrast-header",
"className": "accessibility-check-header",
},
"children": [
"Color and Contrast",
@ -45,13 +45,13 @@ window._snapshots = {
"type": "div",
"props": {
"role": "presentation",
"className": "accessibility-color-contrast-check",
"className": "accessibility-check",
},
"children": [
{
"type": "h3",
"props": {
"className": "accessibility-color-contrast-header",
"className": "accessibility-check-header",
},
"children": [
"Color and Contrast",
@ -83,7 +83,7 @@ window._snapshots = {
{
"type": "p",
"props": {
"className": "accessibility-color-contrast-annotation",
"className": "accessibility-check-annotation",
},
"children": [
"Does not meet WCAG standards for accessible text. ",
@ -110,13 +110,13 @@ window._snapshots = {
"type": "div",
"props": {
"role": "presentation",
"className": "accessibility-color-contrast-check",
"className": "accessibility-check",
},
"children": [
{
"type": "h3",
"props": {
"className": "accessibility-color-contrast-header",
"className": "accessibility-check-header",
},
"children": [
"Color and Contrast",
@ -170,7 +170,7 @@ window._snapshots = {
{
"type": "p",
"props": {
"className": "accessibility-color-contrast-annotation",
"className": "accessibility-check-annotation",
},
"children": [
"Does not meet WCAG standards for accessible text. ",
@ -197,13 +197,13 @@ window._snapshots = {
"type": "div",
"props": {
"role": "presentation",
"className": "accessibility-color-contrast-check",
"className": "accessibility-check",
},
"children": [
{
"type": "h3",
"props": {
"className": "accessibility-color-contrast-header",
"className": "accessibility-check-header",
},
"children": [
"Color and Contrast",
@ -246,7 +246,7 @@ window._snapshots = {
{
"type": "p",
"props": {
"className": "accessibility-color-contrast-annotation",
"className": "accessibility-check-annotation",
},
"children": [
"Meets WCAG AA standards for accessible text. ",

Просмотреть файл

@ -0,0 +1,62 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
### These strings are used inside the Accessibility panel.
accessibility-learn-more = Learn more
accessibility-text-label-header = Text Labels and Names
## Text entries that are used as text alternative for icons that depict accessibility isses.
accessibility-warning =
.alt = Warning
accessibility-fail =
.alt = Error
accessibility-best-practices =
.alt = Best Practices
## Text entries for a paragraph used in the accessibility panel sidebar's checks section
## that describe that currently selected accessible object has an accessibility issue
## with its text label or accessible name.
accessibility-text-label-issue-area = Use <code>alt</code> attribute to label <div>area</div> elements that have the <span>href</span> attribute. <a>Learn more</a>
accessibility-text-label-issue-dialog = Dialogs should be labeled. <a>Learn more</a>
accessibility-text-label-issue-document-title = Documents must have a <code>title</code>. <a>Learn more</a>
accessibility-text-label-issue-embed = Embedded content must be labeled. <a>Learn more</a>
accessibility-text-label-issue-figure = Figures with optional captions should be labeled. <a>Learn more</a>
accessibility-text-label-issue-fieldset = <code>fieldset</code> elements must be labeled. <a>Learn more</a>
accessibility-text-label-issue-fieldset-legend = Use <code>legend</code> element to label <span>fieldset</span> elements. <a>Learn more</a>
accessibility-text-label-issue-form = Form elements must be labeled. <a>Learn more</a>
accessibility-text-label-issue-form-visible = Form elements should have a visible text label. <a>Learn more</a>
accessibility-text-label-issue-frame = <code>frame</code> elements must be labeled. <a>Learn more</a>
accessibility-text-label-issue-glyph = Use <code>alt</code> attribute to label <span>mglyph</span> elements. <a>Learn more</a>
accessibility-text-label-issue-heading = Headings must be labeled. <a>Learn more</a>
accessibility-text-label-issue-heading-content = Headings should have visible text content. <a>Learn more</a>
accessibility-text-label-issue-iframe = Use <code>title</code> attribute to describe <span>iframe</span> content. <a>Learn more</a>
accessibility-text-label-issue-image = Content with images must be labeled. <a>Learn more</a>
accessibility-text-label-issue-interactive = Interactive elements must be labeled. <a>Learn more</a>
accessibility-text-label-issue-optgroup = <code>optgroup</code> elements must be labeled. <a>Learn more</a>
accessibility-text-label-issue-optgroup-label = Use <code>label</code> attribute to label <span>optgroup</span> elements. <a>Learn more</a>
accessibility-text-label-issue-toolbar = Toolbars must be labeled when there is more than one toolbar. <a>Learn more</a>