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,67 +0,0 @@
1
- import { ContentEditableMissingAttributes } from './content-editable-missing-attributes';
2
- import { DomUtility } from '../../../utils/dom';
3
- import { Validator } from '../../../validator';
4
-
5
- describe('Rules', () => {
6
-
7
- describe('#content-editable-missing-attributes', () => {
8
-
9
- let fakeDom;
10
-
11
- new ContentEditableMissingAttributes().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 3 reports when there is an element with attribute [contenteditable] only', () => {
27
- fakeDom.innerHTML = '<p contenteditable="true"></p>';
28
-
29
- const nodes = DomUtility.querySelectorAllExclude('[contenteditable]', fakeDom);
30
-
31
- new ContentEditableMissingAttributes().validate(nodes);
32
-
33
- expect(Object.keys(Validator.getReports()).length).toBe(3);
34
-
35
- expect(Validator.getReport('report_0').message).toBe('Missing attribute <code>role=\'textbox\'</code> on <code>&lt;p contenteditable&#x3D;&quot;true&quot;&gt;&lt;&#x2F;p&gt;</code>');
36
- expect(Validator.getReport('report_1').message).toBe('Missing attribute <code>aria-multiline=\'true\'</code> on <code>&lt;p contenteditable&#x3D;&quot;true&quot;&gt;&lt;&#x2F;p&gt;</code>');
37
- expect(Validator.getReport('report_2').message).toBe('Missing attribute <code>aria-labelledby</code> or <code>aria-label</code> on <code>&lt;p contenteditable&#x3D;&quot;true&quot;&gt;&lt;&#x2F;p&gt;</code>');
38
- });
39
-
40
- it('should return 2 reports when there is an element with attribute [contenteditable] and defined attribute aria-label', () => {
41
- fakeDom.innerHTML = '<p contenteditable="true" aria-label="test"></p><span id="test">test</span>';
42
-
43
- const nodes = DomUtility.querySelectorAllExclude('[contenteditable]', fakeDom);
44
-
45
- new ContentEditableMissingAttributes().validate(nodes);
46
-
47
- expect(Object.keys(Validator.getReports()).length).toBe(2);
48
-
49
- expect(Validator.getReport('report_0').message).toBe('Missing attribute <code>role=\'textbox\'</code> on <code>&lt;p contenteditable&#x3D;&quot;true&quot; aria-label&#x3D;&quot;test&quot;&gt;&lt;&#x2F;p&gt;</code>');
50
- expect(Validator.getReport('report_1').message).toBe('Missing attribute <code>aria-multiline=\'true\'</code> on <code>&lt;p contenteditable&#x3D;&quot;true&quot; aria-label&#x3D;&quot;test&quot;&gt;&lt;&#x2F;p&gt;</code>');
51
- });
52
-
53
- it('should return 1 report for missing attribute role="textbox" when there is an element with attribute [contenteditable], defined attribute aria-label and aria-multiline', () => {
54
- fakeDom.innerHTML = '<p contenteditable="true" aria-label="test" aria-multiline="true"></p><span id="test">test</span>';
55
-
56
- const nodes = DomUtility.querySelectorAllExclude('[contenteditable]', fakeDom);
57
-
58
- new ContentEditableMissingAttributes().validate(nodes);
59
-
60
- expect(Object.keys(Validator.getReports()).length).toBe(1);
61
-
62
- expect(Validator.getReport('report_0').message).toBe('Missing attribute <code>role=\'textbox\'</code> on <code>&lt;p contenteditable&#x3D;&quot;true&quot; aria-label&#x3D;&quot;test&quot; aria-multiline&#x3D;&quot;true&quot;&gt;&lt;&#x2F;p&gt;</code>');
63
- });
64
-
65
- });
66
-
67
- });
@@ -1,63 +0,0 @@
1
- import { DomUtility } from '../../../utils/dom';
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 { $accessibilityAuditRules, $severity } from '../../../constants/accessibility';
7
- import { AbstractRule, IAbstractRuleConfig } from '../../abstract-rule';
8
-
9
- export class ContentEditableMissingAttributes extends AbstractRule {
10
- protected selector: string = '[contenteditable]';
11
- protected ruleConfig: IAbstractRuleConfig = {
12
- id: TextUtility.convertUnderscoresToDashes($accessibilityAuditRules.content_editable_missing_attributes),
13
- links: [],
14
- recommendations: [],
15
- severity: $severity.low,
16
- type: CATEGORY_TYPE.BEST_PRACTICE
17
- };
18
-
19
- public validate(elements: Element[]): void {
20
- const reportMissingAttributes = (element: Element): void => {
21
- let problem: IIssueReport;
22
- const roleValue: string | null = element.getAttribute('role');
23
-
24
- if (roleValue !== 'textbox') {
25
- const reportMessage: string = TranslateService.instant('content_editable_missing_attributes_report_message1', [DomUtility.getEscapedOuterHTML(element)]);
26
-
27
- problem = {
28
- message: reportMessage,
29
- node: element,
30
- ruleId: this.ruleConfig.id
31
- };
32
-
33
- this.validator.report(problem);
34
- }
35
-
36
- if (element.getAttribute('aria-multiline') === null) {
37
- const reportMessage: string = TranslateService.instant('content_editable_missing_attributes_report_message2', [DomUtility.getEscapedOuterHTML(element)]);
38
-
39
- problem = {
40
- message: reportMessage,
41
- node: element,
42
- ruleId: this.ruleConfig.id
43
- };
44
-
45
- this.validator.report(problem);
46
- }
47
-
48
- if (element.getAttribute('aria-labelledby') === null && element.getAttribute('aria-label') === null) {
49
- const reportMessage: string = TranslateService.instant('content_editable_missing_attributes_report_message3', [DomUtility.getEscapedOuterHTML(element)]);
50
-
51
- problem = {
52
- message: reportMessage,
53
- node: element,
54
- ruleId: this.ruleConfig.id
55
- };
56
-
57
- this.validator.report(problem);
58
- }
59
- };
60
-
61
- elements.forEach(reportMissingAttributes);
62
- }
63
- }
@@ -1,12 +0,0 @@
1
- import { UnsupportedRoleOnElement } from './unsupported-role-on-element';
2
-
3
- describe('Rules', () => {
4
-
5
- describe('UnsupportedRoleOnElement', () => {
6
-
7
- it('should indicate that class exists', () => {
8
- expect(UnsupportedRoleOnElement).toBeDefined();
9
- });
10
-
11
- });
12
- });
@@ -1,63 +0,0 @@
1
- import { CATEGORY_TYPE } from '../../../constants/categoryType';
2
- import { TAG_TO_IMPLICIT_SEMANTIC_INFO } from '../../../constants/aria';
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 UnsupportedRoleOnElement extends AbstractRule {
11
- protected selector: string = 'a[href="#"], a[href*=javascript\\:], a[href=""]';
12
-
13
- protected ruleConfig: IAbstractRuleConfig = {
14
- id: TextUtility.convertUnderscoresToDashes($accessibilityAuditRules.unsupported_role_on_element),
15
- links: [],
16
- recommendations: [],
17
- severity: $severity.high,
18
- type: CATEGORY_TYPE.BEST_PRACTICE
19
- };
20
-
21
- public validate(anchorElements: HTMLAnchorElement[]): void {
22
- const checkSingleNode = (anchorElement: HTMLAnchorElement): void => {
23
- const tagName: string = anchorElement.nodeName.toUpperCase();
24
- const roleValue: string | null = anchorElement.getAttribute('role');
25
-
26
- if (typeof TAG_TO_IMPLICIT_SEMANTIC_INFO[tagName] === 'undefined') {
27
- return;
28
- }
29
-
30
- if (roleValue === null) {
31
- return;
32
- }
33
-
34
- if (
35
- Array.isArray(TAG_TO_IMPLICIT_SEMANTIC_INFO[tagName][0].allowed) &&
36
- (TAG_TO_IMPLICIT_SEMANTIC_INFO[tagName][0].allowed as string[]).indexOf(
37
- roleValue
38
- ) !== -1
39
- ) {
40
- return;
41
- }
42
-
43
- const reportMessage: string = TranslateService.instant(
44
- 'unsupported_role_on_element_report_message',
45
- [roleValue]
46
- );
47
-
48
- const report: IIssueReport = {
49
- message: reportMessage,
50
- node: anchorElement,
51
- ruleId: this.ruleConfig.id
52
- };
53
-
54
- this.validator.report(report);
55
- };
56
-
57
- const nodesLength: number = anchorElements.length;
58
-
59
- if (nodesLength > 0) {
60
- anchorElements.forEach(checkSingleNode);
61
- }
62
- }
63
- }
@@ -1,65 +0,0 @@
1
- # elements-not-allowed-in-head
2
-
3
- ## Rule id
4
-
5
- `elements-not-allowed-in-head`
6
-
7
- ## Definition
8
-
9
- This rule verifies if there are elements that shouldn't be in the `<head>` section.
10
-
11
- ## Purpose
12
-
13
- `<head>` section contains elements that provides information of how the document should be perceived, and rendered, by web technologies. e.g. browsers, search engines, bots, screen readers, etc.
14
-
15
- Non valid pages rely on the browser to auto-correct your code, and each browser does this differently. If your code is valid the browser has to do less processing as it doesn't have to correct any code, therefore the page will render faster and more predictable.
16
-
17
- In order to make the code accurate processed and rendered it is recommended to have only valid HTML elements / tags in the `<head>` section.
18
-
19
- Following elements are allowed to be in the `<head>` section:
20
-
21
- <title>
22
- <base>
23
- <link>
24
- <style>
25
- <meta>
26
- <script>
27
- <noscript>
28
- <template>
29
-
30
- All other elements / tags are perceived as non-valid.
31
-
32
- ## Test cases
33
-
34
- ### Passed
35
-
36
- The rule passes when only following elements / tags are specified in the `<head>` section:
37
-
38
- <title>
39
- <base>
40
- <link>
41
- <style>
42
- <meta>
43
- <script>
44
- <noscript>
45
- <template>
46
-
47
- ## WCAG Success Criteria
48
-
49
- Not Applicable
50
-
51
- ## Best Practice
52
-
53
- Yes
54
-
55
- ## User Impact
56
-
57
- * **Severity**: low
58
- * **Disabilities Affected**:
59
- * Visual:
60
- * blindness
61
-
62
- ## Resources
63
-
64
- * https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/The_head_metadata_in_HTML
65
- * https://html.spec.whatwg.org/multipage/semantics.html#the-head-element
@@ -1,53 +0,0 @@
1
- import { ElementsNotAllowed } from './elements-not-allowed-in-head';
2
- import { DomUtility } from '../../../utils/dom';
3
- import { Validator } from '../../../validator';
4
-
5
- describe('Rules', () => {
6
-
7
- describe('ElementsNotAllowed#', () => {
8
-
9
- let fakeDom;
10
- const VALID_ELEMENTS: string[] = [':not(base)', ':not(link)', ':not(meta)', ':not(script)', ':not(style)', ':not(title)', ':not(noscript)', ':not(template)'];
11
- const selector = `head *${VALID_ELEMENTS.join('')}`;
12
-
13
- new ElementsNotAllowed().registerValidator();
14
-
15
- beforeEach(() => {
16
- Validator.reset();
17
- });
18
-
19
- afterEach(() => {
20
- DomUtility.remove(document.getElementById('headfakedom'));
21
- fakeDom = undefined;
22
- });
23
-
24
- it('should return one report when there is an element not supposed to be in head block', () => {
25
- fakeDom = document.createElement('div');
26
- fakeDom.id = 'headfakedom';
27
- document.head.appendChild(fakeDom);
28
-
29
- const nodes = DomUtility.querySelectorAllExclude(selector);
30
-
31
- new ElementsNotAllowed().validate(nodes);
32
-
33
- expect(Object.keys(Validator.getReports()).length).toBe(1);
34
- expect(Validator.getReport('report_0').message).toBe('Expected <code>&lt;div id&#x3D;&quot;headfakedom&quot;&gt;&lt;&#x2F;div&gt;</code> not to be a child of <code>&lt;head&gt;</code>.');
35
- expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('div');
36
- expect(Validator.getReport('report_0').ruleId).toBe('elements-not-allowed-in-head');
37
- });
38
-
39
- it('should return no reports when there is no invalid elements in head section', () => {
40
- fakeDom = document.createElement('noscript');
41
- fakeDom.id = 'headfakedom';
42
- document.head.appendChild(fakeDom);
43
-
44
- const nodes = DomUtility.querySelectorAllExclude(selector);
45
-
46
- new ElementsNotAllowed().validate(nodes);
47
-
48
- expect(Object.keys(Validator.getReports()).length).toBe(0);
49
- });
50
-
51
- });
52
-
53
- });
@@ -1,47 +0,0 @@
1
- import { DomUtility } from '../../../utils/dom';
2
- import { TextUtility } from '../../../utils/text';
3
- import { CATEGORY_TYPE } from '../../../constants/categoryType';
4
- import { IIssueReport } from '../../../interfaces/rule-issue.interface';
5
- import { TranslateService } from '../../../services/translate';
6
- import { $accessibilityAuditRules, $severity } from '../../../constants/accessibility';
7
- import { AbstractRule, IAbstractRuleConfig } from '../../abstract-rule';
8
-
9
- export class ElementsNotAllowed extends AbstractRule {
10
- protected selector: string = `head *${[
11
- ':not(base)',
12
- ':not(link)',
13
- ':not(meta)',
14
- ':not(script)',
15
- ':not(style)',
16
- ':not(title)',
17
- ':not(noscript)',
18
- ':not(template)'
19
- ].join('')}`;
20
-
21
- protected ruleConfig: IAbstractRuleConfig = {
22
- id: TextUtility.convertUnderscoresToDashes($accessibilityAuditRules.elements_not_allowed_in_head),
23
- links: [],
24
- recommendations: [],
25
- severity: $severity.low,
26
- type: CATEGORY_TYPE.BEST_PRACTICE
27
- };
28
-
29
- public validate(elements: Element[]): void {
30
- const reportNode = (element: Element): void => {
31
- const reportMessage: string = TranslateService.instant('elements_not_allowed_in_head_report_message', [
32
- DomUtility.getEscapedOuterHTML(element),
33
- TextUtility.escape('<head>')
34
- ]);
35
-
36
- const report: IIssueReport = {
37
- message: reportMessage,
38
- node: element,
39
- ruleId: this.ruleConfig.id
40
- };
41
-
42
- this.validator.report(report);
43
- };
44
-
45
- elements.forEach(reportNode);
46
- }
47
- }
@@ -1,57 +0,0 @@
1
- # headings-sibling-unique
2
-
3
- ## Rule id
4
-
5
- `headings-sibling-unique`
6
-
7
- ## Definition
8
-
9
- This rule verifies if the accessible names of sibling heading elements of the same level are unique.
10
-
11
- ## Purpose
12
-
13
- If section headings that share the same parent heading are not unique, users of assistive technologies will not be able to discern the differences among sibling sections of the web page.
14
-
15
- This rule checks 1 case:
16
-
17
- * Sibling headings accessible names must be unique.
18
-
19
- ### Example
20
-
21
- #### Incorrect
22
-
23
- <h2>Example</h2>
24
- <h2>Example</h2>
25
-
26
- #### Correct
27
-
28
- <h2>Example 1</h2>
29
- <h2>Example 2</h2>
30
-
31
-
32
- ## Test cases
33
-
34
- ### Passed
35
-
36
- The rule passes when sibiling headings are having unique accessible name.
37
-
38
- ## WCAG Success Criteria
39
-
40
- Not Applicable
41
-
42
- ## Best Practice
43
-
44
- Yes
45
-
46
- ## User Impact
47
-
48
- * **Severity**: critical
49
- * **Disabilities Affected**:
50
- * Visual:
51
- * blindness
52
-
53
- ## Resources
54
-
55
- * http://www.w3.org/TR/WCAG20/#navigation-mechanisms-descriptive
56
- * http://www.w3.org/TR/WCAG20-TECHS/G130
57
- * https://www.w3.org/TR/WCAG20-TECHS/G141.html
@@ -1,52 +0,0 @@
1
- import { DomUtility } from '../../../utils/dom';
2
- import { Validator } from '../../../validator';
3
- import { HeadingsSiblingUnique } from './headings-sibling-unique';
4
-
5
- describe('Rules', () => {
6
-
7
- describe('HeadingsSiblingUnique', () => {
8
-
9
- it('should indicate that class exists', () => {
10
- expect(HeadingsSiblingUnique).toBeDefined();
11
- });
12
-
13
- let fakeDom;
14
-
15
- new HeadingsSiblingUnique().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 are non-unique siblings headings', () => {
31
- fakeDom.innerHTML = '<h1>Test</h1><h1>Test</h1>';
32
- const nodes = DomUtility.querySelectorAllExclude('h1', fakeDom) as HTMLHeadingElement[];
33
-
34
- new HeadingsSiblingUnique().validate(nodes);
35
-
36
- expect(Object.keys(Validator.getReports()).length).toBe(1);
37
- expect(Validator.getReport('report_0').message).toBe('The accessible names of sibling heading elements of the same level are not unique. If section headings that share the same parent heading are not unique, users of assistive technologies will not be able to discern the differences among sibling sections of the web page. Same level <code>h1</code> and same description: <q>Test</q>.');
38
- expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('h1');
39
- expect(Validator.getReport('report_0').ruleId).toBe('headings-sibling-unique');
40
- });
41
-
42
- it('should return no reports when two headings description are different', () => {
43
- fakeDom.innerHTML = '<h1>Test</h1><h1>Test 2</h1>';
44
- const nodes = DomUtility.querySelectorAllExclude('h1', fakeDom) as HTMLHeadingElement[];
45
-
46
- new HeadingsSiblingUnique().validate(nodes);
47
-
48
- expect(Object.keys(Validator.getReports()).length).toBe(0);
49
- });
50
-
51
- });
52
- });
@@ -1,63 +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 { TranslateService } from '../../../services/translate';
5
- import { $accessibilityAuditRules, $severity } from '../../../constants/accessibility';
6
- import { AbstractRule, IAbstractRuleConfig } from '../../abstract-rule';
7
-
8
- export class HeadingsSiblingUnique extends AbstractRule {
9
- protected selector: string = 'h1, h2, h3, h4, h5, h6';
10
-
11
- protected ruleConfig: IAbstractRuleConfig = {
12
- id: TextUtility.convertUnderscoresToDashes($accessibilityAuditRules.headings_sibling_unique),
13
- links: [
14
- {
15
- content: '2.4.6 Headings and Labels (Level AA, Primary Success Criterion)',
16
- url: 'http://www.w3.org/TR/WCAG20/#navigation-mechanisms-descriptive'
17
- },
18
- {
19
- content: 'G130: Providing descriptive headings',
20
- url: 'http://www.w3.org/TR/WCAG20-TECHS/G130'
21
- },
22
- {
23
- content: 'G141: Organizing a page using headings',
24
- url: 'https://www.w3.org/TR/WCAG20-TECHS/G141.html'
25
- }
26
- ],
27
- recommendations: [],
28
- severity: $severity.high,
29
- type: CATEGORY_TYPE.WCAG_AA
30
- };
31
-
32
- public validate(headings: HTMLHeadingElement[]): void {
33
-
34
- const checkForSiblings = (headingElement: HTMLHeadingElement): void => {
35
- const nextElementSibling: Element | null = headingElement.nextElementSibling;
36
-
37
- if (nextElementSibling === null) {
38
- return;
39
- }
40
-
41
- if (nextElementSibling.nodeName.toLowerCase() !== headingElement.nodeName.toLowerCase()) {
42
- return;
43
- }
44
-
45
- const headingText: string = typeof headingElement.textContent === 'string' ? TextUtility.safeTrim(headingElement.textContent) : '';
46
- const nextElementSiblingText: string = typeof nextElementSibling.textContent === 'string' ? TextUtility.safeTrim(nextElementSibling.textContent) : '';
47
-
48
- if (TextUtility.areStringsTheSame(headingText, nextElementSiblingText) === false) {
49
- return;
50
- }
51
-
52
- const report: IIssueReport = {
53
- message: TranslateService.instant('headings_sibling_unique_report_message', [headingElement.nodeName.toLowerCase(), nextElementSibling.textContent]),
54
- node: headingElement,
55
- ruleId: this.ruleConfig.id
56
- };
57
-
58
- this.validator.report(report);
59
- };
60
-
61
- headings.forEach(checkForSiblings);
62
- }
63
- }
@@ -1,39 +0,0 @@
1
- # horizontal-rule
2
-
3
- ## Rule id
4
-
5
- `horizontal-rule`
6
-
7
- ## Definition
8
-
9
- This rule determines `<hr/>` elements and gives a tip.
10
-
11
- ## Purpose
12
-
13
- The `<hr/>` element adds extra "noise" and can be confusing. For example VoiceOver reads it as "dimmed collapsed on top, horizontal separator", Windows Narrator reads it as "end of line".
14
-
15
- A better option is to replace `<hr/>` with `<div>` and use CSS for styling. Alternatively, `aria-hidden="true"` or `role="presentation"` can be applied to the `<hr/>` element.
16
-
17
- ## Test cases
18
-
19
- ### Passed
20
-
21
- The rule passes when there are:
22
-
23
- * no `<hr/>` elements or
24
- * `<hr/>` use `aria-hidden="true"` or `role="presentation"`
25
-
26
- ## WCAG Success Criteria
27
-
28
- Not Applicable
29
-
30
- ## Best Practice
31
-
32
- Yes
33
-
34
- ## User Impact
35
-
36
- * **Severity**: info
37
- * **Disabilities Affected**:
38
- * Visual:
39
- * blindness
@@ -1,66 +0,0 @@
1
- import { HorizontalRule } from './horizontal-rule';
2
- import { Validator } from '../../../validator';
3
- import { DomUtility } from '../../../utils/dom';
4
-
5
- describe('Rules', () => {
6
-
7
- describe('HorizontalRule', () => {
8
-
9
- it('should indicate that class exists', () => {
10
- expect(HorizontalRule).toBeDefined();
11
- });
12
-
13
- const selector: string = `hr${[
14
- ':not([aria-hidden="true"])',
15
- ':not([role="presentation"])'
16
- ].join('')}`;
17
-
18
- let fakeDom;
19
-
20
- new HorizontalRule().registerValidator();
21
-
22
- beforeEach(() => {
23
- fakeDom = document.createElement('div');
24
- fakeDom.id = 'fakedom';
25
- document.body.appendChild(fakeDom);
26
-
27
- Validator.reset();
28
- });
29
-
30
- afterEach(() => {
31
- DomUtility.remove(document.getElementById('fakedom'));
32
- fakeDom = undefined;
33
- });
34
-
35
- it('should return one report when there is an element with hr', () => {
36
- fakeDom.innerHTML = '<p>Text 1</p><hr/><p>Text 2</p>';
37
- const nodes: HTMLHRElement[] = DomUtility.querySelectorAllExclude(selector, fakeDom) as HTMLHRElement[];
38
-
39
- new HorizontalRule().validate(nodes);
40
-
41
- expect(Object.keys(Validator.getReports()).length).toBe(1);
42
- expect(Validator.getReport('report_0').message).toBe('The <code>&lt;hr&gt;</code> element adds extra <q>noise</q> and can be confusing. For example VoiceOver reads it as <q>dimmed collapsed on top, horizontal separator</q>, Windows Narrator reads it as <q>end of line</q>. A better option is to replace <code>&lt;hr&gt;</code> with <code>&lt;div&gt;</code> and use CSS for styling. Alternatively, <code>aria-hidden=\'true\'</code> or <code>role=\'presentation\'</code> can be applied to the <code>&lt;hr&gt;</code> element.');
43
- expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('hr');
44
- expect(Validator.getReport('report_0').ruleId).toBe('horizontal-rule');
45
- });
46
-
47
- it('should return no reports when there is no elements with hr', () => {
48
- fakeDom.innerHTML = '<p>Text 1</p>hr<p>Text 2</p>';
49
- const nodes: HTMLHRElement[] = DomUtility.querySelectorAllExclude(selector, fakeDom) as HTMLHRElement[];
50
-
51
- new HorizontalRule().validate(nodes);
52
-
53
- expect(Object.keys(Validator.getReports()).length).toBe(0);
54
- });
55
-
56
- it('should return no reports when there is an element hr, but with attribue aria-hidden="true" or role="presentation"', () => {
57
- fakeDom.innerHTML = '<p>Text 1</p><hr aria-hidden="true"/><hr role="presentation"/><p>Text 2</p>';
58
- const nodes: HTMLHRElement[] = DomUtility.querySelectorAllExclude(selector, fakeDom) as HTMLHRElement[];
59
-
60
- new HorizontalRule().validate(nodes);
61
-
62
- expect(Object.keys(Validator.getReports()).length).toBe(0);
63
- });
64
-
65
- });
66
- });