@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,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
+ });