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,120 +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 { $severity } from '../../../constants/accessibility';
|
|
8
|
-
import { $accessibilityAuditRules } from '../../../constants/accessibility';
|
|
9
|
-
import { AbstractRule, IAbstractRuleConfig } from '../../abstract-rule';
|
|
10
|
-
|
|
11
|
-
export class CapitalLettersWords extends AbstractRule {
|
|
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.capital_letters_words),
|
|
45
|
-
links: [
|
|
46
|
-
{
|
|
47
|
-
content: 'Dyslexia Font and Style Guide',
|
|
48
|
-
url: 'https://www.dyslexia-reading-well.com/dyslexia-font.html'
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
content: 'Typefaces for dyslexia',
|
|
52
|
-
url: 'https://bdatech.org/what-technology/typefaces-for-dyslexia/'
|
|
53
|
-
}
|
|
54
|
-
],
|
|
55
|
-
recommendations: [],
|
|
56
|
-
severity: $severity.high,
|
|
57
|
-
type: CATEGORY_TYPE.BEST_PRACTICE
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
public validate(nodes: HTMLElement[]): void {
|
|
61
|
-
const onlyWordsWithUpperCases = (word: string): boolean => {
|
|
62
|
-
return TextUtility.isUpperCase(word);
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
const processNode = (element: HTMLElement): void => {
|
|
66
|
-
const report: IIssueReport = {
|
|
67
|
-
message: '',
|
|
68
|
-
node: element,
|
|
69
|
-
ruleId: this.ruleConfig.id
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
let reportMessage: string = '';
|
|
73
|
-
|
|
74
|
-
let words: string[];
|
|
75
|
-
let onlyWordsWithUpperCase: string[] = [];
|
|
76
|
-
|
|
77
|
-
const text: string = DomUtility.getTextFromDescendantContent(element).trim();
|
|
78
|
-
|
|
79
|
-
words = text.split(' ');
|
|
80
|
-
|
|
81
|
-
if (text.length > 0 && words.length > 0) {
|
|
82
|
-
if (Css.isCssTextTransformUsed(element)) {
|
|
83
|
-
reportMessage = TranslateService.instant('capital_letters_words_report_message1', [text.toUpperCase()]);
|
|
84
|
-
} else {
|
|
85
|
-
|
|
86
|
-
onlyWordsWithUpperCase = words.filter(onlyWordsWithUpperCases);
|
|
87
|
-
|
|
88
|
-
if (onlyWordsWithUpperCase.length > 1) {
|
|
89
|
-
reportMessage = TranslateService.instant('capital_letters_words_report_message2');
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const titleAttribute: string | null = element.getAttribute('title');
|
|
95
|
-
|
|
96
|
-
if (typeof titleAttribute === 'string' && titleAttribute.trim().length > 0) {
|
|
97
|
-
words = titleAttribute.split(' ');
|
|
98
|
-
onlyWordsWithUpperCase = words.filter(onlyWordsWithUpperCases);
|
|
99
|
-
|
|
100
|
-
if (onlyWordsWithUpperCase.length > 1) {
|
|
101
|
-
if (reportMessage.length === 0) {
|
|
102
|
-
reportMessage = TranslateService.instant('capital_letters_words_report_message3', [titleAttribute]);
|
|
103
|
-
} else {
|
|
104
|
-
reportMessage = TranslateService.instant('capital_letters_words_report_message4', [titleAttribute]);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
if (reportMessage.length === 0) {
|
|
110
|
-
return;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
report.message = `${reportMessage} ${TranslateService.instant('capital_letters_words_report_explanation')}`;
|
|
114
|
-
|
|
115
|
-
this.validator.report(report);
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
nodes.forEach(processNode);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# contentinfo-landmark-only-one
|
|
2
|
-
|
|
3
|
-
## Rule id
|
|
4
|
-
|
|
5
|
-
`contentinfo-landmark-only-one`
|
|
6
|
-
|
|
7
|
-
## Definition
|
|
8
|
-
|
|
9
|
-
This rule verifies if there is no more than 1 element with an attribute `role="contentinfo"`.
|
|
10
|
-
|
|
11
|
-
## Purpose
|
|
12
|
-
|
|
13
|
-
Based on https://www.w3.org/TR/wai-aria/#contentinfo
|
|
14
|
-
|
|
15
|
-
> Within any document or application, the author SHOULD mark no more than one element with the contentinfo role.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
## Test cases
|
|
19
|
-
|
|
20
|
-
### Passed
|
|
21
|
-
|
|
22
|
-
The rule passes when all of the following cases are fulfilled:
|
|
23
|
-
|
|
24
|
-
1. There is no more than 1 element with an attribute `role="contentinfo"`
|
|
25
|
-
|
|
26
|
-
## WCAG Success Criteria
|
|
27
|
-
|
|
28
|
-
Not Applicable
|
|
29
|
-
|
|
30
|
-
## Best Practice
|
|
31
|
-
|
|
32
|
-
Yes
|
|
33
|
-
|
|
34
|
-
## User Impact
|
|
35
|
-
|
|
36
|
-
* **Severity**: low
|
|
37
|
-
* **Disabilities Affected**:
|
|
38
|
-
* Visual:
|
|
39
|
-
* blindness
|
|
40
|
-
|
|
41
|
-
## Resources
|
|
42
|
-
|
|
43
|
-
* https://www.w3.org/TR/wai-aria/#contentinfo
|
|
44
|
-
* http://www.w3.org/TR/WCAG20-TECHS/ARIA11
|
|
45
|
-
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { ContentinfoLandmarkOnlyOne } from './contentinfo-landmark-only-one';
|
|
2
|
-
import { DomUtility } from '../../../utils/dom';
|
|
3
|
-
import { Validator } from '../../../validator';
|
|
4
|
-
|
|
5
|
-
describe('Rules', () => {
|
|
6
|
-
|
|
7
|
-
describe('ContentinfoLandmarkOnlyOne', () => {
|
|
8
|
-
|
|
9
|
-
let fakeDom;
|
|
10
|
-
|
|
11
|
-
new ContentinfoLandmarkOnlyOne().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 an element with more than one attribute role="contentinfo"', () => {
|
|
27
|
-
fakeDom.innerHTML = '<div role="contentinfo"></div><div role="contentinfo"></div>';
|
|
28
|
-
|
|
29
|
-
const nodes = DomUtility.querySelectorAllExclude('[role=contentinfo]', fakeDom);
|
|
30
|
-
|
|
31
|
-
new ContentinfoLandmarkOnlyOne().validate(nodes);
|
|
32
|
-
|
|
33
|
-
expect(Object.keys(Validator.getReports()).length).toBe(2);
|
|
34
|
-
expect(Validator.getReport('report_0').message).toBe('Expected attribute <code>role="contentinfo"</code> to be defined only once. You have 2 .');
|
|
35
|
-
expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('div');
|
|
36
|
-
expect(Validator.getReport('report_0').ruleId).toBe('contentinfo-landmark-only-one');
|
|
37
|
-
expect(Validator.getReport('report_1').message).toBe('Expected attribute <code>role="contentinfo"</code> to be defined only once. You have 2 .');
|
|
38
|
-
expect(Validator.getReport('report_1').node.nodeName.toLowerCase()).toBe('div');
|
|
39
|
-
expect(Validator.getReport('report_1').ruleId).toBe('contentinfo-landmark-only-one');
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('should return no reports when there is 1 element with attribute role="contentinfo"', () => {
|
|
43
|
-
fakeDom.innerHTML = '<div role="contentinfo">';
|
|
44
|
-
|
|
45
|
-
const nodes = DomUtility.querySelectorAllExclude('[role=contentinfo]', fakeDom);
|
|
46
|
-
|
|
47
|
-
new ContentinfoLandmarkOnlyOne().validate(nodes);
|
|
48
|
-
|
|
49
|
-
expect(Object.keys(Validator.getReports()).length).toBe(0);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it('should return no reports when there is no elements with attribute role="contentinfo"', () => {
|
|
53
|
-
fakeDom.innerHTML = '<div>contentinfo</div>';
|
|
54
|
-
const nodes = DomUtility.querySelectorAllExclude('[role=contentinfo]', fakeDom);
|
|
55
|
-
|
|
56
|
-
new ContentinfoLandmarkOnlyOne().validate(nodes);
|
|
57
|
-
|
|
58
|
-
expect(Object.keys(Validator.getReports()).length).toBe(0);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
});
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import { TextUtility } from '../../../utils/text';
|
|
2
|
-
import { CATEGORY_TYPE } from '../../../constants/categoryType';
|
|
3
|
-
import { IIssueReport } from '../../../interfaces/rule-issue.interface';
|
|
4
|
-
import { $accessibilityAuditRules, $severity } from '../../../constants/accessibility';
|
|
5
|
-
import { TranslateService } from '../../../services/translate';
|
|
6
|
-
import { AbstractRule, IAbstractRuleConfig } from '../../abstract-rule';
|
|
7
|
-
|
|
8
|
-
export class ContentinfoLandmarkOnlyOne extends AbstractRule {
|
|
9
|
-
protected selector: string = '[role="contentinfo"]';
|
|
10
|
-
protected ruleConfig: IAbstractRuleConfig = {
|
|
11
|
-
id: TextUtility.convertUnderscoresToDashes($accessibilityAuditRules.contentinfo_landmark_only_one),
|
|
12
|
-
links: [
|
|
13
|
-
{
|
|
14
|
-
content: 'ARIA11: Using ARIA landmarks to identify regions of a page',
|
|
15
|
-
url: 'http://www.w3.org/TR/WCAG20-TECHS/ARIA11'
|
|
16
|
-
},
|
|
17
|
-
{
|
|
18
|
-
content: 'Accessible Rich Internet Applications (WAI-ARIA) 1.0 Specification: contentinfo role',
|
|
19
|
-
url: 'https://www.w3.org/TR/wai-aria/#contentinfo'
|
|
20
|
-
}
|
|
21
|
-
],
|
|
22
|
-
recommendations: [],
|
|
23
|
-
severity: $severity.low,
|
|
24
|
-
type: CATEGORY_TYPE.BEST_PRACTICE
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
public validate(nodes: Element[]): void {
|
|
28
|
-
const total: number = nodes.length;
|
|
29
|
-
|
|
30
|
-
if (total > 1) {
|
|
31
|
-
nodes.forEach((element: Element): void => {
|
|
32
|
-
const reportMessage: string = TranslateService.instant('contentinfo_landmark_only_one_report_message', [TextUtility.escape('role="contentinfo"'), total, '.']);
|
|
33
|
-
|
|
34
|
-
const report: IIssueReport = {
|
|
35
|
-
message: reportMessage,
|
|
36
|
-
node: element,
|
|
37
|
-
ruleId: this.ruleConfig.id
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
this.validator.report(report);
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
# empty-title-attribute
|
|
2
|
-
|
|
3
|
-
## Rule id
|
|
4
|
-
|
|
5
|
-
`empty-title-attribute`
|
|
6
|
-
|
|
7
|
-
## Definition
|
|
8
|
-
|
|
9
|
-
This rule verifies if there are elements that have an attribute `title` with an empty value. This includes also whitespaces.
|
|
10
|
-
|
|
11
|
-
## Purpose
|
|
12
|
-
|
|
13
|
-
`title` attribute should not be empty. This will ensure that the value of `title` will be processed in a predictable way. As a side effect removing an empty value of `title` attribute will make the code smaller, which means less data to transfer and faster processing by e.g. the browser.
|
|
14
|
-
|
|
15
|
-
Following elements are being skip while evaluating this rule:
|
|
16
|
-
|
|
17
|
-
<img/>,
|
|
18
|
-
<html>,
|
|
19
|
-
<head>,
|
|
20
|
-
<title>,
|
|
21
|
-
<body>,
|
|
22
|
-
<link/>,
|
|
23
|
-
<meta>,
|
|
24
|
-
<title>,
|
|
25
|
-
<style>,
|
|
26
|
-
<script>,
|
|
27
|
-
<noscript>,
|
|
28
|
-
<iframe>,
|
|
29
|
-
<br/>,
|
|
30
|
-
<hr/>
|
|
31
|
-
|
|
32
|
-
## Test cases
|
|
33
|
-
|
|
34
|
-
### Passed
|
|
35
|
-
|
|
36
|
-
The rule passes when element have an attribute `title` with non-empty value. This includes also whitespaces.
|
|
37
|
-
|
|
38
|
-
## WCAG Success Criteria
|
|
39
|
-
|
|
40
|
-
Not Applicable
|
|
41
|
-
|
|
42
|
-
## Best Practice
|
|
43
|
-
|
|
44
|
-
Yes
|
|
45
|
-
|
|
46
|
-
## User Impact
|
|
47
|
-
|
|
48
|
-
* **Severity**: low
|
|
49
|
-
* **Disabilities Affected**:
|
|
50
|
-
* Visual:
|
|
51
|
-
* blindness
|
|
52
|
-
|
|
53
|
-
## Resources
|
|
54
|
-
|
|
55
|
-
* https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/title#accessibility_concerns
|
package/aslint/app/rules/aslint/redundant/empty-title-attribute/empty-title-attribute.test.ts
DELETED
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import { DomUtility } from '../../../utils/dom';
|
|
2
|
-
import { Validator } from '../../../validator';
|
|
3
|
-
import { EmptyTitleAttribute } from './empty-title-attribute';
|
|
4
|
-
|
|
5
|
-
describe('Rules', () => {
|
|
6
|
-
|
|
7
|
-
describe('EmptyTitleAttribute', () => {
|
|
8
|
-
|
|
9
|
-
const selector: string = `[title]${[
|
|
10
|
-
':not(img)',
|
|
11
|
-
':not(html)',
|
|
12
|
-
':not(head)',
|
|
13
|
-
':not(title)',
|
|
14
|
-
':not(body)',
|
|
15
|
-
':not(link)',
|
|
16
|
-
':not(meta)',
|
|
17
|
-
':not(title)',
|
|
18
|
-
':not(style)',
|
|
19
|
-
':not(script)',
|
|
20
|
-
':not(noscript)',
|
|
21
|
-
':not(iframe)',
|
|
22
|
-
':not(br)',
|
|
23
|
-
':not(hr)'
|
|
24
|
-
].join('')}`;
|
|
25
|
-
|
|
26
|
-
let fakeDom;
|
|
27
|
-
|
|
28
|
-
new EmptyTitleAttribute().registerValidator();
|
|
29
|
-
|
|
30
|
-
beforeEach(() => {
|
|
31
|
-
fakeDom = document.createElement('div');
|
|
32
|
-
fakeDom.id = 'fakedom';
|
|
33
|
-
document.body.appendChild(fakeDom);
|
|
34
|
-
|
|
35
|
-
Validator.reset();
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
afterEach(() => {
|
|
39
|
-
DomUtility.remove(document.getElementById('fakedom'));
|
|
40
|
-
fakeDom = undefined;
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('should return one report when there is an element with defined an attribute title with an empty value', () => {
|
|
44
|
-
fakeDom.innerHTML = '<div title="">test</div>';
|
|
45
|
-
|
|
46
|
-
const nodes = DomUtility.querySelectorAllExclude(selector, fakeDom);
|
|
47
|
-
|
|
48
|
-
new EmptyTitleAttribute().validate(nodes);
|
|
49
|
-
|
|
50
|
-
expect(Object.keys(Validator.getReports()).length).toBe(1);
|
|
51
|
-
expect(Validator.getReport('report_0').message).toBe('You have an attribute <code>title</code> with an empty content.');
|
|
52
|
-
expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('div');
|
|
53
|
-
expect(Validator.getReport('report_0').ruleId).toBe('empty-title-attribute');
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it('should return one report when there is an element with defined an attribute title with an empty value (only spaces)', () => {
|
|
57
|
-
fakeDom.innerHTML = '<div title=" ">test</div>';
|
|
58
|
-
|
|
59
|
-
const nodes = DomUtility.querySelectorAllExclude(selector, fakeDom);
|
|
60
|
-
|
|
61
|
-
new EmptyTitleAttribute().validate(nodes);
|
|
62
|
-
|
|
63
|
-
expect(Object.keys(Validator.getReports()).length).toBe(1);
|
|
64
|
-
expect(Validator.getReport('report_0').message).toBe('You have an attribute <code>title</code> with an empty content.');
|
|
65
|
-
expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('div');
|
|
66
|
-
expect(Validator.getReport('report_0').ruleId).toBe('empty-title-attribute');
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
it('should return no reports when there is an element with attribute title and non-empty value', () => {
|
|
70
|
-
fakeDom.innerHTML = '<div title="some title">test</div>';
|
|
71
|
-
|
|
72
|
-
const nodes = DomUtility.querySelectorAllExclude(selector, fakeDom);
|
|
73
|
-
|
|
74
|
-
new EmptyTitleAttribute().validate(nodes);
|
|
75
|
-
|
|
76
|
-
expect(Object.keys(Validator.getReports()).length).toBe(0);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
});
|
|
80
|
-
});
|
|
@@ -1,58 +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 EmptyTitleAttribute extends AbstractRule {
|
|
9
|
-
protected selector: string = `[title]${[
|
|
10
|
-
':not(img)',
|
|
11
|
-
':not(html)',
|
|
12
|
-
':not(head)',
|
|
13
|
-
':not(title)',
|
|
14
|
-
':not(body)',
|
|
15
|
-
':not(link)',
|
|
16
|
-
':not(meta)',
|
|
17
|
-
':not(title)',
|
|
18
|
-
':not(style)',
|
|
19
|
-
':not(script)',
|
|
20
|
-
':not(noscript)',
|
|
21
|
-
':not(iframe)',
|
|
22
|
-
':not(br)',
|
|
23
|
-
':not(hr)'
|
|
24
|
-
].join('')}`;
|
|
25
|
-
|
|
26
|
-
protected ruleConfig: IAbstractRuleConfig = {
|
|
27
|
-
id: TextUtility.convertUnderscoresToDashes($accessibilityAuditRules.empty_title_attribute),
|
|
28
|
-
links: [
|
|
29
|
-
{
|
|
30
|
-
content: 'H67: Using null alt text and no title attribute on img elements for images that AT should ignore',
|
|
31
|
-
url: 'https://www.w3.org/TR/WCAG20-TECHS/H67.html'
|
|
32
|
-
}
|
|
33
|
-
],
|
|
34
|
-
recommendations: [],
|
|
35
|
-
severity: $severity.low,
|
|
36
|
-
type: CATEGORY_TYPE.BEST_PRACTICE
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
public validate(elements: Element[]): void {
|
|
40
|
-
const reportEmptyTitle = (element: Element): void => {
|
|
41
|
-
const titleAttribute: string | null = element.getAttribute('title');
|
|
42
|
-
|
|
43
|
-
if (titleAttribute === null || titleAttribute.trim().length > 0) {
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const report: IIssueReport = {
|
|
48
|
-
message: TranslateService.instant('empty_title_attribute_report_message'),
|
|
49
|
-
node: element,
|
|
50
|
-
ruleId: this.ruleConfig.id
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
this.validator.report(report);
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
elements.forEach(reportEmptyTitle);
|
|
57
|
-
}
|
|
58
|
-
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
# flash-content
|
|
2
|
-
|
|
3
|
-
## Rule id
|
|
4
|
-
|
|
5
|
-
`flash-content`
|
|
6
|
-
|
|
7
|
-
## Definition
|
|
8
|
-
|
|
9
|
-
This rule verifies if there are Adobe Flash Player components.
|
|
10
|
-
|
|
11
|
-
## Purpose
|
|
12
|
-
|
|
13
|
-
> Since Adobe no longer supports Flash Player after December 31, 2020 and blocked Flash content from running in Flash Player beginning January 12, 2021, Adobe strongly recommends all users immediately uninstall Flash Player to help protect their systems.
|
|
14
|
-
|
|
15
|
-
Source: https://www.adobe.com/products/flashplayer/end-of-life.html
|
|
16
|
-
|
|
17
|
-
Due to above security reasons and poor an accessibility support Adobe Flash player should be removed.
|
|
18
|
-
|
|
19
|
-
Following elements are being considered as Adobe Flash Player while evaluating this rule:
|
|
20
|
-
|
|
21
|
-
CSS selector:
|
|
22
|
-
|
|
23
|
-
[classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"], embed[type="application/x-shockwave-flash"], object[type="application/x-shockwave-flash"]
|
|
24
|
-
|
|
25
|
-
## Test cases
|
|
26
|
-
|
|
27
|
-
### Passed
|
|
28
|
-
|
|
29
|
-
The rule passes when there are no elements that refers to Adobe Flash Player.
|
|
30
|
-
|
|
31
|
-
## WCAG Success Criteria
|
|
32
|
-
|
|
33
|
-
Not Applicable
|
|
34
|
-
|
|
35
|
-
## Best Practice
|
|
36
|
-
|
|
37
|
-
Yes
|
|
38
|
-
|
|
39
|
-
## User Impact
|
|
40
|
-
|
|
41
|
-
* **Severity**: low
|
|
42
|
-
* **Disabilities Affected**:
|
|
43
|
-
* Visual:
|
|
44
|
-
* blindness
|
|
45
|
-
|
|
46
|
-
## Resources
|
|
47
|
-
|
|
48
|
-
* https://www.adobe.com/products/flashplayer/end-of-life.html
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { FlashContent } from './flash-content';
|
|
2
|
-
import { DomUtility } from '../../../utils/dom';
|
|
3
|
-
import { Validator } from '../../../validator';
|
|
4
|
-
|
|
5
|
-
describe('Rules', () => {
|
|
6
|
-
|
|
7
|
-
describe('#flash-content', () => {
|
|
8
|
-
|
|
9
|
-
let fakeDom;
|
|
10
|
-
|
|
11
|
-
new FlashContent().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 for one flash object', () => {
|
|
27
|
-
const objectEl = document.createElement('object');
|
|
28
|
-
|
|
29
|
-
objectEl.setAttribute('classid', 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000');
|
|
30
|
-
objectEl.setAttribute('codebase', 'http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,19,0');
|
|
31
|
-
fakeDom.appendChild(objectEl);
|
|
32
|
-
|
|
33
|
-
const nodes = DomUtility.querySelectorAllExclude('[classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"]', fakeDom);
|
|
34
|
-
|
|
35
|
-
new FlashContent().validate(nodes);
|
|
36
|
-
|
|
37
|
-
expect(Object.keys(Validator.getReports()).length).toBe(1);
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('should return no reports where there are no flash objects', () => {
|
|
41
|
-
fakeDom.innerHTML = '<a href="#">test</a>';
|
|
42
|
-
|
|
43
|
-
const nodes = DomUtility.querySelectorAllExclude('[classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"]', fakeDom);
|
|
44
|
-
|
|
45
|
-
new FlashContent().validate(nodes);
|
|
46
|
-
|
|
47
|
-
expect(Object.keys(Validator.getReports()).length).toBe(0);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
});
|
|
@@ -1,32 +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 FlashContent extends AbstractRule {
|
|
10
|
-
protected selector: string = '[classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"], embed[type="application/x-shockwave-flash"], object[type="application/x-shockwave-flash"]';
|
|
11
|
-
protected ruleConfig: IAbstractRuleConfig = {
|
|
12
|
-
id: TextUtility.convertUnderscoresToDashes($accessibilityAuditRules.flash_content),
|
|
13
|
-
links: [],
|
|
14
|
-
recommendations: [],
|
|
15
|
-
severity: $severity.critical,
|
|
16
|
-
type: CATEGORY_TYPE.BEST_PRACTICE
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
public validate(elements: Element[]): void {
|
|
20
|
-
const reportFlash = (element: Element): void => {
|
|
21
|
-
const problem: IIssueReport = {
|
|
22
|
-
message: TranslateService.instant('flash_content_report_message'),
|
|
23
|
-
node: element,
|
|
24
|
-
ruleId: this.ruleConfig.id
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
this.validator.report(problem);
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
elements.forEach(reportFlash);
|
|
31
|
-
}
|
|
32
|
-
}
|
package/aslint/app/rules/aslint/redundant/font-style-italic/font-style-italic.documentation.md
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
# font-style-italic
|
|
2
|
-
|
|
3
|
-
## Rule id
|
|
4
|
-
|
|
5
|
-
`font-style-italic`
|
|
6
|
-
|
|
7
|
-
## Definition
|
|
8
|
-
|
|
9
|
-
This rule verifies if there is defined `font-style` type `italic` for a text with length > 80 chars.
|
|
10
|
-
|
|
11
|
-
## Purpose
|
|
12
|
-
|
|
13
|
-
[WCAG Understanding Guideline 3.1](https://www.w3.org/TR/UNDERSTANDING-WCAG20/meaning.html) includes an advisory technique for "avoiding chunks of italic text". Similarly [WebAIM advises](https://webaim.org/articles/evaluatingcognitive/#readability) as follows: "Do not use italics or bold on long sections of text", but at the same time "use various stylistic elements (italics, bold, color, brief animation, or differently-styled content) to highlight important content".
|
|
14
|
-
|
|
15
|
-
This rule checks 2 cases:
|
|
16
|
-
|
|
17
|
-
* Determine reasonable text length - must be < 80 chars.
|
|
18
|
-
* Determine if element has defined `font-style` type `italic`.
|
|
19
|
-
|
|
20
|
-
## Test cases
|
|
21
|
-
|
|
22
|
-
### Passed
|
|
23
|
-
|
|
24
|
-
The rule passes when specified element contains text with length > 80 chars and have no defined style `font-style` type `italic`.
|
|
25
|
-
|
|
26
|
-
## WCAG Success Criteria
|
|
27
|
-
|
|
28
|
-
Not Applicable
|
|
29
|
-
|
|
30
|
-
## Best Practice
|
|
31
|
-
|
|
32
|
-
Yes
|
|
33
|
-
|
|
34
|
-
## User Impact
|
|
35
|
-
|
|
36
|
-
* **Severity**: low
|
|
37
|
-
* **Disabilities Affected**:
|
|
38
|
-
* Visual:
|
|
39
|
-
* blindness
|
|
40
|
-
|
|
41
|
-
## Resources
|
|
42
|
-
|
|
43
|
-
* https://www.w3.org/TR/UNDERSTANDING-WCAG20/meaning.html
|
|
44
|
-
* https://webaim.org/articles/evaluatingcognitive/#readability
|