@afixt/test-utils 1.3.0 → 2.0.1

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.
@@ -1,275 +1,268 @@
1
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
2
  import { isFocusable } from '../src/isFocusable.js';
3
3
 
4
4
  describe('isFocusable', () => {
5
- // Setup common mocking for all tests
6
- beforeEach(() => {
7
- document.body.innerHTML = '';
8
-
9
- // Mock the closest method for all tests since JSDOM doesn't support :hidden
10
- const originalClosest = Element.prototype.closest;
11
- Element.prototype.closest = vi.fn().mockImplementation(function(selector) {
12
- if (selector === ':hidden') return null; // By default, elements are not hidden
13
- return originalClosest.call(this, selector);
14
- });
15
- });
16
-
17
- // Clean up after each test
18
- afterEach(() => {
19
- vi.restoreAllMocks();
20
- });
21
-
22
- it('should return false for null or undefined elements', () => {
23
- // Assert
24
- expect(isFocusable(null)).toBe(false);
25
- expect(isFocusable(undefined)).toBe(false);
26
- });
27
-
28
- it('should return true for focusable input elements', () => {
29
- // Arrange
30
- const input = document.createElement('input');
31
- input.type = 'text';
32
- document.body.appendChild(input);
33
-
34
- // Act & Assert
35
- expect(isFocusable(input)).toBe(true);
36
- });
37
-
38
- it('should return false for disabled input elements', () => {
39
- // Arrange
40
- const input = document.createElement('input');
41
- input.type = 'text';
42
- input.disabled = true;
43
- document.body.appendChild(input);
44
-
45
- // Act & Assert
46
- expect(isFocusable(input)).toBe(false);
47
- });
48
-
49
- it('should return true for focusable button elements', () => {
50
- // Arrange
51
- const button = document.createElement('button');
52
- document.body.appendChild(button);
53
-
54
- // Act & Assert
55
- expect(isFocusable(button)).toBe(true);
56
- });
57
-
58
- it('should return false for disabled button elements', () => {
59
- // Arrange
60
- const button = document.createElement('button');
61
- button.disabled = true;
62
- document.body.appendChild(button);
63
-
64
- // Act & Assert
65
- expect(isFocusable(button)).toBe(false);
66
- });
67
-
68
- it('should return true for select elements', () => {
69
- // Arrange
70
- const select = document.createElement('select');
71
- document.body.appendChild(select);
72
-
73
- // Act & Assert
74
- expect(isFocusable(select)).toBe(true);
75
- });
76
-
77
- it('should return true for textarea elements', () => {
78
- // Arrange
79
- const textarea = document.createElement('textarea');
80
- document.body.appendChild(textarea);
81
-
82
- // Act & Assert
83
- expect(isFocusable(textarea)).toBe(true);
84
- });
85
-
86
- it('should return true for anchors with href attribute', () => {
87
- // Arrange
88
- const anchor = document.createElement('a');
89
- anchor.setAttribute('href', '#');
90
- document.body.appendChild(anchor);
91
-
92
- // Act & Assert
93
- expect(isFocusable(anchor)).toBe(true);
94
- });
95
-
96
- it('should return false for anchors without href attribute', () => {
97
- // Arrange
98
- const anchor = document.createElement('a');
99
- document.body.appendChild(anchor);
100
-
101
- // Act & Assert
102
- expect(isFocusable(anchor)).toBe(false);
103
- });
104
-
105
- it('should return true for area elements with href attribute', () => {
106
- // Arrange
107
- const map = document.createElement('map');
108
- const area = document.createElement('area');
109
- area.setAttribute('href', '#');
110
- map.appendChild(area);
111
- document.body.appendChild(map);
112
-
113
- // Act & Assert
114
- expect(isFocusable(area)).toBe(true);
115
- });
116
-
117
- it('should return false for area elements without href attribute', () => {
118
- // Arrange
119
- const map = document.createElement('map');
120
- const area = document.createElement('area');
121
- map.appendChild(area);
122
- document.body.appendChild(map);
123
-
124
- // Act & Assert
125
- expect(isFocusable(area)).toBe(false);
126
- });
127
-
128
- it('should return false for non-form elements with tabindex >= 0', () => {
129
- // Arrange
130
- const div = document.createElement('div');
131
- div.setAttribute('tabindex', '0');
132
- document.body.appendChild(div);
133
-
134
- // Act & Assert
135
- // According to the implementation, non-form elements with tabindex
136
- // are not considered focusable in this utility
137
- expect(isFocusable(div)).toBe(false);
138
- });
139
-
140
- it('should return false for elements with tabindex < 0', () => {
141
- // Arrange
142
- const div = document.createElement('div');
143
- div.setAttribute('tabindex', '-1');
144
- document.body.appendChild(div);
145
-
146
- // Act & Assert
147
- expect(isFocusable(div)).toBe(false);
148
- });
149
-
150
- it('should return false for regular divs without tabindex', () => {
151
- // Arrange
152
- const div = document.createElement('div');
153
- document.body.appendChild(div);
154
-
155
- // Act & Assert
156
- expect(isFocusable(div)).toBe(false);
157
- });
158
-
159
- it('should return false for hidden elements', () => {
160
- // Arrange
161
- const input = document.createElement('input');
162
- document.body.appendChild(input);
163
-
164
- // Override the mock to simulate a hidden element
165
- Element.prototype.closest = vi.fn().mockImplementation(function(selector) {
166
- if (selector === ':hidden') return this; // Element is hidden
167
- return null;
168
- });
169
-
170
- // Act & Assert
171
- expect(isFocusable(input)).toBe(false);
172
- });
173
-
174
- it('should return true for object elements', () => {
175
- // Arrange
176
- const object = document.createElement('object');
177
- document.body.appendChild(object);
178
-
179
- // Act & Assert
180
- expect(isFocusable(object)).toBe(true);
181
- });
182
-
183
- it('should return false for disabled object elements', () => {
184
- // Arrange
185
- const object = document.createElement('object');
186
- object.disabled = true;
187
- document.body.appendChild(object);
188
-
189
- // Act & Assert
190
- expect(isFocusable(object)).toBe(false);
191
- });
192
-
193
- it('should handle elements with tabindex="0" on form controls', () => {
194
- // Arrange
195
- const input = document.createElement('input');
196
- input.setAttribute('tabindex', '0');
197
- document.body.appendChild(input);
198
-
199
- // Act & Assert
200
- expect(isFocusable(input)).toBe(true);
201
- });
202
-
203
- it('should handle elements with positive tabindex on form controls', () => {
204
- // Arrange
205
- const button = document.createElement('button');
206
- button.setAttribute('tabindex', '1');
207
- document.body.appendChild(button);
208
-
209
- // Act & Assert
210
- expect(isFocusable(button)).toBe(true);
211
- });
212
-
213
- it('should return false for form controls with negative tabindex', () => {
214
- // Arrange
215
- const input = document.createElement('input');
216
- input.setAttribute('tabindex', '-1');
217
- document.body.appendChild(input);
218
-
219
- // Act & Assert
220
- expect(isFocusable(input)).toBe(false);
221
- });
222
-
223
- it('should return false for disabled select elements', () => {
224
- // Arrange
225
- const select = document.createElement('select');
226
- select.disabled = true;
227
- document.body.appendChild(select);
228
-
229
- // Act & Assert
230
- expect(isFocusable(select)).toBe(false);
231
- });
232
-
233
- it('should return false for disabled textarea elements', () => {
234
- // Arrange
235
- const textarea = document.createElement('textarea');
236
- textarea.disabled = true;
237
- document.body.appendChild(textarea);
238
-
239
- // Act & Assert
240
- expect(isFocusable(textarea)).toBe(false);
241
- });
242
-
243
- it('should handle anchors with tabindex >= 0 and href', () => {
244
- // Arrange
245
- const anchor = document.createElement('a');
246
- anchor.setAttribute('href', 'https://example.com');
247
- anchor.setAttribute('tabindex', '0');
248
- document.body.appendChild(anchor);
249
-
250
- // Act & Assert
251
- expect(isFocusable(anchor)).toBe(true);
252
- });
253
-
254
- it('should return false for anchors with negative tabindex even with href', () => {
255
- // Arrange
256
- const anchor = document.createElement('a');
257
- anchor.setAttribute('href', 'https://example.com');
258
- anchor.setAttribute('tabindex', '-1');
259
- document.body.appendChild(anchor);
260
-
261
- // Act & Assert
262
- expect(isFocusable(anchor)).toBe(false);
263
- });
264
-
265
- it('should return false for area with negative tabindex even with href', () => {
266
- // Arrange
267
- const area = document.createElement('area');
268
- area.setAttribute('href', '#map');
269
- area.setAttribute('tabindex', '-1');
270
- document.body.appendChild(area);
271
-
272
- // Act & Assert
273
- expect(isFocusable(area)).toBe(false);
274
- });
275
- });
5
+ beforeEach(() => {
6
+ document.body.innerHTML = '';
7
+ });
8
+
9
+ it('should return false for null or undefined elements', () => {
10
+ expect(isFocusable(null)).toBe(false);
11
+ expect(isFocusable(undefined)).toBe(false);
12
+ });
13
+
14
+ it('should return true for focusable input elements', () => {
15
+ const input = document.createElement('input');
16
+ input.type = 'text';
17
+ document.body.appendChild(input);
18
+
19
+ expect(isFocusable(input)).toBe(true);
20
+ });
21
+
22
+ it('should return false for disabled input elements', () => {
23
+ const input = document.createElement('input');
24
+ input.type = 'text';
25
+ input.disabled = true;
26
+ document.body.appendChild(input);
27
+
28
+ expect(isFocusable(input)).toBe(false);
29
+ });
30
+
31
+ it('should return true for focusable button elements', () => {
32
+ const button = document.createElement('button');
33
+ document.body.appendChild(button);
34
+
35
+ expect(isFocusable(button)).toBe(true);
36
+ });
37
+
38
+ it('should return false for disabled button elements', () => {
39
+ const button = document.createElement('button');
40
+ button.disabled = true;
41
+ document.body.appendChild(button);
42
+
43
+ expect(isFocusable(button)).toBe(false);
44
+ });
45
+
46
+ it('should return true for select elements', () => {
47
+ const select = document.createElement('select');
48
+ document.body.appendChild(select);
49
+
50
+ expect(isFocusable(select)).toBe(true);
51
+ });
52
+
53
+ it('should return true for textarea elements', () => {
54
+ const textarea = document.createElement('textarea');
55
+ document.body.appendChild(textarea);
56
+
57
+ expect(isFocusable(textarea)).toBe(true);
58
+ });
59
+
60
+ it('should return true for anchors with href attribute', () => {
61
+ const anchor = document.createElement('a');
62
+ anchor.setAttribute('href', '#');
63
+ document.body.appendChild(anchor);
64
+
65
+ expect(isFocusable(anchor)).toBe(true);
66
+ });
67
+
68
+ it('should return false for anchors without href attribute', () => {
69
+ const anchor = document.createElement('a');
70
+ document.body.appendChild(anchor);
71
+
72
+ expect(isFocusable(anchor)).toBe(false);
73
+ });
74
+
75
+ it('should return true for area elements with href attribute', () => {
76
+ const map = document.createElement('map');
77
+ const area = document.createElement('area');
78
+ area.setAttribute('href', '#');
79
+ map.appendChild(area);
80
+ document.body.appendChild(map);
81
+
82
+ expect(isFocusable(area)).toBe(true);
83
+ });
84
+
85
+ it('should return false for area elements without href attribute', () => {
86
+ const map = document.createElement('map');
87
+ const area = document.createElement('area');
88
+ map.appendChild(area);
89
+ document.body.appendChild(map);
90
+
91
+ expect(isFocusable(area)).toBe(false);
92
+ });
93
+
94
+ it('should return true for non-form elements with tabindex >= 0', () => {
95
+ const div = document.createElement('div');
96
+ div.setAttribute('tabindex', '0');
97
+ document.body.appendChild(div);
98
+
99
+ expect(isFocusable(div)).toBe(true);
100
+ });
101
+
102
+ it('should return true for span with tabindex="0"', () => {
103
+ const span = document.createElement('span');
104
+ span.setAttribute('tabindex', '0');
105
+ document.body.appendChild(span);
106
+
107
+ expect(isFocusable(span)).toBe(true);
108
+ });
109
+
110
+ it('should return false for elements with tabindex < 0 (not in tab order)', () => {
111
+ const div = document.createElement('div');
112
+ div.setAttribute('tabindex', '-1');
113
+ document.body.appendChild(div);
114
+
115
+ expect(isFocusable(div)).toBe(false);
116
+ });
117
+
118
+ it('should return false for regular divs without tabindex', () => {
119
+ const div = document.createElement('div');
120
+ document.body.appendChild(div);
121
+
122
+ expect(isFocusable(div)).toBe(false);
123
+ });
124
+
125
+ it('should return false for elements with hidden attribute', () => {
126
+ const input = document.createElement('input');
127
+ input.setAttribute('hidden', '');
128
+ document.body.appendChild(input);
129
+
130
+ expect(isFocusable(input)).toBe(false);
131
+ });
132
+
133
+ it('should return false for elements with display:none', () => {
134
+ const input = document.createElement('input');
135
+ input.style.display = 'none';
136
+ document.body.appendChild(input);
137
+
138
+ expect(isFocusable(input)).toBe(false);
139
+ });
140
+
141
+ it('should return false for elements inside a hidden ancestor', () => {
142
+ const wrapper = document.createElement('div');
143
+ wrapper.setAttribute('hidden', '');
144
+ const input = document.createElement('input');
145
+ wrapper.appendChild(input);
146
+ document.body.appendChild(wrapper);
147
+
148
+ expect(isFocusable(input)).toBe(false);
149
+ });
150
+
151
+ it('should return true for object elements', () => {
152
+ const object = document.createElement('object');
153
+ document.body.appendChild(object);
154
+
155
+ expect(isFocusable(object)).toBe(true);
156
+ });
157
+
158
+ it('should return false for disabled object elements', () => {
159
+ const object = document.createElement('object');
160
+ object.disabled = true;
161
+ document.body.appendChild(object);
162
+
163
+ expect(isFocusable(object)).toBe(false);
164
+ });
165
+
166
+ it('should handle elements with tabindex="0" on form controls', () => {
167
+ const input = document.createElement('input');
168
+ input.setAttribute('tabindex', '0');
169
+ document.body.appendChild(input);
170
+
171
+ expect(isFocusable(input)).toBe(true);
172
+ });
173
+
174
+ it('should handle elements with positive tabindex on form controls', () => {
175
+ const button = document.createElement('button');
176
+ button.setAttribute('tabindex', '1');
177
+ document.body.appendChild(button);
178
+
179
+ expect(isFocusable(button)).toBe(true);
180
+ });
181
+
182
+ it('should return false for form controls with negative tabindex', () => {
183
+ const input = document.createElement('input');
184
+ input.setAttribute('tabindex', '-1');
185
+ document.body.appendChild(input);
186
+
187
+ expect(isFocusable(input)).toBe(false);
188
+ });
189
+
190
+ it('should return false for disabled select elements', () => {
191
+ const select = document.createElement('select');
192
+ select.disabled = true;
193
+ document.body.appendChild(select);
194
+
195
+ expect(isFocusable(select)).toBe(false);
196
+ });
197
+
198
+ it('should return false for disabled textarea elements', () => {
199
+ const textarea = document.createElement('textarea');
200
+ textarea.disabled = true;
201
+ document.body.appendChild(textarea);
202
+
203
+ expect(isFocusable(textarea)).toBe(false);
204
+ });
205
+
206
+ it('should handle anchors with tabindex >= 0 and href', () => {
207
+ const anchor = document.createElement('a');
208
+ anchor.setAttribute('href', 'https://example.com');
209
+ anchor.setAttribute('tabindex', '0');
210
+ document.body.appendChild(anchor);
211
+
212
+ expect(isFocusable(anchor)).toBe(true);
213
+ });
214
+
215
+ it('should return false for anchors with negative tabindex even with href', () => {
216
+ const anchor = document.createElement('a');
217
+ anchor.setAttribute('href', 'https://example.com');
218
+ anchor.setAttribute('tabindex', '-1');
219
+ document.body.appendChild(anchor);
220
+
221
+ expect(isFocusable(anchor)).toBe(false);
222
+ });
223
+
224
+ it('should return false for area with negative tabindex even with href', () => {
225
+ const area = document.createElement('area');
226
+ area.setAttribute('href', '#map');
227
+ area.setAttribute('tabindex', '-1');
228
+ document.body.appendChild(area);
229
+
230
+ expect(isFocusable(area)).toBe(false);
231
+ });
232
+
233
+ it('should return true for contenteditable="true" elements', () => {
234
+ const div = document.createElement('div');
235
+ div.setAttribute('contenteditable', 'true');
236
+ document.body.appendChild(div);
237
+
238
+ expect(isFocusable(div)).toBe(true);
239
+ });
240
+
241
+ it('should return true for contenteditable="" elements', () => {
242
+ const div = document.createElement('div');
243
+ div.setAttribute('contenteditable', '');
244
+ document.body.appendChild(div);
245
+
246
+ expect(isFocusable(div)).toBe(true);
247
+ });
248
+
249
+ it('should return false for hidden contenteditable elements', () => {
250
+ const div = document.createElement('div');
251
+ div.setAttribute('contenteditable', 'true');
252
+ div.setAttribute('hidden', '');
253
+ document.body.appendChild(div);
254
+
255
+ expect(isFocusable(div)).toBe(false);
256
+ });
257
+
258
+ it('should return false for contenteditable inside hidden ancestor', () => {
259
+ const wrapper = document.createElement('div');
260
+ wrapper.style.display = 'none';
261
+ const div = document.createElement('div');
262
+ div.setAttribute('contenteditable', 'true');
263
+ wrapper.appendChild(div);
264
+ document.body.appendChild(wrapper);
265
+
266
+ expect(isFocusable(div)).toBe(false);
267
+ });
268
+ });