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,83 +0,0 @@
1
- import { IRule } from '../interfaces/rule.interface';
2
- import { CATEGORY_TYPE } from '../constants/categoryType';
3
- import { $severity } from '../constants/accessibility';
4
- import { DomUtility } from '../utils/dom';
5
- import { Validator } from '../validator';
6
- import { Config } from '../config';
7
- import { Context } from '../interfaces/context.interface';
8
-
9
- type Nodes = Document[] | HTMLElement[] | Element[] | StyleSheetList[] | CSSStyleSheet[];
10
-
11
- export interface IAbstractRuleConfig {
12
- id: string;
13
- type: CATEGORY_TYPE;
14
- severity: $severity;
15
- links: { content: string; url: string }[];
16
- recommendations: any[];
17
- }
18
-
19
- export abstract class AbstractRule implements IRule {
20
- protected context: Context;
21
- protected options: any;
22
- protected validator: typeof Validator;
23
- protected selector: string | (() => Nodes);
24
- protected abstract ruleConfig: IAbstractRuleConfig;
25
-
26
- constructor() {
27
- this.validator = Validator;
28
- this.selector = 'html';
29
- this.context = document.documentElement;
30
- }
31
-
32
- protected collectElements(): Nodes | null {
33
- if (typeof this.selector === 'undefined') {
34
- throw new Error(`[AbstractRule] The selector must be a string or function, but there is type of ${typeof this.selector}`);
35
- }
36
-
37
- if (typeof this.selector === 'function') {
38
- return this.selector();
39
- }
40
-
41
- return DomUtility.querySelectorAllExclude(
42
- this.selector,
43
- this.context,
44
- Config.excludeContainers,
45
- []
46
- );
47
- }
48
-
49
- public abstract validate(nodes: Document[] | HTMLElement[] | Element[] | StyleSheetList | StyleSheetList[] | CSSStyleSheet[] | null): void;
50
-
51
- public get config(): IAbstractRuleConfig {
52
- return this.ruleConfig;
53
- }
54
-
55
- public get id(): string {
56
- return this.config.id;
57
- }
58
-
59
- // eslint-disable-next-line require-await
60
- public async run(context: Context, validator?: typeof Validator, options?: any): Promise<void> {
61
- this.context = context;
62
- this.options = (typeof options === 'object') ? options : {};
63
- this.validator = (typeof validator !== 'undefined') ? validator : Validator;
64
-
65
- let nodes: Nodes | null = this.collectElements();
66
- const totalElementsEvaluated: number = nodes === null ? 0 : nodes.length;
67
-
68
- this.validator.setTotalElementsEvaluated(this.ruleConfig.id, totalElementsEvaluated);
69
-
70
- const getFilter = (filter: Function): void => {
71
- nodes = filter(this.ruleConfig.id, nodes);
72
- };
73
-
74
- Config.getFilters('before-rule-validate').forEach(getFilter);
75
-
76
- this.validate(nodes);
77
- }
78
-
79
- public registerValidator(): void {
80
- this.validator.register(this.ruleConfig, this.run.bind(this));
81
- }
82
-
83
- }
@@ -1,36 +0,0 @@
1
- # incorrect-technique-for-hiding-content
2
-
3
- ## Rule id
4
-
5
- `incorrect-technique-for-hiding-content`
6
-
7
- ## Definition
8
-
9
- This rule determines if there is defined style `text-indent` with the value so that the element is being positioned out of the viewport.
10
-
11
- ## Purpose
12
-
13
- The technique e.g. `text-indent: -10000px` is still being used to hide the content visually. However, the downside of that technique is that the screen reader focus follows that and it gets out of the visible area.
14
-
15
- **Tip**: to avoid that use tecnique that hides the content visually, but does not move the element outside of the visible viewport. Example: https://github.com/twbs/bootstrap/blob/main/scss/mixins/_visually-hidden.scss
16
-
17
- ## Test cases
18
-
19
- ### Passed
20
-
21
- The rule passes when there is no defined style `text-indent` that hides the content outside of viewport.
22
-
23
- ## WCAG Success Criteria
24
-
25
- Not Applicable
26
-
27
- ## Best Practice
28
-
29
- Yes
30
-
31
- ## User Impact
32
-
33
- * **Severity**: info
34
- * **Disabilities Affected**:
35
- * Visual:
36
- * keyboard users
@@ -1,113 +0,0 @@
1
- import { DomUtility } from '../../../utils/dom';
2
- import { Validator } from '../../../validator';
3
- import { IncorrectTechniqueForHidingContent } from './incorrect-technique-for-hiding-content';
4
-
5
- describe('Rules', () => {
6
-
7
- describe('IncorrectTechniqueForHidingContent', () => {
8
-
9
- it('should indicate that class exists', () => {
10
- expect(IncorrectTechniqueForHidingContent).toBeDefined();
11
- });
12
-
13
- let fakeDom;
14
-
15
- new IncorrectTechniqueForHidingContent().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
- // Note: untestable until https://github.com/facebook/jest/issues/11291 gets resolved
31
-
32
- /*
33
- *
34
- *it('should return 1 report when there is an element with defined style text-indent: -1000px;', () => {
35
- * fakeDom.innerHTML = '<p style="text-indent: -1000px">Example text</p>';
36
- * const nodes: HTMLParagraphElement[] = DomUtility.querySelectorAllExclude('p', fakeDom) as HTMLParagraphElement[];
37
- *
38
- * new IncorrectTechniqueForHidingContent().validate(nodes);
39
- *
40
- * expect(Object.keys(Validator.getReports()).length).toBe(1);
41
- * expect(Validator.getReport('report_0').message).toBe('CSS technique <code>text-indent: -1000px </code> is used to hide text. However, it causes problems for right-to-left language and also keep focus for screen reader outside of visible area.');
42
- * expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('p');
43
- * expect(Validator.getReport('report_0').ruleId).toBe('incorrect-technique-for-hiding-content');
44
- *});
45
- *
46
- *it('should return 1 report when there is an element with defined style text-indent: 1000px;', () => {
47
- * fakeDom.innerHTML = '<p style="text-indent: 1000px">Example text</p>';
48
- * const nodes: HTMLParagraphElement[] = DomUtility.querySelectorAllExclude('p', fakeDom) as HTMLParagraphElement[];
49
- *
50
- * new IncorrectTechniqueForHidingContent().validate(nodes);
51
- *
52
- * expect(Object.keys(Validator.getReports()).length).toBe(1);
53
- * expect(Validator.getReport('report_0').message).toBe('CSS technique <code>text-indent: 1000px </code> is used to hide text. However, it causes problems for right-to-left language and also keep focus for screen reader outside of visible area.');
54
- * expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('p');
55
- * expect(Validator.getReport('report_0').ruleId).toBe('incorrect-technique-for-hiding-content');
56
- *});
57
- *
58
- *it('should return no report when there is an element with no defined style text-indent', () => {
59
- * fakeDom.innerHTML = '<p>Example text</p>';
60
- * const nodes: HTMLParagraphElement[] = DomUtility.querySelectorAllExclude('p', fakeDom) as HTMLParagraphElement[];
61
- *
62
- * new IncorrectTechniqueForHidingContent().validate(nodes);
63
- *
64
- * expect(Object.keys(Validator.getReports()).length).toBe(0);
65
- *});
66
- *
67
- *it('should return no report when there is an element with defined style text-indent that doesn\'t move content outside of visible area', () => {
68
- * const createMockDiv = (width, height) => {
69
- * const div = document.createElement('div');
70
- *
71
- * Object.assign(div.style, {
72
- * height: `${height}px`,
73
- * width: `${width}px`
74
- * });
75
- *
76
- * div.getBoundingClientRect = () => {
77
- * return {
78
- * bottom: height,
79
- * height,
80
- * left: 0,
81
- * right: width,
82
- * toJSON: () => { },
83
- * top: 0,
84
- * width,
85
- * x: 0,
86
- * y: 0
87
- * };
88
- * };
89
- *
90
- * return div;
91
- * };
92
- *
93
- * const div = createMockDiv(100, 100);
94
- *
95
- * div.innerText = 'Example text';
96
- * div.style.textIndent = '-1rem';
97
- *
98
- * fakeDom.appendChild(div);
99
- *
100
- * const nodes: HTMLDivElement[] = DomUtility.querySelectorAllExclude('div', fakeDom) as HTMLDivElement[];
101
- *
102
- * global.innerHeight = 500;
103
- * global.innerWidth = 500;
104
- *
105
- * new IncorrectTechniqueForHidingContent().validate(nodes);
106
- *
107
- * expect(Object.keys(Validator.getReports()).length).toBe(0);
108
- *});
109
- *
110
- */
111
-
112
- });
113
- });
@@ -1,103 +0,0 @@
1
- import { Css } from '../../../utils/css';
2
- import { CATEGORY_TYPE } from '../../../constants/categoryType';
3
- import { IIssueReport } from '../../../interfaces/rule-issue.interface';
4
- import { TextUtility } from '../../../utils/text';
5
- import { TranslateService } from '../../../services/translate';
6
- import { $accessibilityAuditRules, $severity } from '../../../constants/accessibility';
7
- import { AbstractRule, IAbstractRuleConfig } from '../../abstract-rule';
8
- import { DomUtility } from '../../../utils/dom';
9
- import { ObjectUtility } from '../../../utils/object';
10
-
11
- export class IncorrectTechniqueForHidingContent 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.incorrect_technique_for_hiding_content),
40
- links: [
41
- {
42
- content: 'Hiding Content for Accessibility',
43
- url: 'https://snook.ca/archives/html_and_css/hiding-content-for-accessibility'
44
- }
45
- ],
46
- recommendations: [],
47
- severity: $severity.high,
48
- type: CATEGORY_TYPE.BEST_PRACTICE
49
- };
50
-
51
- public validate(elements: HTMLElement[]): void {
52
-
53
- if (ObjectUtility.isHostMethod(document, 'getSelection') === false && ObjectUtility.isHostMethod(document, 'createRange') === false) {
54
- return;
55
- }
56
-
57
- const reportNode = (element: HTMLElement): void => {
58
- const styles: CSSStyleDeclaration | null = Css.getComputedStyle(element);
59
-
60
- if (styles === null) {
61
- return;
62
- }
63
-
64
- const textIndentValue: string = styles.getPropertyValue('text-indent');
65
- const indent: number = Number(textIndentValue.replace(/[^0-9]/g, ''));
66
-
67
- if (indent === 0) {
68
- return;
69
- }
70
-
71
- const selection: Selection | null = document.getSelection();
72
-
73
- if (selection === null) {
74
- return;
75
- }
76
-
77
- const range: Range = document.createRange();
78
-
79
- range.selectNodeContents(element);
80
-
81
- selection.removeAllRanges();
82
- selection.addRange(range);
83
-
84
- for (let i: number = 0; i < selection.rangeCount; i += 1) {
85
- if (DomUtility.isRangeOffPage(selection.getRangeAt(i))) {
86
- const reportMessage: string = TranslateService.instant('incorrect_technique_for_hiding_content_report_message', [textIndentValue]);
87
-
88
- const report: IIssueReport = {
89
- message: reportMessage,
90
- node: element,
91
- ruleId: this.ruleConfig.id
92
- };
93
-
94
- this.validator.report(report);
95
-
96
- return;
97
- }
98
- }
99
- };
100
-
101
- elements.forEach(reportNode);
102
- }
103
- }
@@ -1,34 +0,0 @@
1
- # invalid-attribute-dir-value
2
-
3
- ## Rule id
4
-
5
- `invalid-attribute-dir-value`
6
-
7
- ## Definition
8
-
9
- This rule determines if a given attribute `dir` have the correct value: `rtl`, `ltr` or `auto`.
10
-
11
- ## Purpose
12
-
13
- The dir global attribute is an enumerated attribute that indicates the directionality of the element's text. To avoid unexpected behaviour the value of `dir` should be correct and should contains one of following string: `rtl`, `ltr` or `auto`.
14
-
15
- ## Test cases
16
-
17
- ### Passed
18
-
19
- The rule passes when there is no `dir` attribute with value other than `rtl`, `ltr` or `auto`.
20
-
21
- ## WCAG Success Criteria
22
-
23
- Not Applicable
24
-
25
- ## Best Practice
26
-
27
- Yes
28
-
29
- ## User Impact
30
-
31
- * **Severity**: info
32
- * **Disabilities Affected**:
33
- * Visual:
34
- * blindness
@@ -1,82 +0,0 @@
1
- import { InvalidAttributeDirValue } from './invalid-attribute-dir-value';
2
- import { Validator } from '../../../validator';
3
- import { DomUtility } from '../../../utils/dom';
4
-
5
- describe('Rules', () => {
6
-
7
- describe('InvalidAttributeDirValue', () => {
8
-
9
- it('should indicate that class exists', () => {
10
- expect(InvalidAttributeDirValue).toBeDefined();
11
- });
12
-
13
- let fakeDom;
14
-
15
- new InvalidAttributeDirValue().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 correct data for dir with wrong attribute value', () => {
31
- fakeDom.innerHTML = '<p dir="wrong">Wrong attribute</p>';
32
- const nodes = DomUtility.querySelectorAllExclude('[dir]:not([dir="rtl"]):not([dir="ltr"]):not([dir="auto"])', fakeDom) as HTMLElement[];
33
-
34
- new InvalidAttributeDirValue().validate(nodes);
35
-
36
- expect(Object.keys(Validator.getReports()).length).toBe(1);
37
- expect(Validator.getReport('report_0').message).toBe('Attribute <code>dir</code> has invalid value <code>wrong</code>.');
38
- expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('p');
39
- expect(Validator.getReport('report_0').ruleId).toBe('invalid-attribute-dir-value');
40
- });
41
-
42
- it('should return correct data for dir with empty attribute value', () => {
43
- fakeDom.innerHTML = '<p dir>Wrong attribute</p>';
44
- const nodes = DomUtility.querySelectorAllExclude('[dir]:not([dir="rtl"]):not([dir="ltr"]):not([dir="auto"])', fakeDom) as HTMLElement[];
45
-
46
- new InvalidAttributeDirValue().validate(nodes);
47
-
48
- expect(Object.keys(Validator.getReports()).length).toBe(1);
49
- expect(Validator.getReport('report_0').message).toBe('Attribute <code>dir</code> has invalid value <code></code>.');
50
- expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('p');
51
- expect(Validator.getReport('report_0').ruleId).toBe('invalid-attribute-dir-value');
52
- });
53
-
54
- it('should return no reports in case of dir is ltr', () => {
55
- fakeDom.innerHTML = '<p dir="ltr">Left to right(English)</p>';
56
- const nodes = DomUtility.querySelectorAllExclude('[dir]:not([dir="rtl"]):not([dir="ltr"]):not([dir="auto"])', fakeDom) as HTMLElement[];
57
-
58
- new InvalidAttributeDirValue().validate(nodes);
59
-
60
- expect(Object.keys(Validator.getReports()).length).toBe(0);
61
- });
62
-
63
- it('should return no reports in case of dir is rtl', () => {
64
- fakeDom.innerHTML = '<p dir="rtl">Right to left(Arabic)</p>';
65
- const nodes = DomUtility.querySelectorAllExclude('[dir]:not([dir="rtl"]):not([dir="ltr"]):not([dir="auto"])', fakeDom) as HTMLElement[];
66
-
67
- new InvalidAttributeDirValue().validate(nodes);
68
-
69
- expect(Object.keys(Validator.getReports()).length).toBe(0);
70
- });
71
-
72
- it('should return no reports in case of dir is auto', () => {
73
- fakeDom.innerHTML = '<p dir="auto">Auto</p>';
74
- const nodes = DomUtility.querySelectorAllExclude('[dir]:not([dir="rtl"]):not([dir="ltr"]):not([dir="auto"])', fakeDom) as HTMLElement[];
75
-
76
- new InvalidAttributeDirValue().validate(nodes);
77
-
78
- expect(Object.keys(Validator.getReports()).length).toBe(0);
79
- });
80
-
81
- });
82
- });
@@ -1,44 +0,0 @@
1
- import { CATEGORY_TYPE } from '../../../constants/categoryType';
2
- import { IIssueReport } from '../../../interfaces/rule-issue.interface';
3
- import { TextUtility } from '../../../utils/text';
4
- import { TranslateService } from '../../../services/translate';
5
- import { $accessibilityAuditRules, $severity } from '../../../constants/accessibility';
6
- import { AbstractRule, IAbstractRuleConfig } from '../../abstract-rule';
7
-
8
- export class InvalidAttributeDirValue extends AbstractRule {
9
- protected selector: string = '[dir]:not([dir="rtl"]):not([dir="ltr"]):not([dir="auto"])';
10
- protected ruleConfig: IAbstractRuleConfig = {
11
- id: TextUtility.convertUnderscoresToDashes($accessibilityAuditRules.invalid_attribute_dir_value),
12
- links: [
13
- {
14
- content: 'H56: Using the dir attribute on an inline element to resolve problems with nested directional runs',
15
- url: 'https://www.w3.org/TR/WCAG20-TECHS/H56.html'
16
- }
17
- ],
18
- recommendations: [],
19
- severity: $severity.critical,
20
- type: CATEGORY_TYPE.BEST_PRACTICE
21
- };
22
-
23
- public validate(elements: HTMLElement[]): void {
24
- const checkValue = (element: HTMLElement): void => {
25
- const dirAttribute: string | null = element.getAttribute('dir');
26
-
27
- if (dirAttribute === null) {
28
- return;
29
- }
30
-
31
- const reportMessage: string = TranslateService.instant('invalid_attribute_dir_value_report_message', [TextUtility.escape(dirAttribute)]);
32
-
33
- const report: IIssueReport = {
34
- message: reportMessage,
35
- node: element,
36
- ruleId: this.ruleConfig.id
37
- };
38
-
39
- this.validator.report(report);
40
- };
41
-
42
- elements.forEach(checkValue);
43
- }
44
- }
@@ -1,40 +0,0 @@
1
- # label-duplicated-content-title
2
-
3
- ## Rule id
4
-
5
- `label-duplicated-content-title`
6
-
7
- ## Definition
8
-
9
- This rule determines if a given element `<label>` contains attribute `title` with the same accessible name.
10
-
11
- ## Purpose
12
-
13
- Let's examine following example:
14
-
15
- `<label for="example" title="This is an example">This is an example</label>`
16
-
17
- Assuming screen reader can read `title`<sup>*</sup>. In above case then `This is an example` will be read twice. To avoid that this rule helps to find such cases.
18
-
19
- `*` - by default, for example, VoiceOver doesn't read `title` until Hints are turned on.
20
-
21
- ## Test cases
22
-
23
- ### Passed
24
-
25
- The rule passes when there is no `<label>` with an attribute `title` that contains same content as `<label>`'s accessible name.
26
-
27
- ## WCAG Success Criteria
28
-
29
- Not Applicable
30
-
31
- ## Best Practice
32
-
33
- Yes
34
-
35
- ## User Impact
36
-
37
- * **Severity**: info
38
- * **Disabilities Affected**:
39
- * Visual:
40
- * blindness
@@ -1,48 +0,0 @@
1
- import { LabelDuplicatedContentTitle } from './label-duplicated-content-title';
2
- import { Validator } from '../../../validator';
3
- import { DomUtility } from '../../../utils/dom';
4
-
5
- describe('Rules', () => {
6
-
7
- describe('LabelDuplicatedContentTitle', () => {
8
-
9
- let fakeDom;
10
-
11
- new LabelDuplicatedContentTitle().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 = '<label title="main">main</label>';
28
- const nodes = DomUtility.querySelectorAllExclude('[title=main]', fakeDom) as HTMLElement[];
29
-
30
- new LabelDuplicatedContentTitle().validate(nodes);
31
-
32
- expect(Object.keys(Validator.getReports()).length).toBe(1);
33
- expect(Validator.getReport('report_0').message).toBe('This element has the same content as its <code>title</code> attribute. Consider removing <code>title</code> as some screen readers read both.');
34
- expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('label');
35
- expect(Validator.getReport('report_0').ruleId).toBe('label-duplicated-content-title');
36
- });
37
-
38
- it('should return no reports in case of a element with href attribute', () => {
39
- fakeDom.innerHTML = '<label title="main">main1</label>';
40
- const nodes = DomUtility.querySelectorAllExclude('[title=main]', fakeDom) as HTMLElement[];
41
-
42
- new LabelDuplicatedContentTitle().validate(nodes);
43
-
44
- expect(Object.keys(Validator.getReports()).length).toBe(0);
45
- });
46
-
47
- });
48
- });
@@ -1,37 +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 LabelDuplicatedContentTitle extends AbstractRule {
10
- protected selector: string = 'label[title]';
11
- protected ruleConfig: IAbstractRuleConfig = {
12
- id: TextUtility.convertUnderscoresToDashes($accessibilityAuditRules.label_duplicated_content_title),
13
- links: [],
14
- recommendations: [],
15
- severity: $severity.high,
16
- type: CATEGORY_TYPE.BEST_PRACTICE
17
- };
18
-
19
- public validate(elements: HTMLElement[]): void {
20
- const checkLabel = (element: HTMLElement): void => {
21
- const labelContent: string = DomUtility.getText(element, true);
22
- const labelTitle: string = element.title;
23
-
24
- if (labelContent === labelTitle) {
25
- const report: IIssueReport = {
26
- message: TranslateService.instant('label_duplicated_content_title_report_message'),
27
- node: element,
28
- ruleId: this.ruleConfig.id
29
- };
30
-
31
- this.validator.report(report);
32
- }
33
- };
34
-
35
- elements.forEach(checkLabel);
36
- }
37
- }
@@ -1,50 +0,0 @@
1
- import { DomUtility } from '../../../utils/dom';
2
- import { Validator } from '../../../validator';
3
- import { LinksLanguageDestination } from './links-language-destination';
4
-
5
- describe('Rules', () => {
6
-
7
- describe('LinksLanguageDestination', () => {
8
-
9
- it('should indicate that class exists', () => {
10
- expect(LinksLanguageDestination).toBeDefined();
11
- });
12
-
13
- let fakeDom;
14
-
15
- new LinksLanguageDestination().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 no reports when there is an anchor element with url pointed within page base uri', () => {
31
- fakeDom.innerHTML = '<a href="http://localhost/example">example</a>';
32
-
33
- new LinksLanguageDestination().validate(Array.from(document.links));
34
-
35
- expect(Object.keys(Validator.getReports()).length).toBe(0);
36
- });
37
-
38
- it('should return 1 report when there is an anchor element with url pointed outside of base uri', () => {
39
- fakeDom.innerHTML = '<a href="http://example.com/example">example</a>';
40
-
41
- new LinksLanguageDestination().validate(Array.from(document.links));
42
-
43
- expect(Object.keys(Validator.getReports()).length).toBe(1);
44
- expect(Validator.getReport('report_0').message).toBe('Following url <code>http:&#x2F;&#x2F;example.com&#x2F;example</code> points to an external resource. If the content behind the link is in a different language then consider add some text or graphic to the link indicating that the target document is in another language.');
45
- expect(Validator.getReport('report_0').node.nodeName.toLowerCase()).toBe('a');
46
- expect(Validator.getReport('report_0').ruleId).toBe('links-language-destination');
47
- });
48
-
49
- });
50
- });