@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.
- package/.editorconfig +13 -0
- package/.eslintrc +78 -0
- package/.gitattributes +5 -0
- package/.nvmrc +1 -0
- package/CLAUDE.md +33 -0
- package/README.md +72 -0
- package/docs/arrayUtils.js.html +69 -0
- package/docs/data/search.json +1 -0
- package/docs/domUtils.js.html +182 -0
- package/docs/fonts/Inconsolata-Regular.ttf +0 -0
- package/docs/fonts/OpenSans-Regular.ttf +0 -0
- package/docs/fonts/WorkSans-Bold.ttf +0 -0
- package/docs/getAccessibleName.js.html +456 -0
- package/docs/getAccessibleText.js.html +65 -0
- package/docs/getAriaAttributesByElement.js.html +22 -0
- package/docs/getCSSGeneratedContent.js.html +62 -0
- package/docs/getComputedRole.js.html +172 -0
- package/docs/getFocusableElements.js.html +29 -0
- package/docs/getGeneratedContent.js.html +18 -0
- package/docs/getImageText.js.html +28 -0
- package/docs/getStyleObject.js.html +48 -0
- package/docs/global.html +3 -0
- package/docs/hasAccessibleName.js.html +30 -0
- package/docs/hasAttribute.js.html +18 -0
- package/docs/hasCSSGeneratedContent.js.html +23 -0
- package/docs/hasHiddenParent.js.html +32 -0
- package/docs/hasParent.js.html +57 -0
- package/docs/hasValidAriaAttributes.js.html +33 -0
- package/docs/hasValidAriaRole.js.html +32 -0
- package/docs/index.html +3 -0
- package/docs/index.js.html +66 -0
- package/docs/isAriaAttributesValid.js.html +76 -0
- package/docs/isComplexTable.js.html +112 -0
- package/docs/isDataTable.js.html +241 -0
- package/docs/isFocusable.js.html +37 -0
- package/docs/isHidden.js.html +20 -0
- package/docs/isOffScreen.js.html +19 -0
- package/docs/isValidUrl.js.html +16 -0
- package/docs/isVisible.js.html +65 -0
- package/docs/module-afixt-test-utils.html +3 -0
- package/docs/scripts/core.js +726 -0
- package/docs/scripts/core.min.js +23 -0
- package/docs/scripts/resize.js +90 -0
- package/docs/scripts/search.js +265 -0
- package/docs/scripts/search.min.js +6 -0
- package/docs/scripts/third-party/Apache-License-2.0.txt +202 -0
- package/docs/scripts/third-party/fuse.js +9 -0
- package/docs/scripts/third-party/hljs-line-num-original.js +369 -0
- package/docs/scripts/third-party/hljs-line-num.js +1 -0
- package/docs/scripts/third-party/hljs-original.js +5171 -0
- package/docs/scripts/third-party/hljs.js +1 -0
- package/docs/scripts/third-party/popper.js +5 -0
- package/docs/scripts/third-party/tippy.js +1 -0
- package/docs/scripts/third-party/tocbot.js +672 -0
- package/docs/scripts/third-party/tocbot.min.js +1 -0
- package/docs/styles/clean-jsdoc-theme-base.css +1159 -0
- package/docs/styles/clean-jsdoc-theme-dark.css +412 -0
- package/docs/styles/clean-jsdoc-theme-light.css +482 -0
- package/docs/styles/clean-jsdoc-theme-scrollbar.css +30 -0
- package/docs/styles/clean-jsdoc-theme-without-scrollbar.min.css +1 -0
- package/docs/styles/clean-jsdoc-theme.min.css +1 -0
- package/docs/testContrast.js.html +236 -0
- package/docs/testLang.js.html +578 -0
- package/docs/testOrder.js.html +93 -0
- package/jsdoc.json +67 -0
- package/package.json +32 -0
- package/src/arrayUtils.js +67 -0
- package/src/domUtils.js +179 -0
- package/src/getAccessibleName.js +454 -0
- package/src/getAccessibleText.js +63 -0
- package/src/getAriaAttributesByElement.js +19 -0
- package/src/getCSSGeneratedContent.js +60 -0
- package/src/getComputedRole.js +169 -0
- package/src/getFocusableElements.js +26 -0
- package/src/getGeneratedContent.js +15 -0
- package/src/getImageText.js +25 -0
- package/src/getStyleObject.js +45 -0
- package/src/hasAccessibleName.js +28 -0
- package/src/hasAttribute.js +15 -0
- package/src/hasCSSGeneratedContent.js +20 -0
- package/src/hasHiddenParent.js +29 -0
- package/src/hasParent.js +54 -0
- package/src/hasValidAriaAttributes.js +30 -0
- package/src/hasValidAriaRole.js +29 -0
- package/src/index.js +64 -0
- package/src/interactiveRoles.js +20 -0
- package/src/isAriaAttributesValid.js +74 -0
- package/src/isComplexTable.js +109 -0
- package/src/isDataTable.js +239 -0
- package/src/isFocusable.js +34 -0
- package/src/isHidden.js +17 -0
- package/src/isOffScreen.js +16 -0
- package/src/isValidUrl.js +13 -0
- package/src/isVisible.js +62 -0
- package/src/stringUtils.js +150 -0
- package/src/testContrast.js +233 -0
- package/src/testLang.js +575 -0
- package/src/testOrder.js +90 -0
- package/test/_template.test.js +21 -0
- package/test/arrayUtils.test.js +84 -0
- package/test/domUtils.test.js +147 -0
- package/test/generate-test-stubs.js +37 -0
- package/test/getAccessibleName.test.js +113 -0
- package/test/getAccessibleText.test.js +94 -0
- package/test/getAriaAttributesByElement.test.js +112 -0
- package/test/getCSSGeneratedContent.test.js +102 -0
- package/test/getComputedRole.test.js +180 -0
- package/test/getFocusableElements.test.js +134 -0
- package/test/getGeneratedContent.test.js +321 -0
- package/test/getImageText.test.js +21 -0
- package/test/getStyleObject.test.js +134 -0
- package/test/hasAccessibleName.test.js +59 -0
- package/test/hasAttribute.test.js +132 -0
- package/test/hasCSSGeneratedContent.test.js +143 -0
- package/test/hasHiddenParent.test.js +176 -0
- package/test/hasParent.test.js +266 -0
- package/test/hasValidAriaAttributes.test.js +79 -0
- package/test/hasValidAriaRole.test.js +98 -0
- package/test/isAriaAttributesValid.test.js +83 -0
- package/test/isComplexTable.test.js +363 -0
- package/test/isDataTable.test.js +948 -0
- package/test/isFocusable.test.js +182 -0
- package/test/isHidden.test.js +157 -0
- package/test/isOffScreen.test.js +249 -0
- package/test/isValidUrl.test.js +63 -0
- package/test/isVisible.test.js +104 -0
- package/test/setup.js +11 -0
- package/test/stringUtils.test.js +106 -0
- package/test/testContrast.test.js +77 -0
- package/test/testLang.test.js +21 -0
- package/test/testOrder.test.js +157 -0
- package/vitest.config.js +25 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
2
|
+
import { getStyleObject } from '../src/getStyleObject.js';
|
|
3
|
+
|
|
4
|
+
describe('getStyleObject', () => {
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
document.body.innerHTML = '';
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('should retrieve computed styles as an object with camelCased properties', () => {
|
|
10
|
+
// Arrange
|
|
11
|
+
const div = document.createElement('div');
|
|
12
|
+
div.style.color = 'red';
|
|
13
|
+
div.style.backgroundColor = 'blue';
|
|
14
|
+
div.style.fontSize = '16px';
|
|
15
|
+
document.body.appendChild(div);
|
|
16
|
+
|
|
17
|
+
// Mock the getComputedStyle to return predictable values
|
|
18
|
+
const originalGetComputedStyle = window.getComputedStyle;
|
|
19
|
+
window.getComputedStyle = vi.fn().mockImplementation(() => {
|
|
20
|
+
const styleObj = {
|
|
21
|
+
length: 3,
|
|
22
|
+
0: 'color',
|
|
23
|
+
1: 'background-color',
|
|
24
|
+
2: 'font-size',
|
|
25
|
+
getPropertyValue: (prop) => {
|
|
26
|
+
if (prop === 'color') return 'rgb(255, 0, 0)';
|
|
27
|
+
if (prop === 'background-color') return 'rgb(0, 0, 255)';
|
|
28
|
+
if (prop === 'font-size') return '16px';
|
|
29
|
+
return '';
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
return styleObj;
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Act
|
|
36
|
+
const result = getStyleObject(div);
|
|
37
|
+
|
|
38
|
+
// Clean up
|
|
39
|
+
window.getComputedStyle = originalGetComputedStyle;
|
|
40
|
+
|
|
41
|
+
// Assert
|
|
42
|
+
expect(result).toEqual({
|
|
43
|
+
color: 'rgb(255, 0, 0)',
|
|
44
|
+
backgroundColor: 'rgb(0, 0, 255)',
|
|
45
|
+
fontSize: '16px'
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should return false if getComputedStyle is not available', () => {
|
|
50
|
+
// Arrange
|
|
51
|
+
const div = document.createElement('div');
|
|
52
|
+
|
|
53
|
+
// Mock the absence of getComputedStyle
|
|
54
|
+
const originalGetComputedStyle = window.getComputedStyle;
|
|
55
|
+
window.getComputedStyle = undefined;
|
|
56
|
+
|
|
57
|
+
// Act
|
|
58
|
+
const result = getStyleObject(div);
|
|
59
|
+
|
|
60
|
+
// Clean up
|
|
61
|
+
window.getComputedStyle = originalGetComputedStyle;
|
|
62
|
+
|
|
63
|
+
// Assert
|
|
64
|
+
expect(result).toBe(false);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should return false if style object is empty', () => {
|
|
68
|
+
// Arrange
|
|
69
|
+
const div = document.createElement('div');
|
|
70
|
+
|
|
71
|
+
// Mock getComputedStyle to return an empty style object
|
|
72
|
+
const originalGetComputedStyle = window.getComputedStyle;
|
|
73
|
+
window.getComputedStyle = vi.fn().mockImplementation(() => {
|
|
74
|
+
return {
|
|
75
|
+
length: 0
|
|
76
|
+
};
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Act
|
|
80
|
+
const result = getStyleObject(div);
|
|
81
|
+
|
|
82
|
+
// Clean up
|
|
83
|
+
window.getComputedStyle = originalGetComputedStyle;
|
|
84
|
+
|
|
85
|
+
// Assert
|
|
86
|
+
expect(result).toBe(false);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should convert hyphenated CSS properties to camelCase', () => {
|
|
90
|
+
// Arrange
|
|
91
|
+
const div = document.createElement('div');
|
|
92
|
+
div.style.marginTop = '10px';
|
|
93
|
+
div.style.borderLeftWidth = '2px';
|
|
94
|
+
document.body.appendChild(div);
|
|
95
|
+
|
|
96
|
+
// Mock getComputedStyle with hyphenated properties
|
|
97
|
+
const originalGetComputedStyle = window.getComputedStyle;
|
|
98
|
+
window.getComputedStyle = vi.fn().mockImplementation(() => {
|
|
99
|
+
const styleObj = {
|
|
100
|
+
length: 2,
|
|
101
|
+
0: 'margin-top',
|
|
102
|
+
1: 'border-left-width',
|
|
103
|
+
getPropertyValue: (prop) => {
|
|
104
|
+
if (prop === 'margin-top') return '10px';
|
|
105
|
+
if (prop === 'border-left-width') return '2px';
|
|
106
|
+
return '';
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
return styleObj;
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Act
|
|
113
|
+
const result = getStyleObject(div);
|
|
114
|
+
|
|
115
|
+
// Clean up
|
|
116
|
+
window.getComputedStyle = originalGetComputedStyle;
|
|
117
|
+
|
|
118
|
+
// Assert
|
|
119
|
+
expect(result).toEqual({
|
|
120
|
+
marginTop: '10px',
|
|
121
|
+
borderLeftWidth: '2px'
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should return false for invalid DOM elements', () => {
|
|
126
|
+
// Arrange - test with various invalid inputs
|
|
127
|
+
const nonElements = [null, undefined, {}, 123, 'string', []];
|
|
128
|
+
|
|
129
|
+
// Act & Assert
|
|
130
|
+
nonElements.forEach(input => {
|
|
131
|
+
expect(getStyleObject(input)).toBe(false);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import hasAccessibleName from '../src/hasAccessibleName';
|
|
3
|
+
|
|
4
|
+
describe('hasAccessibleName', () => {
|
|
5
|
+
// Setup before each test
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
document.body.innerHTML = '';
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it('should return false for null or undefined elements', () => {
|
|
11
|
+
expect(hasAccessibleName(null)).toBe(false);
|
|
12
|
+
expect(hasAccessibleName(undefined)).toBe(false);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('should return true when element has aria-label', () => {
|
|
16
|
+
const element = document.createElement('div');
|
|
17
|
+
element.setAttribute('aria-label', 'Test Label');
|
|
18
|
+
document.body.appendChild(element);
|
|
19
|
+
|
|
20
|
+
expect(hasAccessibleName(element)).toBe(true);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should return true when element has aria-labelledby that references an existing element', () => {
|
|
24
|
+
const label = document.createElement('div');
|
|
25
|
+
label.id = 'test-label';
|
|
26
|
+
label.textContent = 'Test Label';
|
|
27
|
+
|
|
28
|
+
const element = document.createElement('div');
|
|
29
|
+
element.setAttribute('aria-labelledby', 'test-label');
|
|
30
|
+
|
|
31
|
+
document.body.appendChild(label);
|
|
32
|
+
document.body.appendChild(element);
|
|
33
|
+
|
|
34
|
+
expect(hasAccessibleName(element)).toBe(true);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should return false when element has no accessible name', () => {
|
|
38
|
+
const element = document.createElement('div');
|
|
39
|
+
document.body.appendChild(element);
|
|
40
|
+
|
|
41
|
+
expect(hasAccessibleName(element)).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should return true for img element with alt text', () => {
|
|
45
|
+
const element = document.createElement('img');
|
|
46
|
+
element.alt = 'Alt text description';
|
|
47
|
+
document.body.appendChild(element);
|
|
48
|
+
|
|
49
|
+
expect(hasAccessibleName(element)).toBe(true);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should return true for button with text content', () => {
|
|
53
|
+
const element = document.createElement('button');
|
|
54
|
+
element.textContent = 'Click me';
|
|
55
|
+
document.body.appendChild(element);
|
|
56
|
+
|
|
57
|
+
expect(hasAccessibleName(element)).toBe(true);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { hasAttribute } from '../src/hasAttribute.js';
|
|
3
|
+
|
|
4
|
+
describe('hasAttribute', () => {
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
document.body.innerHTML = '';
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('should return true when element has the specified attribute', () => {
|
|
10
|
+
// Arrange
|
|
11
|
+
const element = document.createElement('div');
|
|
12
|
+
element.setAttribute('data-test', 'value');
|
|
13
|
+
document.body.appendChild(element);
|
|
14
|
+
|
|
15
|
+
// Act
|
|
16
|
+
const result = hasAttribute('data-test', element);
|
|
17
|
+
|
|
18
|
+
// Assert
|
|
19
|
+
expect(result).toBe(true);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should return false when element does not have the specified attribute', () => {
|
|
23
|
+
// Arrange
|
|
24
|
+
const element = document.createElement('div');
|
|
25
|
+
document.body.appendChild(element);
|
|
26
|
+
|
|
27
|
+
// Act
|
|
28
|
+
const result = hasAttribute('data-test', element);
|
|
29
|
+
|
|
30
|
+
// Assert
|
|
31
|
+
expect(result).toBe(false);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should return true when attribute has empty string value', () => {
|
|
35
|
+
// Arrange
|
|
36
|
+
const element = document.createElement('div');
|
|
37
|
+
element.setAttribute('data-empty', '');
|
|
38
|
+
document.body.appendChild(element);
|
|
39
|
+
|
|
40
|
+
// Act
|
|
41
|
+
const result = hasAttribute('data-empty', element);
|
|
42
|
+
|
|
43
|
+
// Assert
|
|
44
|
+
expect(result).toBe(true); // Element has the attribute even if value is empty
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should return true for boolean attributes', () => {
|
|
48
|
+
// Arrange
|
|
49
|
+
const element = document.createElement('button');
|
|
50
|
+
element.setAttribute('disabled', '');
|
|
51
|
+
document.body.appendChild(element);
|
|
52
|
+
|
|
53
|
+
// Act
|
|
54
|
+
const result = hasAttribute('disabled', element);
|
|
55
|
+
|
|
56
|
+
// Assert
|
|
57
|
+
expect(result).toBe(true);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should return false if element is null or undefined', () => {
|
|
61
|
+
// Act & Assert
|
|
62
|
+
expect(hasAttribute('data-test', null)).toBe(false);
|
|
63
|
+
expect(hasAttribute('data-test', undefined)).toBe(false);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should return false if element is not a DOM element', () => {
|
|
67
|
+
// Arrange
|
|
68
|
+
const notElements = [{}, [], 123, 'string', () => {}];
|
|
69
|
+
|
|
70
|
+
// Act & Assert
|
|
71
|
+
notElements.forEach(item => {
|
|
72
|
+
expect(hasAttribute('data-test', item)).toBe(false);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should return false if attribute name is not a string', () => {
|
|
77
|
+
// Arrange
|
|
78
|
+
const element = document.createElement('div');
|
|
79
|
+
element.setAttribute('data-test', 'value');
|
|
80
|
+
document.body.appendChild(element);
|
|
81
|
+
|
|
82
|
+
const invalidAttributes = [null, undefined, 123, {}, [], () => {}];
|
|
83
|
+
|
|
84
|
+
// Act & Assert
|
|
85
|
+
invalidAttributes.forEach(attr => {
|
|
86
|
+
expect(hasAttribute(attr, element)).toBe(false);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should correctly identify attributes with various values', () => {
|
|
91
|
+
// Arrange
|
|
92
|
+
const element = document.createElement('div');
|
|
93
|
+
element.setAttribute('data-number', '123');
|
|
94
|
+
element.setAttribute('data-string', 'test');
|
|
95
|
+
element.setAttribute('data-boolean', 'true');
|
|
96
|
+
document.body.appendChild(element);
|
|
97
|
+
|
|
98
|
+
// Act & Assert
|
|
99
|
+
expect(hasAttribute('data-number', element)).toBe(true);
|
|
100
|
+
expect(hasAttribute('data-string', element)).toBe(true);
|
|
101
|
+
expect(hasAttribute('data-boolean', element)).toBe(true);
|
|
102
|
+
expect(hasAttribute('data-nonexistent', element)).toBe(false);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should handle case-insensitive attribute names', () => {
|
|
106
|
+
// Arrange
|
|
107
|
+
const element = document.createElement('div');
|
|
108
|
+
element.setAttribute('data-test', 'value');
|
|
109
|
+
document.body.appendChild(element);
|
|
110
|
+
|
|
111
|
+
// Act & Assert
|
|
112
|
+
expect(hasAttribute('data-test', element)).toBe(true);
|
|
113
|
+
expect(hasAttribute('DATA-TEST', element)).toBe(true); // Standard DOM hasAttribute is case-insensitive
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('should work with dynamically added and removed attributes', () => {
|
|
117
|
+
// Arrange
|
|
118
|
+
const element = document.createElement('div');
|
|
119
|
+
document.body.appendChild(element);
|
|
120
|
+
|
|
121
|
+
// Act & Assert - Initially doesn't have the attribute
|
|
122
|
+
expect(hasAttribute('data-dynamic', element)).toBe(false);
|
|
123
|
+
|
|
124
|
+
// Add attribute
|
|
125
|
+
element.setAttribute('data-dynamic', 'added');
|
|
126
|
+
expect(hasAttribute('data-dynamic', element)).toBe(true);
|
|
127
|
+
|
|
128
|
+
// Remove attribute
|
|
129
|
+
element.removeAttribute('data-dynamic');
|
|
130
|
+
expect(hasAttribute('data-dynamic', element)).toBe(false);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
2
|
+
import { hasCSSGeneratedContent } from '../src/hasCSSGeneratedContent.js';
|
|
3
|
+
import * as generatedContentModule from '../src/getGeneratedContent.js';
|
|
4
|
+
|
|
5
|
+
describe('hasCSSGeneratedContent', () => {
|
|
6
|
+
beforeEach(() => {
|
|
7
|
+
document.body.innerHTML = '';
|
|
8
|
+
// Remove any added stylesheets
|
|
9
|
+
const styleElements = document.querySelectorAll('style');
|
|
10
|
+
styleElements.forEach(style => style.remove());
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
// Helper function to create a stylesheet with CSS rules
|
|
14
|
+
const addStyleToDocument = (cssRules) => {
|
|
15
|
+
const styleElement = document.createElement('style');
|
|
16
|
+
styleElement.textContent = cssRules;
|
|
17
|
+
document.head.appendChild(styleElement);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
it('should return true for elements with text content', () => {
|
|
21
|
+
// Arrange
|
|
22
|
+
const element = document.createElement('div');
|
|
23
|
+
element.textContent = 'Text content';
|
|
24
|
+
document.body.appendChild(element);
|
|
25
|
+
|
|
26
|
+
// Act
|
|
27
|
+
const result = hasCSSGeneratedContent(element);
|
|
28
|
+
|
|
29
|
+
// Assert
|
|
30
|
+
expect(result).toBe(true);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should return false for elements with no content', () => {
|
|
34
|
+
// Arrange
|
|
35
|
+
const element = document.createElement('div');
|
|
36
|
+
document.body.appendChild(element);
|
|
37
|
+
|
|
38
|
+
// Act
|
|
39
|
+
const result = hasCSSGeneratedContent(element);
|
|
40
|
+
|
|
41
|
+
// Assert
|
|
42
|
+
expect(result).toBe(false);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('should return false for null or undefined elements', () => {
|
|
46
|
+
// Act & Assert
|
|
47
|
+
expect(hasCSSGeneratedContent(null)).toBe(false);
|
|
48
|
+
expect(hasCSSGeneratedContent(undefined)).toBe(false);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should return true for elements with whitespace-only text content', () => {
|
|
52
|
+
// Arrange
|
|
53
|
+
const element = document.createElement('div');
|
|
54
|
+
element.textContent = ' ';
|
|
55
|
+
document.body.appendChild(element);
|
|
56
|
+
|
|
57
|
+
// Act
|
|
58
|
+
const result = hasCSSGeneratedContent(element);
|
|
59
|
+
|
|
60
|
+
// Assert
|
|
61
|
+
expect(result).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// The following tests rely on proper implementation of getGeneratedContent
|
|
65
|
+
// and may need to be run in a real browser environment for CSS pseudo-elements
|
|
66
|
+
|
|
67
|
+
it('should correctly identify elements with ::before content', () => {
|
|
68
|
+
// Arrange
|
|
69
|
+
const element = document.createElement('div');
|
|
70
|
+
element.id = 'with-before';
|
|
71
|
+
document.body.appendChild(element);
|
|
72
|
+
|
|
73
|
+
// Mock getGeneratedContent to simulate browser behavior
|
|
74
|
+
const spy = vi.spyOn(generatedContentModule, 'getGeneratedContent');
|
|
75
|
+
spy.mockImplementation(() => 'Before content');
|
|
76
|
+
|
|
77
|
+
// Act
|
|
78
|
+
const result = hasCSSGeneratedContent(element);
|
|
79
|
+
|
|
80
|
+
// Assert
|
|
81
|
+
expect(result).toBe(true);
|
|
82
|
+
|
|
83
|
+
// Clean up
|
|
84
|
+
spy.mockRestore();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should correctly identify elements with ::after content', () => {
|
|
88
|
+
// Arrange
|
|
89
|
+
const element = document.createElement('div');
|
|
90
|
+
element.id = 'with-after';
|
|
91
|
+
document.body.appendChild(element);
|
|
92
|
+
|
|
93
|
+
// Mock getGeneratedContent to simulate browser behavior
|
|
94
|
+
const spy = vi.spyOn(generatedContentModule, 'getGeneratedContent');
|
|
95
|
+
spy.mockImplementation(() => 'After content');
|
|
96
|
+
|
|
97
|
+
// Act
|
|
98
|
+
const result = hasCSSGeneratedContent(element);
|
|
99
|
+
|
|
100
|
+
// Assert
|
|
101
|
+
expect(result).toBe(true);
|
|
102
|
+
|
|
103
|
+
// Clean up
|
|
104
|
+
spy.mockRestore();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should return false when getGeneratedContent returns false', () => {
|
|
108
|
+
// Arrange
|
|
109
|
+
const element = document.createElement('div');
|
|
110
|
+
|
|
111
|
+
// Mock getGeneratedContent to simulate no content
|
|
112
|
+
const spy = vi.spyOn(generatedContentModule, 'getGeneratedContent');
|
|
113
|
+
spy.mockImplementation(() => false);
|
|
114
|
+
|
|
115
|
+
// Act
|
|
116
|
+
const result = hasCSSGeneratedContent(element);
|
|
117
|
+
|
|
118
|
+
// Assert
|
|
119
|
+
expect(result).toBe(false);
|
|
120
|
+
|
|
121
|
+
// Clean up
|
|
122
|
+
spy.mockRestore();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('should handle complex cases with mixed content', () => {
|
|
126
|
+
// Arrange
|
|
127
|
+
const element = document.createElement('div');
|
|
128
|
+
element.textContent = 'Text';
|
|
129
|
+
|
|
130
|
+
// Mock getGeneratedContent to simulate mixed content
|
|
131
|
+
const spy = vi.spyOn(generatedContentModule, 'getGeneratedContent');
|
|
132
|
+
spy.mockImplementation(() => 'Before Text After');
|
|
133
|
+
|
|
134
|
+
// Act
|
|
135
|
+
const result = hasCSSGeneratedContent(element);
|
|
136
|
+
|
|
137
|
+
// Assert
|
|
138
|
+
expect(result).toBe(true);
|
|
139
|
+
|
|
140
|
+
// Clean up
|
|
141
|
+
spy.mockRestore();
|
|
142
|
+
});
|
|
143
|
+
});
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import hasHiddenParent from '../src/hasHiddenParent.js';
|
|
3
|
+
|
|
4
|
+
describe('hasHiddenParent', () => {
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
document.body.innerHTML = '';
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
it('should return false for an element with no hidden parents', () => {
|
|
10
|
+
// Arrange
|
|
11
|
+
const grandparent = document.createElement('div');
|
|
12
|
+
const parent = document.createElement('div');
|
|
13
|
+
const child = document.createElement('div');
|
|
14
|
+
|
|
15
|
+
grandparent.appendChild(parent);
|
|
16
|
+
parent.appendChild(child);
|
|
17
|
+
document.body.appendChild(grandparent);
|
|
18
|
+
|
|
19
|
+
// Act
|
|
20
|
+
const result = hasHiddenParent(child);
|
|
21
|
+
|
|
22
|
+
// Assert
|
|
23
|
+
expect(result).toBe(false);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should return true when immediate parent is hidden via display:none', () => {
|
|
27
|
+
// Arrange
|
|
28
|
+
const parent = document.createElement('div');
|
|
29
|
+
const child = document.createElement('div');
|
|
30
|
+
|
|
31
|
+
parent.style.display = 'none'; // Set parent to be hidden
|
|
32
|
+
parent.appendChild(child);
|
|
33
|
+
document.body.appendChild(parent);
|
|
34
|
+
|
|
35
|
+
// Act
|
|
36
|
+
const result = hasHiddenParent(child);
|
|
37
|
+
|
|
38
|
+
// Assert
|
|
39
|
+
expect(result).toBe(true);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should return true when immediate parent has hidden attribute', () => {
|
|
43
|
+
// Arrange
|
|
44
|
+
const parent = document.createElement('div');
|
|
45
|
+
const child = document.createElement('div');
|
|
46
|
+
|
|
47
|
+
parent.setAttribute('hidden', ''); // Set parent to be hidden
|
|
48
|
+
parent.appendChild(child);
|
|
49
|
+
document.body.appendChild(parent);
|
|
50
|
+
|
|
51
|
+
// Act
|
|
52
|
+
const result = hasHiddenParent(child);
|
|
53
|
+
|
|
54
|
+
// Assert
|
|
55
|
+
expect(result).toBe(true);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should return true when a grandparent is hidden', () => {
|
|
59
|
+
// Arrange
|
|
60
|
+
const grandparent = document.createElement('div');
|
|
61
|
+
const parent = document.createElement('div');
|
|
62
|
+
const child = document.createElement('div');
|
|
63
|
+
|
|
64
|
+
grandparent.style.display = 'none'; // Set grandparent to be hidden
|
|
65
|
+
grandparent.appendChild(parent);
|
|
66
|
+
parent.appendChild(child);
|
|
67
|
+
document.body.appendChild(grandparent);
|
|
68
|
+
|
|
69
|
+
// Act
|
|
70
|
+
const result = hasHiddenParent(child);
|
|
71
|
+
|
|
72
|
+
// Assert
|
|
73
|
+
expect(result).toBe(true);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should return true when great-grandparent is hidden', () => {
|
|
77
|
+
// Arrange
|
|
78
|
+
const greatGrandparent = document.createElement('div');
|
|
79
|
+
const grandparent = document.createElement('div');
|
|
80
|
+
const parent = document.createElement('div');
|
|
81
|
+
const child = document.createElement('div');
|
|
82
|
+
|
|
83
|
+
greatGrandparent.style.display = 'none'; // Set great-grandparent to be hidden
|
|
84
|
+
greatGrandparent.appendChild(grandparent);
|
|
85
|
+
grandparent.appendChild(parent);
|
|
86
|
+
parent.appendChild(child);
|
|
87
|
+
document.body.appendChild(greatGrandparent);
|
|
88
|
+
|
|
89
|
+
// Act
|
|
90
|
+
const result = hasHiddenParent(child);
|
|
91
|
+
|
|
92
|
+
// Assert
|
|
93
|
+
expect(result).toBe(true);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('should return false for elements without parents', () => {
|
|
97
|
+
// Arrange
|
|
98
|
+
const element = document.createElement('div');
|
|
99
|
+
|
|
100
|
+
// Act
|
|
101
|
+
const result = hasHiddenParent(element);
|
|
102
|
+
|
|
103
|
+
// Assert
|
|
104
|
+
expect(result).toBe(false);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should return false when element itself is hidden but parents are not', () => {
|
|
108
|
+
// Arrange
|
|
109
|
+
const parent = document.createElement('div');
|
|
110
|
+
const child = document.createElement('div');
|
|
111
|
+
|
|
112
|
+
child.style.display = 'none'; // Child is hidden, but we're testing parents
|
|
113
|
+
parent.appendChild(child);
|
|
114
|
+
document.body.appendChild(parent);
|
|
115
|
+
|
|
116
|
+
// Act
|
|
117
|
+
const result = hasHiddenParent(child);
|
|
118
|
+
|
|
119
|
+
// Assert
|
|
120
|
+
expect(result).toBe(false); // Function checks parents, not the element itself
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('should return false for null or undefined elements', () => {
|
|
124
|
+
// Act & Assert
|
|
125
|
+
expect(hasHiddenParent(null)).toBe(false);
|
|
126
|
+
expect(hasHiddenParent(undefined)).toBe(false);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('should return false for non-Element objects', () => {
|
|
130
|
+
// Arrange
|
|
131
|
+
const nonElements = [{}, [], 123, 'string', () => {}];
|
|
132
|
+
|
|
133
|
+
// Act & Assert
|
|
134
|
+
nonElements.forEach(item => {
|
|
135
|
+
expect(hasHiddenParent(item)).toBe(false);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should handle complex nested DOM structures', () => {
|
|
140
|
+
// Arrange
|
|
141
|
+
// Create a more complex DOM structure
|
|
142
|
+
const structure = `
|
|
143
|
+
<div id="root">
|
|
144
|
+
<div id="level1">
|
|
145
|
+
<div id="level2-1">
|
|
146
|
+
<div id="target1"></div>
|
|
147
|
+
</div>
|
|
148
|
+
<div id="level2-2" style="display:none">
|
|
149
|
+
<div id="level3-1">
|
|
150
|
+
<div id="target2"></div>
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
<div id="level2-3" hidden>
|
|
154
|
+
<div id="target3"></div>
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
</div>
|
|
158
|
+
`;
|
|
159
|
+
|
|
160
|
+
document.body.innerHTML = structure;
|
|
161
|
+
|
|
162
|
+
const target1 = document.getElementById('target1');
|
|
163
|
+
const target2 = document.getElementById('target2');
|
|
164
|
+
const target3 = document.getElementById('target3');
|
|
165
|
+
|
|
166
|
+
// Act
|
|
167
|
+
const result1 = hasHiddenParent(target1);
|
|
168
|
+
const result2 = hasHiddenParent(target2);
|
|
169
|
+
const result3 = hasHiddenParent(target3);
|
|
170
|
+
|
|
171
|
+
// Assert
|
|
172
|
+
expect(result1).toBe(false); // No hidden parents
|
|
173
|
+
expect(result2).toBe(true); // Has a hidden ancestor (level2-2)
|
|
174
|
+
expect(result3).toBe(true); // Has a hidden ancestor (level2-3)
|
|
175
|
+
});
|
|
176
|
+
});
|