testaro 27.0.0 → 28.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +3 -1
- package/README.md +14 -3
- package/package.json +2 -1
- package/procs/aslint.js +83 -0
- package/procs/nav.js +56 -14
- package/procs/standardize.js +36 -0
- package/run.js +35 -22
- package/tests/aslint.js +83 -0
- package/tests/axe.js +4 -0
- package/tests/qualWeb.js +6 -0
- package/aslint/LICENSE +0 -362
- package/aslint/README.md +0 -260
- package/aslint/app/rules/abstract-rule.ts +0 -83
- package/aslint/app/rules/aslint/incorrect-technique-for-hiding-content/incorrect-technique-for-hiding-content.documentation.md +0 -36
- package/aslint/app/rules/aslint/incorrect-technique-for-hiding-content/incorrect-technique-for-hiding-content.test.ts +0 -113
- package/aslint/app/rules/aslint/incorrect-technique-for-hiding-content/incorrect-technique-for-hiding-content.ts +0 -103
- package/aslint/app/rules/aslint/invalid-attribute-dir-value/invalid-attribute-dir-value.documentation.md +0 -34
- package/aslint/app/rules/aslint/invalid-attribute-dir-value/invalid-attribute-dir-value.test.ts +0 -82
- package/aslint/app/rules/aslint/invalid-attribute-dir-value/invalid-attribute-dir-value.ts +0 -44
- package/aslint/app/rules/aslint/label-duplicated-content-title/label-duplicated-content-title.documentation.md +0 -40
- package/aslint/app/rules/aslint/label-duplicated-content-title/label-duplicated-content-title.test.ts +0 -48
- package/aslint/app/rules/aslint/label-duplicated-content-title/label-duplicated-content-title.ts +0 -37
- package/aslint/app/rules/aslint/links-language-destination/links-language-destination.test.ts +0 -50
- package/aslint/app/rules/aslint/links-language-destination/links-language-destination.ts +0 -70
- package/aslint/app/rules/aslint/main-element-only-one/main-element-only-one.test.ts +0 -55
- package/aslint/app/rules/aslint/main-element-only-one/main-element-only-one.ts +0 -83
- package/aslint/app/rules/aslint/main-landmark-must-be-top-level/main-landmark-must-be-top-level.test.ts +0 -12
- package/aslint/app/rules/aslint/main-landmark-must-be-top-level/main-landmark-must-be-top-level.ts +0 -73
- package/aslint/app/rules/aslint/minimum-font-size/minimum-font-size.test.ts +0 -12
- package/aslint/app/rules/aslint/minimum-font-size/minimum-font-size.ts +0 -87
- package/aslint/app/rules/aslint/missing-href-on-a/missing-href-on-a.test.ts +0 -48
- package/aslint/app/rules/aslint/missing-href-on-a/missing-href-on-a.ts +0 -40
- package/aslint/app/rules/aslint/misused-aria-on-focusable-element/misused-aria-on-focusable-element.test.ts +0 -12
- package/aslint/app/rules/aslint/misused-aria-on-focusable-element/misused-aria-on-focusable-element.ts +0 -66
- package/aslint/app/rules/aslint/misused-input-attribute/misused-input-attribute.test.ts +0 -12
- package/aslint/app/rules/aslint/misused-input-attribute/misused-input-attribute.ts +0 -134
- package/aslint/app/rules/aslint/misused-required-attribute/misused-required-attribute.test.ts +0 -12
- package/aslint/app/rules/aslint/misused-required-attribute/misused-required-attribute.ts +0 -90
- package/aslint/app/rules/aslint/navigation-landmark-restrictions/navigation-landmark-restrictions.test.ts +0 -12
- package/aslint/app/rules/aslint/navigation-landmark-restrictions/navigation-landmark-restrictions.ts +0 -48
- package/aslint/app/rules/aslint/obsolete-html-attributes/obsolete-html-attributes.test.ts +0 -12
- package/aslint/app/rules/aslint/obsolete-html-attributes/obsolete-html-attributes.ts +0 -148
- package/aslint/app/rules/aslint/obsolete-html-elements/obsolete-html-elements.test.ts +0 -12
- package/aslint/app/rules/aslint/obsolete-html-elements/obsolete-html-elements.ts +0 -66
- package/aslint/app/rules/aslint/outline-zero/outline-zero.test.ts +0 -12
- package/aslint/app/rules/aslint/outline-zero/outline-zero.ts +0 -85
- package/aslint/app/rules/aslint/overlay/overlay.test.ts +0 -122
- package/aslint/app/rules/aslint/overlay/overlay.ts +0 -141
- package/aslint/app/rules/aslint/redundant/aria-role-dialog/aria-role-dialog.documentation.md +0 -49
- package/aslint/app/rules/aslint/redundant/aria-role-dialog/aria-role-dialog.test.ts +0 -91
- package/aslint/app/rules/aslint/redundant/aria-role-dialog/aria-role-dialog.ts +0 -62
- package/aslint/app/rules/aslint/redundant/capital-letters-words/capital-letters-words.documentation.md +0 -44
- package/aslint/app/rules/aslint/redundant/capital-letters-words/capital-letters-words.test.ts +0 -111
- package/aslint/app/rules/aslint/redundant/capital-letters-words/capital-letters-words.ts +0 -120
- package/aslint/app/rules/aslint/redundant/contentinfo-landmark-only-one/contentinfo-landmark-only-one.documentation.md +0 -45
- package/aslint/app/rules/aslint/redundant/contentinfo-landmark-only-one/contentinfo-landmark-only-one.test.ts +0 -63
- package/aslint/app/rules/aslint/redundant/contentinfo-landmark-only-one/contentinfo-landmark-only-one.ts +0 -44
- package/aslint/app/rules/aslint/redundant/empty-title-attribute/empty-title-attribute.documentation.md +0 -55
- package/aslint/app/rules/aslint/redundant/empty-title-attribute/empty-title-attribute.test.ts +0 -80
- package/aslint/app/rules/aslint/redundant/empty-title-attribute/empty-title-attribute.ts +0 -58
- package/aslint/app/rules/aslint/redundant/flash-content/flash-content.documentation.md +0 -48
- package/aslint/app/rules/aslint/redundant/flash-content/flash-content.test.ts +0 -52
- package/aslint/app/rules/aslint/redundant/flash-content/flash-content.ts +0 -32
- package/aslint/app/rules/aslint/redundant/font-style-italic/font-style-italic.documentation.md +0 -44
- package/aslint/app/rules/aslint/redundant/font-style-italic/font-style-italic.test.ts +0 -12
- package/aslint/app/rules/aslint/redundant/font-style-italic/font-style-italic.ts +0 -83
- package/aslint/app/rules/aslint/redundant/h1-must-be/h1-must-be.documentation.md +0 -46
- package/aslint/app/rules/aslint/redundant/h1-must-be/h1-must-be.test.ts +0 -46
- package/aslint/app/rules/aslint/redundant/h1-must-be/h1-must-be.ts +0 -36
- package/aslint/app/rules/aslint/role-application/role-application.test.ts +0 -48
- package/aslint/app/rules/aslint/role-application/role-application.ts +0 -38
- package/aslint/app/rules/aslint/rtl-content/rtl-content.test.ts +0 -12
- package/aslint/app/rules/aslint/rtl-content/rtl-content.ts +0 -75
- package/aslint/app/rules/aslint/unclear-uri-on-a/unclear-anchor-uri.test.ts +0 -12
- package/aslint/app/rules/aslint/unclear-uri-on-a/unclear-anchor-uri.ts +0 -48
- package/aslint/app/rules/aslint/unimportant/aria-hidden-false/aria-hidden-false.test.ts +0 -73
- package/aslint/app/rules/aslint/unimportant/aria-hidden-false/aria-hidden-false.ts +0 -34
- package/aslint/app/rules/aslint/unimportant/aria-hidden-false/aria-hidden.documentation.md +0 -32
- package/aslint/app/rules/aslint/unimportant/content-editable-missing-attributes/content-editable-missing-attributes.docmentation.md +0 -48
- package/aslint/app/rules/aslint/unimportant/content-editable-missing-attributes/content-editable-missing-attributes.test.ts +0 -67
- package/aslint/app/rules/aslint/unimportant/content-editable-missing-attributes/content-editable-missing-attributes.ts +0 -63
- package/aslint/app/rules/aslint/unsupported-role-on-element/unsupported-role-on-element.test.ts +0 -12
- package/aslint/app/rules/aslint/unsupported-role-on-element/unsupported-role-on-element.ts +0 -63
- package/aslint/app/rules/aslint/used/elements-not-allowed-in-head/elements-not-allowed-in-head.documentation.md +0 -65
- package/aslint/app/rules/aslint/used/elements-not-allowed-in-head/elements-not-allowed-in-head.test.ts +0 -53
- package/aslint/app/rules/aslint/used/elements-not-allowed-in-head/elements-not-allowed-in-head.ts +0 -47
- package/aslint/app/rules/aslint/used/headings-sibling-unique/headings-sibling-unique.documentation.md +0 -57
- package/aslint/app/rules/aslint/used/headings-sibling-unique/headings-sibling-unique.test.ts +0 -52
- package/aslint/app/rules/aslint/used/headings-sibling-unique/headings-sibling-unique.ts +0 -63
- package/aslint/app/rules/aslint/used/horizontal-rule/horizontal-rule.documentation.md +0 -39
- package/aslint/app/rules/aslint/used/horizontal-rule/horizontal-rule.test.ts +0 -66
- package/aslint/app/rules/aslint/used/horizontal-rule/horizontal-rule.ts +0 -37
- package/aslint/utils/aria.test.ts +0 -12
- package/aslint/utils/aria.ts +0 -120
- package/aslint/utils/async.test.ts +0 -25
- package/aslint/utils/async.ts +0 -22
- package/aslint/utils/common.test.ts +0 -239
- package/aslint/utils/common.ts +0 -168
- package/aslint/utils/console.test.ts +0 -85
- package/aslint/utils/console.ts +0 -89
- package/aslint/utils/css.test.ts +0 -153
- package/aslint/utils/css.ts +0 -191
- package/aslint/utils/dom.test.ts +0 -627
- package/aslint/utils/dom.ts +0 -1051
- package/aslint/utils/env.test.ts +0 -14
- package/aslint/utils/env.ts +0 -8
- package/aslint/utils/func.test.ts +0 -160
- package/aslint/utils/func.ts +0 -70
- package/aslint/utils/global.test.ts +0 -12
- package/aslint/utils/global.ts +0 -25
- package/aslint/utils/object.test.ts +0 -524
- package/aslint/utils/object.ts +0 -278
- package/aslint/utils/report.test.ts +0 -56
- package/aslint/utils/report.ts +0 -36
- package/aslint/utils/text.test.ts +0 -270
- package/aslint/utils/text.ts +0 -165
- package/aslint/utils/time.test.ts +0 -43
- package/aslint/utils/time.ts +0 -33
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import { DomUtility } from '../../../utils/dom';
|
|
2
|
-
import { Css } from '../../../utils/css';
|
|
3
|
-
import { TextUtility } from '../../../utils/text';
|
|
4
|
-
import { CATEGORY_TYPE } from '../../../constants/categoryType';
|
|
5
|
-
import { IIssueReport } from '../../../interfaces/rule-issue.interface';
|
|
6
|
-
import { TranslateService } from '../../../services/translate';
|
|
7
|
-
import { $accessibilityAuditRules, $severity } from '../../../constants/accessibility';
|
|
8
|
-
import { AbstractRule, IAbstractRuleConfig } from '../../abstract-rule';
|
|
9
|
-
|
|
10
|
-
export class FontStyleItalic extends AbstractRule {
|
|
11
|
-
|
|
12
|
-
protected selector: string = `*${[
|
|
13
|
-
':root',
|
|
14
|
-
'head',
|
|
15
|
-
'style',
|
|
16
|
-
'script',
|
|
17
|
-
'noscript',
|
|
18
|
-
'meta',
|
|
19
|
-
'link',
|
|
20
|
-
'br',
|
|
21
|
-
'hr',
|
|
22
|
-
'object',
|
|
23
|
-
'svg',
|
|
24
|
-
'path',
|
|
25
|
-
'defs',
|
|
26
|
-
'rect',
|
|
27
|
-
'clippath',
|
|
28
|
-
'use',
|
|
29
|
-
'g',
|
|
30
|
-
'b',
|
|
31
|
-
'filter',
|
|
32
|
-
'img',
|
|
33
|
-
'picture',
|
|
34
|
-
'input',
|
|
35
|
-
'iframe',
|
|
36
|
-
'code',
|
|
37
|
-
'metadata',
|
|
38
|
-
':empty'
|
|
39
|
-
].map((i: string): string => {
|
|
40
|
-
return `:not(${i})`;
|
|
41
|
-
}).join('')}`;
|
|
42
|
-
|
|
43
|
-
protected ruleConfig: IAbstractRuleConfig = {
|
|
44
|
-
id: TextUtility.convertUnderscoresToDashes($accessibilityAuditRules.font_style_italic),
|
|
45
|
-
links: [
|
|
46
|
-
{
|
|
47
|
-
content: 'Avoiding chunks of italic text',
|
|
48
|
-
url: 'https://www.w3.org/TR/UNDERSTANDING-WCAG20/meaning.html'
|
|
49
|
-
}
|
|
50
|
-
],
|
|
51
|
-
recommendations: [],
|
|
52
|
-
severity: $severity.info,
|
|
53
|
-
type: CATEGORY_TYPE.BEST_PRACTICE
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
public validate(elements: HTMLElement[]): void {
|
|
57
|
-
const reportNode = (element: HTMLElement): void => {
|
|
58
|
-
let isItalic: boolean = false;
|
|
59
|
-
const textContent: string = DomUtility.getTextFromDescendantContent(element).trim();
|
|
60
|
-
const textContentLength: number = textContent.length;
|
|
61
|
-
const REASONABLE_LONG_TEXT: number = 80;
|
|
62
|
-
|
|
63
|
-
// Note: element.style may not exists, e.g. for an element in a different namespace
|
|
64
|
-
if (Css.getStyle(element, 'font-style') === 'italic' || typeof element.style === 'object' && element.style.fontStyle === 'italic') {
|
|
65
|
-
isItalic = true;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (isItalic === false || textContentLength < REASONABLE_LONG_TEXT) {
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const report: IIssueReport = {
|
|
73
|
-
message: TranslateService.instant('font_style_italic_report_message', [textContentLength]),
|
|
74
|
-
node: element,
|
|
75
|
-
ruleId: this.ruleConfig.id
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
this.validator.report(report);
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
elements.forEach(reportNode);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# h1-must-be
|
|
2
|
-
|
|
3
|
-
## Rule id
|
|
4
|
-
|
|
5
|
-
`h1-must-be`
|
|
6
|
-
|
|
7
|
-
## Definition
|
|
8
|
-
|
|
9
|
-
This rule verifies if there is defined heading `h1` on the page.
|
|
10
|
-
|
|
11
|
-
## Purpose
|
|
12
|
-
|
|
13
|
-
Most content on web pages should be organized into sections. When pages are organized into sections, a heading should be present.
|
|
14
|
-
|
|
15
|
-
All pages should at least have a `<h1>` level heading giving the title of the page.
|
|
16
|
-
|
|
17
|
-
This rule checks 1 case:
|
|
18
|
-
|
|
19
|
-
* Determine if there is at least 1 element `<h1>`.
|
|
20
|
-
|
|
21
|
-
**Note**: the rule does not check if the content of `<h1>` is empty.
|
|
22
|
-
|
|
23
|
-
## Test cases
|
|
24
|
-
|
|
25
|
-
### Passed
|
|
26
|
-
|
|
27
|
-
The rule passes when there is at least 1 `<h1>` element.
|
|
28
|
-
|
|
29
|
-
## WCAG Success Criteria
|
|
30
|
-
|
|
31
|
-
Not Applicable
|
|
32
|
-
|
|
33
|
-
## Best Practice
|
|
34
|
-
|
|
35
|
-
Yes
|
|
36
|
-
|
|
37
|
-
## User Impact
|
|
38
|
-
|
|
39
|
-
* **Severity**: critical
|
|
40
|
-
* **Disabilities Affected**:
|
|
41
|
-
* Visual:
|
|
42
|
-
* blindness
|
|
43
|
-
|
|
44
|
-
## Resources
|
|
45
|
-
|
|
46
|
-
* https://www.w3.org/WAI/tutorials/page-structure/headings/
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { H1MustBe } from './h1-must-be';
|
|
2
|
-
import { Validator } from '../../../validator';
|
|
3
|
-
import { DomUtility } from '../../../utils/dom';
|
|
4
|
-
|
|
5
|
-
describe('Rules', () => {
|
|
6
|
-
|
|
7
|
-
describe('H1MustBe', () => {
|
|
8
|
-
|
|
9
|
-
let fakeDom;
|
|
10
|
-
|
|
11
|
-
new H1MustBe().registerValidator();
|
|
12
|
-
|
|
13
|
-
beforeEach(() => {
|
|
14
|
-
fakeDom = document.createElement('div');
|
|
15
|
-
fakeDom.id = 'fakedom';
|
|
16
|
-
document.body.appendChild(fakeDom);
|
|
17
|
-
|
|
18
|
-
Validator.reset();
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
afterEach(() => {
|
|
22
|
-
DomUtility.remove(document.getElementById('fakedom'));
|
|
23
|
-
fakeDom = undefined;
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('should return one report when there is no elements with h1', () => {
|
|
27
|
-
fakeDom.innerHTML = '<div><h2>h1</h2></div>';
|
|
28
|
-
|
|
29
|
-
new H1MustBe().run(fakeDom);
|
|
30
|
-
|
|
31
|
-
expect(Object.keys(Validator.getReports()).length).toBe(1);
|
|
32
|
-
expect(Validator.getReport('report_0').message).toBe('Expected at least one heading <code>h1</code> element, but found none.');
|
|
33
|
-
expect(Validator.getReport('report_0').node).toBe(null);
|
|
34
|
-
expect(Validator.getReport('report_0').ruleId).toBe('h1-must-be');
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
it('should return no reports when there is element with h1', () => {
|
|
38
|
-
fakeDom.innerHTML = '<div><h1>h1</h1></div>';
|
|
39
|
-
|
|
40
|
-
new H1MustBe().run(fakeDom);
|
|
41
|
-
|
|
42
|
-
expect(Object.keys(Validator.getReports()).length).toBe(0);
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
});
|
|
46
|
-
});
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { CATEGORY_TYPE } from '../../../constants/categoryType';
|
|
2
|
-
import { IIssueReport } from '../../../interfaces/rule-issue.interface';
|
|
3
|
-
import { TextUtility } from '../../../utils/text';
|
|
4
|
-
import { TranslateService } from '../../../services/translate';
|
|
5
|
-
import { $accessibilityAuditRules, $severity } from '../../../constants/accessibility';
|
|
6
|
-
import { AbstractRule, IAbstractRuleConfig } from '../../abstract-rule';
|
|
7
|
-
|
|
8
|
-
export class H1MustBe extends AbstractRule {
|
|
9
|
-
protected selector: string = 'h1';
|
|
10
|
-
protected ruleConfig: IAbstractRuleConfig = {
|
|
11
|
-
id: TextUtility.convertUnderscoresToDashes($accessibilityAuditRules.h1_must_be),
|
|
12
|
-
links: [
|
|
13
|
-
{
|
|
14
|
-
content: 'Web Accessibility Tutorials: Headings',
|
|
15
|
-
url: 'https://www.w3.org/WAI/tutorials/page-structure/headings/'
|
|
16
|
-
}
|
|
17
|
-
],
|
|
18
|
-
recommendations: [],
|
|
19
|
-
severity: $severity.critical,
|
|
20
|
-
type: CATEGORY_TYPE.BEST_PRACTICE
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
public validate(elements: Element[]): void {
|
|
24
|
-
if (elements.length > 0) {
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const report: IIssueReport = {
|
|
29
|
-
message: TranslateService.instant('h1_must_report_message'),
|
|
30
|
-
node: null,
|
|
31
|
-
ruleId: this.ruleConfig.id
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
this.validator.report(report);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { RoleApplication } from './role-application';
|
|
2
|
-
import { Validator } from '../../../validator';
|
|
3
|
-
import { DomUtility } from '../../../utils/dom';
|
|
4
|
-
|
|
5
|
-
describe('Rules', () => {
|
|
6
|
-
|
|
7
|
-
describe('RoleApplication', () => {
|
|
8
|
-
|
|
9
|
-
let fakeDom;
|
|
10
|
-
|
|
11
|
-
new RoleApplication().registerValidator();
|
|
12
|
-
|
|
13
|
-
beforeEach(() => {
|
|
14
|
-
fakeDom = document.createElement('div');
|
|
15
|
-
fakeDom.id = 'fakedom';
|
|
16
|
-
document.body.appendChild(fakeDom);
|
|
17
|
-
|
|
18
|
-
Validator.reset();
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
afterEach(() => {
|
|
22
|
-
DomUtility.remove(document.getElementById('fakedom'));
|
|
23
|
-
fakeDom = undefined;
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('should return correct data for p with role="application"', () => {
|
|
27
|
-
fakeDom.innerHTML = '<p role="application"></p>';
|
|
28
|
-
const nodes = DomUtility.querySelectorAllExclude('[role="application"]', fakeDom) as HTMLElement[];
|
|
29
|
-
|
|
30
|
-
new RoleApplication().validate(nodes);
|
|
31
|
-
|
|
32
|
-
expect(Object.keys(Validator.getReports()).length).toBe(1);
|
|
33
|
-
expect(Validator.getReport('report_0').message).toBe('Use <code>role="application"</code> carefully as it is used to denote a region of a web application that is to be treated like a desktop application, not like a regular web page.');
|
|
34
|
-
expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('p');
|
|
35
|
-
expect(Validator.getReport('report_0').ruleId).toBe('role-application');
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('should return no reports in case no elements with p with role="application"', () => {
|
|
39
|
-
fakeDom.innerHTML = '<p>Test</p>';
|
|
40
|
-
const nodes = DomUtility.querySelectorAllExclude('[role="application"]', fakeDom) as HTMLElement[];
|
|
41
|
-
|
|
42
|
-
new RoleApplication().validate(nodes);
|
|
43
|
-
|
|
44
|
-
expect(Object.keys(Validator.getReports()).length).toBe(0);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
});
|
|
48
|
-
});
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { CATEGORY_TYPE } from '../../../constants/categoryType';
|
|
2
|
-
import { IIssueReport } from '../../../interfaces/rule-issue.interface';
|
|
3
|
-
import { TextUtility } from '../../../utils/text';
|
|
4
|
-
import { TranslateService } from '../../../services/translate';
|
|
5
|
-
import { $severity } from '../../../constants/accessibility';
|
|
6
|
-
import { $accessibilityAuditRules } from '../../../constants/accessibility';
|
|
7
|
-
import { AbstractRule, IAbstractRuleConfig } from '../../abstract-rule';
|
|
8
|
-
|
|
9
|
-
export class RoleApplication extends AbstractRule {
|
|
10
|
-
protected selector: string = '[role="application"]';
|
|
11
|
-
|
|
12
|
-
protected ruleConfig: IAbstractRuleConfig = {
|
|
13
|
-
id: TextUtility.convertUnderscoresToDashes($accessibilityAuditRules.role_application),
|
|
14
|
-
links: [
|
|
15
|
-
{
|
|
16
|
-
content: 'Using ARIA role=application',
|
|
17
|
-
url: 'https://w3c.github.io/aria-in-html/'
|
|
18
|
-
}
|
|
19
|
-
],
|
|
20
|
-
recommendations: [],
|
|
21
|
-
severity: $severity.critical,
|
|
22
|
-
type: CATEGORY_TYPE.BEST_PRACTICE
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
public validate(elements: HTMLElement[]): void {
|
|
26
|
-
const checkTabindex = (element: HTMLElement): void => {
|
|
27
|
-
const report: IIssueReport = {
|
|
28
|
-
message: TranslateService.instant('role_application_report_message'),
|
|
29
|
-
node: element,
|
|
30
|
-
ruleId: this.ruleConfig.id
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
this.validator.report(report);
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
elements.forEach(checkTabindex);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { Css } from '../../../utils/css';
|
|
2
|
-
import { CATEGORY_TYPE } from '../../../constants/categoryType';
|
|
3
|
-
import { IIssueReport } from '../../../interfaces/rule-issue.interface';
|
|
4
|
-
import { TextUtility } from '../../../utils/text';
|
|
5
|
-
import { TranslateService } from '../../../services/translate';
|
|
6
|
-
import { $severity } from '../../../constants/accessibility';
|
|
7
|
-
import { $accessibilityAuditRules } from '../../../constants/accessibility';
|
|
8
|
-
import { AbstractRule, IAbstractRuleConfig } from '../../abstract-rule';
|
|
9
|
-
|
|
10
|
-
export class RtlContent extends AbstractRule {
|
|
11
|
-
protected selector: string = `*${[
|
|
12
|
-
':root',
|
|
13
|
-
'head',
|
|
14
|
-
'style',
|
|
15
|
-
'script',
|
|
16
|
-
'meta',
|
|
17
|
-
'link',
|
|
18
|
-
'br',
|
|
19
|
-
'hr',
|
|
20
|
-
'object',
|
|
21
|
-
'path',
|
|
22
|
-
'g',
|
|
23
|
-
'filter',
|
|
24
|
-
'img',
|
|
25
|
-
'input',
|
|
26
|
-
'iframe',
|
|
27
|
-
'code',
|
|
28
|
-
':empty'
|
|
29
|
-
].map((i: string): string => {
|
|
30
|
-
return `:not(${i})`;
|
|
31
|
-
}).join('')}`;
|
|
32
|
-
|
|
33
|
-
protected ruleConfig: IAbstractRuleConfig = {
|
|
34
|
-
id: TextUtility.convertUnderscoresToDashes($accessibilityAuditRules.rtl_content),
|
|
35
|
-
links: [
|
|
36
|
-
{
|
|
37
|
-
content: 'Right to left implementation tricks',
|
|
38
|
-
url: 'http://www.ctomczyk.pl/right-to-left-implementation-tricks/642/'
|
|
39
|
-
}
|
|
40
|
-
],
|
|
41
|
-
recommendations: [],
|
|
42
|
-
severity: $severity.info,
|
|
43
|
-
type: CATEGORY_TYPE.BEST_PRACTICE
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
public validate(elements: HTMLElement[]): any {
|
|
47
|
-
const nodesToReport: HTMLElement[] = [];
|
|
48
|
-
|
|
49
|
-
const reportRTL = (element: HTMLElement): void => {
|
|
50
|
-
if (element.nodeType !== element.ELEMENT_NODE) {
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const direction: string | null = Css.getStyle(element, 'direction');
|
|
55
|
-
|
|
56
|
-
if (typeof direction === 'string' && direction.toLowerCase() === 'rtl') {
|
|
57
|
-
nodesToReport.push(element);
|
|
58
|
-
}
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
elements.forEach(reportRTL);
|
|
62
|
-
|
|
63
|
-
const createReport = (element: HTMLElement): void => {
|
|
64
|
-
const problem: IIssueReport = {
|
|
65
|
-
message: TranslateService.instant('rtl_content_report_message'),
|
|
66
|
-
node: element,
|
|
67
|
-
ruleId: this.ruleConfig.id
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
this.validator.report(problem);
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
nodesToReport.forEach(createReport);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { CATEGORY_TYPE } from '../../../constants/categoryType';
|
|
2
|
-
import { IIssueReport } from '../../../interfaces/rule-issue.interface';
|
|
3
|
-
import { TextUtility } from '../../../utils/text';
|
|
4
|
-
import { TranslateService } from '../../../services/translate';
|
|
5
|
-
import { $severity } from '../../../constants/accessibility';
|
|
6
|
-
import { $accessibilityAuditRules } from '../../../constants/accessibility';
|
|
7
|
-
import { AbstractRule, IAbstractRuleConfig } from '../../abstract-rule';
|
|
8
|
-
|
|
9
|
-
export class UnclearAnchorUri extends AbstractRule {
|
|
10
|
-
protected selector: string = 'a[href="#"], a[href*=javascript\\:], a[href=""]';
|
|
11
|
-
|
|
12
|
-
protected ruleConfig: IAbstractRuleConfig = {
|
|
13
|
-
id: TextUtility.convertUnderscoresToDashes($accessibilityAuditRules.unclear_anchor_uri),
|
|
14
|
-
links: [
|
|
15
|
-
{
|
|
16
|
-
content: 'Making AJAX applications crawlable',
|
|
17
|
-
url: 'https://developers.google.com/webmasters/ajax-crawling/docs/learn-more#what-the-user-sees-what-the-crawler-sees'
|
|
18
|
-
}
|
|
19
|
-
],
|
|
20
|
-
recommendations: [],
|
|
21
|
-
severity: $severity.high,
|
|
22
|
-
type: CATEGORY_TYPE.BEST_PRACTICE
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
public validate(anchorElements: HTMLAnchorElement[]): void {
|
|
26
|
-
const checkHref = (anchorElement: HTMLAnchorElement): void => {
|
|
27
|
-
const hrefAttr: string | null = anchorElement.getAttribute('href');
|
|
28
|
-
|
|
29
|
-
if (hrefAttr === null) {
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const report: IIssueReport = {
|
|
34
|
-
message: TranslateService.instant('unclear_uri_on_a_report_message_1', [anchorElement.href]),
|
|
35
|
-
node: anchorElement,
|
|
36
|
-
ruleId: this.ruleConfig.id
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
this.validator.report(report);
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
const nodesLength: number = anchorElements.length;
|
|
43
|
-
|
|
44
|
-
if (nodesLength) {
|
|
45
|
-
anchorElements.forEach(checkHref);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { AriaHiddenFalse } from './aria-hidden-false';
|
|
2
|
-
import { DomUtility } from '../../../utils/dom';
|
|
3
|
-
import { Validator } from '../../../validator';
|
|
4
|
-
|
|
5
|
-
describe('Rules', () => {
|
|
6
|
-
|
|
7
|
-
describe('AriaHiddenFalse', () => {
|
|
8
|
-
|
|
9
|
-
let fakeDom;
|
|
10
|
-
const selector = 'body [aria-hidden="false"]';
|
|
11
|
-
|
|
12
|
-
new AriaHiddenFalse().registerValidator();
|
|
13
|
-
|
|
14
|
-
beforeEach(() => {
|
|
15
|
-
fakeDom = document.createElement('div');
|
|
16
|
-
fakeDom.id = 'fakedom';
|
|
17
|
-
document.body.appendChild(fakeDom);
|
|
18
|
-
|
|
19
|
-
Validator.reset();
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
afterEach(() => {
|
|
23
|
-
DomUtility.remove(document.getElementById('fakedom'));
|
|
24
|
-
fakeDom = undefined;
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
it('should return one report when there is an element with aria-hidden="false"', () => {
|
|
28
|
-
fakeDom.innerHTML = '<p aria-hidden="false"></p>';
|
|
29
|
-
|
|
30
|
-
const nodes: Element[] = DomUtility.querySelectorAllExclude(selector, fakeDom);
|
|
31
|
-
|
|
32
|
-
new AriaHiddenFalse().validate(nodes);
|
|
33
|
-
|
|
34
|
-
expect(Validator.getReport('report_0').ruleId).toBe('aria-hidden-false');
|
|
35
|
-
expect(Validator.getReport('report_0').message).toBe('You have defined <code>aria-hidden="false"</code>. Caution, as the child content is always readable by screen readers regardless of setting <code>display: none</code> on any child element.');
|
|
36
|
-
expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('p');
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it('should return 1 report when there is an element with attribute aria-hidden="false" and style="display: none"', () => {
|
|
40
|
-
fakeDom.innerHTML = '<p aria-hidden="false" style="display: none"></p>';
|
|
41
|
-
|
|
42
|
-
const nodes = DomUtility.querySelectorAllExclude(selector, fakeDom);
|
|
43
|
-
|
|
44
|
-
new AriaHiddenFalse().validate(nodes);
|
|
45
|
-
|
|
46
|
-
expect(Object.keys(Validator.getReports()).length).toBe(1);
|
|
47
|
-
expect(Validator.getReport('report_0').message).toBe('You have defined <code>aria-hidden="false"</code>. Caution, as the child content is always readable by screen readers regardless of setting <code>display: none</code> on any child element.');
|
|
48
|
-
expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('p');
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
it('should return no report when there is an element with attribute aria-hidden="true"', () => {
|
|
52
|
-
fakeDom.innerHTML = '<p aria-hidden="true"></p>';
|
|
53
|
-
|
|
54
|
-
const nodes = DomUtility.querySelectorAllExclude(selector, fakeDom);
|
|
55
|
-
|
|
56
|
-
new AriaHiddenFalse().validate(nodes);
|
|
57
|
-
|
|
58
|
-
expect(Object.keys(Validator.getReports()).length).toBe(0);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('should return no report when there is no element with attribute aria-hidden="false"', () => {
|
|
62
|
-
fakeDom.innerHTML = '<p>test</p>';
|
|
63
|
-
|
|
64
|
-
const nodes = DomUtility.querySelectorAllExclude(selector, fakeDom);
|
|
65
|
-
|
|
66
|
-
new AriaHiddenFalse().validate(nodes);
|
|
67
|
-
|
|
68
|
-
expect(Object.keys(Validator.getReports()).length).toBe(0);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
});
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import { CATEGORY_TYPE } from '../../../constants/categoryType';
|
|
2
|
-
import { IIssueReport } from '../../../interfaces/rule-issue.interface';
|
|
3
|
-
import { TranslateService } from '../../../services/translate';
|
|
4
|
-
import { $severity, $accessibilityAuditRules } from '../../../constants/accessibility';
|
|
5
|
-
import { TextUtility } from '../../../utils/text';
|
|
6
|
-
import { AbstractRule, IAbstractRuleConfig } from '../../abstract-rule';
|
|
7
|
-
|
|
8
|
-
export class AriaHiddenFalse extends AbstractRule {
|
|
9
|
-
protected selector: string = 'body [aria-hidden="false"]';
|
|
10
|
-
|
|
11
|
-
protected ruleConfig: IAbstractRuleConfig = {
|
|
12
|
-
id: TextUtility.convertUnderscoresToDashes($accessibilityAuditRules.aria_hidden_false),
|
|
13
|
-
links: [],
|
|
14
|
-
recommendations: [],
|
|
15
|
-
severity: $severity.low,
|
|
16
|
-
type: CATEGORY_TYPE.BEST_PRACTICE
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
public validate(elements: Element[]): void {
|
|
20
|
-
const reportProblem = (element: Element): void => {
|
|
21
|
-
const reportMessage: string = TranslateService.instant('aria_hidden_false_report_message', [TextUtility.escape('aria-hidden="false"'), TextUtility.escape('display: none')]);
|
|
22
|
-
|
|
23
|
-
const problem: IIssueReport = {
|
|
24
|
-
message: reportMessage,
|
|
25
|
-
node: element,
|
|
26
|
-
ruleId: this.ruleConfig.id
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
this.validator.report(problem);
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
elements.forEach(reportProblem);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
# aria-hidden
|
|
2
|
-
|
|
3
|
-
## Rule id
|
|
4
|
-
|
|
5
|
-
`aria-hidden`
|
|
6
|
-
|
|
7
|
-
## Definition
|
|
8
|
-
|
|
9
|
-
`aria-hidden="false"` should be used with caution.
|
|
10
|
-
|
|
11
|
-
## Purpose
|
|
12
|
-
|
|
13
|
-
When `aria-hidden="false"` is defined then we need to be cautious, as the child content is always readable by screen readers regardless of setting `aria-hidden="false"` on any child element.
|
|
14
|
-
|
|
15
|
-
## WCAG Success Criteria
|
|
16
|
-
|
|
17
|
-
Not Applicable
|
|
18
|
-
|
|
19
|
-
## Best Practice
|
|
20
|
-
|
|
21
|
-
Yes
|
|
22
|
-
|
|
23
|
-
## User Impact
|
|
24
|
-
|
|
25
|
-
* **Severity**: low
|
|
26
|
-
* **Disabilities Affected**:
|
|
27
|
-
* Visual:
|
|
28
|
-
* blindness
|
|
29
|
-
|
|
30
|
-
## Resources
|
|
31
|
-
|
|
32
|
-
Not available
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
# content-editable-missing-attributes
|
|
2
|
-
|
|
3
|
-
## Rule id
|
|
4
|
-
|
|
5
|
-
`content-editable-missing-attributes`
|
|
6
|
-
|
|
7
|
-
## Definition
|
|
8
|
-
|
|
9
|
-
This rule verifies if element with attribute `contenteditable` have defined also following attributes:
|
|
10
|
-
|
|
11
|
-
1. `aria-multiline`
|
|
12
|
-
2. `aria-labelledby` or `aria-label`
|
|
13
|
-
|
|
14
|
-
## Purpose
|
|
15
|
-
|
|
16
|
-
When `aria-multiline="true"` is set then Assistive Technologies informs the user that the textbox supports multi-line input, with the expectation that <kbd>Enter</kbd> or <kbd>Return</kbd> will create a line break rather than submitting the form.
|
|
17
|
-
|
|
18
|
-
`aria-label` here is recommended to specify a string to be used as the accessible label.
|
|
19
|
-
|
|
20
|
-
Eventually `aria-labelledby` can be used to specify the `id` of another element in the DOM as an element's label.
|
|
21
|
-
|
|
22
|
-
## Test cases
|
|
23
|
-
|
|
24
|
-
### Passed
|
|
25
|
-
|
|
26
|
-
The rule passes when all of the following cases are fulfilled:
|
|
27
|
-
|
|
28
|
-
1. Attribute `contenteditable` is defined.
|
|
29
|
-
2. `aria-label` or `aria-labelledby` is defined. The rule does not validate `aria-labelledby` ids if the referenced elements exists.
|
|
30
|
-
|
|
31
|
-
## WCAG Success Criteria
|
|
32
|
-
|
|
33
|
-
Not Applicable
|
|
34
|
-
|
|
35
|
-
## Best Practice
|
|
36
|
-
|
|
37
|
-
Yes
|
|
38
|
-
|
|
39
|
-
## User Impact
|
|
40
|
-
|
|
41
|
-
* **Severity**: high
|
|
42
|
-
* **Disabilities Affected**:
|
|
43
|
-
* Visual:
|
|
44
|
-
* blindness
|
|
45
|
-
|
|
46
|
-
## Resources
|
|
47
|
-
|
|
48
|
-
Not available
|