@afixt/test-utils 1.2.3 → 2.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.
- package/.claude/settings.local.json +1 -6
- package/BROWSER_TESTING.md +42 -22
- package/CHANGELOG.md +40 -0
- package/CLAUDE.md +10 -9
- package/package.json +1 -1
- package/src/constants.js +438 -1
- package/src/domUtils.js +17 -38
- package/src/formUtils.js +7 -24
- package/src/getAccessibleName.js +20 -56
- package/src/getCSSGeneratedContent.js +2 -0
- package/src/getFocusableElements.js +12 -21
- package/src/getGeneratedContent.js +18 -11
- package/src/getImageText.js +22 -7
- package/src/hasValidAriaRole.js +11 -19
- package/src/index.js +4 -4
- package/src/interactiveRoles.js +2 -19
- package/src/isA11yVisible.js +95 -0
- package/src/isAriaAttributesValid.js +5 -64
- package/src/isFocusable.js +30 -10
- package/src/isHidden.js +44 -8
- package/src/listEventListeners.js +115 -10
- package/src/stringUtils.js +19 -98
- package/src/tableUtils.js +4 -36
- package/src/testContrast.js +54 -0
- package/test/domUtils.test.js +156 -0
- package/test/formUtils.test.js +0 -47
- package/test/getAccessibleName.test.js +39 -0
- package/test/getGeneratedContent.test.js +305 -241
- package/test/getImageText.test.js +158 -99
- package/test/index.test.js +54 -17
- package/test/{isVisible.test.js → isA11yVisible.test.js} +39 -33
- package/test/isFocusable.test.js +265 -272
- package/test/isHidden.test.js +257 -153
- package/test/listEventListeners.test.js +163 -44
- package/test/playwright/css-pseudo-elements.spec.js +3 -13
- package/test/stringUtils.test.js +55 -228
- package/test/testContrast.test.js +104 -2
- package/todo.md +2 -2
- package/src/isVisible.js +0 -103
|
@@ -1,97 +1,98 @@
|
|
|
1
1
|
/**
|
|
2
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
|
|
3
|
+
*
|
|
4
|
+
* These tests are designed to work with the '--browser' flag, which uses a real browser
|
|
5
5
|
* environment to ensure proper testing of CSS pseudo-elements.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* Run with: npm run test -- getGeneratedContent --browser
|
|
8
8
|
*/
|
|
9
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
9
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
10
10
|
import { getGeneratedContent } from '../src/getGeneratedContent.js';
|
|
11
11
|
|
|
12
12
|
// Helper to detect if we're running in a real browser or JSDOM
|
|
13
|
-
const isJsdom =
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
const isJsdom =
|
|
14
|
+
typeof window !== 'undefined' &&
|
|
15
|
+
window.navigator &&
|
|
16
|
+
/jsdom|node/i.test(window.navigator.userAgent);
|
|
16
17
|
|
|
17
18
|
describe('getGeneratedContent', () => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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);
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
document.body.innerHTML = '';
|
|
21
|
+
// Remove any added stylesheets
|
|
22
|
+
const styleElements = document.querySelectorAll('style');
|
|
23
|
+
styleElements.forEach(style => style.remove());
|
|
37
24
|
});
|
|
38
25
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
// Act
|
|
46
|
-
const result = getGeneratedContent(element);
|
|
47
|
-
|
|
48
|
-
// Assert
|
|
49
|
-
expect(result).toBe('Test content');
|
|
50
|
-
});
|
|
26
|
+
// Helper function to create a stylesheet with CSS rules
|
|
27
|
+
const addStyleToDocument = cssRules => {
|
|
28
|
+
const styleElement = document.createElement('style');
|
|
29
|
+
styleElement.textContent = cssRules;
|
|
30
|
+
document.head.appendChild(styleElement);
|
|
31
|
+
};
|
|
51
32
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
33
|
+
// Basic tests that will pass in any environment
|
|
34
|
+
describe('Basic functionality tests', () => {
|
|
35
|
+
it('should return false for null or undefined elements', () => {
|
|
36
|
+
expect(getGeneratedContent(null)).toBe(false);
|
|
37
|
+
expect(getGeneratedContent(undefined)).toBe(false);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should return element text content when no pseudo-elements exist', () => {
|
|
41
|
+
// Arrange
|
|
42
|
+
const element = document.createElement('div');
|
|
43
|
+
element.textContent = 'Test content';
|
|
44
|
+
document.body.appendChild(element);
|
|
45
|
+
|
|
46
|
+
// Act
|
|
47
|
+
const result = getGeneratedContent(element);
|
|
48
|
+
|
|
49
|
+
// Assert
|
|
50
|
+
expect(result).toBe('Test content');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('should return false for empty elements with no generated content', () => {
|
|
54
|
+
// Arrange
|
|
55
|
+
const element = document.createElement('div');
|
|
56
|
+
document.body.appendChild(element);
|
|
57
|
+
|
|
58
|
+
// Act
|
|
59
|
+
const result = getGeneratedContent(element);
|
|
60
|
+
|
|
61
|
+
// Assert
|
|
62
|
+
expect(result).toBe(false);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('should handle elements with CSS but no content property', () => {
|
|
66
|
+
// Arrange
|
|
67
|
+
const element = document.createElement('div');
|
|
68
|
+
element.id = 'with-css-no-content';
|
|
69
|
+
element.textContent = 'Just text';
|
|
70
|
+
document.body.appendChild(element);
|
|
63
71
|
|
|
64
|
-
|
|
65
|
-
|
|
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(`
|
|
72
|
+
// Add CSS rule without content property
|
|
73
|
+
addStyleToDocument(`
|
|
73
74
|
#with-css-no-content {
|
|
74
75
|
color: red;
|
|
75
76
|
font-weight: bold;
|
|
76
77
|
}
|
|
77
78
|
`);
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
79
|
+
|
|
80
|
+
// Act
|
|
81
|
+
const result = getGeneratedContent(element);
|
|
82
|
+
|
|
83
|
+
// Assert
|
|
84
|
+
expect(result).toBe('Just text');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should handle empty string content in CSS', () => {
|
|
88
|
+
// Arrange
|
|
89
|
+
const element = document.createElement('div');
|
|
90
|
+
element.id = 'empty-content';
|
|
91
|
+
element.textContent = 'Main content';
|
|
92
|
+
document.body.appendChild(element);
|
|
93
|
+
|
|
94
|
+
// Add CSS rule with empty content
|
|
95
|
+
addStyleToDocument(`
|
|
95
96
|
#empty-content::before {
|
|
96
97
|
content: "";
|
|
97
98
|
}
|
|
@@ -99,68 +100,131 @@ describe('getGeneratedContent', () => {
|
|
|
99
100
|
content: "";
|
|
100
101
|
}
|
|
101
102
|
`);
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
103
|
+
|
|
104
|
+
// Act
|
|
105
|
+
const result = getGeneratedContent(element);
|
|
106
|
+
|
|
107
|
+
// Assert
|
|
108
|
+
expect(result).toBe('Main content');
|
|
109
|
+
});
|
|
108
110
|
});
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
111
|
+
|
|
112
|
+
describe('Delegation to getCSSGeneratedContent', () => {
|
|
113
|
+
// Mock window.getComputedStyle to support pseudo-element arguments in JSDOM
|
|
114
|
+
const mockGetComputedStyle = pseudoContentMap => {
|
|
115
|
+
const original = window.getComputedStyle;
|
|
116
|
+
window.getComputedStyle = vi.fn((el, pseudoElt) => {
|
|
117
|
+
if (pseudoElt) {
|
|
118
|
+
const key = pseudoElt.replace('::', '');
|
|
119
|
+
return {
|
|
120
|
+
getPropertyValue: prop => {
|
|
121
|
+
if (prop === 'content' && pseudoContentMap[key]) {
|
|
122
|
+
return `"${pseudoContentMap[key]}"`;
|
|
123
|
+
}
|
|
124
|
+
return '';
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return original(el);
|
|
129
|
+
});
|
|
130
|
+
return () => {
|
|
131
|
+
window.getComputedStyle = original;
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
it('should include pseudo-element content from getCSSGeneratedContent', () => {
|
|
136
|
+
const element = document.createElement('div');
|
|
137
|
+
element.textContent = 'Inner text';
|
|
138
|
+
document.body.appendChild(element);
|
|
139
|
+
|
|
140
|
+
const restore = mockGetComputedStyle({ before: 'Before', after: 'After' });
|
|
141
|
+
|
|
142
|
+
const result = getGeneratedContent(element);
|
|
143
|
+
expect(result).toBe('Before Inner text After');
|
|
144
|
+
|
|
145
|
+
restore();
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('should handle only ::before content from getCSSGeneratedContent', () => {
|
|
149
|
+
const element = document.createElement('div');
|
|
150
|
+
element.textContent = 'Content';
|
|
151
|
+
document.body.appendChild(element);
|
|
152
|
+
|
|
153
|
+
const restore = mockGetComputedStyle({ before: 'Prefix' });
|
|
154
|
+
|
|
155
|
+
const result = getGeneratedContent(element);
|
|
156
|
+
expect(result).toBe('Prefix Content');
|
|
157
|
+
|
|
158
|
+
restore();
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('should handle only ::after content from getCSSGeneratedContent', () => {
|
|
162
|
+
const element = document.createElement('div');
|
|
163
|
+
element.textContent = 'Content';
|
|
164
|
+
document.body.appendChild(element);
|
|
165
|
+
|
|
166
|
+
const restore = mockGetComputedStyle({ after: 'Suffix' });
|
|
167
|
+
|
|
168
|
+
const result = getGeneratedContent(element);
|
|
169
|
+
expect(result).toBe('Content Suffix');
|
|
170
|
+
|
|
171
|
+
restore();
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// Tests that need a real browser environment
|
|
176
|
+
// These will be conditionally skipped in JSDOM
|
|
177
|
+
describe('CSS Pseudo-element tests', () => {
|
|
178
|
+
// For each test that requires CSS pseudo-elements, conditionally skip in JSDOM
|
|
179
|
+
(isJsdom ? it.skip : it)('should return ::before content when present', () => {
|
|
180
|
+
// Arrange
|
|
181
|
+
const element = document.createElement('div');
|
|
182
|
+
element.id = 'with-before';
|
|
183
|
+
document.body.appendChild(element);
|
|
184
|
+
|
|
185
|
+
// Add CSS rule for ::before content
|
|
186
|
+
addStyleToDocument(`
|
|
123
187
|
#with-before::before {
|
|
124
188
|
content: "Before content";
|
|
125
189
|
}
|
|
126
190
|
`);
|
|
127
|
-
|
|
128
|
-
// Act
|
|
129
|
-
const result = getGeneratedContent(element);
|
|
130
|
-
|
|
131
|
-
// Assert
|
|
132
|
-
expect(result).toContain('Before content');
|
|
133
|
-
});
|
|
134
191
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
192
|
+
// Act
|
|
193
|
+
const result = getGeneratedContent(element);
|
|
194
|
+
|
|
195
|
+
// Assert
|
|
196
|
+
expect(result).toContain('Before content');
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
(isJsdom ? it.skip : it)('should return ::after content when present', () => {
|
|
200
|
+
// Arrange
|
|
201
|
+
const element = document.createElement('div');
|
|
202
|
+
element.id = 'with-after';
|
|
203
|
+
document.body.appendChild(element);
|
|
204
|
+
|
|
205
|
+
// Add CSS rule for ::after content
|
|
206
|
+
addStyleToDocument(`
|
|
143
207
|
#with-after::after {
|
|
144
208
|
content: "After content";
|
|
145
209
|
}
|
|
146
210
|
`);
|
|
147
|
-
|
|
148
|
-
// Act
|
|
149
|
-
const result = getGeneratedContent(element);
|
|
150
|
-
|
|
151
|
-
// Assert
|
|
152
|
-
expect(result).toContain('After content');
|
|
153
|
-
});
|
|
154
211
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
212
|
+
// Act
|
|
213
|
+
const result = getGeneratedContent(element);
|
|
214
|
+
|
|
215
|
+
// Assert
|
|
216
|
+
expect(result).toContain('After content');
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
(isJsdom ? it.skip : it)('should combine ::before, text content, and ::after', () => {
|
|
220
|
+
// Arrange
|
|
221
|
+
const element = document.createElement('div');
|
|
222
|
+
element.id = 'with-all';
|
|
223
|
+
element.textContent = 'Inner content';
|
|
224
|
+
document.body.appendChild(element);
|
|
225
|
+
|
|
226
|
+
// Add CSS rules for ::before and ::after
|
|
227
|
+
addStyleToDocument(`
|
|
164
228
|
#with-all::before {
|
|
165
229
|
content: "Before content";
|
|
166
230
|
}
|
|
@@ -168,72 +232,72 @@ describe('getGeneratedContent', () => {
|
|
|
168
232
|
content: "After content";
|
|
169
233
|
}
|
|
170
234
|
`);
|
|
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
235
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
236
|
+
// Act
|
|
237
|
+
const result = getGeneratedContent(element);
|
|
238
|
+
|
|
239
|
+
// Assert - check that all parts are included in the result
|
|
240
|
+
expect(result).toContain('Before content');
|
|
241
|
+
expect(result).toContain('Inner content');
|
|
242
|
+
expect(result).toContain('After content');
|
|
243
|
+
|
|
244
|
+
// The combined string should have proper spacing
|
|
245
|
+
expect(result).toBe('Before content Inner content After content');
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
(isJsdom ? it.skip : it)('should handle quoted content values in CSS', () => {
|
|
249
|
+
// Arrange
|
|
250
|
+
const element = document.createElement('div');
|
|
251
|
+
element.id = 'with-quotes';
|
|
252
|
+
document.body.appendChild(element);
|
|
253
|
+
|
|
254
|
+
// Add CSS rule with quoted content
|
|
255
|
+
addStyleToDocument(`
|
|
192
256
|
#with-quotes::before {
|
|
193
257
|
content: '"Quoted content"';
|
|
194
258
|
}
|
|
195
259
|
`);
|
|
196
|
-
|
|
197
|
-
// Act
|
|
198
|
-
const result = getGeneratedContent(element);
|
|
199
|
-
|
|
200
|
-
// Assert
|
|
201
|
-
expect(result).toContain('"Quoted content"');
|
|
202
|
-
});
|
|
203
260
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
261
|
+
// Act
|
|
262
|
+
const result = getGeneratedContent(element);
|
|
263
|
+
|
|
264
|
+
// Assert
|
|
265
|
+
expect(result).toContain('"Quoted content"');
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
(isJsdom ? it.skip : it)('should handle CSS content with special characters', () => {
|
|
269
|
+
// Arrange
|
|
270
|
+
const element = document.createElement('div');
|
|
271
|
+
element.id = 'with-special-chars';
|
|
272
|
+
document.body.appendChild(element);
|
|
273
|
+
|
|
274
|
+
// Add CSS rule with special characters
|
|
275
|
+
addStyleToDocument(`
|
|
212
276
|
#with-special-chars::before {
|
|
213
277
|
content: "\\2022"; /* Unicode for bullet point */
|
|
214
278
|
}
|
|
215
279
|
`);
|
|
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
280
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
281
|
+
// Act
|
|
282
|
+
const result = getGeneratedContent(element);
|
|
283
|
+
|
|
284
|
+
// Assert
|
|
285
|
+
// In a real browser (with --browser flag), this will be a bullet point
|
|
286
|
+
expect(result).not.toBe(false);
|
|
287
|
+
|
|
288
|
+
// The exact value may depend on the browser, but it should be a bullet character
|
|
289
|
+
expect(result).toMatch(/•|\\2022/);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
(isJsdom ? it.skip : it)('should trim whitespace from the combined result', () => {
|
|
293
|
+
// Arrange
|
|
294
|
+
const element = document.createElement('div');
|
|
295
|
+
element.id = 'trim-test';
|
|
296
|
+
element.textContent = ' Inner content ';
|
|
297
|
+
document.body.appendChild(element);
|
|
298
|
+
|
|
299
|
+
// Add CSS rules with extra spaces
|
|
300
|
+
addStyleToDocument(`
|
|
237
301
|
#trim-test::before {
|
|
238
302
|
content: " Before ";
|
|
239
303
|
}
|
|
@@ -241,33 +305,33 @@ describe('getGeneratedContent', () => {
|
|
|
241
305
|
content: " After ";
|
|
242
306
|
}
|
|
243
307
|
`);
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
308
|
+
|
|
309
|
+
// Act
|
|
310
|
+
const result = getGeneratedContent(element);
|
|
311
|
+
|
|
312
|
+
// Assert - the result should be trimmed at the edges but preserve inner spaces
|
|
313
|
+
expect(result).not.toMatch(/^\s+|\s+$/); // No leading/trailing whitespace
|
|
314
|
+
|
|
315
|
+
// Check specific content is included
|
|
316
|
+
expect(result).toContain('Before');
|
|
317
|
+
expect(result).toContain('Inner content');
|
|
318
|
+
expect(result).toContain('After');
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
(isJsdom ? it.skip : it)('should handle nested elements with generated content', () => {
|
|
322
|
+
// Arrange
|
|
323
|
+
const parent = document.createElement('div');
|
|
324
|
+
parent.id = 'parent';
|
|
325
|
+
|
|
326
|
+
const child = document.createElement('span');
|
|
327
|
+
child.id = 'child';
|
|
328
|
+
child.textContent = 'Child content';
|
|
329
|
+
|
|
330
|
+
parent.appendChild(child);
|
|
331
|
+
document.body.appendChild(parent);
|
|
332
|
+
|
|
333
|
+
// Add CSS rules
|
|
334
|
+
addStyleToDocument(`
|
|
271
335
|
#parent::before {
|
|
272
336
|
content: "Parent before";
|
|
273
337
|
}
|
|
@@ -281,41 +345,41 @@ describe('getGeneratedContent', () => {
|
|
|
281
345
|
content: "Parent after";
|
|
282
346
|
}
|
|
283
347
|
`);
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
348
|
+
|
|
349
|
+
// Act
|
|
350
|
+
const parentResult = getGeneratedContent(parent);
|
|
351
|
+
const childResult = getGeneratedContent(child);
|
|
352
|
+
|
|
353
|
+
// Assert
|
|
354
|
+
expect(parentResult).toContain('Parent before');
|
|
355
|
+
expect(parentResult).toContain('Child content');
|
|
356
|
+
expect(parentResult).toContain('Parent after');
|
|
357
|
+
|
|
358
|
+
expect(childResult).toContain('Child before');
|
|
359
|
+
expect(childResult).toContain('Child content');
|
|
360
|
+
expect(childResult).toContain('Child after');
|
|
361
|
+
});
|
|
362
|
+
|
|
363
|
+
(isJsdom ? it.skip : it)('should handle content with HTML entities in CSS', () => {
|
|
364
|
+
// Arrange
|
|
365
|
+
const element = document.createElement('div');
|
|
366
|
+
element.id = 'with-entities';
|
|
367
|
+
document.body.appendChild(element);
|
|
368
|
+
|
|
369
|
+
// Add CSS rule with HTML entity
|
|
370
|
+
addStyleToDocument(`
|
|
307
371
|
#with-entities::before {
|
|
308
372
|
content: "\\00A9"; /* Copyright symbol */
|
|
309
373
|
}
|
|
310
374
|
`);
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
375
|
+
|
|
376
|
+
// Act
|
|
377
|
+
const result = getGeneratedContent(element);
|
|
378
|
+
|
|
379
|
+
// Assert
|
|
380
|
+
// In a real browser, this would be a copyright symbol
|
|
381
|
+
expect(result).not.toBe(false);
|
|
382
|
+
expect(result).toMatch(/©|\\00A9/);
|
|
383
|
+
});
|
|
319
384
|
});
|
|
320
|
-
|
|
321
|
-
});
|
|
385
|
+
});
|