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.
Files changed (118) hide show
  1. package/CONTRIBUTING.md +3 -1
  2. package/README.md +14 -3
  3. package/package.json +2 -1
  4. package/procs/aslint.js +83 -0
  5. package/procs/nav.js +56 -14
  6. package/procs/standardize.js +36 -0
  7. package/run.js +35 -22
  8. package/tests/aslint.js +83 -0
  9. package/tests/axe.js +4 -0
  10. package/tests/qualWeb.js +6 -0
  11. package/aslint/LICENSE +0 -362
  12. package/aslint/README.md +0 -260
  13. package/aslint/app/rules/abstract-rule.ts +0 -83
  14. package/aslint/app/rules/aslint/incorrect-technique-for-hiding-content/incorrect-technique-for-hiding-content.documentation.md +0 -36
  15. package/aslint/app/rules/aslint/incorrect-technique-for-hiding-content/incorrect-technique-for-hiding-content.test.ts +0 -113
  16. package/aslint/app/rules/aslint/incorrect-technique-for-hiding-content/incorrect-technique-for-hiding-content.ts +0 -103
  17. package/aslint/app/rules/aslint/invalid-attribute-dir-value/invalid-attribute-dir-value.documentation.md +0 -34
  18. package/aslint/app/rules/aslint/invalid-attribute-dir-value/invalid-attribute-dir-value.test.ts +0 -82
  19. package/aslint/app/rules/aslint/invalid-attribute-dir-value/invalid-attribute-dir-value.ts +0 -44
  20. package/aslint/app/rules/aslint/label-duplicated-content-title/label-duplicated-content-title.documentation.md +0 -40
  21. package/aslint/app/rules/aslint/label-duplicated-content-title/label-duplicated-content-title.test.ts +0 -48
  22. package/aslint/app/rules/aslint/label-duplicated-content-title/label-duplicated-content-title.ts +0 -37
  23. package/aslint/app/rules/aslint/links-language-destination/links-language-destination.test.ts +0 -50
  24. package/aslint/app/rules/aslint/links-language-destination/links-language-destination.ts +0 -70
  25. package/aslint/app/rules/aslint/main-element-only-one/main-element-only-one.test.ts +0 -55
  26. package/aslint/app/rules/aslint/main-element-only-one/main-element-only-one.ts +0 -83
  27. package/aslint/app/rules/aslint/main-landmark-must-be-top-level/main-landmark-must-be-top-level.test.ts +0 -12
  28. package/aslint/app/rules/aslint/main-landmark-must-be-top-level/main-landmark-must-be-top-level.ts +0 -73
  29. package/aslint/app/rules/aslint/minimum-font-size/minimum-font-size.test.ts +0 -12
  30. package/aslint/app/rules/aslint/minimum-font-size/minimum-font-size.ts +0 -87
  31. package/aslint/app/rules/aslint/missing-href-on-a/missing-href-on-a.test.ts +0 -48
  32. package/aslint/app/rules/aslint/missing-href-on-a/missing-href-on-a.ts +0 -40
  33. package/aslint/app/rules/aslint/misused-aria-on-focusable-element/misused-aria-on-focusable-element.test.ts +0 -12
  34. package/aslint/app/rules/aslint/misused-aria-on-focusable-element/misused-aria-on-focusable-element.ts +0 -66
  35. package/aslint/app/rules/aslint/misused-input-attribute/misused-input-attribute.test.ts +0 -12
  36. package/aslint/app/rules/aslint/misused-input-attribute/misused-input-attribute.ts +0 -134
  37. package/aslint/app/rules/aslint/misused-required-attribute/misused-required-attribute.test.ts +0 -12
  38. package/aslint/app/rules/aslint/misused-required-attribute/misused-required-attribute.ts +0 -90
  39. package/aslint/app/rules/aslint/navigation-landmark-restrictions/navigation-landmark-restrictions.test.ts +0 -12
  40. package/aslint/app/rules/aslint/navigation-landmark-restrictions/navigation-landmark-restrictions.ts +0 -48
  41. package/aslint/app/rules/aslint/obsolete-html-attributes/obsolete-html-attributes.test.ts +0 -12
  42. package/aslint/app/rules/aslint/obsolete-html-attributes/obsolete-html-attributes.ts +0 -148
  43. package/aslint/app/rules/aslint/obsolete-html-elements/obsolete-html-elements.test.ts +0 -12
  44. package/aslint/app/rules/aslint/obsolete-html-elements/obsolete-html-elements.ts +0 -66
  45. package/aslint/app/rules/aslint/outline-zero/outline-zero.test.ts +0 -12
  46. package/aslint/app/rules/aslint/outline-zero/outline-zero.ts +0 -85
  47. package/aslint/app/rules/aslint/overlay/overlay.test.ts +0 -122
  48. package/aslint/app/rules/aslint/overlay/overlay.ts +0 -141
  49. package/aslint/app/rules/aslint/redundant/aria-role-dialog/aria-role-dialog.documentation.md +0 -49
  50. package/aslint/app/rules/aslint/redundant/aria-role-dialog/aria-role-dialog.test.ts +0 -91
  51. package/aslint/app/rules/aslint/redundant/aria-role-dialog/aria-role-dialog.ts +0 -62
  52. package/aslint/app/rules/aslint/redundant/capital-letters-words/capital-letters-words.documentation.md +0 -44
  53. package/aslint/app/rules/aslint/redundant/capital-letters-words/capital-letters-words.test.ts +0 -111
  54. package/aslint/app/rules/aslint/redundant/capital-letters-words/capital-letters-words.ts +0 -120
  55. package/aslint/app/rules/aslint/redundant/contentinfo-landmark-only-one/contentinfo-landmark-only-one.documentation.md +0 -45
  56. package/aslint/app/rules/aslint/redundant/contentinfo-landmark-only-one/contentinfo-landmark-only-one.test.ts +0 -63
  57. package/aslint/app/rules/aslint/redundant/contentinfo-landmark-only-one/contentinfo-landmark-only-one.ts +0 -44
  58. package/aslint/app/rules/aslint/redundant/empty-title-attribute/empty-title-attribute.documentation.md +0 -55
  59. package/aslint/app/rules/aslint/redundant/empty-title-attribute/empty-title-attribute.test.ts +0 -80
  60. package/aslint/app/rules/aslint/redundant/empty-title-attribute/empty-title-attribute.ts +0 -58
  61. package/aslint/app/rules/aslint/redundant/flash-content/flash-content.documentation.md +0 -48
  62. package/aslint/app/rules/aslint/redundant/flash-content/flash-content.test.ts +0 -52
  63. package/aslint/app/rules/aslint/redundant/flash-content/flash-content.ts +0 -32
  64. package/aslint/app/rules/aslint/redundant/font-style-italic/font-style-italic.documentation.md +0 -44
  65. package/aslint/app/rules/aslint/redundant/font-style-italic/font-style-italic.test.ts +0 -12
  66. package/aslint/app/rules/aslint/redundant/font-style-italic/font-style-italic.ts +0 -83
  67. package/aslint/app/rules/aslint/redundant/h1-must-be/h1-must-be.documentation.md +0 -46
  68. package/aslint/app/rules/aslint/redundant/h1-must-be/h1-must-be.test.ts +0 -46
  69. package/aslint/app/rules/aslint/redundant/h1-must-be/h1-must-be.ts +0 -36
  70. package/aslint/app/rules/aslint/role-application/role-application.test.ts +0 -48
  71. package/aslint/app/rules/aslint/role-application/role-application.ts +0 -38
  72. package/aslint/app/rules/aslint/rtl-content/rtl-content.test.ts +0 -12
  73. package/aslint/app/rules/aslint/rtl-content/rtl-content.ts +0 -75
  74. package/aslint/app/rules/aslint/unclear-uri-on-a/unclear-anchor-uri.test.ts +0 -12
  75. package/aslint/app/rules/aslint/unclear-uri-on-a/unclear-anchor-uri.ts +0 -48
  76. package/aslint/app/rules/aslint/unimportant/aria-hidden-false/aria-hidden-false.test.ts +0 -73
  77. package/aslint/app/rules/aslint/unimportant/aria-hidden-false/aria-hidden-false.ts +0 -34
  78. package/aslint/app/rules/aslint/unimportant/aria-hidden-false/aria-hidden.documentation.md +0 -32
  79. package/aslint/app/rules/aslint/unimportant/content-editable-missing-attributes/content-editable-missing-attributes.docmentation.md +0 -48
  80. package/aslint/app/rules/aslint/unimportant/content-editable-missing-attributes/content-editable-missing-attributes.test.ts +0 -67
  81. package/aslint/app/rules/aslint/unimportant/content-editable-missing-attributes/content-editable-missing-attributes.ts +0 -63
  82. package/aslint/app/rules/aslint/unsupported-role-on-element/unsupported-role-on-element.test.ts +0 -12
  83. package/aslint/app/rules/aslint/unsupported-role-on-element/unsupported-role-on-element.ts +0 -63
  84. package/aslint/app/rules/aslint/used/elements-not-allowed-in-head/elements-not-allowed-in-head.documentation.md +0 -65
  85. package/aslint/app/rules/aslint/used/elements-not-allowed-in-head/elements-not-allowed-in-head.test.ts +0 -53
  86. package/aslint/app/rules/aslint/used/elements-not-allowed-in-head/elements-not-allowed-in-head.ts +0 -47
  87. package/aslint/app/rules/aslint/used/headings-sibling-unique/headings-sibling-unique.documentation.md +0 -57
  88. package/aslint/app/rules/aslint/used/headings-sibling-unique/headings-sibling-unique.test.ts +0 -52
  89. package/aslint/app/rules/aslint/used/headings-sibling-unique/headings-sibling-unique.ts +0 -63
  90. package/aslint/app/rules/aslint/used/horizontal-rule/horizontal-rule.documentation.md +0 -39
  91. package/aslint/app/rules/aslint/used/horizontal-rule/horizontal-rule.test.ts +0 -66
  92. package/aslint/app/rules/aslint/used/horizontal-rule/horizontal-rule.ts +0 -37
  93. package/aslint/utils/aria.test.ts +0 -12
  94. package/aslint/utils/aria.ts +0 -120
  95. package/aslint/utils/async.test.ts +0 -25
  96. package/aslint/utils/async.ts +0 -22
  97. package/aslint/utils/common.test.ts +0 -239
  98. package/aslint/utils/common.ts +0 -168
  99. package/aslint/utils/console.test.ts +0 -85
  100. package/aslint/utils/console.ts +0 -89
  101. package/aslint/utils/css.test.ts +0 -153
  102. package/aslint/utils/css.ts +0 -191
  103. package/aslint/utils/dom.test.ts +0 -627
  104. package/aslint/utils/dom.ts +0 -1051
  105. package/aslint/utils/env.test.ts +0 -14
  106. package/aslint/utils/env.ts +0 -8
  107. package/aslint/utils/func.test.ts +0 -160
  108. package/aslint/utils/func.ts +0 -70
  109. package/aslint/utils/global.test.ts +0 -12
  110. package/aslint/utils/global.ts +0 -25
  111. package/aslint/utils/object.test.ts +0 -524
  112. package/aslint/utils/object.ts +0 -278
  113. package/aslint/utils/report.test.ts +0 -56
  114. package/aslint/utils/report.ts +0 -36
  115. package/aslint/utils/text.test.ts +0 -270
  116. package/aslint/utils/text.ts +0 -165
  117. package/aslint/utils/time.test.ts +0 -43
  118. package/aslint/utils/time.ts +0 -33
@@ -1,122 +0,0 @@
1
- import { DomUtility } from '../../../utils/dom';
2
- import { Validator } from '../../../validator';
3
- import { Overlay } from './overlay';
4
-
5
- describe('Rules', () => {
6
-
7
- describe('Overlay', () => {
8
-
9
- it('should indicate that class exists', () => {
10
- expect(Overlay).toBeDefined();
11
- });
12
-
13
- let fakeDom;
14
-
15
- new Overlay().registerValidator();
16
-
17
- beforeEach(() => {
18
- fakeDom = document.createElement('div');
19
- fakeDom.id = 'fakedom';
20
- document.body.appendChild(fakeDom);
21
-
22
- Validator.reset();
23
- });
24
-
25
- afterEach(() => {
26
- DomUtility.remove(document.getElementById('fakedom'));
27
- fakeDom = undefined;
28
- });
29
-
30
- it('should return 1 report when there is one known Overlay detected', () => {
31
- fakeDom.innerHTML = '<script src="https://cdn.userway.org/widget.js"></script>';
32
- const nodes = DomUtility.querySelectorAllExclude('script', fakeDom) as HTMLScriptElement[];
33
-
34
- new Overlay().validate(nodes);
35
-
36
- expect(Object.keys(Validator.getReports()).length).toBe(1);
37
- expect(Validator.getReport('report_0').message).toBe('Accessibility overlay UserWay has been detected on the page. Overlays are third-party widgets that attempt to automatically fix the accessibility issues of page they are added to. Therefore the results from the scanning may not be accurate.');
38
- expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('script');
39
- expect(Validator.getReport('report_0').ruleId).toBe('overlay');
40
- });
41
-
42
- it('should return 1 report when there is one known Overlay detected inside HTML', () => {
43
- fakeDom.innerHTML = '<div data-src="https://cdn.userway.org/widget.js"></div>';
44
- const nodes = DomUtility.querySelectorAllExclude('script', fakeDom) as HTMLScriptElement[];
45
-
46
- new Overlay().validate(nodes);
47
-
48
- expect(Object.keys(Validator.getReports()).length).toBe(1);
49
- expect(Validator.getReport('report_0').message).toBe('Accessibility overlay UserWay has been detected on the page. Overlays are third-party widgets that attempt to automatically fix the accessibility issues of page they are added to. Therefore the results from the scanning may not be accurate.');
50
- expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('html');
51
- expect(Validator.getReport('report_0').ruleId).toBe('overlay');
52
- });
53
-
54
- it('should return reports for all known detected overlays', () => {
55
- let overlays: string = '';
56
-
57
- overlays += '<script src="https://cdn.acsbap.com/widget.js"></script>';
58
- overlays += '<script src="https://cdn.acsbapp.com/widget.js"></script>';
59
- overlays += '<script src="https://cdn.audioeye.com/widget.js"></script>';
60
- overlays += '<script src="https://cdn.nagich.com/widget.js"></script>';
61
- overlays += '<script src="https://cdn.nagich.co.il/widget.js"></script>';
62
- overlays += '<script src="https://cdn.maxaccess.io/widget.js"></script>';
63
- overlays += '<script src="https://cdn.truabilities.com/widget.js"></script>';
64
- overlays += '<script src="https://cdn.user1st.info/widget.js"></script>';
65
- overlays += '<script src="https://cdn.userway.org/widget.js"></script>';
66
-
67
- fakeDom.innerHTML = overlays;
68
-
69
- const nodes = DomUtility.querySelectorAllExclude('script', fakeDom) as HTMLScriptElement[];
70
-
71
- new Overlay().validate(nodes);
72
-
73
- expect(Object.keys(Validator.getReports()).length).toBe(9);
74
-
75
- expect(Validator.getReport('report_0').message).toBe('Accessibility overlay AccessiBe has been detected on the page. Overlays are third-party widgets that attempt to automatically fix the accessibility issues of page they are added to. Therefore the results from the scanning may not be accurate.');
76
- expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('script');
77
- expect(Validator.getReport('report_0').ruleId).toBe('overlay');
78
-
79
- expect(Validator.getReport('report_1').message).toBe('Accessibility overlay AccessiBe has been detected on the page. Overlays are third-party widgets that attempt to automatically fix the accessibility issues of page they are added to. Therefore the results from the scanning may not be accurate.');
80
- expect(Validator.getReport('report_1').node.nodeName.toLowerCase()).toBe('script');
81
- expect(Validator.getReport('report_1').ruleId).toBe('overlay');
82
-
83
- expect(Validator.getReport('report_2').message).toBe('Accessibility overlay AudioEye has been detected on the page. Overlays are third-party widgets that attempt to automatically fix the accessibility issues of page they are added to. Therefore the results from the scanning may not be accurate.');
84
- expect(Validator.getReport('report_2').node.nodeName.toLowerCase()).toBe('script');
85
- expect(Validator.getReport('report_2').ruleId).toBe('overlay');
86
-
87
- expect(Validator.getReport('report_3').message).toBe('Accessibility overlay EqualWeb has been detected on the page. Overlays are third-party widgets that attempt to automatically fix the accessibility issues of page they are added to. Therefore the results from the scanning may not be accurate.');
88
- expect(Validator.getReport('report_3').node.nodeName.toLowerCase()).toBe('script');
89
- expect(Validator.getReport('report_3').ruleId).toBe('overlay');
90
-
91
- expect(Validator.getReport('report_4').message).toBe('Accessibility overlay EqualWeb has been detected on the page. Overlays are third-party widgets that attempt to automatically fix the accessibility issues of page they are added to. Therefore the results from the scanning may not be accurate.');
92
- expect(Validator.getReport('report_4').node.nodeName.toLowerCase()).toBe('script');
93
- expect(Validator.getReport('report_4').ruleId).toBe('overlay');
94
-
95
- expect(Validator.getReport('report_5').message).toBe('Accessibility overlay MaxAccess has been detected on the page. Overlays are third-party widgets that attempt to automatically fix the accessibility issues of page they are added to. Therefore the results from the scanning may not be accurate.');
96
- expect(Validator.getReport('report_5').node.nodeName.toLowerCase()).toBe('script');
97
- expect(Validator.getReport('report_5').ruleId).toBe('overlay');
98
-
99
- expect(Validator.getReport('report_6').message).toBe('Accessibility overlay TruAbilities has been detected on the page. Overlays are third-party widgets that attempt to automatically fix the accessibility issues of page they are added to. Therefore the results from the scanning may not be accurate.');
100
- expect(Validator.getReport('report_6').node.nodeName.toLowerCase()).toBe('script');
101
- expect(Validator.getReport('report_6').ruleId).toBe('overlay');
102
-
103
- expect(Validator.getReport('report_7').message).toBe('Accessibility overlay User1st has been detected on the page. Overlays are third-party widgets that attempt to automatically fix the accessibility issues of page they are added to. Therefore the results from the scanning may not be accurate.');
104
- expect(Validator.getReport('report_7').node.nodeName.toLowerCase()).toBe('script');
105
- expect(Validator.getReport('report_7').ruleId).toBe('overlay');
106
-
107
- expect(Validator.getReport('report_8').message).toBe('Accessibility overlay UserWay has been detected on the page. Overlays are third-party widgets that attempt to automatically fix the accessibility issues of page they are added to. Therefore the results from the scanning may not be accurate.');
108
- expect(Validator.getReport('report_8').node.nodeName.toLowerCase()).toBe('script');
109
- expect(Validator.getReport('report_8').ruleId).toBe('overlay');
110
- });
111
-
112
- it('should return no reports when there are no overlays on the page', () => {
113
- fakeDom.innerHTML = '<script src="empty.js"></script>';
114
- const nodes = DomUtility.querySelectorAllExclude('script', fakeDom) as HTMLScriptElement[];
115
-
116
- new Overlay().validate(nodes);
117
-
118
- expect(Object.keys(Validator.getReports()).length).toBe(0);
119
- });
120
-
121
- });
122
- });
@@ -1,141 +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
- import { Context } from '../../../interfaces/context.interface';
8
-
9
- export class Overlay extends AbstractRule {
10
- protected selector: string = 'script';
11
-
12
- protected ruleConfig: IAbstractRuleConfig = {
13
- id: TextUtility.convertUnderscoresToDashes($accessibilityAuditRules.overlay),
14
- links: [
15
- {
16
- content: 'The Many Pitfalls of Accessibility Overlays',
17
- url: 'https://www.essentialaccessibility.com/blog/the-many-pitfalls-of-accessibility-overlays'
18
- }
19
- ],
20
- recommendations: [],
21
- severity: $severity.high,
22
- type: CATEGORY_TYPE.BEST_PRACTICE
23
- };
24
-
25
- public validate(scripts: HTMLScriptElement[]): void {
26
- let foundedInScripts: boolean = false;
27
-
28
- const findByScripts = (_overlayEntries: [string, string[]][]): void => {
29
- const findOverlay = (script: HTMLScriptElement): void => {
30
-
31
- let url: URL | null;
32
-
33
- if (script.src.length === 0) {
34
- // Note: this means script is inline embedded
35
- return;
36
- }
37
-
38
- try {
39
- url = new URL(script.src);
40
- } catch (_) {
41
- url = null;
42
- }
43
-
44
- if (url === null) {
45
- return;
46
- }
47
-
48
- const hostname: string = url.hostname;
49
- const foundedOverlays: Map<string, null> = new Map();
50
-
51
- for (const [overlayName, overlayUrls] of _overlayEntries) {
52
-
53
- for (const overlayUrl of overlayUrls) {
54
- if (hostname.includes(overlayUrl)) {
55
- foundedOverlays.set(overlayName, null);
56
- }
57
- }
58
- }
59
-
60
- if (Array.from(foundedOverlays).length === 0) {
61
- return;
62
- }
63
-
64
- const reportMessage: string = TranslateService.instant('overlay_report_message', Array.from(foundedOverlays.keys()).join(', '));
65
-
66
- const report: IIssueReport = {
67
- message: reportMessage,
68
- node: script,
69
- ruleId: this.ruleConfig.id
70
- };
71
-
72
- this.validator.report(report);
73
-
74
- foundedInScripts = true;
75
- };
76
-
77
- scripts.forEach(findOverlay);
78
- };
79
-
80
- const findThroughHtml = (_overlayEntries: [string, string[]][]): void => {
81
- const context: Context = this.context;
82
- let html: string = '';
83
-
84
- if (typeof (context as any).innerHTML === 'string') {
85
- html = (context as any).innerHTML;
86
- } else if ((context as any).outerHTML === 'string') {
87
- html = (context as any).outerHTML;
88
- }
89
-
90
- if (html.trim().length === 0) {
91
- return;
92
- }
93
-
94
- const foundedOverlays: Map<string, null> = new Map();
95
-
96
- for (const [overlayName, overlayUrls] of _overlayEntries) {
97
-
98
- for (const overlayUrl of overlayUrls) {
99
- if (html.includes(overlayUrl)) {
100
- foundedOverlays.set(overlayName, null);
101
- }
102
- }
103
- }
104
-
105
- if (Array.from(foundedOverlays).length === 0) {
106
- return;
107
- }
108
-
109
- const reportMessage: string = TranslateService.instant('overlay_report_message', Array.from(foundedOverlays.keys()).join(', '));
110
-
111
- const report: IIssueReport = {
112
- message: reportMessage,
113
- node: context,
114
- ruleId: this.ruleConfig.id
115
- };
116
-
117
- this.validator.report(report);
118
- };
119
-
120
- // Note: key of below object is later used as a name of overlay vendor
121
- const overlay: { [key: string]: string[] } = {
122
- AccessiBe: ['acsbap.com', 'acsbapp.com'],
123
- AudioEye: ['audioeye.com'],
124
- EqualWeb: ['nagich.com', 'nagich.co.il'],
125
- MaxAccess: ['maxaccess.io'],
126
- TruAbilities: ['truabilities.com'],
127
- User1st: ['user1st.info'],
128
- UserWay: ['userway.org']
129
- };
130
-
131
- const overlayEntries: [string, string[]][] = Object.entries(overlay);
132
-
133
- if (scripts.length > 0) {
134
- findByScripts(overlayEntries);
135
- }
136
-
137
- if (foundedInScripts === false) {
138
- findThroughHtml(overlayEntries);
139
- }
140
- }
141
- }
@@ -1,49 +0,0 @@
1
- # aria-role-dialog
2
-
3
- ## Rule id
4
-
5
- `aria-role-dialog`
6
-
7
- ## Definition
8
-
9
- Ensures that element with attribute `role="dialog"` is having defined an accessible name.
10
-
11
- ## Purpose
12
-
13
- Using `role="dialog"` on the HTML element helps assistive technology identify the dialog's content as being grouped and separated from the rest of the page content. However, having only `role="dialog"` defined alone is not sufficient to make a dialog accessible. Additionally, the following needs to be done:
14
-
15
- 1. The dialog must be properly labeled
16
- 2. Keyboard focus must be managed correctly
17
-
18
- `aria-role-dialog` rule test cases below describe how #1 requirement can be met.
19
-
20
- **Note**: when possible you may consider using native [&lt;dialog&gt;](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog) box feature.
21
-
22
- ## Test cases
23
-
24
- ### Passed
25
-
26
- The rule passes when one of the following case is fulfilled:
27
-
28
- 1. Attribute `aria-labelledby` is defined AND is not empty.
29
- 2. Attribute `aria-label` is defined AND is not empty.
30
- 2. Attribute `title` is defined AND is not empty.
31
-
32
- ## WCAG Success Criteria
33
-
34
- Not Applicable
35
-
36
- ## Best Practice
37
-
38
- Yes
39
-
40
- ## User Impact
41
-
42
- * **Severity**: high
43
- * **Disabilities Affected**:
44
- * Visual:
45
- * blindness
46
-
47
- ## Resources
48
-
49
- Not available
@@ -1,91 +0,0 @@
1
- import { AriaRoleDialog } from './aria-role-dialog';
2
- import { DomUtility } from '../../../utils/dom';
3
- import { Validator } from '../../../validator';
4
-
5
- describe('Rules', () => {
6
-
7
- describe('AriaRoleDialog', () => {
8
-
9
- let fakeDom;
10
- const selector = '[role="dialog"], [role="alertdialog"]';
11
-
12
- new AriaRoleDialog().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 no report when there is an element with role="dialog" and aria-label', () => {
28
- fakeDom.innerHTML = '<div role="dialog" aria-label="name"></div>';
29
-
30
- const nodes: Element[] = DomUtility.querySelectorAllExclude(selector, fakeDom);
31
-
32
- new AriaRoleDialog().validate(nodes);
33
-
34
- expect(Object.keys(Validator.getReports()).length).toBe(0);
35
- });
36
-
37
- it('should return 1 report when there is an element with role="dialog" and aria-label=""', () => {
38
- fakeDom.innerHTML = '<div role="dialog" aria-label=""></div>';
39
-
40
- const nodes: Element[] = DomUtility.querySelectorAllExclude(selector, fakeDom);
41
-
42
- new AriaRoleDialog().validate(nodes);
43
-
44
- expect(Object.keys(Validator.getReports()).length).toBe(1);
45
- expect(Validator.getReport('report_0').ruleId).toBe('aria-role-dialog');
46
- expect(Validator.getReport('report_0').message).toBe('Element with <code>role&#x3D;&quot;dialog&quot;</code> attribute has no accessible name because attribute <code>aria-label</code> has no content (it\'s empty).');
47
- expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('div');
48
- });
49
-
50
- it('should return 1 report when there is an element with role="dialog" and title=""', () => {
51
- fakeDom.innerHTML = '<div role="dialog" title=""></div>';
52
-
53
- const nodes: Element[] = DomUtility.querySelectorAllExclude(selector, fakeDom);
54
-
55
- new AriaRoleDialog().validate(nodes);
56
-
57
- expect(Object.keys(Validator.getReports()).length).toBe(1);
58
- expect(Validator.getReport('report_0').ruleId).toBe('aria-role-dialog');
59
- expect(Validator.getReport('report_0').message).toBe('Element with <code>role&#x3D;&quot;dialog&quot;</code> attribute has no accessible name because attribute <code>title</code> has no content (it\'s empty).');
60
- expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('div');
61
- });
62
-
63
- it('should return 1 report when there is an element with role="dialog" without any accesible name', () => {
64
- fakeDom.innerHTML = '<div role="dialog"></div>';
65
-
66
- const nodes: Element[] = DomUtility.querySelectorAllExclude(selector, fakeDom);
67
-
68
- new AriaRoleDialog().validate(nodes);
69
-
70
- expect(Object.keys(Validator.getReports()).length).toBe(1);
71
- expect(Validator.getReport('report_0').ruleId).toBe('aria-role-dialog');
72
- expect(Validator.getReport('report_0').message).toBe('Element with <code>role&#x3D;&quot;dialog&quot;</code> attribute has no accessible name.');
73
- expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('div');
74
- });
75
-
76
- it('should return 1 report when there is an element with role="alertdialog" without any accesible name', () => {
77
- fakeDom.innerHTML = '<div role="alertdialog"></div>';
78
-
79
- const nodes: Element[] = DomUtility.querySelectorAllExclude(selector, fakeDom);
80
-
81
- new AriaRoleDialog().validate(nodes);
82
-
83
- expect(Object.keys(Validator.getReports()).length).toBe(1);
84
- expect(Validator.getReport('report_0').ruleId).toBe('aria-role-dialog');
85
- expect(Validator.getReport('report_0').message).toBe('Element with <code>role&#x3D;&quot;alertdialog&quot;</code> attribute has no accessible name.');
86
- expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('div');
87
- });
88
-
89
- });
90
-
91
- });
@@ -1,62 +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 AriaRoleDialog extends AbstractRule {
9
- protected selector: string = '[role="dialog"], [role="alertdialog"]';
10
-
11
- protected ruleConfig: IAbstractRuleConfig = {
12
- id: TextUtility.convertUnderscoresToDashes($accessibilityAuditRules.aria_role_dialog),
13
- links: [],
14
- recommendations: [],
15
- severity: $severity.high,
16
- type: CATEGORY_TYPE.BEST_PRACTICE
17
- };
18
-
19
- public validate(elements: Element[]): void {
20
- const reportProblem = (element: Element): void => {
21
-
22
- const ariaLabelledby: string | null = element.getAttribute('aria-labelledby');
23
- const ariaLabel: string | null = element.getAttribute('aria-label');
24
- const titleAttr: string | null = element.getAttribute('title');
25
- const roleAttr: string | null = element.getAttribute('role');
26
-
27
- let reportMessage: string = '';
28
-
29
- if (typeof ariaLabelledby === 'string') {
30
- if (ariaLabelledby.trim().length > 0) {
31
- return;
32
- }
33
-
34
- reportMessage = TranslateService.instant('aria_role_dialog_report_message_1', [TextUtility.escape(`role="${roleAttr}"`), TextUtility.escape('aria-labelledby')]);
35
- } else if (typeof ariaLabel === 'string') {
36
- if (ariaLabel.trim().length > 0) {
37
- return;
38
- }
39
-
40
- reportMessage = TranslateService.instant('aria_role_dialog_report_message_1', [TextUtility.escape(`role="${roleAttr}"`), TextUtility.escape('aria-label')]);
41
- } else if (typeof titleAttr === 'string') {
42
- if (titleAttr.trim().length > 0) {
43
- return;
44
- }
45
-
46
- reportMessage = TranslateService.instant('aria_role_dialog_report_message_1', [TextUtility.escape(`role="${roleAttr}"`), TextUtility.escape('title')]);
47
- } else {
48
- reportMessage = TranslateService.instant('aria_role_dialog_report_message_2', [TextUtility.escape(`role="${roleAttr}"`)]);
49
- }
50
-
51
- const problem: IIssueReport = {
52
- message: reportMessage,
53
- node: element,
54
- ruleId: this.ruleConfig.id
55
- };
56
-
57
- this.validator.report(problem);
58
- };
59
-
60
- elements.forEach(reportProblem);
61
- }
62
- }
@@ -1,44 +0,0 @@
1
- # capital-letters-words
2
-
3
- ## Rule id
4
-
5
- `capital-letters-words`
6
-
7
- ## Definition
8
-
9
- This rule detects words written in all capital letters, including text in an attribute `title` as well as using `text-transform` CSS.
10
-
11
- ## Purpose
12
-
13
- Unless you are dealing with an acronym, there should not be any content in all caps. Some screen readers will announce the capital letters separately (like an acronym) or otherwise misleadingly emphasise the capital letters.
14
-
15
- **Example**: CONTACT US and Contact Us will be read be screen reader differently. You can use [Pronunciation checker](https://voicenotebook.com/prononce.php) to verify how these two words are being readable.
16
-
17
- ## Test cases
18
-
19
- ### Passed
20
-
21
- The rule passes when all of the following cases are fulfilled:
22
-
23
- 1. Text is not using all capital letters.
24
- 2. There is no `text-transform` CSS rule used.
25
- 3. Attribute `title` does not contains text written in all capital letters.
26
-
27
- ## WCAG Success Criteria
28
-
29
- Not Applicable
30
-
31
- ## Best Practice
32
-
33
- Yes
34
-
35
- ## User Impact
36
-
37
- * **Severity**: high
38
- * **Disabilities Affected**:
39
- * Visual:
40
- * blindness
41
-
42
- ## Resources
43
-
44
- Not available
@@ -1,111 +0,0 @@
1
- import { DomUtility } from '../../../utils/dom';
2
- import { Validator } from '../../../validator';
3
- import { CapitalLettersWords } from './capital-letters-words';
4
-
5
- describe('Rules', () => {
6
-
7
- describe('CapitalLettersWords', () => {
8
-
9
- it('should indicate that class exists', () => {
10
- expect(CapitalLettersWords).toBeDefined();
11
- });
12
-
13
- const selector: string = `*${[
14
- ':root',
15
- 'head',
16
- 'style',
17
- 'script',
18
- 'meta',
19
- 'link',
20
- 'br',
21
- 'hr',
22
- 'object',
23
- 'path',
24
- 'g',
25
- 'filter',
26
- 'img',
27
- 'input',
28
- 'iframe',
29
- 'code',
30
- ':empty'
31
- ].map((i: string): string => {
32
- return `:not(${i})`;
33
- }).join('')}`;
34
-
35
- let fakeDom;
36
-
37
- new CapitalLettersWords().registerValidator();
38
-
39
- beforeEach(() => {
40
- fakeDom = document.createElement('div');
41
- fakeDom.id = 'fakedom';
42
- document.body.appendChild(fakeDom);
43
-
44
- Validator.reset();
45
- });
46
-
47
- afterEach(() => {
48
- DomUtility.remove(document.getElementById('fakedom'));
49
- fakeDom = undefined;
50
- });
51
-
52
- it('should return no report when text does not contains words in capital letters', () => {
53
- fakeDom.innerHTML = '<p>Text contains no capital letters</p>';
54
-
55
- const nodes = DomUtility.querySelectorAllExclude(selector, fakeDom) as HTMLParagraphElement[];
56
-
57
- new CapitalLettersWords().validate(nodes);
58
-
59
- expect(Object.keys(Validator.getReports()).length).toBe(0);
60
- });
61
-
62
- it('should return 1 report when text contains words in capital letters transformed through CSS text-transform', () => {
63
- fakeDom.innerHTML = '<p style="text-transform: uppercase;">capital letters</p>';
64
-
65
- const nodes = DomUtility.querySelectorAllExclude(selector, fakeDom) as HTMLParagraphElement[];
66
-
67
- new CapitalLettersWords().validate(nodes);
68
-
69
- expect(Object.keys(Validator.getReports()).length).toBe(1);
70
- expect(Validator.getReport('report_0').message).toBe('Element have a text <q>CAPITAL LETTERS</q> that contains words in upper case. <strong>Note</strong>: the text is transformed using <code>(text-transform: uppercase)</code>. Unless you are dealing with an acronym, there should not be any content in all caps. Some screen readers will announce the capital letters separately (like an acronym) or otherwise misleadingly emphasise the capital letters.');
71
- expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('p');
72
- });
73
-
74
- it('should return 1 report when text contains words in capital letters', () => {
75
- fakeDom.innerHTML = '<p>Text contains CAPITAL LETTERS</p>';
76
-
77
- const nodes = DomUtility.querySelectorAllExclude(selector, fakeDom) as HTMLParagraphElement[];
78
-
79
- new CapitalLettersWords().validate(nodes);
80
-
81
- expect(Object.keys(Validator.getReports()).length).toBe(1);
82
- expect(Validator.getReport('report_0').message).toBe('Element have a text that contains words in upper case. Unless you are dealing with an acronym, there should not be any content in all caps. Some screen readers will announce the capital letters separately (like an acronym) or otherwise misleadingly emphasise the capital letters.');
83
- expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('p');
84
- });
85
-
86
- it('should return 1 report when element have an attribute title with text that contains words in capital letters', () => {
87
- fakeDom.innerHTML = '<p title="CAPITAL LETTERS">Example text</p>';
88
-
89
- const nodes = DomUtility.querySelectorAllExclude(selector, fakeDom) as HTMLParagraphElement[];
90
-
91
- new CapitalLettersWords().validate(nodes);
92
-
93
- expect(Object.keys(Validator.getReports()).length).toBe(1);
94
- expect(Validator.getReport('report_0').message).toBe('This element has a <code>title</code> attribute that contains words in upper case. Unless you are dealing with an acronym, there should not be any content in all caps. Some screen readers will announce the capital letters separately (like an acronym) or otherwise misleadingly emphasise the capital letters.');
95
- expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('p');
96
- });
97
-
98
- it('should return 1 report when element have an attribute title and content with text that contains words in capital letters', () => {
99
- fakeDom.innerHTML = '<p title="CAPITAL LETTERS">Example text WITH CAPITAL LETTERS</p>';
100
-
101
- const nodes = DomUtility.querySelectorAllExclude(selector, fakeDom) as HTMLParagraphElement[];
102
-
103
- new CapitalLettersWords().validate(nodes);
104
-
105
- expect(Object.keys(Validator.getReports()).length).toBe(1);
106
- expect(Validator.getReport('report_0').message).toBe('Element have a text and has a <code>title</code> attribute that contains words in upper case. Unless you are dealing with an acronym, there should not be any content in all caps. Some screen readers will announce the capital letters separately (like an acronym) or otherwise misleadingly emphasise the capital letters.');
107
- expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('p');
108
- });
109
-
110
- });
111
- });