@afixt/test-utils 2.0.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@afixt/test-utils",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "Various utilities for accessibility testing",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -174,6 +174,40 @@ const stringUtils = (function () {
174
174
  return (element.textContent || '').trim();
175
175
  }
176
176
 
177
+ /**
178
+ * Checks if an accessible name contains the visible text as a whole-word phrase.
179
+ * Prevents false positives where aria-label is a superset of visible text
180
+ * (e.g. "Report a Concern Opens in new window" contains "Report a Concern").
181
+ * Uses word-boundary matching to avoid partial matches
182
+ * (e.g. "Homepage" does NOT contain "Home" as a whole word).
183
+ * @param {string} accessibleName - The accessible name (e.g. aria-label value)
184
+ * @param {string} visibleText - The visible text content of the element
185
+ * @returns {boolean} True if the accessible name contains the visible text at word boundaries
186
+ */
187
+ function containsVisibleText(accessibleName, visibleText) {
188
+ if (!accessibleName || !visibleText) {
189
+ return false;
190
+ }
191
+ const haystack = accessibleName.toLowerCase().replace(/\s+/g, ' ').trim();
192
+ const needle = visibleText.toLowerCase().replace(/\s+/g, ' ').trim();
193
+ if (!needle) {
194
+ return false;
195
+ }
196
+ const index = haystack.indexOf(needle);
197
+ if (index === -1) {
198
+ return false;
199
+ }
200
+ // Check word boundaries
201
+ if (index > 0 && /\w/.test(haystack.charAt(index - 1))) {
202
+ return false;
203
+ }
204
+ const endIndex = index + needle.length;
205
+ if (endIndex < haystack.length && /\w/.test(haystack.charAt(endIndex))) {
206
+ return false;
207
+ }
208
+ return true;
209
+ }
210
+
177
211
  /**
178
212
  * Checks if text contains a warning about new window/tab behavior.
179
213
  * @param {string} text - The text to check
@@ -211,6 +245,7 @@ const stringUtils = (function () {
211
245
  isGenericTitle,
212
246
  isGenericLinkText,
213
247
  getActualVisibleText,
248
+ containsVisibleText,
214
249
  hasNewWindowWarning,
215
250
  };
216
251
  })();
@@ -436,6 +436,66 @@ describe('stringUtils', () => {
436
436
  });
437
437
  });
438
438
 
439
+ describe('containsVisibleText', () => {
440
+ it('should return true when accessible name exactly matches visible text', () => {
441
+ expect(stringUtils.containsVisibleText('Home', 'Home')).toBe(true);
442
+ });
443
+
444
+ it('should return true when accessible name is a superset of visible text', () => {
445
+ expect(
446
+ stringUtils.containsVisibleText(
447
+ 'Report a Concern Opens in new window',
448
+ 'Report a Concern'
449
+ )
450
+ ).toBe(true);
451
+ });
452
+
453
+ it('should be case-insensitive', () => {
454
+ expect(stringUtils.containsVisibleText('REPORT A CONCERN', 'Report a Concern')).toBe(
455
+ true
456
+ );
457
+ });
458
+
459
+ it('should return false when visible text is a partial word match', () => {
460
+ expect(stringUtils.containsVisibleText('Homepage', 'Home')).toBe(false);
461
+ });
462
+
463
+ it('should return false when accessible name does not contain visible text', () => {
464
+ expect(
465
+ stringUtils.containsVisibleText('Click here for more information', 'Learn more')
466
+ ).toBe(false);
467
+ });
468
+
469
+ it('should return false for null/undefined inputs', () => {
470
+ expect(stringUtils.containsVisibleText(null, 'text')).toBe(false);
471
+ expect(stringUtils.containsVisibleText('text', null)).toBe(false);
472
+ expect(stringUtils.containsVisibleText(undefined, undefined)).toBe(false);
473
+ });
474
+
475
+ it('should return false for empty visible text', () => {
476
+ expect(stringUtils.containsVisibleText('some name', '')).toBe(false);
477
+ expect(stringUtils.containsVisibleText('some name', ' ')).toBe(false);
478
+ });
479
+
480
+ it('should normalize whitespace before matching', () => {
481
+ expect(stringUtils.containsVisibleText('Report a Concern', 'Report a Concern')).toBe(
482
+ true
483
+ );
484
+ });
485
+
486
+ it('should match visible text at the end of accessible name', () => {
487
+ expect(stringUtils.containsVisibleText('Click here to Search', 'Search')).toBe(true);
488
+ });
489
+
490
+ it('should not match across word boundaries at end', () => {
491
+ expect(stringUtils.containsVisibleText('Searching', 'Search')).toBe(false);
492
+ });
493
+
494
+ it('should handle visible text that is the entire accessible name', () => {
495
+ expect(stringUtils.containsVisibleText('Buy now', 'Buy now')).toBe(true);
496
+ });
497
+ });
498
+
439
499
  describe('hasNewWindowWarning', () => {
440
500
  it('should return true for text containing "new window"', () => {
441
501
  expect(stringUtils.hasNewWindowWarning('Opens in a new window')).toBe(true);