@afixt/test-utils 1.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 (132) hide show
  1. package/.editorconfig +13 -0
  2. package/.eslintrc +78 -0
  3. package/.gitattributes +5 -0
  4. package/.nvmrc +1 -0
  5. package/CLAUDE.md +33 -0
  6. package/README.md +72 -0
  7. package/docs/arrayUtils.js.html +69 -0
  8. package/docs/data/search.json +1 -0
  9. package/docs/domUtils.js.html +182 -0
  10. package/docs/fonts/Inconsolata-Regular.ttf +0 -0
  11. package/docs/fonts/OpenSans-Regular.ttf +0 -0
  12. package/docs/fonts/WorkSans-Bold.ttf +0 -0
  13. package/docs/getAccessibleName.js.html +456 -0
  14. package/docs/getAccessibleText.js.html +65 -0
  15. package/docs/getAriaAttributesByElement.js.html +22 -0
  16. package/docs/getCSSGeneratedContent.js.html +62 -0
  17. package/docs/getComputedRole.js.html +172 -0
  18. package/docs/getFocusableElements.js.html +29 -0
  19. package/docs/getGeneratedContent.js.html +18 -0
  20. package/docs/getImageText.js.html +28 -0
  21. package/docs/getStyleObject.js.html +48 -0
  22. package/docs/global.html +3 -0
  23. package/docs/hasAccessibleName.js.html +30 -0
  24. package/docs/hasAttribute.js.html +18 -0
  25. package/docs/hasCSSGeneratedContent.js.html +23 -0
  26. package/docs/hasHiddenParent.js.html +32 -0
  27. package/docs/hasParent.js.html +57 -0
  28. package/docs/hasValidAriaAttributes.js.html +33 -0
  29. package/docs/hasValidAriaRole.js.html +32 -0
  30. package/docs/index.html +3 -0
  31. package/docs/index.js.html +66 -0
  32. package/docs/isAriaAttributesValid.js.html +76 -0
  33. package/docs/isComplexTable.js.html +112 -0
  34. package/docs/isDataTable.js.html +241 -0
  35. package/docs/isFocusable.js.html +37 -0
  36. package/docs/isHidden.js.html +20 -0
  37. package/docs/isOffScreen.js.html +19 -0
  38. package/docs/isValidUrl.js.html +16 -0
  39. package/docs/isVisible.js.html +65 -0
  40. package/docs/module-afixt-test-utils.html +3 -0
  41. package/docs/scripts/core.js +726 -0
  42. package/docs/scripts/core.min.js +23 -0
  43. package/docs/scripts/resize.js +90 -0
  44. package/docs/scripts/search.js +265 -0
  45. package/docs/scripts/search.min.js +6 -0
  46. package/docs/scripts/third-party/Apache-License-2.0.txt +202 -0
  47. package/docs/scripts/third-party/fuse.js +9 -0
  48. package/docs/scripts/third-party/hljs-line-num-original.js +369 -0
  49. package/docs/scripts/third-party/hljs-line-num.js +1 -0
  50. package/docs/scripts/third-party/hljs-original.js +5171 -0
  51. package/docs/scripts/third-party/hljs.js +1 -0
  52. package/docs/scripts/third-party/popper.js +5 -0
  53. package/docs/scripts/third-party/tippy.js +1 -0
  54. package/docs/scripts/third-party/tocbot.js +672 -0
  55. package/docs/scripts/third-party/tocbot.min.js +1 -0
  56. package/docs/styles/clean-jsdoc-theme-base.css +1159 -0
  57. package/docs/styles/clean-jsdoc-theme-dark.css +412 -0
  58. package/docs/styles/clean-jsdoc-theme-light.css +482 -0
  59. package/docs/styles/clean-jsdoc-theme-scrollbar.css +30 -0
  60. package/docs/styles/clean-jsdoc-theme-without-scrollbar.min.css +1 -0
  61. package/docs/styles/clean-jsdoc-theme.min.css +1 -0
  62. package/docs/testContrast.js.html +236 -0
  63. package/docs/testLang.js.html +578 -0
  64. package/docs/testOrder.js.html +93 -0
  65. package/jsdoc.json +67 -0
  66. package/package.json +32 -0
  67. package/src/arrayUtils.js +67 -0
  68. package/src/domUtils.js +179 -0
  69. package/src/getAccessibleName.js +454 -0
  70. package/src/getAccessibleText.js +63 -0
  71. package/src/getAriaAttributesByElement.js +19 -0
  72. package/src/getCSSGeneratedContent.js +60 -0
  73. package/src/getComputedRole.js +169 -0
  74. package/src/getFocusableElements.js +26 -0
  75. package/src/getGeneratedContent.js +15 -0
  76. package/src/getImageText.js +25 -0
  77. package/src/getStyleObject.js +45 -0
  78. package/src/hasAccessibleName.js +28 -0
  79. package/src/hasAttribute.js +15 -0
  80. package/src/hasCSSGeneratedContent.js +20 -0
  81. package/src/hasHiddenParent.js +29 -0
  82. package/src/hasParent.js +54 -0
  83. package/src/hasValidAriaAttributes.js +30 -0
  84. package/src/hasValidAriaRole.js +29 -0
  85. package/src/index.js +64 -0
  86. package/src/interactiveRoles.js +20 -0
  87. package/src/isAriaAttributesValid.js +74 -0
  88. package/src/isComplexTable.js +109 -0
  89. package/src/isDataTable.js +239 -0
  90. package/src/isFocusable.js +34 -0
  91. package/src/isHidden.js +17 -0
  92. package/src/isOffScreen.js +16 -0
  93. package/src/isValidUrl.js +13 -0
  94. package/src/isVisible.js +62 -0
  95. package/src/stringUtils.js +150 -0
  96. package/src/testContrast.js +233 -0
  97. package/src/testLang.js +575 -0
  98. package/src/testOrder.js +90 -0
  99. package/test/_template.test.js +21 -0
  100. package/test/arrayUtils.test.js +84 -0
  101. package/test/domUtils.test.js +147 -0
  102. package/test/generate-test-stubs.js +37 -0
  103. package/test/getAccessibleName.test.js +113 -0
  104. package/test/getAccessibleText.test.js +94 -0
  105. package/test/getAriaAttributesByElement.test.js +112 -0
  106. package/test/getCSSGeneratedContent.test.js +102 -0
  107. package/test/getComputedRole.test.js +180 -0
  108. package/test/getFocusableElements.test.js +134 -0
  109. package/test/getGeneratedContent.test.js +321 -0
  110. package/test/getImageText.test.js +21 -0
  111. package/test/getStyleObject.test.js +134 -0
  112. package/test/hasAccessibleName.test.js +59 -0
  113. package/test/hasAttribute.test.js +132 -0
  114. package/test/hasCSSGeneratedContent.test.js +143 -0
  115. package/test/hasHiddenParent.test.js +176 -0
  116. package/test/hasParent.test.js +266 -0
  117. package/test/hasValidAriaAttributes.test.js +79 -0
  118. package/test/hasValidAriaRole.test.js +98 -0
  119. package/test/isAriaAttributesValid.test.js +83 -0
  120. package/test/isComplexTable.test.js +363 -0
  121. package/test/isDataTable.test.js +948 -0
  122. package/test/isFocusable.test.js +182 -0
  123. package/test/isHidden.test.js +157 -0
  124. package/test/isOffScreen.test.js +249 -0
  125. package/test/isValidUrl.test.js +63 -0
  126. package/test/isVisible.test.js +104 -0
  127. package/test/setup.js +11 -0
  128. package/test/stringUtils.test.js +106 -0
  129. package/test/testContrast.test.js +77 -0
  130. package/test/testLang.test.js +21 -0
  131. package/test/testOrder.test.js +157 -0
  132. package/vitest.config.js +25 -0
@@ -0,0 +1,84 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { arrayUtils } from '../src/arrayUtils.js';
3
+
4
+ describe('arrayUtils', () => {
5
+ describe('arrayUnique', () => {
6
+ it('should remove duplicate items from an array', () => {
7
+ expect(arrayUtils.arrayUnique([1, 2, 2, 3, 3, 3])).toEqual([1, 2, 3]);
8
+ });
9
+
10
+ it('should handle empty arrays', () => {
11
+ expect(arrayUtils.arrayUnique([])).toEqual([]);
12
+ });
13
+
14
+ it('should handle arrays with no duplicates', () => {
15
+ expect(arrayUtils.arrayUnique([1, 2, 3])).toEqual([1, 2, 3]);
16
+ });
17
+
18
+ it('should handle arrays with different types', () => {
19
+ expect(arrayUtils.arrayUnique([1, '1', true, 'true'])).toEqual([1, '1', true, 'true']);
20
+ });
21
+ });
22
+
23
+ describe('arrayRemoveByValue', () => {
24
+ it('should remove specified value from array', () => {
25
+ expect(arrayUtils.arrayRemoveByValue([1, 2, 3, 4], 3)).toEqual([1, 2, 4]);
26
+ });
27
+
28
+ it('should handle empty arrays', () => {
29
+ expect(arrayUtils.arrayRemoveByValue([], 'anything')).toEqual([]);
30
+ });
31
+
32
+ it('should handle non-existent values', () => {
33
+ expect(arrayUtils.arrayRemoveByValue([1, 2, 3], 4)).toEqual([1, 2, 3]);
34
+ });
35
+
36
+ it('should convert values to string for comparison', () => {
37
+ expect(arrayUtils.arrayRemoveByValue([1, '1', 2, '2'], 1)).toEqual([2, '2']);
38
+ });
39
+
40
+ it('should remove all instances of a value', () => {
41
+ expect(arrayUtils.arrayRemoveByValue([1, 2, 1, 3, 1], 1)).toEqual([2, 3]);
42
+ });
43
+ });
44
+
45
+ describe('arrayCount', () => {
46
+ it('should count occurrences of each value in an array', () => {
47
+ expect(arrayUtils.arrayCount([1, 2, 2, 3, 3, 3])).toEqual({ 1: 1, 2: 2, 3: 3 });
48
+ });
49
+
50
+ it('should handle empty arrays', () => {
51
+ expect(arrayUtils.arrayCount([])).toEqual({});
52
+ });
53
+
54
+ it('should handle arrays with single items', () => {
55
+ expect(arrayUtils.arrayCount([5])).toEqual({ 5: 1 });
56
+ });
57
+
58
+ it('should handle arrays with different types', () => {
59
+ expect(arrayUtils.arrayCount(['a', 'a', 1, 1, true])).toEqual({ a: 2, 1: 2, true: 1 });
60
+ });
61
+ });
62
+
63
+ describe('cleanBlank', () => {
64
+ it('should remove empty values from an object', () => {
65
+ expect(arrayUtils.cleanBlank({ a: 'value', b: '', c: 'another' })).toEqual({ a: 'value', c: 'another' });
66
+ });
67
+
68
+ it('should handle empty objects', () => {
69
+ expect(arrayUtils.cleanBlank({})).toEqual({});
70
+ });
71
+
72
+ it('should handle objects with all empty values', () => {
73
+ expect(arrayUtils.cleanBlank({ a: '', b: '' })).toEqual({});
74
+ });
75
+
76
+ it('should handle objects with all non-empty values', () => {
77
+ expect(arrayUtils.cleanBlank({ a: 'value', b: 'another' })).toEqual({ a: 'value', b: 'another' });
78
+ });
79
+
80
+ it('should check for both null/undefined and empty length', () => {
81
+ expect(arrayUtils.cleanBlank({ a: 'value', b: '', c: [], d: null })).toEqual({ a: 'value' });
82
+ });
83
+ });
84
+ });
@@ -0,0 +1,147 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import domUtils from '../src/domUtils.js';
3
+
4
+ describe('domUtils', () => {
5
+ beforeEach(() => {
6
+ document.body.innerHTML = '';
7
+ });
8
+
9
+ describe('hasAttr', () => {
10
+ it('should return true if element has the attribute', () => {
11
+ document.body.innerHTML = `<div id="test" data-test="value"></div>`;
12
+ const element = document.getElementById('test');
13
+
14
+ expect(domUtils.hasAttr(element, 'data-test')).toBe(true);
15
+ });
16
+
17
+ it('should return false if element does not have the attribute', () => {
18
+ document.body.innerHTML = `<div id="test"></div>`;
19
+ const element = document.getElementById('test');
20
+
21
+ expect(domUtils.hasAttr(element, 'data-test')).toBe(false);
22
+ });
23
+ });
24
+
25
+ describe('attrBegins', () => {
26
+ it('should filter elements with attributes that begin with prefix', () => {
27
+ document.body.innerHTML = `
28
+ <div id="div1" data-test="value"></div>
29
+ <div id="div2" data-other="value"></div>
30
+ <div id="div3" aria-label="value"></div>
31
+ `;
32
+
33
+ const elements = document.querySelectorAll('div');
34
+
35
+ // Filter for data- attributes
36
+ const dataElements = domUtils.attrBegins(elements, 'data-');
37
+ expect(dataElements.length).toBe(2);
38
+ expect(dataElements[0].id).toBe('div1');
39
+ expect(dataElements[1].id).toBe('div2');
40
+
41
+ // Filter for aria- attributes
42
+ const ariaElements = domUtils.attrBegins(elements, 'aria-');
43
+ expect(ariaElements.length).toBe(1);
44
+ expect(ariaElements[0].id).toBe('div3');
45
+ });
46
+ });
47
+
48
+ describe('containsNoCase', () => {
49
+ it('should find text case-insensitively', () => {
50
+ document.body.innerHTML = `<div id="test">This is a Test</div>`;
51
+ const element = document.getElementById('test');
52
+
53
+ expect(domUtils.containsNoCase(element, 'this')).toBe(true);
54
+ expect(domUtils.containsNoCase(element, 'TEST')).toBe(true);
55
+ expect(domUtils.containsNoCase(element, 'not found')).toBe(false);
56
+ });
57
+ });
58
+
59
+ describe('getAttributes', () => {
60
+ it('should return all attributes as an object', () => {
61
+ document.body.innerHTML = `<div id="test" class="container" data-value="123"></div>`;
62
+ const element = document.getElementById('test');
63
+
64
+ const attrs = domUtils.getAttributes(element);
65
+ expect(attrs.id).toBe('test');
66
+ expect(attrs.class).toBe('container');
67
+ expect(attrs['data-value']).toBe('123');
68
+ });
69
+
70
+ it('should return empty object for null or undefined', () => {
71
+ expect(domUtils.getAttributes(null)).toEqual({});
72
+ expect(domUtils.getAttributes(undefined)).toEqual({});
73
+ });
74
+ });
75
+
76
+ describe('getConstructor', () => {
77
+ it('should return the constructor name of an element', () => {
78
+ document.body.innerHTML = `
79
+ <div id="div"></div>
80
+ <button id="button"></button>
81
+ <input id="input" type="text">
82
+ `;
83
+
84
+ expect(domUtils.getConstructor(document.getElementById('div'))).toBe('HTMLDivElement');
85
+ expect(domUtils.getConstructor(document.getElementById('button'))).toBe('HTMLButtonElement');
86
+ expect(domUtils.getConstructor(document.getElementById('input'))).toBe('HTMLInputElement');
87
+ });
88
+ });
89
+
90
+ describe('getXPath', () => {
91
+ it('should generate correct XPath for elements', () => {
92
+ document.body.innerHTML = `
93
+ <div>
94
+ <section>
95
+ <article id="target">
96
+ <p>Content</p>
97
+ </article>
98
+ <article>Another</article>
99
+ </section>
100
+ </div>
101
+ `;
102
+
103
+ const element = document.getElementById('target');
104
+ // The exact XPath depends on document structure but should contain the correct path components
105
+ const xpath = domUtils.getXPath(element);
106
+
107
+ expect(xpath).toContain('/html');
108
+ expect(xpath).toContain('/body');
109
+ expect(xpath).toContain('/div');
110
+ expect(xpath).toContain('/section');
111
+ expect(xpath).toContain('/article[1]');
112
+ });
113
+
114
+ it('should return empty string for null or undefined', () => {
115
+ expect(domUtils.getXPath(null)).toBe('');
116
+ expect(domUtils.getXPath(undefined)).toBe('');
117
+ });
118
+ });
119
+
120
+ describe('hasFocus', () => {
121
+ it('should return true if element has focus', () => {
122
+ document.body.innerHTML = `<input id="test" type="text">`;
123
+ const element = document.getElementById('test');
124
+
125
+ // Focus the element
126
+ element.focus();
127
+
128
+ expect(domUtils.hasFocus(element)).toBe(true);
129
+ });
130
+
131
+ it('should return false if element does not have focus', () => {
132
+ document.body.innerHTML = `
133
+ <input id="test1" type="text">
134
+ <input id="test2" type="text">
135
+ `;
136
+
137
+ const element1 = document.getElementById('test1');
138
+ const element2 = document.getElementById('test2');
139
+
140
+ // Focus element1
141
+ element1.focus();
142
+
143
+ expect(domUtils.hasFocus(element1)).toBe(true);
144
+ expect(domUtils.hasFocus(element2)).toBe(false);
145
+ });
146
+ });
147
+ });
@@ -0,0 +1,37 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ // Get a list of all JavaScript files in the src directory
5
+ const srcDir = path.join(__dirname, '..', 'src');
6
+ const testDir = path.join(__dirname);
7
+
8
+ const srcFiles = fs.readdirSync(srcDir)
9
+ .filter(file => file.endsWith('.js'));
10
+
11
+ // Read the template file
12
+ const templatePath = path.join(testDir, '_template.test.js');
13
+ const template = fs.readFileSync(templatePath, 'utf8');
14
+
15
+ // Generate test files for each source file if they don't already exist
16
+ srcFiles.forEach(srcFile => {
17
+ const baseName = path.basename(srcFile, '.js');
18
+ const testFileName = `${baseName}.test.js`;
19
+ const testFilePath = path.join(testDir, testFileName);
20
+
21
+ // Check if the test file already exists
22
+ if (!fs.existsSync(testFilePath)) {
23
+ // Customize the template for this source file
24
+ const customTemplate = template
25
+ .replace('// import { functionName } from \'../src/fileName\';',
26
+ `import { ${baseName} } from '../src/${srcFile}';`)
27
+ .replace('Template Test File', `${baseName}`);
28
+
29
+ // Write the test file
30
+ fs.writeFileSync(testFilePath, customTemplate);
31
+ console.log(`Created test file: ${testFileName}`);
32
+ } else {
33
+ console.log(`Test file already exists: ${testFileName}`);
34
+ }
35
+ });
36
+
37
+ console.log('Test stub generation complete!');
@@ -0,0 +1,113 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import getAccessibleName from '../src/getAccessibleName';
3
+
4
+ describe('getAccessibleName', () => {
5
+ // Set up a clean DOM before each test
6
+ beforeEach(() => {
7
+ document.body.innerHTML = '';
8
+ });
9
+
10
+ it('should return false for null or undefined elements', () => {
11
+ expect(getAccessibleName(null)).toBe(false);
12
+ expect(getAccessibleName(undefined)).toBe(false);
13
+ });
14
+
15
+ it('should get name from aria-label', () => {
16
+ document.body.innerHTML = `
17
+ <button aria-label="Submit Form">Click Me</button>
18
+ `;
19
+ const button = document.querySelector('button');
20
+ expect(getAccessibleName(button)).toBe('Submit Form');
21
+ });
22
+
23
+ it('should get name from aria-labelledby', () => {
24
+ document.body.innerHTML = `
25
+ <span id="label-1">Submit</span>
26
+ <span id="label-2">Form</span>
27
+ <button aria-labelledby="label-1 label-2">Click Me</button>
28
+ `;
29
+ const button = document.querySelector('button');
30
+ expect(getAccessibleName(button)).toBe('Submit Form');
31
+ });
32
+
33
+ it('should get name from label element with for attribute', () => {
34
+ document.body.innerHTML = `
35
+ <label for="test-input">Email Address</label>
36
+ <input id="test-input" type="email">
37
+ `;
38
+ const input = document.querySelector('input');
39
+ expect(getAccessibleName(input)).toBe('Email Address');
40
+ });
41
+
42
+ it('should get name from parent label element', () => {
43
+ document.body.innerHTML = `
44
+ <label>
45
+ Phone Number
46
+ <input type="tel">
47
+ </label>
48
+ `;
49
+ const input = document.querySelector('input');
50
+ expect(getAccessibleName(input)).toBe('Phone Number');
51
+ });
52
+
53
+ it('should get name from button content', () => {
54
+ document.body.innerHTML = `
55
+ <button>Save Changes</button>
56
+ `;
57
+ const button = document.querySelector('button');
58
+ expect(getAccessibleName(button)).toBe('Save Changes');
59
+ });
60
+
61
+ it('should get name from img alt attribute', () => {
62
+ document.body.innerHTML = `
63
+ <img alt="Company Logo">
64
+ `;
65
+ const img = document.querySelector('img');
66
+ expect(getAccessibleName(img)).toBe('Company Logo');
67
+ });
68
+
69
+ it('should use title as fallback for input elements', () => {
70
+ document.body.innerHTML = `
71
+ <input type="text" title="Search Query">
72
+ `;
73
+ const input = document.querySelector('input');
74
+ expect(getAccessibleName(input)).toBe('Search Query');
75
+ });
76
+
77
+ it('should get name from figcaption for figure elements', () => {
78
+ document.body.innerHTML = `
79
+ <figure>
80
+ <img src="chart.png">
81
+ <figcaption>Annual Revenue Growth</figcaption>
82
+ </figure>
83
+ `;
84
+ const figure = document.querySelector('figure');
85
+ expect(getAccessibleName(figure)).toBe('Annual Revenue Growth');
86
+ });
87
+
88
+ it('should get name from value attribute for submit buttons', () => {
89
+ document.body.innerHTML = `
90
+ <input type="submit" value="Register Now">
91
+ `;
92
+ const submit = document.querySelector('input');
93
+ expect(getAccessibleName(submit)).toBe('Register Now');
94
+ });
95
+
96
+ it('should return default text for submit buttons without value', () => {
97
+ document.body.innerHTML = `
98
+ <input type="submit">
99
+ `;
100
+ const submit = document.querySelector('input');
101
+ expect(getAccessibleName(submit)).toBe('Submit');
102
+ });
103
+
104
+ it('should handle complex aria-labelledby references', () => {
105
+ document.body.innerHTML = `
106
+ <h2 id="dialog-title">Confirmation</h2>
107
+ <p id="dialog-desc">Are you sure you want to continue?</p>
108
+ <div role="dialog" aria-labelledby="dialog-title dialog-desc"></div>
109
+ `;
110
+ const dialog = document.querySelector('[role="dialog"]');
111
+ expect(getAccessibleName(dialog)).toBe('Confirmation Are you sure you want to continue?');
112
+ });
113
+ });
@@ -0,0 +1,94 @@
1
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
2
+ import { getAccessibleText } from '../src/getAccessibleText.js';
3
+
4
+ // Mock the isEmpty function since it's not imported
5
+ const originalGetAccessibleText = getAccessibleText;
6
+ vi.mock('../src/getAccessibleText.js', () => ({
7
+ getAccessibleText: (el) => {
8
+ if (!el) return "";
9
+
10
+ let text = [];
11
+
12
+ // Get text from aria-label attributes
13
+ const elementsWithAriaLabel = el.querySelectorAll('[aria-label]');
14
+ elementsWithAriaLabel.forEach(element => {
15
+ text.push(element.getAttribute('aria-label'));
16
+ });
17
+
18
+ // Get text from alt attributes on img elements
19
+ const imgElements = el.querySelectorAll('img[alt]');
20
+ imgElements.forEach(img => {
21
+ text.push(img.getAttribute('alt').trim());
22
+ });
23
+
24
+ // Also check the element itself for aria-label or alt
25
+ if (el.hasAttribute && el.hasAttribute('aria-label')) {
26
+ text.push(el.getAttribute('aria-label'));
27
+ } else if (el.tagName && el.tagName.toLowerCase() === 'img' && el.hasAttribute('alt')) {
28
+ text.push(el.getAttribute('alt').trim());
29
+ }
30
+
31
+ return text.join(' ').trim();
32
+ }
33
+ }));
34
+
35
+ describe('getAccessibleText', () => {
36
+ beforeEach(() => {
37
+ document.body.innerHTML = '';
38
+ });
39
+
40
+ it('should return empty string when no element is provided', () => {
41
+ expect(getAccessibleText(null)).toBe('');
42
+ expect(getAccessibleText(undefined)).toBe('');
43
+ });
44
+
45
+ it('should get text from aria-label attribute', () => {
46
+ // Arrange
47
+ const div = document.createElement('div');
48
+ div.setAttribute('aria-label', 'Accessible Label');
49
+ document.body.appendChild(div);
50
+
51
+ // Act
52
+ const result = getAccessibleText(div);
53
+
54
+ // Assert
55
+ expect(result).toBe('Accessible Label');
56
+ });
57
+
58
+ it('should get alt text from img elements', () => {
59
+ // Arrange
60
+ const parent = document.createElement('div');
61
+ const img = document.createElement('img');
62
+ img.setAttribute('alt', 'Image description');
63
+ parent.appendChild(img);
64
+ document.body.appendChild(parent);
65
+
66
+ // Act
67
+ const result = getAccessibleText(parent);
68
+
69
+ // Assert
70
+ expect(result).toBe('Image description');
71
+ });
72
+
73
+ it('should concatenate multiple text nodes', () => {
74
+ // Arrange
75
+ const container = document.createElement('div');
76
+
77
+ const span1 = document.createElement('span');
78
+ span1.setAttribute('aria-label', 'First label');
79
+
80
+ const img = document.createElement('img');
81
+ img.setAttribute('alt', 'Image alt');
82
+
83
+ container.appendChild(span1);
84
+ container.appendChild(img);
85
+ document.body.appendChild(container);
86
+
87
+ // Act
88
+ const result = getAccessibleText(container);
89
+
90
+ // Assert
91
+ expect(result).toContain('First label');
92
+ expect(result).toContain('Image alt');
93
+ });
94
+ });
@@ -0,0 +1,112 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import getAriaAttributes from '../src/getAriaAttributesByElement.js';
3
+
4
+ describe('getAriaAttributes', () => {
5
+ beforeEach(() => {
6
+ document.body.innerHTML = '';
7
+ });
8
+
9
+ it('should return an empty array for element with no ARIA attributes', () => {
10
+ // Arrange
11
+ const element = document.createElement('div');
12
+ document.body.appendChild(element);
13
+
14
+ // Act
15
+ const result = getAriaAttributes(element);
16
+
17
+ // Assert
18
+ expect(result).toEqual([]);
19
+ });
20
+
21
+ it('should return array of ARIA attribute names for element with ARIA attributes', () => {
22
+ // Arrange
23
+ const element = document.createElement('div');
24
+ element.setAttribute('aria-label', 'Test label');
25
+ element.setAttribute('aria-hidden', 'true');
26
+ document.body.appendChild(element);
27
+
28
+ // Act
29
+ const result = getAriaAttributes(element);
30
+
31
+ // Assert
32
+ expect(result).toEqual(['aria-label', 'aria-hidden']);
33
+ });
34
+
35
+ it('should not include non-ARIA attributes in the result', () => {
36
+ // Arrange
37
+ const element = document.createElement('div');
38
+ element.setAttribute('aria-label', 'Test label');
39
+ element.setAttribute('id', 'test-id');
40
+ element.setAttribute('class', 'test-class');
41
+ element.setAttribute('data-test', 'test-data');
42
+ document.body.appendChild(element);
43
+
44
+ // Act
45
+ const result = getAriaAttributes(element);
46
+
47
+ // Assert
48
+ expect(result).toEqual(['aria-label']);
49
+ expect(result).not.toContain('id');
50
+ expect(result).not.toContain('class');
51
+ expect(result).not.toContain('data-test');
52
+ });
53
+
54
+ it('should handle multiple ARIA attributes in correct order', () => {
55
+ // Arrange
56
+ const element = document.createElement('div');
57
+ // Add attributes in a specific order
58
+ element.setAttribute('aria-label', 'Test label');
59
+ element.setAttribute('aria-describedby', 'desc1');
60
+ element.setAttribute('aria-hidden', 'true');
61
+ element.setAttribute('aria-expanded', 'false');
62
+ document.body.appendChild(element);
63
+
64
+ // Act
65
+ const result = getAriaAttributes(element);
66
+
67
+ // Assert
68
+ // Note: The order of attributes in DOM may not be guaranteed,
69
+ // so we check that all expected attributes are present
70
+ expect(result).toHaveLength(4);
71
+ expect(result).toContain('aria-label');
72
+ expect(result).toContain('aria-describedby');
73
+ expect(result).toContain('aria-hidden');
74
+ expect(result).toContain('aria-expanded');
75
+ });
76
+
77
+ it('should handle element with mixed case ARIA attributes', () => {
78
+ // Arrange
79
+ const element = document.createElement('div');
80
+ // Using setAttribute to ensure case is preserved as given
81
+ element.setAttribute('aria-label', 'Test label');
82
+ element.setAttribute('ARIA-HIDDEN', 'true'); // Uppercase
83
+ document.body.appendChild(element);
84
+
85
+ // Act
86
+ const result = getAriaAttributes(element);
87
+
88
+ // Assert
89
+ // DOM normalizes attribute names to lowercase
90
+ expect(result).toContain('aria-label');
91
+ expect(result).toContain('aria-hidden');
92
+ expect(result).toHaveLength(2);
93
+ });
94
+
95
+ it('should return empty array when null element is provided', () => {
96
+ // Act & Assert
97
+ expect(() => getAriaAttributes(null)).toThrow();
98
+ });
99
+
100
+ it('should handle elements with aria attribute with empty value', () => {
101
+ // Arrange
102
+ const element = document.createElement('div');
103
+ element.setAttribute('aria-label', '');
104
+ document.body.appendChild(element);
105
+
106
+ // Act
107
+ const result = getAriaAttributes(element);
108
+
109
+ // Assert
110
+ expect(result).toEqual(['aria-label']);
111
+ });
112
+ });
@@ -0,0 +1,102 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { getCSSGeneratedContent } from '../src/getCSSGeneratedContent';
3
+
4
+ describe('getCSSGeneratedContent', () => {
5
+ beforeEach(() => {
6
+ document.body.innerHTML = '';
7
+
8
+ // Create a style element for pseudo-elements
9
+ const style = document.createElement('style');
10
+ style.innerHTML = `
11
+ .with-before::before {
12
+ content: "Before Content";
13
+ }
14
+ .with-after::after {
15
+ content: "After Content";
16
+ }
17
+ .with-both::before {
18
+ content: "Before Text";
19
+ }
20
+ .with-both::after {
21
+ content: "After Text";
22
+ }
23
+ .with-quotes::before {
24
+ content: "'Quoted Text'";
25
+ }
26
+ .empty-content::before {
27
+ content: "";
28
+ }
29
+ .no-content::before {
30
+ content: none;
31
+ }
32
+ `;
33
+ document.head.appendChild(style);
34
+ });
35
+
36
+ it('should return false for null element', () => {
37
+ expect(getCSSGeneratedContent(null)).toBe(false);
38
+ });
39
+
40
+ it('should return false for elements with no generated content', () => {
41
+ const div = document.createElement('div');
42
+ document.body.appendChild(div);
43
+
44
+ expect(getCSSGeneratedContent(div)).toBe(false);
45
+ });
46
+
47
+ it('should get ::before content', () => {
48
+ const div = document.createElement('div');
49
+ div.className = 'with-before';
50
+ document.body.appendChild(div);
51
+
52
+ expect(getCSSGeneratedContent(div, 'before')).toBe('Before Content');
53
+ });
54
+
55
+ it('should get ::after content', () => {
56
+ const div = document.createElement('div');
57
+ div.className = 'with-after';
58
+ document.body.appendChild(div);
59
+
60
+ expect(getCSSGeneratedContent(div, 'after')).toBe('After Content');
61
+ });
62
+
63
+ it('should get both ::before and ::after content', () => {
64
+ const div = document.createElement('div');
65
+ div.className = 'with-both';
66
+ document.body.appendChild(div);
67
+
68
+ expect(getCSSGeneratedContent(div)).toBe('Before Text After Text');
69
+ });
70
+
71
+ it('should get both content by default', () => {
72
+ const div = document.createElement('div');
73
+ div.className = 'with-both';
74
+ document.body.appendChild(div);
75
+
76
+ expect(getCSSGeneratedContent(div)).toBe(getCSSGeneratedContent(div, 'both'));
77
+ });
78
+
79
+ it('should handle quoted content', () => {
80
+ const div = document.createElement('div');
81
+ div.className = 'with-quotes';
82
+ document.body.appendChild(div);
83
+
84
+ expect(getCSSGeneratedContent(div, 'before')).toBe('Quoted Text');
85
+ });
86
+
87
+ it('should return false for empty content', () => {
88
+ const div = document.createElement('div');
89
+ div.className = 'empty-content';
90
+ document.body.appendChild(div);
91
+
92
+ expect(getCSSGeneratedContent(div)).toBe(false);
93
+ });
94
+
95
+ it('should return false for content: none', () => {
96
+ const div = document.createElement('div');
97
+ div.className = 'no-content';
98
+ document.body.appendChild(div);
99
+
100
+ expect(getCSSGeneratedContent(div)).toBe(false);
101
+ });
102
+ });