@afixt/test-utils 1.1.8 → 1.2.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.
@@ -2,381 +2,647 @@ import { describe, it, expect } from 'vitest';
2
2
  import stringUtils from '../src/stringUtils.js';
3
3
 
4
4
  describe('stringUtils', () => {
5
- describe('isEmpty', () => {
6
- it('should return true for empty strings', () => {
7
- expect(stringUtils.isEmpty('')).toBe(true);
8
- expect(stringUtils.isEmpty(' ')).toBe(true);
9
- expect(stringUtils.isEmpty('\n\t')).toBe(true);
10
- });
5
+ describe('isEmpty', () => {
6
+ it('should return true for empty strings', () => {
7
+ expect(stringUtils.isEmpty('')).toBe(true);
8
+ expect(stringUtils.isEmpty(' ')).toBe(true);
9
+ expect(stringUtils.isEmpty('\n\t')).toBe(true);
10
+ });
11
+
12
+ it('should return true for null or undefined', () => {
13
+ expect(stringUtils.isEmpty(null)).toBe(true);
14
+ expect(stringUtils.isEmpty(undefined)).toBe(true);
15
+ });
16
+
17
+ it('should return false for non-empty strings', () => {
18
+ expect(stringUtils.isEmpty('hello')).toBe(false);
19
+ expect(stringUtils.isEmpty(' hello ')).toBe(false);
20
+ expect(stringUtils.isEmpty('0')).toBe(false);
21
+ });
22
+ });
23
+
24
+ describe('isString', () => {
25
+ it('should return true for string literals', () => {
26
+ expect(stringUtils.isString('')).toBe(true);
27
+ expect(stringUtils.isString('hello')).toBe(true);
28
+ });
29
+
30
+ it('should return true for String objects', () => {
31
+ expect(stringUtils.isString(new String('hello'))).toBe(true);
32
+ });
33
+
34
+ it('should return false for non-strings', () => {
35
+ expect(stringUtils.isString(123)).toBe(false);
36
+ expect(stringUtils.isString({})).toBe(false);
37
+ expect(stringUtils.isString([])).toBe(false);
38
+ expect(stringUtils.isString(null)).toBe(false);
39
+ expect(stringUtils.isString(undefined)).toBe(false);
40
+ });
41
+ });
42
+
43
+ describe('strlen', () => {
44
+ it('should return correct length for trimmed strings', () => {
45
+ expect(stringUtils.strlen('hello')).toBe(5);
46
+ expect(stringUtils.strlen(' hello ')).toBe(5);
47
+ });
48
+
49
+ it('should return 0 for empty strings', () => {
50
+ expect(stringUtils.strlen('')).toBe(0);
51
+ expect(stringUtils.strlen(' ')).toBe(0);
52
+ });
53
+
54
+ it('should return 0 for non-strings', () => {
55
+ expect(stringUtils.strlen(null)).toBe(0);
56
+ expect(stringUtils.strlen(undefined)).toBe(0);
57
+ expect(stringUtils.strlen(123)).toBe(0);
58
+ });
59
+ });
60
+
61
+ describe('isNormalInteger', () => {
62
+ it('should return true for valid integer strings', () => {
63
+ expect(stringUtils.isNormalInteger('0')).toBe(true);
64
+ expect(stringUtils.isNormalInteger('1')).toBe(true);
65
+ expect(stringUtils.isNormalInteger('123')).toBe(true);
66
+ });
67
+
68
+ it('should return false for non-integer strings', () => {
69
+ expect(stringUtils.isNormalInteger('1.5')).toBe(false);
70
+ expect(stringUtils.isNormalInteger('-1')).toBe(false);
71
+ expect(stringUtils.isNormalInteger('abc')).toBe(false);
72
+ expect(stringUtils.isNormalInteger('')).toBe(false);
73
+ });
74
+ });
75
+
76
+ describe('isUpperCase', () => {
77
+ it('should return true for uppercase strings', () => {
78
+ expect(stringUtils.isUpperCase('HELLO')).toBe(true);
79
+ expect(stringUtils.isUpperCase('HELLO WORLD')).toBe(true);
80
+ expect(stringUtils.isUpperCase('HELLO123')).toBe(true);
81
+ expect(stringUtils.isUpperCase('HELLO!')).toBe(true);
82
+ });
83
+
84
+ it('should return false for strings with lowercase characters', () => {
85
+ expect(stringUtils.isUpperCase('Hello')).toBe(false);
86
+ expect(stringUtils.isUpperCase('HELLO world')).toBe(false);
87
+ });
88
+
89
+ it('should handle edge cases', () => {
90
+ expect(stringUtils.isUpperCase('')).toBe(true); // Empty string has no lowercase letters
91
+ expect(stringUtils.isUpperCase('123')).toBe(true); // Numbers only
92
+ expect(stringUtils.isUpperCase('!@#')).toBe(true); // Symbols only
93
+ expect(stringUtils.isUpperCase(undefined)).toBe(false);
94
+ });
95
+ });
96
+
97
+ describe('isAlphaNumeric', () => {
98
+ it('should return true for strings containing only alphanumeric characters', () => {
99
+ expect(stringUtils.isAlphaNumeric('abc123')).toBe(true);
100
+ expect(stringUtils.isAlphaNumeric('ABC')).toBe(true);
101
+ expect(stringUtils.isAlphaNumeric('123')).toBe(true);
102
+ expect(stringUtils.isAlphaNumeric('Test123')).toBe(true);
103
+ expect(stringUtils.isAlphaNumeric('a')).toBe(true);
104
+ expect(stringUtils.isAlphaNumeric('1')).toBe(true);
105
+ });
106
+
107
+ it('should return false for strings containing non-alphanumeric characters', () => {
108
+ expect(stringUtils.isAlphaNumeric('abc 123')).toBe(false); // space
109
+ expect(stringUtils.isAlphaNumeric('abc-123')).toBe(false); // hyphen
110
+ expect(stringUtils.isAlphaNumeric('abc_123')).toBe(false); // underscore
111
+ expect(stringUtils.isAlphaNumeric('abc@123')).toBe(false); // special character
112
+ expect(stringUtils.isAlphaNumeric('abc.123')).toBe(false); // period
113
+ expect(stringUtils.isAlphaNumeric('abc!123')).toBe(false); // exclamation
114
+ expect(stringUtils.isAlphaNumeric('')).toBe(false); // empty string
115
+ });
116
+
117
+ it('should return false for special edge cases', () => {
118
+ expect(stringUtils.isAlphaNumeric('\n')).toBe(false); // newline
119
+ expect(stringUtils.isAlphaNumeric('\t')).toBe(false); // tab
120
+ expect(stringUtils.isAlphaNumeric(' ')).toBe(false); // whitespace
121
+ });
122
+ });
123
+
124
+ describe('getPathFromUrl', () => {
125
+ it('should extract the pathname correctly', () => {
126
+ expect(stringUtils.getPathFromUrl('https://example.com/path/to/resource')).toBe(
127
+ '/path/to/resource'
128
+ );
129
+ expect(stringUtils.getPathFromUrl('https://example.com/')).toBe('/');
130
+ expect(stringUtils.getPathFromUrl('https://example.com/path?query=string')).toBe(
131
+ '/path'
132
+ );
133
+ });
134
+
135
+ it('should handle complex URLs', () => {
136
+ expect(
137
+ stringUtils.getPathFromUrl('https://subdomain.example.com/path/to/resource')
138
+ ).toBe('/path/to/resource');
139
+ expect(stringUtils.getPathFromUrl('http://example.com/path/to/resource#hash')).toBe(
140
+ '/path/to/resource'
141
+ );
142
+ expect(stringUtils.getPathFromUrl('https://example.com:8080/path')).toBe('/path');
143
+ });
144
+
145
+ it('should handle URLs with encoded characters', () => {
146
+ expect(stringUtils.getPathFromUrl('https://example.com/path%20with%20spaces')).toBe(
147
+ '/path%20with%20spaces'
148
+ );
149
+ expect(
150
+ stringUtils.getPathFromUrl('https://example.com/path/with/special%20chars')
151
+ ).toBe('/path/with/special%20chars');
152
+ });
153
+ });
154
+
155
+ describe('getAllText', () => {
156
+ it('should extract text from simple text nodes', () => {
157
+ const div = document.createElement('div');
158
+ div.textContent = 'Hello World';
159
+
160
+ expect(stringUtils.getAllText(div)).toBe('Hello World');
161
+ });
162
+
163
+ it('should extract text from nested elements', () => {
164
+ const div = document.createElement('div');
165
+ const span = document.createElement('span');
166
+ span.textContent = 'Hello';
167
+ const text = document.createTextNode(' World');
168
+
169
+ div.appendChild(span);
170
+ div.appendChild(text);
171
+
172
+ expect(stringUtils.getAllText(div)).toBe('Hello World');
173
+ });
174
+
175
+ it('should extract aria-label attributes', () => {
176
+ const div = document.createElement('div');
177
+ const button = document.createElement('button');
178
+ button.setAttribute('aria-label', 'Close dialog');
179
+ button.textContent = 'X';
180
+
181
+ div.appendChild(button);
182
+
183
+ const result = stringUtils.getAllText(div);
184
+ expect(result).toContain('Close dialog');
185
+ expect(result).toContain('X');
186
+ });
187
+
188
+ it('should extract alt attributes from images', () => {
189
+ const div = document.createElement('div');
190
+ const img = document.createElement('img');
191
+ img.setAttribute('alt', 'Profile picture');
192
+ img.setAttribute('src', 'profile.jpg');
193
+
194
+ div.appendChild(img);
195
+
196
+ expect(stringUtils.getAllText(div)).toBe('Profile picture');
197
+ });
198
+
199
+ it('should handle mixed content with text, aria-labels, and alt text', () => {
200
+ const div = document.createElement('div');
201
+
202
+ // Add some text
203
+ const textNode = document.createTextNode('Welcome ');
204
+ div.appendChild(textNode);
205
+
206
+ // Add element with aria-label
207
+ const button = document.createElement('button');
208
+ button.setAttribute('aria-label', 'Help');
209
+ button.textContent = '?';
210
+ div.appendChild(button);
211
+
212
+ // Add some more text
213
+ const moreText = document.createTextNode(' to our site ');
214
+ div.appendChild(moreText);
215
+
216
+ // Add image with alt text
217
+ const img = document.createElement('img');
218
+ img.setAttribute('alt', 'Company logo');
219
+ div.appendChild(img);
220
+
221
+ const result = stringUtils.getAllText(div);
222
+ expect(result).toContain('Welcome');
223
+ expect(result).toContain('Help');
224
+ expect(result).toContain('?');
225
+ expect(result).toContain('to our site');
226
+ expect(result).toContain('Company logo');
227
+ });
228
+
229
+ it('should handle empty elements', () => {
230
+ const div = document.createElement('div');
231
+ expect(stringUtils.getAllText(div)).toBe('');
232
+ });
233
+
234
+ it('should trim whitespace from text nodes', () => {
235
+ const div = document.createElement('div');
236
+ const textNode = document.createTextNode(' Hello World ');
237
+ div.appendChild(textNode);
238
+
239
+ expect(stringUtils.getAllText(div)).toBe('Hello World');
240
+ });
11
241
 
12
- it('should return true for null or undefined', () => {
13
- expect(stringUtils.isEmpty(null)).toBe(true);
14
- expect(stringUtils.isEmpty(undefined)).toBe(true);
15
- });
242
+ it('should handle elements with only whitespace', () => {
243
+ const div = document.createElement('div');
244
+ const textNode = document.createTextNode(' ');
245
+ div.appendChild(textNode);
16
246
 
17
- it('should return false for non-empty strings', () => {
18
- expect(stringUtils.isEmpty('hello')).toBe(false);
19
- expect(stringUtils.isEmpty(' hello ')).toBe(false);
20
- expect(stringUtils.isEmpty('0')).toBe(false);
21
- });
22
- });
247
+ // Should use textContent.trim() as fallback for empty text
248
+ expect(stringUtils.getAllText(div)).toBe('');
249
+ });
23
250
 
24
- describe('isString', () => {
25
- it('should return true for string literals', () => {
26
- expect(stringUtils.isString('')).toBe(true);
27
- expect(stringUtils.isString('hello')).toBe(true);
28
- });
251
+ it('should handle deeply nested structures', () => {
252
+ const div = document.createElement('div');
253
+ const section = document.createElement('section');
254
+ const article = document.createElement('article');
255
+ const p = document.createElement('p');
29
256
 
30
- it('should return true for String objects', () => {
31
- expect(stringUtils.isString(new String('hello'))).toBe(true);
32
- });
33
-
34
- it('should return false for non-strings', () => {
35
- expect(stringUtils.isString(123)).toBe(false);
36
- expect(stringUtils.isString({})).toBe(false);
37
- expect(stringUtils.isString([])).toBe(false);
38
- expect(stringUtils.isString(null)).toBe(false);
39
- expect(stringUtils.isString(undefined)).toBe(false);
40
- });
41
- });
42
-
43
- describe('strlen', () => {
44
- it('should return correct length for trimmed strings', () => {
45
- expect(stringUtils.strlen('hello')).toBe(5);
46
- expect(stringUtils.strlen(' hello ')).toBe(5);
47
- });
48
-
49
- it('should return 0 for empty strings', () => {
50
- expect(stringUtils.strlen('')).toBe(0);
51
- expect(stringUtils.strlen(' ')).toBe(0);
52
- });
53
-
54
- it('should return 0 for non-strings', () => {
55
- expect(stringUtils.strlen(null)).toBe(0);
56
- expect(stringUtils.strlen(undefined)).toBe(0);
57
- expect(stringUtils.strlen(123)).toBe(0);
58
- });
59
- });
60
-
61
- describe('isNormalInteger', () => {
62
- it('should return true for valid integer strings', () => {
63
- expect(stringUtils.isNormalInteger('0')).toBe(true);
64
- expect(stringUtils.isNormalInteger('1')).toBe(true);
65
- expect(stringUtils.isNormalInteger('123')).toBe(true);
66
- });
67
-
68
- it('should return false for non-integer strings', () => {
69
- expect(stringUtils.isNormalInteger('1.5')).toBe(false);
70
- expect(stringUtils.isNormalInteger('-1')).toBe(false);
71
- expect(stringUtils.isNormalInteger('abc')).toBe(false);
72
- expect(stringUtils.isNormalInteger('')).toBe(false);
73
- });
74
- });
75
-
76
- describe('isUpperCase', () => {
77
- it('should return true for uppercase strings', () => {
78
- expect(stringUtils.isUpperCase('HELLO')).toBe(true);
79
- expect(stringUtils.isUpperCase('HELLO WORLD')).toBe(true);
80
- expect(stringUtils.isUpperCase('HELLO123')).toBe(true);
81
- expect(stringUtils.isUpperCase('HELLO!')).toBe(true);
82
- });
83
-
84
- it('should return false for strings with lowercase characters', () => {
85
- expect(stringUtils.isUpperCase('Hello')).toBe(false);
86
- expect(stringUtils.isUpperCase('HELLO world')).toBe(false);
87
- });
88
-
89
- it('should handle edge cases', () => {
90
- expect(stringUtils.isUpperCase('')).toBe(true); // Empty string has no lowercase letters
91
- expect(stringUtils.isUpperCase('123')).toBe(true); // Numbers only
92
- expect(stringUtils.isUpperCase('!@#')).toBe(true); // Symbols only
93
- expect(stringUtils.isUpperCase(undefined)).toBe(false);
94
- });
95
- });
96
-
97
- describe('isAlphaNumeric', () => {
98
- it('should return true for strings containing only alphanumeric characters', () => {
99
- expect(stringUtils.isAlphaNumeric('abc123')).toBe(true);
100
- expect(stringUtils.isAlphaNumeric('ABC')).toBe(true);
101
- expect(stringUtils.isAlphaNumeric('123')).toBe(true);
102
- expect(stringUtils.isAlphaNumeric('Test123')).toBe(true);
103
- expect(stringUtils.isAlphaNumeric('a')).toBe(true);
104
- expect(stringUtils.isAlphaNumeric('1')).toBe(true);
105
- });
106
-
107
- it('should return false for strings containing non-alphanumeric characters', () => {
108
- expect(stringUtils.isAlphaNumeric('abc 123')).toBe(false); // space
109
- expect(stringUtils.isAlphaNumeric('abc-123')).toBe(false); // hyphen
110
- expect(stringUtils.isAlphaNumeric('abc_123')).toBe(false); // underscore
111
- expect(stringUtils.isAlphaNumeric('abc@123')).toBe(false); // special character
112
- expect(stringUtils.isAlphaNumeric('abc.123')).toBe(false); // period
113
- expect(stringUtils.isAlphaNumeric('abc!123')).toBe(false); // exclamation
114
- expect(stringUtils.isAlphaNumeric('')).toBe(false); // empty string
115
- });
257
+ p.textContent = 'Deep content';
258
+ article.appendChild(p);
259
+ section.appendChild(article);
260
+ div.appendChild(section);
116
261
 
117
- it('should return false for special edge cases', () => {
118
- expect(stringUtils.isAlphaNumeric('\n')).toBe(false); // newline
119
- expect(stringUtils.isAlphaNumeric('\t')).toBe(false); // tab
120
- expect(stringUtils.isAlphaNumeric(' ')).toBe(false); // whitespace
121
- });
122
- });
262
+ expect(stringUtils.getAllText(div)).toBe('Deep content');
263
+ });
123
264
 
124
- describe('getPathFromUrl', () => {
125
- it('should extract the pathname correctly', () => {
126
- expect(stringUtils.getPathFromUrl('https://example.com/path/to/resource')).toBe('/path/to/resource');
127
- expect(stringUtils.getPathFromUrl('https://example.com/')).toBe('/');
128
- expect(stringUtils.getPathFromUrl('https://example.com/path?query=string')).toBe('/path');
129
- });
265
+ it('should handle images without alt attributes', () => {
266
+ const div = document.createElement('div');
267
+ const img = document.createElement('img');
268
+ img.setAttribute('src', 'image.jpg');
269
+ // No alt attribute
130
270
 
131
- it('should handle complex URLs', () => {
132
- expect(stringUtils.getPathFromUrl('https://subdomain.example.com/path/to/resource')).toBe('/path/to/resource');
133
- expect(stringUtils.getPathFromUrl('http://example.com/path/to/resource#hash')).toBe('/path/to/resource');
134
- expect(stringUtils.getPathFromUrl('https://example.com:8080/path')).toBe('/path');
135
- });
271
+ const text = document.createTextNode('Some text');
272
+ div.appendChild(text);
273
+ div.appendChild(img);
136
274
 
137
- it('should handle URLs with encoded characters', () => {
138
- expect(stringUtils.getPathFromUrl('https://example.com/path%20with%20spaces')).toBe('/path%20with%20spaces');
139
- expect(stringUtils.getPathFromUrl('https://example.com/path/with/special%20chars')).toBe('/path/with/special%20chars');
140
- });
141
- });
142
-
143
- describe('getAllText', () => {
144
- it('should extract text from simple text nodes', () => {
145
- const div = document.createElement('div');
146
- div.textContent = 'Hello World';
147
-
148
- expect(stringUtils.getAllText(div)).toBe('Hello World');
149
- });
275
+ expect(stringUtils.getAllText(div)).toBe('Some text');
276
+ });
150
277
 
151
- it('should extract text from nested elements', () => {
152
- const div = document.createElement('div');
153
- const span = document.createElement('span');
154
- span.textContent = 'Hello';
155
- const text = document.createTextNode(' World');
156
-
157
- div.appendChild(span);
158
- div.appendChild(text);
159
-
160
- expect(stringUtils.getAllText(div)).toBe('Hello World');
161
- });
278
+ it('should handle elements without aria-label', () => {
279
+ const div = document.createElement('div');
280
+ const button = document.createElement('button');
281
+ button.textContent = 'Click me';
282
+ // No aria-label attribute
162
283
 
163
- it('should extract aria-label attributes', () => {
164
- const div = document.createElement('div');
165
- const button = document.createElement('button');
166
- button.setAttribute('aria-label', 'Close dialog');
167
- button.textContent = 'X';
168
-
169
- div.appendChild(button);
170
-
171
- const result = stringUtils.getAllText(div);
172
- expect(result).toContain('Close dialog');
173
- expect(result).toContain('X');
174
- });
284
+ div.appendChild(button);
175
285
 
176
- it('should extract alt attributes from images', () => {
177
- const div = document.createElement('div');
178
- const img = document.createElement('img');
179
- img.setAttribute('alt', 'Profile picture');
180
- img.setAttribute('src', 'profile.jpg');
181
-
182
- div.appendChild(img);
183
-
184
- expect(stringUtils.getAllText(div)).toBe('Profile picture');
286
+ expect(stringUtils.getAllText(div)).toBe('Click me');
287
+ });
185
288
  });
186
289
 
187
- it('should handle mixed content with text, aria-labels, and alt text', () => {
188
- const div = document.createElement('div');
189
-
190
- // Add some text
191
- const textNode = document.createTextNode('Welcome ');
192
- div.appendChild(textNode);
193
-
194
- // Add element with aria-label
195
- const button = document.createElement('button');
196
- button.setAttribute('aria-label', 'Help');
197
- button.textContent = '?';
198
- div.appendChild(button);
199
-
200
- // Add some more text
201
- const moreText = document.createTextNode(' to our site ');
202
- div.appendChild(moreText);
203
-
204
- // Add image with alt text
205
- const img = document.createElement('img');
206
- img.setAttribute('alt', 'Company logo');
207
- div.appendChild(img);
208
-
209
- const result = stringUtils.getAllText(div);
210
- expect(result).toContain('Welcome');
211
- expect(result).toContain('Help');
212
- expect(result).toContain('?');
213
- expect(result).toContain('to our site');
214
- expect(result).toContain('Company logo');
215
- });
290
+ describe('hasText', () => {
291
+ it('should return true for elements with text content', () => {
292
+ const div = document.createElement('div');
293
+ div.textContent = 'Hello World';
216
294
 
217
- it('should handle empty elements', () => {
218
- const div = document.createElement('div');
219
- expect(stringUtils.getAllText(div)).toBe('');
220
- });
295
+ expect(stringUtils.hasText(div)).toBe(true);
296
+ });
221
297
 
222
- it('should trim whitespace from text nodes', () => {
223
- const div = document.createElement('div');
224
- const textNode = document.createTextNode(' Hello World ');
225
- div.appendChild(textNode);
226
-
227
- expect(stringUtils.getAllText(div)).toBe('Hello World');
228
- });
298
+ it('should return false for empty elements', () => {
299
+ const div = document.createElement('div');
229
300
 
230
- it('should handle elements with only whitespace', () => {
231
- const div = document.createElement('div');
232
- const textNode = document.createTextNode(' ');
233
- div.appendChild(textNode);
234
-
235
- // Should use textContent.trim() as fallback for empty text
236
- expect(stringUtils.getAllText(div)).toBe('');
237
- });
301
+ expect(stringUtils.hasText(div)).toBe(false);
302
+ });
238
303
 
239
- it('should handle deeply nested structures', () => {
240
- const div = document.createElement('div');
241
- const section = document.createElement('section');
242
- const article = document.createElement('article');
243
- const p = document.createElement('p');
244
-
245
- p.textContent = 'Deep content';
246
- article.appendChild(p);
247
- section.appendChild(article);
248
- div.appendChild(section);
249
-
250
- expect(stringUtils.getAllText(div)).toBe('Deep content');
251
- });
304
+ it('should return false for elements with only whitespace', () => {
305
+ const div = document.createElement('div');
306
+ div.textContent = ' \n\t ';
252
307
 
253
- it('should handle images without alt attributes', () => {
254
- const div = document.createElement('div');
255
- const img = document.createElement('img');
256
- img.setAttribute('src', 'image.jpg');
257
- // No alt attribute
258
-
259
- const text = document.createTextNode('Some text');
260
- div.appendChild(text);
261
- div.appendChild(img);
262
-
263
- expect(stringUtils.getAllText(div)).toBe('Some text');
264
- });
308
+ expect(stringUtils.hasText(div)).toBe(false);
309
+ });
265
310
 
266
- it('should handle elements without aria-label', () => {
267
- const div = document.createElement('div');
268
- const button = document.createElement('button');
269
- button.textContent = 'Click me';
270
- // No aria-label attribute
271
-
272
- div.appendChild(button);
273
-
274
- expect(stringUtils.getAllText(div)).toBe('Click me');
275
- });
276
- });
277
-
278
- describe('hasText', () => {
279
- it('should return true for elements with text content', () => {
280
- const div = document.createElement('div');
281
- div.textContent = 'Hello World';
282
-
283
- expect(stringUtils.hasText(div)).toBe(true);
284
- });
311
+ it('should return true for elements with aria-label', () => {
312
+ const div = document.createElement('div');
313
+ const button = document.createElement('button');
314
+ button.setAttribute('aria-label', 'Close');
285
315
 
286
- it('should return false for empty elements', () => {
287
- const div = document.createElement('div');
288
-
289
- expect(stringUtils.hasText(div)).toBe(false);
290
- });
316
+ div.appendChild(button);
291
317
 
292
- it('should return false for elements with only whitespace', () => {
293
- const div = document.createElement('div');
294
- div.textContent = ' \n\t ';
295
-
296
- expect(stringUtils.hasText(div)).toBe(false);
297
- });
318
+ expect(stringUtils.hasText(div)).toBe(true);
319
+ });
298
320
 
299
- it('should return true for elements with aria-label', () => {
300
- const div = document.createElement('div');
301
- const button = document.createElement('button');
302
- button.setAttribute('aria-label', 'Close');
303
-
304
- div.appendChild(button);
305
-
306
- expect(stringUtils.hasText(div)).toBe(true);
307
- });
321
+ it('should return true for elements with image alt text', () => {
322
+ const div = document.createElement('div');
323
+ const img = document.createElement('img');
324
+ img.setAttribute('alt', 'Profile picture');
308
325
 
309
- it('should return true for elements with image alt text', () => {
310
- const div = document.createElement('div');
311
- const img = document.createElement('img');
312
- img.setAttribute('alt', 'Profile picture');
313
-
314
- div.appendChild(img);
315
-
316
- expect(stringUtils.hasText(div)).toBe(true);
317
- });
326
+ div.appendChild(img);
318
327
 
319
- it('should return true for nested elements with text', () => {
320
- const div = document.createElement('div');
321
- const span = document.createElement('span');
322
- span.textContent = 'Nested text';
323
-
324
- div.appendChild(span);
325
-
326
- expect(stringUtils.hasText(div)).toBe(true);
327
- });
328
+ expect(stringUtils.hasText(div)).toBe(true);
329
+ });
328
330
 
329
- it('should return false for elements with empty nested structure', () => {
330
- const div = document.createElement('div');
331
- const span = document.createElement('span');
332
- const p = document.createElement('p');
331
+ it('should return true for nested elements with text', () => {
332
+ const div = document.createElement('div');
333
+ const span = document.createElement('span');
334
+ span.textContent = 'Nested text';
333
335
 
334
- div.appendChild(span);
335
- span.appendChild(p);
336
+ div.appendChild(span);
336
337
 
337
- expect(stringUtils.hasText(div)).toBe(false);
338
- });
339
- });
338
+ expect(stringUtils.hasText(div)).toBe(true);
339
+ });
340
340
 
341
- describe('getAllText edge cases', () => {
342
- it('should handle text nodes with empty nodeValue but non-empty textContent', () => {
343
- const div = document.createElement('div');
344
- const textNode = document.createTextNode(' ');
345
- div.appendChild(textNode);
341
+ it('should return false for elements with empty nested structure', () => {
342
+ const div = document.createElement('div');
343
+ const span = document.createElement('span');
344
+ const p = document.createElement('p');
346
345
 
347
- // This tests the else branch where nodeValue.trim() is empty
348
- const result = stringUtils.getAllText(div);
349
- expect(typeof result).toBe('string');
350
- });
346
+ div.appendChild(span);
347
+ span.appendChild(p);
351
348
 
352
- it('should handle mixed content with whitespace text nodes', () => {
353
- const div = document.createElement('div');
354
- div.innerHTML = ' <span>Text</span> ';
349
+ expect(stringUtils.hasText(div)).toBe(false);
350
+ });
355
351
 
356
- const result = stringUtils.getAllText(div);
357
- expect(result).toContain('Text');
358
- });
352
+ it('should return true for input elements with a value', () => {
353
+ const input = document.createElement('input');
354
+ input.type = 'text';
355
+ input.value = 'Some input text';
359
356
 
360
- it('should handle elements with both aria-label and text content', () => {
361
- const div = document.createElement('div');
362
- const button = document.createElement('button');
363
- button.textContent = 'Visual Text';
364
- button.setAttribute('aria-label', 'Accessible Label');
365
- div.appendChild(button);
357
+ expect(stringUtils.hasText(input)).toBe(true);
358
+ });
366
359
 
367
- const result = stringUtils.getAllText(div);
368
- expect(result).toContain('Accessible Label');
369
- expect(result).toContain('Visual Text');
370
- });
360
+ it('should return false for input elements with empty value', () => {
361
+ const input = document.createElement('input');
362
+ input.type = 'text';
363
+ input.value = '';
371
364
 
372
- it('should handle img without alt attribute', () => {
373
- const div = document.createElement('div');
374
- const img = document.createElement('img');
375
- // No alt attribute
376
- div.appendChild(img);
365
+ expect(stringUtils.hasText(input)).toBe(false);
366
+ });
367
+
368
+ it('should return true for textarea elements with a value', () => {
369
+ const textarea = document.createElement('textarea');
370
+ textarea.value = 'Some textarea text';
371
+
372
+ expect(stringUtils.hasText(textarea)).toBe(true);
373
+ });
377
374
 
378
- const result = stringUtils.getAllText(div);
379
- expect(typeof result).toBe('string');
380
- });
381
- });
382
- });
375
+ it('should return true for select elements with selected option text', () => {
376
+ const select = document.createElement('select');
377
+ const option = document.createElement('option');
378
+ option.textContent = 'Option 1';
379
+ select.appendChild(option);
380
+
381
+ expect(stringUtils.hasText(select)).toBe(true);
382
+ });
383
+ });
384
+
385
+ describe('getAllText edge cases', () => {
386
+ it('should handle text nodes with empty nodeValue but non-empty textContent', () => {
387
+ const div = document.createElement('div');
388
+ const textNode = document.createTextNode(' ');
389
+ div.appendChild(textNode);
390
+
391
+ // This tests the else branch where nodeValue.trim() is empty
392
+ const result = stringUtils.getAllText(div);
393
+ expect(typeof result).toBe('string');
394
+ });
395
+
396
+ it('should handle mixed content with whitespace text nodes', () => {
397
+ const div = document.createElement('div');
398
+ div.innerHTML = ' <span>Text</span> ';
399
+
400
+ const result = stringUtils.getAllText(div);
401
+ expect(result).toContain('Text');
402
+ });
403
+
404
+ it('should handle elements with both aria-label and text content', () => {
405
+ const div = document.createElement('div');
406
+ const button = document.createElement('button');
407
+ button.textContent = 'Visual Text';
408
+ button.setAttribute('aria-label', 'Accessible Label');
409
+ div.appendChild(button);
410
+
411
+ const result = stringUtils.getAllText(div);
412
+ expect(result).toContain('Accessible Label');
413
+ expect(result).toContain('Visual Text');
414
+ });
415
+
416
+ it('should handle img without alt attribute', () => {
417
+ const div = document.createElement('div');
418
+ const img = document.createElement('img');
419
+ // No alt attribute
420
+ div.appendChild(img);
421
+
422
+ const result = stringUtils.getAllText(div);
423
+ expect(typeof result).toBe('string');
424
+ });
425
+ });
426
+
427
+ describe('isEmptyOrWhitespace', () => {
428
+ it('should return true for null/undefined/empty', () => {
429
+ expect(stringUtils.isEmptyOrWhitespace(null)).toBe(true);
430
+ expect(stringUtils.isEmptyOrWhitespace(undefined)).toBe(true);
431
+ expect(stringUtils.isEmptyOrWhitespace('')).toBe(true);
432
+ });
433
+
434
+ it('should return true for whitespace-only strings', () => {
435
+ expect(stringUtils.isEmptyOrWhitespace(' ')).toBe(true);
436
+ expect(stringUtils.isEmptyOrWhitespace('\t\n')).toBe(true);
437
+ });
438
+
439
+ it('should return true for strings with zero-width spaces', () => {
440
+ expect(stringUtils.isEmptyOrWhitespace('\u200B')).toBe(true);
441
+ expect(stringUtils.isEmptyOrWhitespace('\u200C')).toBe(true);
442
+ expect(stringUtils.isEmptyOrWhitespace('\u200D')).toBe(true);
443
+ expect(stringUtils.isEmptyOrWhitespace('\uFEFF')).toBe(true);
444
+ expect(stringUtils.isEmptyOrWhitespace('\u2060')).toBe(true);
445
+ });
446
+
447
+ it('should return true for non-breaking spaces only', () => {
448
+ expect(stringUtils.isEmptyOrWhitespace('\u00A0')).toBe(true);
449
+ });
450
+
451
+ it('should return false for strings with visible characters', () => {
452
+ expect(stringUtils.isEmptyOrWhitespace('hello')).toBe(false);
453
+ expect(stringUtils.isEmptyOrWhitespace(' a ')).toBe(false);
454
+ expect(stringUtils.isEmptyOrWhitespace('\u200Bx')).toBe(false);
455
+ });
456
+ });
457
+
458
+ describe('isGenericTitle', () => {
459
+ it('should return true for known generic titles', () => {
460
+ expect(stringUtils.isGenericTitle('iframe')).toBe(true);
461
+ expect(stringUtils.isGenericTitle('frame')).toBe(true);
462
+ expect(stringUtils.isGenericTitle('untitled')).toBe(true);
463
+ expect(stringUtils.isGenericTitle('title')).toBe(true);
464
+ expect(stringUtils.isGenericTitle('content')).toBe(true);
465
+ expect(stringUtils.isGenericTitle('main')).toBe(true);
466
+ expect(stringUtils.isGenericTitle('page')).toBe(true);
467
+ });
468
+
469
+ it('should be case-insensitive', () => {
470
+ expect(stringUtils.isGenericTitle('IFRAME')).toBe(true);
471
+ expect(stringUtils.isGenericTitle('Untitled')).toBe(true);
472
+ expect(stringUtils.isGenericTitle('TITLE')).toBe(true);
473
+ });
474
+
475
+ it('should match numbered variants', () => {
476
+ expect(stringUtils.isGenericTitle('frame1')).toBe(true);
477
+ expect(stringUtils.isGenericTitle('iframe2')).toBe(true);
478
+ expect(stringUtils.isGenericTitle('untitled3')).toBe(true);
479
+ expect(stringUtils.isGenericTitle('title42')).toBe(true);
480
+ });
481
+
482
+ it('should return false for descriptive titles', () => {
483
+ expect(stringUtils.isGenericTitle('Contact Form')).toBe(false);
484
+ expect(stringUtils.isGenericTitle('Product Details')).toBe(false);
485
+ expect(stringUtils.isGenericTitle('Navigation Menu')).toBe(false);
486
+ });
487
+
488
+ it('should return false for null/undefined', () => {
489
+ expect(stringUtils.isGenericTitle(null)).toBe(false);
490
+ expect(stringUtils.isGenericTitle(undefined)).toBe(false);
491
+ });
492
+
493
+ it('should trim whitespace', () => {
494
+ expect(stringUtils.isGenericTitle(' iframe ')).toBe(true);
495
+ });
496
+ });
497
+
498
+ describe('isGenericLinkText', () => {
499
+ it('should return true for common generic link text', () => {
500
+ expect(stringUtils.isGenericLinkText('click here')).toBe(true);
501
+ expect(stringUtils.isGenericLinkText('here')).toBe(true);
502
+ expect(stringUtils.isGenericLinkText('more')).toBe(true);
503
+ expect(stringUtils.isGenericLinkText('read more')).toBe(true);
504
+ expect(stringUtils.isGenericLinkText('learn more')).toBe(true);
505
+ expect(stringUtils.isGenericLinkText('link')).toBe(true);
506
+ });
507
+
508
+ it('should be case-insensitive', () => {
509
+ expect(stringUtils.isGenericLinkText('Click Here')).toBe(true);
510
+ expect(stringUtils.isGenericLinkText('READ MORE')).toBe(true);
511
+ expect(stringUtils.isGenericLinkText('LEARN MORE')).toBe(true);
512
+ });
513
+
514
+ it('should return false for descriptive text', () => {
515
+ expect(stringUtils.isGenericLinkText('View product details')).toBe(false);
516
+ expect(stringUtils.isGenericLinkText('Download annual report')).toBe(false);
517
+ });
518
+
519
+ it('should return false for null/undefined', () => {
520
+ expect(stringUtils.isGenericLinkText(null)).toBe(false);
521
+ expect(stringUtils.isGenericLinkText(undefined)).toBe(false);
522
+ });
523
+
524
+ it('should support custom generic list', () => {
525
+ const custom = ['foo', 'bar'];
526
+ expect(stringUtils.isGenericLinkText('foo', custom)).toBe(true);
527
+ expect(stringUtils.isGenericLinkText('bar', custom)).toBe(true);
528
+ expect(stringUtils.isGenericLinkText('click here', custom)).toBe(false);
529
+ });
530
+
531
+ it('should trim whitespace', () => {
532
+ expect(stringUtils.isGenericLinkText(' here ')).toBe(true);
533
+ });
534
+ });
535
+
536
+ describe('getActualVisibleText', () => {
537
+ it('should return empty string for null/undefined', () => {
538
+ expect(stringUtils.getActualVisibleText(null)).toBe('');
539
+ expect(stringUtils.getActualVisibleText(undefined)).toBe('');
540
+ });
541
+
542
+ it('should return text content of element', () => {
543
+ const el = document.createElement('span');
544
+ el.textContent = 'Hello World';
545
+ expect(stringUtils.getActualVisibleText(el)).toBe('Hello World');
546
+ });
547
+
548
+ it('should trim whitespace', () => {
549
+ const el = document.createElement('span');
550
+ el.textContent = ' Hello ';
551
+ expect(stringUtils.getActualVisibleText(el)).toBe('Hello');
552
+ });
553
+
554
+ it('should return empty string for empty element', () => {
555
+ const el = document.createElement('div');
556
+ expect(stringUtils.getActualVisibleText(el)).toBe('');
557
+ });
558
+
559
+ it('should include nested text content', () => {
560
+ const el = document.createElement('div');
561
+ el.innerHTML = '<span>Nested</span> text';
562
+ expect(stringUtils.getActualVisibleText(el)).toBe('Nested text');
563
+ });
564
+ });
565
+
566
+ describe('hasNewWindowWarning', () => {
567
+ it('should return true for text containing "new window"', () => {
568
+ expect(stringUtils.hasNewWindowWarning('Opens in a new window')).toBe(true);
569
+ });
570
+
571
+ it('should return true for text containing "new tab"', () => {
572
+ expect(stringUtils.hasNewWindowWarning('Opens in new tab')).toBe(true);
573
+ });
574
+
575
+ it('should return true for "opens in new" variant', () => {
576
+ expect(stringUtils.hasNewWindowWarning('Link opens in new browser window')).toBe(true);
577
+ });
578
+
579
+ it('should return true for "external link"', () => {
580
+ expect(stringUtils.hasNewWindowWarning('External link to resource')).toBe(true);
581
+ });
582
+
583
+ it('should return true for "external site"', () => {
584
+ expect(stringUtils.hasNewWindowWarning('Goes to external site')).toBe(true);
585
+ });
586
+
587
+ it('should be case-insensitive', () => {
588
+ expect(stringUtils.hasNewWindowWarning('Opens In A New Window')).toBe(true);
589
+ expect(stringUtils.hasNewWindowWarning('EXTERNAL LINK')).toBe(true);
590
+ });
591
+
592
+ it('should return false for text without warning', () => {
593
+ expect(stringUtils.hasNewWindowWarning('Contact us')).toBe(false);
594
+ expect(stringUtils.hasNewWindowWarning('Read the article')).toBe(false);
595
+ });
596
+
597
+ it('should return false for null/undefined', () => {
598
+ expect(stringUtils.hasNewWindowWarning(null)).toBe(false);
599
+ expect(stringUtils.hasNewWindowWarning(undefined)).toBe(false);
600
+ });
601
+ });
602
+
603
+ describe('textIncludingImgAlt', () => {
604
+ it('should return text content from text nodes', () => {
605
+ const el = document.createElement('div');
606
+ el.textContent = 'Hello World';
607
+ expect(stringUtils.textIncludingImgAlt(el).trim()).toBe('Hello World');
608
+ });
609
+
610
+ it('should include img alt text', () => {
611
+ const el = document.createElement('div');
612
+ el.innerHTML = 'Text <img alt="photo"> more text';
613
+ const result = stringUtils.textIncludingImgAlt(el);
614
+ expect(result).toContain('Text');
615
+ expect(result).toContain('photo');
616
+ expect(result).toContain('more text');
617
+ });
618
+
619
+ it('should handle img without alt', () => {
620
+ const el = document.createElement('div');
621
+ el.innerHTML = 'Text <img src="img.png"> more';
622
+ const result = stringUtils.textIncludingImgAlt(el);
623
+ expect(result).toContain('Text');
624
+ expect(result).toContain('more');
625
+ });
626
+
627
+ it('should not include aria-label text', () => {
628
+ const el = document.createElement('div');
629
+ el.innerHTML = '<button aria-label="Close">X</button>';
630
+ const result = stringUtils.textIncludingImgAlt(el);
631
+ expect(result).toContain('X');
632
+ expect(result).not.toContain('Close');
633
+ });
634
+
635
+ it('should handle empty element', () => {
636
+ const el = document.createElement('div');
637
+ expect(stringUtils.textIncludingImgAlt(el)).toBe('');
638
+ });
639
+
640
+ it('should concatenate text from nested elements', () => {
641
+ const el = document.createElement('div');
642
+ el.innerHTML = '<span>First</span> <span>Second</span>';
643
+ const result = stringUtils.textIncludingImgAlt(el);
644
+ expect(result).toContain('First');
645
+ expect(result).toContain('Second');
646
+ });
647
+ });
648
+ });