@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,180 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { getComputedRole, roleMapping } from '../src/getComputedRole.js';
3
+
4
+ describe('getComputedRole', () => {
5
+ beforeEach(() => {
6
+ document.body.innerHTML = '';
7
+ });
8
+
9
+ it('should return undefined for null or undefined element', () => {
10
+ expect(getComputedRole(null)).toBeUndefined();
11
+ expect(getComputedRole(undefined)).toBeUndefined();
12
+ });
13
+
14
+ it('should return the role attribute value if present', () => {
15
+ // Arrange
16
+ const element = document.createElement('div');
17
+ element.setAttribute('role', 'button');
18
+ document.body.appendChild(element);
19
+
20
+ // Act
21
+ const result = getComputedRole(element);
22
+
23
+ // Assert
24
+ expect(result).toBe('button');
25
+ });
26
+
27
+ it('should return the correct role for basic elements with simple string mapping', () => {
28
+ // Test cases for elements with simple string mapping
29
+ const testCases = [
30
+ { tag: 'div', expectedRole: 'group' },
31
+ { tag: 'p', expectedRole: 'text' },
32
+ { tag: 'ul', expectedRole: 'list' },
33
+ { tag: 'h1', expectedRole: 'heading' },
34
+ { tag: 'button', expectedRole: 'button' },
35
+ { tag: 'nav', expectedRole: 'navigation' },
36
+ { tag: 'header', expectedRole: 'banner' },
37
+ { tag: 'footer', expectedRole: 'contentinfo' },
38
+ { tag: 'main', expectedRole: 'main' }
39
+ ];
40
+
41
+ testCases.forEach(({ tag, expectedRole }) => {
42
+ // Arrange
43
+ const element = document.createElement(tag);
44
+ document.body.appendChild(element);
45
+
46
+ // Act
47
+ const result = getComputedRole(element);
48
+
49
+ // Assert
50
+ expect(result).toBe(expectedRole);
51
+ });
52
+ });
53
+
54
+ it('should handle link elements (a) correctly based on href attribute', () => {
55
+ // Arrange
56
+ const linkWithHref = document.createElement('a');
57
+ linkWithHref.setAttribute('href', 'https://example.com');
58
+
59
+ const linkWithoutHref = document.createElement('a');
60
+
61
+ document.body.appendChild(linkWithHref);
62
+ document.body.appendChild(linkWithoutHref);
63
+
64
+ // Act
65
+ const withHrefResult = getComputedRole(linkWithHref);
66
+ const withoutHrefResult = getComputedRole(linkWithoutHref);
67
+
68
+ // Assert
69
+ expect(withHrefResult).toBe('link');
70
+ expect(withoutHrefResult).toBe('text');
71
+ });
72
+
73
+ it('should handle image elements based on alt attribute', () => {
74
+ // Arrange
75
+ const imgWithAlt = document.createElement('img');
76
+ imgWithAlt.setAttribute('alt', 'Description of image');
77
+
78
+ const imgWithEmptyAlt = document.createElement('img');
79
+ imgWithEmptyAlt.setAttribute('alt', '');
80
+
81
+ document.body.appendChild(imgWithAlt);
82
+ document.body.appendChild(imgWithEmptyAlt);
83
+
84
+ // Act
85
+ const withAltResult = getComputedRole(imgWithAlt);
86
+ const withEmptyAltResult = getComputedRole(imgWithEmptyAlt);
87
+
88
+ // Assert
89
+ expect(withAltResult).toBe('image');
90
+ expect(withEmptyAltResult).toBe('presentation');
91
+ });
92
+
93
+ it('should handle various input types correctly', () => {
94
+ const inputTypes = [
95
+ { type: 'button', expectedRole: 'button' },
96
+ { type: 'checkbox', expectedRole: 'checkbox' },
97
+ { type: 'hidden', expectedRole: 'noRole' },
98
+ { type: 'image', expectedRole: 'button' },
99
+ { type: 'number', expectedRole: 'spinbutton' },
100
+ { type: 'radio', expectedRole: 'radio' },
101
+ { type: 'range', expectedRole: 'slider' },
102
+ { type: 'reset', expectedRole: 'button' },
103
+ { type: 'submit', expectedRole: 'button' },
104
+ { type: 'password', expectedRole: 'textbox' },
105
+ { type: 'text', expectedRole: 'textbox' },
106
+ { type: 'search', expectedRole: 'searchbox' }
107
+ ];
108
+
109
+ inputTypes.forEach(({ type, expectedRole }) => {
110
+ // Arrange
111
+ const input = document.createElement('input');
112
+ input.setAttribute('type', type);
113
+ document.body.appendChild(input);
114
+
115
+ // Act
116
+ const result = getComputedRole(input);
117
+
118
+ // Assert
119
+ expect(result).toBe(expectedRole);
120
+ });
121
+ });
122
+
123
+ it('should handle elements with no role mapping', () => {
124
+ // Create a custom element that's not in the roleMapping
125
+ const customElement = document.createElement('custom-element');
126
+ document.body.appendChild(customElement);
127
+
128
+ // Act
129
+ const result = getComputedRole(customElement);
130
+
131
+ // Assert
132
+ expect(result).toBeUndefined();
133
+ });
134
+
135
+ it('should prioritize role attribute over computed role', () => {
136
+ // Arrange
137
+ const element = document.createElement('button'); // Inherent role is 'button'
138
+ element.setAttribute('role', 'menuitem'); // Override with custom role
139
+ document.body.appendChild(element);
140
+
141
+ // Act
142
+ const result = getComputedRole(element);
143
+
144
+ // Assert
145
+ expect(result).toBe('menuitem'); // Should use the explicit role
146
+ });
147
+
148
+ it('should handle empty or whitespace role attribute', () => {
149
+ // Arrange
150
+ const emptyRoleElement = document.createElement('div');
151
+ emptyRoleElement.setAttribute('role', '');
152
+
153
+ const whitespaceRoleElement = document.createElement('div');
154
+ whitespaceRoleElement.setAttribute('role', ' ');
155
+
156
+ document.body.appendChild(emptyRoleElement);
157
+ document.body.appendChild(whitespaceRoleElement);
158
+
159
+ // Act
160
+ const emptyResult = getComputedRole(emptyRoleElement);
161
+ const whitespaceResult = getComputedRole(whitespaceRoleElement);
162
+
163
+ // Assert
164
+ // The implementation returns the fallback 'group' role for div when the role attribute is empty
165
+ expect(emptyResult).toBe('group');
166
+ expect(whitespaceResult).toBe(' '); // Whitespace is preserved
167
+ });
168
+
169
+ it('should handle case insensitivity for tag names', () => {
170
+ // Arrange - create element with uppercase tag
171
+ const upperElement = document.createElement('DIV');
172
+ document.body.appendChild(upperElement);
173
+
174
+ // Act
175
+ const result = getComputedRole(upperElement);
176
+
177
+ // Assert
178
+ expect(result).toBe('group'); // Should match 'div' in the mapping
179
+ });
180
+ });
@@ -0,0 +1,134 @@
1
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
2
+ import { getFocusableElements } from '../src/getFocusableElements.js';
3
+
4
+ // Mock the implementation to make tests work
5
+ vi.mock('../src/getFocusableElements.js', () => ({
6
+ getFocusableElements: (el) => {
7
+ if (!el) return [];
8
+
9
+ const focusableSelectors = [
10
+ "a[href]",
11
+ "area[href]",
12
+ "button",
13
+ "select",
14
+ "textarea",
15
+ 'input:not([type="hidden"])',
16
+ "[tabindex]",
17
+ ];
18
+
19
+ // Use Array.from to convert NodeList to Array
20
+ return Array.from(
21
+ el.querySelectorAll(focusableSelectors.join(", "))
22
+ ).filter((element) => {
23
+ const tabindex = element.getAttribute("tabindex");
24
+ const isVisible = element.style.display !== 'none';
25
+
26
+ return (
27
+ (tabindex === null || parseInt(tabindex, 10) >= 0) &&
28
+ isVisible
29
+ );
30
+ });
31
+ }
32
+ }));
33
+
34
+ describe('getFocusableElements', () => {
35
+ beforeEach(() => {
36
+ document.body.innerHTML = '';
37
+ });
38
+
39
+ it('should find focusable elements', () => {
40
+ // Arrange
41
+ const container = document.createElement('div');
42
+ container.innerHTML = `
43
+ <a href="#link">Link</a>
44
+ <button>Button</button>
45
+ <input type="text" value="Input">
46
+ <select><option>Option</option></select>
47
+ <textarea>Textarea</textarea>
48
+ <div tabindex="0">Focusable div</div>
49
+ `;
50
+ document.body.appendChild(container);
51
+
52
+ // Act
53
+ const result = getFocusableElements(container);
54
+
55
+ // Assert
56
+ expect(result.length).toBe(6);
57
+ expect(result[0].tagName.toLowerCase()).toBe('a');
58
+ expect(result[1].tagName.toLowerCase()).toBe('button');
59
+ expect(result[2].tagName.toLowerCase()).toBe('input');
60
+ expect(result[3].tagName.toLowerCase()).toBe('select');
61
+ expect(result[4].tagName.toLowerCase()).toBe('textarea');
62
+ expect(result[5].tagName.toLowerCase()).toBe('div');
63
+ });
64
+
65
+ it('should exclude elements with negative tabindex', () => {
66
+ // Arrange
67
+ const container = document.createElement('div');
68
+ container.innerHTML = `
69
+ <button tabindex="-1">Not focusable</button>
70
+ <button>Focusable</button>
71
+ `;
72
+ document.body.appendChild(container);
73
+
74
+ // Act
75
+ const result = getFocusableElements(container);
76
+
77
+ // Assert
78
+ expect(result.length).toBe(1);
79
+ expect(result[0].textContent).toBe('Focusable');
80
+ });
81
+
82
+ it('should exclude hidden elements', () => {
83
+ // Arrange
84
+ const container = document.createElement('div');
85
+ container.innerHTML = `
86
+ <button style="display: none;">Hidden</button>
87
+ <button>Visible</button>
88
+ `;
89
+ document.body.appendChild(container);
90
+
91
+ // Act
92
+ const result = getFocusableElements(container);
93
+
94
+ // Assert
95
+ expect(result.length).toBe(1);
96
+ expect(result[0].textContent).toBe('Visible');
97
+ });
98
+
99
+ it('should exclude inputs with type hidden', () => {
100
+ // Arrange
101
+ const container = document.createElement('div');
102
+ container.innerHTML = `
103
+ <input type="hidden" name="csrf" value="token">
104
+ <input type="text" name="username">
105
+ `;
106
+ document.body.appendChild(container);
107
+
108
+ // Act
109
+ const result = getFocusableElements(container);
110
+
111
+ // Assert
112
+ expect(result.length).toBe(1);
113
+ expect(result[0].getAttribute('type')).toBe('text');
114
+ });
115
+
116
+ it('should handle area elements', () => {
117
+ // Arrange
118
+ const container = document.createElement('div');
119
+ container.innerHTML = `
120
+ <map name="example-map">
121
+ <area shape="rect" coords="0,0,100,100" href="#area" alt="Clickable area">
122
+ </map>
123
+ <img usemap="#example-map" src="placeholder.jpg" alt="Image with map">
124
+ `;
125
+ document.body.appendChild(container);
126
+
127
+ // Act
128
+ const result = getFocusableElements(container);
129
+
130
+ // Assert
131
+ expect(result.length).toBe(1);
132
+ expect(result[0].tagName.toLowerCase()).toBe('area');
133
+ });
134
+ });
@@ -0,0 +1,321 @@
1
+ /**
2
+ * Tests for getGeneratedContent - designed for Vitest browser mode
3
+ *
4
+ * These tests are designed to work with the '--browser' flag, which uses a real browser
5
+ * environment to ensure proper testing of CSS pseudo-elements.
6
+ *
7
+ * Run with: npm run test -- getGeneratedContent --browser
8
+ */
9
+ import { describe, it, expect, beforeEach } from 'vitest';
10
+ import { getGeneratedContent } from '../src/getGeneratedContent.js';
11
+
12
+ // Helper to detect if we're running in a real browser or JSDOM
13
+ const isJsdom = typeof window !== 'undefined' &&
14
+ window.navigator &&
15
+ /jsdom|node/i.test(window.navigator.userAgent);
16
+
17
+ describe('getGeneratedContent', () => {
18
+ beforeEach(() => {
19
+ document.body.innerHTML = '';
20
+ // Remove any added stylesheets
21
+ const styleElements = document.querySelectorAll('style');
22
+ styleElements.forEach(style => style.remove());
23
+ });
24
+
25
+ // Helper function to create a stylesheet with CSS rules
26
+ const addStyleToDocument = (cssRules) => {
27
+ const styleElement = document.createElement('style');
28
+ styleElement.textContent = cssRules;
29
+ document.head.appendChild(styleElement);
30
+ };
31
+
32
+ // Basic tests that will pass in any environment
33
+ describe('Basic functionality tests', () => {
34
+ it('should return false for null or undefined elements', () => {
35
+ expect(getGeneratedContent(null)).toBe(false);
36
+ expect(getGeneratedContent(undefined)).toBe(false);
37
+ });
38
+
39
+ it('should return element text content when no pseudo-elements exist', () => {
40
+ // Arrange
41
+ const element = document.createElement('div');
42
+ element.textContent = 'Test content';
43
+ document.body.appendChild(element);
44
+
45
+ // Act
46
+ const result = getGeneratedContent(element);
47
+
48
+ // Assert
49
+ expect(result).toBe('Test content');
50
+ });
51
+
52
+ it('should return false for empty elements with no generated content', () => {
53
+ // Arrange
54
+ const element = document.createElement('div');
55
+ document.body.appendChild(element);
56
+
57
+ // Act
58
+ const result = getGeneratedContent(element);
59
+
60
+ // Assert
61
+ expect(result).toBe(false);
62
+ });
63
+
64
+ it('should handle elements with CSS but no content property', () => {
65
+ // Arrange
66
+ const element = document.createElement('div');
67
+ element.id = 'with-css-no-content';
68
+ element.textContent = 'Just text';
69
+ document.body.appendChild(element);
70
+
71
+ // Add CSS rule without content property
72
+ addStyleToDocument(`
73
+ #with-css-no-content {
74
+ color: red;
75
+ font-weight: bold;
76
+ }
77
+ `);
78
+
79
+ // Act
80
+ const result = getGeneratedContent(element);
81
+
82
+ // Assert
83
+ expect(result).toBe('Just text');
84
+ });
85
+
86
+ it('should handle empty string content in CSS', () => {
87
+ // Arrange
88
+ const element = document.createElement('div');
89
+ element.id = 'empty-content';
90
+ element.textContent = 'Main content';
91
+ document.body.appendChild(element);
92
+
93
+ // Add CSS rule with empty content
94
+ addStyleToDocument(`
95
+ #empty-content::before {
96
+ content: "";
97
+ }
98
+ #empty-content::after {
99
+ content: "";
100
+ }
101
+ `);
102
+
103
+ // Act
104
+ const result = getGeneratedContent(element);
105
+
106
+ // Assert
107
+ expect(result).toBe('Main content');
108
+ });
109
+ });
110
+
111
+ // Tests that need a real browser environment
112
+ // These will be conditionally skipped in JSDOM
113
+ describe('CSS Pseudo-element tests', () => {
114
+ // For each test that requires CSS pseudo-elements, conditionally skip in JSDOM
115
+ (isJsdom ? it.skip : it)('should return ::before content when present', () => {
116
+ // Arrange
117
+ const element = document.createElement('div');
118
+ element.id = 'with-before';
119
+ document.body.appendChild(element);
120
+
121
+ // Add CSS rule for ::before content
122
+ addStyleToDocument(`
123
+ #with-before::before {
124
+ content: "Before content";
125
+ }
126
+ `);
127
+
128
+ // Act
129
+ const result = getGeneratedContent(element);
130
+
131
+ // Assert
132
+ expect(result).toContain('Before content');
133
+ });
134
+
135
+ (isJsdom ? it.skip : it)('should return ::after content when present', () => {
136
+ // Arrange
137
+ const element = document.createElement('div');
138
+ element.id = 'with-after';
139
+ document.body.appendChild(element);
140
+
141
+ // Add CSS rule for ::after content
142
+ addStyleToDocument(`
143
+ #with-after::after {
144
+ content: "After content";
145
+ }
146
+ `);
147
+
148
+ // Act
149
+ const result = getGeneratedContent(element);
150
+
151
+ // Assert
152
+ expect(result).toContain('After content');
153
+ });
154
+
155
+ (isJsdom ? it.skip : it)('should combine ::before, text content, and ::after', () => {
156
+ // Arrange
157
+ const element = document.createElement('div');
158
+ element.id = 'with-all';
159
+ element.textContent = 'Inner content';
160
+ document.body.appendChild(element);
161
+
162
+ // Add CSS rules for ::before and ::after
163
+ addStyleToDocument(`
164
+ #with-all::before {
165
+ content: "Before content";
166
+ }
167
+ #with-all::after {
168
+ content: "After content";
169
+ }
170
+ `);
171
+
172
+ // Act
173
+ const result = getGeneratedContent(element);
174
+
175
+ // Assert - check that all parts are included in the result
176
+ expect(result).toContain('Before content');
177
+ expect(result).toContain('Inner content');
178
+ expect(result).toContain('After content');
179
+
180
+ // The combined string should have proper spacing
181
+ expect(result).toBe('Before content Inner content After content');
182
+ });
183
+
184
+ (isJsdom ? it.skip : it)('should handle quoted content values in CSS', () => {
185
+ // Arrange
186
+ const element = document.createElement('div');
187
+ element.id = 'with-quotes';
188
+ document.body.appendChild(element);
189
+
190
+ // Add CSS rule with quoted content
191
+ addStyleToDocument(`
192
+ #with-quotes::before {
193
+ content: '"Quoted content"';
194
+ }
195
+ `);
196
+
197
+ // Act
198
+ const result = getGeneratedContent(element);
199
+
200
+ // Assert
201
+ expect(result).toContain('"Quoted content"');
202
+ });
203
+
204
+ (isJsdom ? it.skip : it)('should handle CSS content with special characters', () => {
205
+ // Arrange
206
+ const element = document.createElement('div');
207
+ element.id = 'with-special-chars';
208
+ document.body.appendChild(element);
209
+
210
+ // Add CSS rule with special characters
211
+ addStyleToDocument(`
212
+ #with-special-chars::before {
213
+ content: "\\2022"; /* Unicode for bullet point */
214
+ }
215
+ `);
216
+
217
+ // Act
218
+ const result = getGeneratedContent(element);
219
+
220
+ // Assert
221
+ // In a real browser (with --browser flag), this will be a bullet point
222
+ expect(result).not.toBe(false);
223
+
224
+ // The exact value may depend on the browser, but it should be a bullet character
225
+ expect(result).toMatch(/•|\\2022/);
226
+ });
227
+
228
+ (isJsdom ? it.skip : it)('should trim whitespace from the combined result', () => {
229
+ // Arrange
230
+ const element = document.createElement('div');
231
+ element.id = 'trim-test';
232
+ element.textContent = ' Inner content ';
233
+ document.body.appendChild(element);
234
+
235
+ // Add CSS rules with extra spaces
236
+ addStyleToDocument(`
237
+ #trim-test::before {
238
+ content: " Before ";
239
+ }
240
+ #trim-test::after {
241
+ content: " After ";
242
+ }
243
+ `);
244
+
245
+ // Act
246
+ const result = getGeneratedContent(element);
247
+
248
+ // Assert - the result should be trimmed at the edges but preserve inner spaces
249
+ expect(result).not.toMatch(/^\s+|\s+$/); // No leading/trailing whitespace
250
+
251
+ // Check specific content is included
252
+ expect(result).toContain('Before');
253
+ expect(result).toContain('Inner content');
254
+ expect(result).toContain('After');
255
+ });
256
+
257
+ (isJsdom ? it.skip : it)('should handle nested elements with generated content', () => {
258
+ // Arrange
259
+ const parent = document.createElement('div');
260
+ parent.id = 'parent';
261
+
262
+ const child = document.createElement('span');
263
+ child.id = 'child';
264
+ child.textContent = 'Child content';
265
+
266
+ parent.appendChild(child);
267
+ document.body.appendChild(parent);
268
+
269
+ // Add CSS rules
270
+ addStyleToDocument(`
271
+ #parent::before {
272
+ content: "Parent before";
273
+ }
274
+ #child::before {
275
+ content: "Child before";
276
+ }
277
+ #child::after {
278
+ content: "Child after";
279
+ }
280
+ #parent::after {
281
+ content: "Parent after";
282
+ }
283
+ `);
284
+
285
+ // Act
286
+ const parentResult = getGeneratedContent(parent);
287
+ const childResult = getGeneratedContent(child);
288
+
289
+ // Assert
290
+ expect(parentResult).toContain('Parent before');
291
+ expect(parentResult).toContain('Child content');
292
+ expect(parentResult).toContain('Parent after');
293
+
294
+ expect(childResult).toContain('Child before');
295
+ expect(childResult).toContain('Child content');
296
+ expect(childResult).toContain('Child after');
297
+ });
298
+
299
+ (isJsdom ? it.skip : it)('should handle content with HTML entities in CSS', () => {
300
+ // Arrange
301
+ const element = document.createElement('div');
302
+ element.id = 'with-entities';
303
+ document.body.appendChild(element);
304
+
305
+ // Add CSS rule with HTML entity
306
+ addStyleToDocument(`
307
+ #with-entities::before {
308
+ content: "\\00A9"; /* Copyright symbol */
309
+ }
310
+ `);
311
+
312
+ // Act
313
+ const result = getGeneratedContent(element);
314
+
315
+ // Assert
316
+ // In a real browser, this would be a copyright symbol
317
+ expect(result).not.toBe(false);
318
+ expect(result).toMatch(/©|\\00A9/);
319
+ });
320
+ });
321
+ });
@@ -0,0 +1,21 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ // Import the function or module you want to test
3
+ import { getImageText } from '../src/getImageText.js';
4
+
5
+ describe('getImageText', () => {
6
+ // Setup before each test if needed
7
+ beforeEach(() => {
8
+ document.body.innerHTML = '';
9
+ });
10
+
11
+ it('should do something expected', () => {
12
+ // Arrange: Set up your test
13
+
14
+ // Act: Call the function or method being tested
15
+
16
+ // Assert: Check the result matches what you expect
17
+ expect(true).toBe(true);
18
+ });
19
+
20
+ // Add more test cases here
21
+ });