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,70 +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 LinksLanguageDestination extends AbstractRule {
10
- protected selector: () => (HTMLAnchorElement | HTMLAreaElement)[] = (): (HTMLAnchorElement | HTMLAreaElement)[] => {
11
- return Array.from(document.links);
12
- };
13
-
14
- protected ruleConfig: IAbstractRuleConfig = {
15
- id: TextUtility.convertUnderscoresToDashes($accessibilityAuditRules.links_language_destination),
16
- links: [
17
- {
18
- content: 'Indicating the language of a link destination',
19
- url: 'https://www.w3.org/International/questions/qa-link-lang'
20
- }
21
- ],
22
- recommendations: [],
23
- severity: $severity.info,
24
- type: CATEGORY_TYPE.BEST_PRACTICE
25
- };
26
-
27
- public validate(links: (HTMLAnchorElement | HTMLAreaElement)[]): void {
28
- let baseURI: string;
29
-
30
- if (typeof document.baseURI === 'string') {
31
- baseURI = document.baseURI;
32
- } else {
33
- baseURI = document.URL || document.location.href;
34
- }
35
-
36
- const onlyIncludeExternalLinks = (link: HTMLAnchorElement | HTMLAreaElement): boolean => {
37
- if (link.hostname.length > 0 && link.href.length > 0) {
38
- let baseHostname: string;
39
-
40
- try {
41
- const url: URL = new URL(link.href, baseURI);
42
-
43
- baseHostname = url.hostname;
44
- } catch (_) {
45
- baseHostname = document.location.hostname;
46
- }
47
-
48
- return baseHostname !== window.location.hostname;
49
- }
50
-
51
- return false;
52
- };
53
-
54
- const externalLinks: (HTMLAnchorElement | HTMLAreaElement)[] = links.filter(onlyIncludeExternalLinks);
55
-
56
- const reportIssue = (anchorElement: (HTMLAnchorElement | HTMLAreaElement)): void => {
57
- const reportMessage: string = TranslateService.instant('links_language_destination_report_message', [TextUtility.escape(anchorElement.href)]);
58
-
59
- const report: IIssueReport = {
60
- message: reportMessage,
61
- node: anchorElement,
62
- ruleId: this.ruleConfig.id
63
- };
64
-
65
- this.validator.report(report);
66
- };
67
-
68
- externalLinks.forEach(reportIssue);
69
- }
70
- }
@@ -1,55 +0,0 @@
1
- import { MainElementOnlyOne } from './main-element-only-one';
2
- import { Validator } from '../../../validator';
3
- import { DomUtility } from '../../../utils/dom';
4
-
5
- describe('Rules', () => {
6
-
7
- describe('MainElementOnlyOne', () => {
8
-
9
- it('should indicate that class exists', () => {
10
- expect(MainElementOnlyOne).toBeDefined();
11
- });
12
-
13
- let fakeDom;
14
-
15
- new MainElementOnlyOne().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 one report when there is more than 1 main element', () => {
31
- fakeDom.innerHTML = '<main>Text1</main><main>Text2</main>';
32
- const nodes = DomUtility.querySelectorAllExclude('main', fakeDom) as HTMLElement[];
33
-
34
- new MainElementOnlyOne().validate(nodes);
35
-
36
- expect(Object.keys(Validator.getReports()).length).toBe(2);
37
- expect(Validator.getReport('report_0').message).toBe('You have defined multiple (2) <code>&lt;main&gt;</code> elements. Assistive technology users expect one main content block and may miss subsequent <code>&lt;main&gt;</code> blocks.');
38
- expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('main');
39
- expect(Validator.getReport('report_0').ruleId).toBe('main-element-only-one');
40
- expect(Validator.getReport('report_1').message).toBe('You have defined multiple (2) <code>&lt;main&gt;</code> elements. Assistive technology users expect one main content block and may miss subsequent <code>&lt;main&gt;</code> blocks.');
41
- expect(Validator.getReport('report_1').node.nodeName.toLowerCase()).toBe('main');
42
- expect(Validator.getReport('report_1').ruleId).toBe('main-element-only-one');
43
- });
44
-
45
- it('should return no reports when there is 1 main element', () => {
46
- fakeDom.innerHTML = '<main>Text1</main>';
47
- const nodes = DomUtility.querySelectorAllExclude('main', fakeDom) as HTMLElement[];
48
-
49
- new MainElementOnlyOne().validate(nodes);
50
-
51
- expect(Object.keys(Validator.getReports()).length).toBe(0);
52
- });
53
-
54
- });
55
- });
@@ -1,83 +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 { $auditRuleNodeSkipReason, $severity } from '../../../constants/accessibility';
6
- import { $accessibilityAuditRules } from '../../../constants/accessibility';
7
- import { AbstractRule, IAbstractRuleConfig } from '../../abstract-rule';
8
- import { DomUtility } from '../../../utils/dom';
9
- import { Config } from '../../../config';
10
- import { $runnerSettings } from '../../../constants/aslint';
11
- import { Css } from '../../../utils/css';
12
-
13
- export class MainElementOnlyOne extends AbstractRule {
14
- private appConfig: Config = Config.getInstance();
15
-
16
- protected selector: string = 'main';
17
-
18
- protected ruleConfig: IAbstractRuleConfig = {
19
- id: TextUtility.convertUnderscoresToDashes($accessibilityAuditRules.main_element_only_one),
20
- links: [
21
- {
22
- content: 'HTML/Elements/main',
23
- url: 'https://www.w3.org/wiki/HTML/Elements/main#Point'
24
- }
25
- ],
26
- recommendations: [],
27
- severity: $severity.high,
28
- type: CATEGORY_TYPE.BEST_PRACTICE
29
- };
30
-
31
- private elementShouldBeSkipped(element: HTMLElement): boolean {
32
- const styles: CSSStyleDeclaration | null = Css.getComputedStyle(element);
33
- const ariaHidden: Attr | null = DomUtility.getElementAttribute(element, 'aria-hidden');
34
- let elementShouldBeSkipped: boolean = true;
35
-
36
- if (ariaHidden && ariaHidden.value === 'true') {
37
- return elementShouldBeSkipped;
38
- }
39
-
40
- if (this.appConfig.get($runnerSettings.includeHidden)) {
41
- elementShouldBeSkipped = false;
42
-
43
- return elementShouldBeSkipped;
44
- }
45
-
46
- if (DomUtility.hasElementSemiOpacity(element, styles)) {
47
- return elementShouldBeSkipped;
48
- }
49
-
50
- return false;
51
- }
52
-
53
- public validate(elements: HTMLElement[]): void {
54
- if (elements.length < 2) {
55
- return;
56
- }
57
-
58
- const checkForIssue = (element: HTMLElement): void => {
59
- if (this.elementShouldBeSkipped(element)) {
60
- this.validator.report({
61
- message: '',
62
- node: element,
63
- ruleId: this.ruleConfig.id,
64
- skipReason: $auditRuleNodeSkipReason.excludedFromScanning
65
- });
66
-
67
- return;
68
- }
69
-
70
- const reportMessage: string = TranslateService.instant('main_element_only_one_report_message', [elements.length, TextUtility.escape('main')]);
71
-
72
- const report: IIssueReport = {
73
- message: reportMessage,
74
- node: element,
75
- ruleId: this.ruleConfig.id
76
- };
77
-
78
- this.validator.report(report);
79
- };
80
-
81
- elements.forEach(checkForIssue);
82
- }
83
- }
@@ -1,12 +0,0 @@
1
- import { MainLandmarkMustBeTopLevel } from './main-landmark-must-be-top-level';
2
-
3
- describe('Rules', () => {
4
-
5
- describe('MainLandmarkMustBeTopLevel', () => {
6
-
7
- it('should indicate that class exists', () => {
8
- expect(MainLandmarkMustBeTopLevel).toBeDefined();
9
- });
10
-
11
- });
12
- });
@@ -1,73 +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 { $severity } from '../../../constants/accessibility';
7
- import { $accessibilityAuditRules } from '../../../constants/accessibility';
8
- import { AbstractRule, IAbstractRuleConfig } from '../../abstract-rule';
9
-
10
- export class MainLandmarkMustBeTopLevel extends AbstractRule {
11
- protected selector: string = '[role="main"]';
12
- protected ruleConfig: IAbstractRuleConfig = {
13
- id: TextUtility.convertUnderscoresToDashes($accessibilityAuditRules.main_landmark_must_be_top_level),
14
- links: [
15
- {
16
- content: 'Accessible Rich Internet Applications (WAI-ARIA) 1.0 Specification: main role',
17
- url: 'http://www.w3.org/TR/wai-aria/roles#main'
18
- },
19
- {
20
- content: 'ARIA11: Using ARIA landmarks to identify regions of a page',
21
- url: 'http://www.w3.org/TR/WCAG20-TECHS/ARIA11'
22
- },
23
- {
24
- content: 'HTML5: The MAIN element',
25
- url: 'http://www.w3.org/TR/html5/sections.html#the-main-element'
26
- }
27
- ],
28
- recommendations: [],
29
- severity: $severity.high,
30
- type: CATEGORY_TYPE.BEST_PRACTICE
31
- };
32
-
33
- public validate(elements: Element[]): void {
34
- let parent: HTMLElement | null;
35
- let parentNodeWithRole: Element | null = null;
36
- let role: string | null;
37
- const PARENT_ROLE_EXCEPTION: string[] = [
38
- 'application',
39
- 'document'
40
- ];
41
-
42
- if (elements.length === 0 || elements[0].parentElement === null) {
43
- return;
44
- }
45
-
46
- parent = elements[0].parentElement;
47
-
48
- while (parent && parent.getAttribute) {
49
- role = parent.getAttribute('role');
50
-
51
- if (typeof role === 'string' && PARENT_ROLE_EXCEPTION.indexOf(role) === -1) {
52
- parentNodeWithRole = parent;
53
- break;
54
- }
55
-
56
- parent = parent.parentElement;
57
- }
58
-
59
- if (parentNodeWithRole === null) {
60
- return;
61
- }
62
-
63
- const reportMessage: string = TranslateService.instant('main_landmark_must_be_top_level_report_message', [DomUtility.getEscapedOuterHTML(parentNodeWithRole)]);
64
-
65
- const report: IIssueReport = {
66
- message: reportMessage,
67
- node: parentNodeWithRole,
68
- ruleId: this.ruleConfig.id
69
- };
70
-
71
- this.validator.report(report);
72
- }
73
- }
@@ -1,12 +0,0 @@
1
- import { MinimumFontSize } from './minimum-font-size';
2
-
3
- describe('Rules', () => {
4
-
5
- describe('MinimumFontSize', () => {
6
-
7
- it('should indicate that class exists', () => {
8
- expect(MinimumFontSize).toBeDefined();
9
- });
10
-
11
- });
12
- });
@@ -1,87 +0,0 @@
1
- import { DomUtility } from '../../../utils/dom';
2
- import { Css } from '../../../utils/css';
3
- import { CATEGORY_TYPE } from '../../../constants/categoryType';
4
- import { IIssueReport } from '../../../interfaces/rule-issue.interface';
5
- import { TextUtility } from '../../../utils/text';
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 MinimumFontSize extends AbstractRule {
12
- protected selector: string = `*${[
13
- ':root',
14
- 'head',
15
- 'title',
16
- 'style',
17
- 'script',
18
- 'noscript',
19
- 'meta',
20
- 'link',
21
- 'br',
22
- 'hr',
23
- 'object',
24
- 'path',
25
- 'g',
26
- 'desc',
27
- 'filter',
28
- 'img',
29
- 'input',
30
- 'iframe',
31
- 'code',
32
- 'defs',
33
- ':empty'
34
- ].map((i: string): string => {
35
- return `:not(${i})`;
36
- }).join('')}`;
37
-
38
- protected ruleConfig: IAbstractRuleConfig = {
39
- id: TextUtility.convertUnderscoresToDashes($accessibilityAuditRules.minimum_font_size),
40
- links: [],
41
- recommendations: [],
42
- severity: $severity.info,
43
- type: CATEGORY_TYPE.BEST_PRACTICE
44
- };
45
-
46
- public validate(elements: HTMLElement[]): void {
47
- const checkFontSize = (element: HTMLElement): void => {
48
- if (DomUtility.hasDirectTextDescendant(element) === false) {
49
- return;
50
- }
51
-
52
- const fontSizeStyle: string | null = Css.getStyle(element, 'font-size');
53
-
54
- if (fontSizeStyle === null) {
55
- return;
56
- }
57
-
58
- const fontSize: number = parseInt(fontSizeStyle, 10);
59
-
60
- if (fontSize < 10) {
61
- let report: IIssueReport;
62
-
63
- if (DomUtility.isElementVisible(element) === false) {
64
- const reportMessage: string = TranslateService.instant('minimum_font_size_report_message_1', [fontSize]);
65
-
66
- report = {
67
- message: reportMessage,
68
- node: element,
69
- ruleId: this.ruleConfig.id
70
- };
71
- } else {
72
- const reportMessage: string = TranslateService.instant('minimum_font_size_report_message_2', [fontSize]);
73
-
74
- report = {
75
- message: reportMessage,
76
- node: element,
77
- ruleId: this.ruleConfig.id
78
- };
79
- }
80
-
81
- this.validator.report(report);
82
- }
83
- };
84
-
85
- elements.forEach(checkFontSize);
86
- }
87
- }
@@ -1,48 +0,0 @@
1
- import { MissingHrefOnA } from './missing-href-on-a';
2
- import { Validator } from '../../../validator';
3
- import { DomUtility } from '../../../utils/dom';
4
-
5
- describe('Rules', () => {
6
-
7
- describe('MissingHrefOnA', () => {
8
-
9
- let fakeDom;
10
-
11
- new MissingHrefOnA().registerValidator();
12
-
13
- beforeEach(() => {
14
- fakeDom = document.createElement('div');
15
- fakeDom.id = 'fakedom';
16
- document.body.appendChild(fakeDom);
17
-
18
- Validator.reset();
19
- });
20
-
21
- afterEach(() => {
22
- DomUtility.remove(document.getElementById('fakedom'));
23
- fakeDom = undefined;
24
- });
25
-
26
- it('should return correct data for a element without href attribute', () => {
27
- fakeDom.innerHTML = '<a>example.com</a>';
28
- const nodes = DomUtility.querySelectorAllExclude('a:not([href])', fakeDom) as HTMLAnchorElement[];
29
-
30
- new MissingHrefOnA().validate(nodes);
31
-
32
- expect(Object.keys(Validator.getReports()).length).toBe(1);
33
- expect(Validator.getReport('report_0').message).toBe('Missing attribute <code>href</code> on link. The user cannot navigate to this element using the keyboard. A better option here is to use a <code>&lt;a&gt;</code> element instead.');
34
- expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('a');
35
- expect(Validator.getReport('report_0').ruleId).toBe('missing-href-on-a');
36
- });
37
-
38
- it('should return no reports in case of a element with href attribute', () => {
39
- fakeDom.innerHTML = '<a href="http://example.com">example.com</a>';
40
- const nodes = DomUtility.querySelectorAllExclude('a:not([href])', fakeDom) as HTMLAnchorElement[];
41
-
42
- new MissingHrefOnA().validate(nodes);
43
-
44
- expect(Object.keys(Validator.getReports()).length).toBe(0);
45
- });
46
-
47
- });
48
- });
@@ -1,40 +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 MissingHrefOnA extends AbstractRule {
10
- protected selector: string = 'a:not([href])';
11
-
12
- protected ruleConfig: IAbstractRuleConfig = {
13
- id: TextUtility.convertUnderscoresToDashes($accessibilityAuditRules.missing_href_on_a),
14
- links: [
15
- {
16
- content: 'F42: Failure of Success Criteria 1.3.1, 2.1.1, 2.1.3, or 4.1.2 when emulating links',
17
- url: 'https://www.w3.org/TR/WCAG20-TECHS/F42.html'
18
- }
19
- ],
20
- recommendations: [],
21
- severity: $severity.critical,
22
- type: CATEGORY_TYPE.BEST_PRACTICE
23
- };
24
-
25
- public validate(anchorElements: HTMLAnchorElement[]): void {
26
- const reportNodeWithoutHref = (anchorElement: HTMLAnchorElement): void => {
27
- const reportMessage: string = TranslateService.instant('missing_href_on_a_report_message', [TextUtility.escape('<a>')]);
28
-
29
- const report: IIssueReport = {
30
- message: reportMessage,
31
- node: anchorElement,
32
- ruleId: this.ruleConfig.id
33
- };
34
-
35
- this.validator.report(report);
36
- };
37
-
38
- anchorElements.forEach(reportNodeWithoutHref);
39
- }
40
- }
@@ -1,12 +0,0 @@
1
- import { MisusedAriaOnFocusableElement } from './misused-aria-on-focusable-element';
2
-
3
- describe('Rules', () => {
4
-
5
- describe('MisusedAriaOnFocusableElement', () => {
6
-
7
- it('should indicate that class exists', () => {
8
- expect(MisusedAriaOnFocusableElement).toBeDefined();
9
- });
10
-
11
- });
12
- });
@@ -1,66 +0,0 @@
1
- import { DomUtility } from '../../../utils/dom';
2
- import { CATEGORY_TYPE } from '../../../constants/categoryType';
3
- import { FOCUSABLE_ELEMENTS } from '../../../constants/focusableElements';
4
- import { IIssueReport } from '../../../interfaces/rule-issue.interface';
5
- import { TextUtility } from '../../../utils/text';
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 MisusedAriaOnFocusableElement extends AbstractRule {
12
- protected selector: string = FOCUSABLE_ELEMENTS
13
- .map((i: string): string => {
14
- return `${i}[role="presentation"], ${i}[aria-hidden="true"]`;
15
- })
16
- .join(', ');
17
-
18
- protected ruleConfig: IAbstractRuleConfig = {
19
- id: TextUtility.convertUnderscoresToDashes($accessibilityAuditRules.misused_aria_on_focusable_element),
20
- links: [
21
- {
22
- content: 'Do not use role="presentation" or aria-hidden="true" on a visible focusable element',
23
- url: 'https://w3c.github.io/using-aria/#4thrule'
24
- }
25
- ],
26
- recommendations: [],
27
- severity: $severity.high,
28
- type: CATEGORY_TYPE.BEST_PRACTICE
29
- };
30
-
31
- public validate(elements: HTMLElement[]): void {
32
- const checkSupportForTabindex = (element: HTMLElement): void => {
33
- const rolePresentation: string | null = element.getAttribute('role');
34
- const ariaHiddenTrue: string | null = element.getAttribute('aria-hidden');
35
- const attributesToReport: string[] = [];
36
-
37
- if (DomUtility.isElementHidden(element)) {
38
- return;
39
- }
40
-
41
- if (rolePresentation) {
42
- const attribute: string = TranslateService.instant('misused_aria_on_focusable_element_attribute_1');
43
-
44
- attributesToReport.push(attribute);
45
- }
46
-
47
- if (ariaHiddenTrue === 'true') {
48
- const attribute: string = TranslateService.instant('misused_aria_on_focusable_element_attribute_2');
49
-
50
- attributesToReport.push(attribute);
51
- }
52
-
53
- const reportMessage: string = TranslateService.instant('misused_aria_on_focusable_element_report_message', [attributesToReport.join(', ')]);
54
-
55
- const report: IIssueReport = {
56
- message: reportMessage,
57
- node: element,
58
- ruleId: this.ruleConfig.id
59
- };
60
-
61
- this.validator.report(report);
62
- };
63
-
64
- elements.forEach(checkSupportForTabindex);
65
- }
66
- }
@@ -1,12 +0,0 @@
1
- import { MisusedInputAttribute } from './misused-input-attribute';
2
-
3
- describe('Rules', () => {
4
-
5
- describe('MisusedInputAttribute', () => {
6
-
7
- it('should indicate that class exists', () => {
8
- expect(MisusedInputAttribute).toBeDefined();
9
- });
10
-
11
- });
12
- });