aria-ease 5.0.2 → 6.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/README.md +23 -13
- package/bin/{chunk-Y2FZWFX7.js → chunk-7RMRFSJL.js} +52 -2
- package/bin/cli.cjs +139 -125
- package/bin/cli.js +1 -1
- package/bin/{contractTestRunnerPlaywright-FFEJJCQO.js → contractTestRunnerPlaywright-PMSOP5FY.js} +42 -91
- package/bin/{test-RHQ2LJVG.js → test-X6K2LCMO.js} +44 -37
- package/dist/{chunk-AVCZIF6G.js → chunk-PDZQOXUN.js} +52 -2
- package/dist/{contractTestRunnerPlaywright-BFHRDJTJ.js → contractTestRunnerPlaywright-ZO6GM4TU.js} +42 -91
- package/dist/index.cjs +142 -127
- package/dist/index.d.cts +11 -6
- package/dist/index.d.ts +11 -6
- package/dist/index.js +46 -39
- package/dist/src/accordion/index.cjs +2 -2
- package/dist/src/accordion/index.d.cts +3 -3
- package/dist/src/accordion/index.d.ts +3 -3
- package/dist/src/accordion/index.js +2 -2
- package/dist/src/utils/test/{chunk-AVCZIF6G.js → chunk-7RMRFSJL.js} +48 -19
- package/dist/src/utils/test/{contractTestRunnerPlaywright-BFHRDJTJ.js → contractTestRunnerPlaywright-CREJNINL.js} +43 -98
- package/dist/src/utils/test/contracts/ComboboxContract.json +2 -1
- package/dist/src/utils/test/contracts/MenuContract.json +2 -1
- package/dist/src/utils/test/index.cjs +135 -166
- package/dist/src/utils/test/index.d.cts +8 -3
- package/dist/src/utils/test/index.d.ts +8 -3
- package/dist/src/utils/test/index.js +43 -38
- package/package.json +5 -5
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var default2 = require('playwright/test');
|
|
4
3
|
var playwright = require('playwright');
|
|
4
|
+
var test = require('@playwright/test');
|
|
5
5
|
var fs = require('fs');
|
|
6
6
|
var jestAxe = require('jest-axe');
|
|
7
7
|
var fs$1 = require('fs/promises');
|
|
@@ -9,31 +9,10 @@ var fs$1 = require('fs/promises');
|
|
|
9
9
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
10
10
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
11
|
|
|
12
|
-
function _interopNamespace(e) {
|
|
13
|
-
if (e && e.__esModule) return e;
|
|
14
|
-
var n = Object.create(null);
|
|
15
|
-
if (e) {
|
|
16
|
-
Object.keys(e).forEach(function (k) {
|
|
17
|
-
if (k !== 'default') {
|
|
18
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
19
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
20
|
-
enumerable: true,
|
|
21
|
-
get: function () { return e[k]; }
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
n.default = e;
|
|
27
|
-
return Object.freeze(n);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
var default2__namespace = /*#__PURE__*/_interopNamespace(default2);
|
|
31
12
|
var fs__default = /*#__PURE__*/_interopDefault(fs$1);
|
|
32
13
|
|
|
33
14
|
var __defProp = Object.defineProperty;
|
|
34
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
35
15
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
36
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
37
16
|
var __esm = (fn, res) => function __init() {
|
|
38
17
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
39
18
|
};
|
|
@@ -41,15 +20,6 @@ var __export = (target, all) => {
|
|
|
41
20
|
for (var name in all)
|
|
42
21
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
43
22
|
};
|
|
44
|
-
var __copyProps = (to, from, except, desc) => {
|
|
45
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
46
|
-
for (let key of __getOwnPropNames(from))
|
|
47
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
48
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
49
|
-
}
|
|
50
|
-
return to;
|
|
51
|
-
};
|
|
52
|
-
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget);
|
|
53
23
|
|
|
54
24
|
// src/utils/test/contract/contract.json
|
|
55
25
|
var contract_default;
|
|
@@ -63,6 +33,10 @@ var init_contract = __esm({
|
|
|
63
33
|
combobox: {
|
|
64
34
|
path: "./contracts/ComboboxContract.json",
|
|
65
35
|
component: "combobox"
|
|
36
|
+
},
|
|
37
|
+
accordion: {
|
|
38
|
+
path: "./contracts/AccordionContract.json",
|
|
39
|
+
component: "accordion"
|
|
66
40
|
}
|
|
67
41
|
};
|
|
68
42
|
}
|
|
@@ -243,7 +217,7 @@ ${"\u2550".repeat(60)}`);
|
|
|
243
217
|
} else if (totalFailures === 0) {
|
|
244
218
|
this.log(`\u2705 ${totalPasses}/${totalRun} required tests passed`);
|
|
245
219
|
if (this.skipped > 0) {
|
|
246
|
-
this.log(`\u25CB ${this.skipped} tests skipped
|
|
220
|
+
this.log(`\u25CB ${this.skipped} tests skipped`);
|
|
247
221
|
}
|
|
248
222
|
if (this.optionalSuggestions > 0) {
|
|
249
223
|
this.log(`\u{1F4A1} ${this.optionalSuggestions} optional enhancement${this.optionalSuggestions > 1 ? "s" : ""} suggested`);
|
|
@@ -293,15 +267,50 @@ ${"\u2550".repeat(60)}`);
|
|
|
293
267
|
};
|
|
294
268
|
}
|
|
295
269
|
});
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
270
|
+
async function getOrCreateBrowser() {
|
|
271
|
+
if (!sharedBrowser) {
|
|
272
|
+
sharedBrowser = await playwright.chromium.launch({
|
|
273
|
+
headless: true,
|
|
274
|
+
// Launch with clean browser profile - no extensions, no user data
|
|
275
|
+
args: [
|
|
276
|
+
"--disable-extensions",
|
|
277
|
+
"--disable-blink-features=AutomationControlled"
|
|
278
|
+
]
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
return sharedBrowser;
|
|
282
|
+
}
|
|
283
|
+
async function getOrCreateContext() {
|
|
284
|
+
if (!sharedContext) {
|
|
285
|
+
const browser = await getOrCreateBrowser();
|
|
286
|
+
sharedContext = await browser.newContext({
|
|
287
|
+
// Isolated context - no permissions, no geolocation, etc.
|
|
288
|
+
permissions: [],
|
|
289
|
+
// Ignore HTTPS errors for local dev servers
|
|
290
|
+
ignoreHTTPSErrors: true
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
return sharedContext;
|
|
294
|
+
}
|
|
295
|
+
async function createTestPage() {
|
|
296
|
+
const context = await getOrCreateContext();
|
|
297
|
+
return await context.newPage();
|
|
298
|
+
}
|
|
299
|
+
async function closeSharedBrowser() {
|
|
300
|
+
if (sharedContext) {
|
|
301
|
+
await sharedContext.close();
|
|
302
|
+
sharedContext = null;
|
|
303
|
+
}
|
|
304
|
+
if (sharedBrowser) {
|
|
305
|
+
await sharedBrowser.close();
|
|
306
|
+
sharedBrowser = null;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
var sharedBrowser, sharedContext;
|
|
310
|
+
var init_playwrightTestHarness = __esm({
|
|
311
|
+
"src/utils/test/contract/playwrightTestHarness.ts"() {
|
|
312
|
+
sharedBrowser = null;
|
|
313
|
+
sharedContext = null;
|
|
305
314
|
}
|
|
306
315
|
});
|
|
307
316
|
|
|
@@ -326,34 +335,35 @@ async function runContractTestsPlaywright(componentName, url) {
|
|
|
326
335
|
const failures = [];
|
|
327
336
|
const passes = [];
|
|
328
337
|
const skipped = [];
|
|
329
|
-
let
|
|
338
|
+
let page = null;
|
|
339
|
+
const useNavigation = !!url;
|
|
330
340
|
try {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
341
|
+
page = await createTestPage();
|
|
342
|
+
if (url) {
|
|
343
|
+
await page.goto(url, {
|
|
344
|
+
waitUntil: "domcontentloaded",
|
|
345
|
+
timeout: 3e4
|
|
346
|
+
});
|
|
347
|
+
await page.addStyleTag({ content: `* { transition: none !important; animation: none !important; }` });
|
|
348
|
+
}
|
|
338
349
|
const mainSelector = componentContract.selectors.trigger || componentContract.selectors.input || componentContract.selectors.container;
|
|
339
350
|
if (!mainSelector) {
|
|
340
351
|
throw new Error(`No main selector (trigger, input, or container) found in contract for ${componentName}`);
|
|
341
352
|
}
|
|
342
|
-
|
|
353
|
+
const elementTimeout = useNavigation ? 3e4 : 5e3;
|
|
354
|
+
await page.locator(mainSelector).first().waitFor({ state: "attached", timeout: elementTimeout });
|
|
343
355
|
if (componentName === "menu" && componentContract.selectors.trigger) {
|
|
344
|
-
await page.
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
componentContract.selectors.trigger,
|
|
350
|
-
{ timeout: 1e4 }
|
|
351
|
-
).catch(() => {
|
|
352
|
-
console.warn("Menu initialization signal not detected, continuing with tests...");
|
|
356
|
+
await page.locator(componentContract.selectors.trigger).first().waitFor({
|
|
357
|
+
state: "visible",
|
|
358
|
+
timeout: 5e3
|
|
359
|
+
}).catch(() => {
|
|
360
|
+
console.warn("Menu trigger not visible, continuing with tests...");
|
|
353
361
|
});
|
|
354
|
-
await page.waitForTimeout(300);
|
|
355
362
|
}
|
|
356
363
|
async function resolveRelativeTarget(selector, relative) {
|
|
364
|
+
if (!page) {
|
|
365
|
+
throw new Error("Page is not initialized");
|
|
366
|
+
}
|
|
357
367
|
const items = await page.locator(selector).all();
|
|
358
368
|
switch (relative) {
|
|
359
369
|
case "first":
|
|
@@ -423,11 +433,11 @@ async function runContractTestsPlaywright(componentName, url) {
|
|
|
423
433
|
for (const dynamicTest of componentContract.dynamic || []) {
|
|
424
434
|
const { action, assertions } = dynamicTest;
|
|
425
435
|
const failuresBeforeTest = failures.length;
|
|
426
|
-
if (componentContract.selectors.
|
|
427
|
-
const popupSelector = componentContract.selectors.
|
|
436
|
+
if (componentContract.selectors.popup) {
|
|
437
|
+
const popupSelector = componentContract.selectors.popup;
|
|
428
438
|
if (!popupSelector) continue;
|
|
429
439
|
const popupElement = page.locator(popupSelector).first();
|
|
430
|
-
const isPopupVisible = await popupElement.isVisible();
|
|
440
|
+
const isPopupVisible = await popupElement.isVisible().catch(() => false);
|
|
431
441
|
if (isPopupVisible) {
|
|
432
442
|
let menuClosed = false;
|
|
433
443
|
let closeSelector = componentContract.selectors.input;
|
|
@@ -439,73 +449,35 @@ async function runContractTestsPlaywright(componentName, url) {
|
|
|
439
449
|
if (closeSelector) {
|
|
440
450
|
const closeElement = page.locator(closeSelector).first();
|
|
441
451
|
await closeElement.focus();
|
|
442
|
-
await page.waitForTimeout(200);
|
|
443
452
|
await page.keyboard.press("Escape");
|
|
444
|
-
menuClosed = await
|
|
445
|
-
(selector) => {
|
|
446
|
-
const popup = document.querySelector(selector);
|
|
447
|
-
return popup && getComputedStyle(popup).display === "none";
|
|
448
|
-
},
|
|
449
|
-
popupSelector,
|
|
450
|
-
{ timeout: 3e3 }
|
|
451
|
-
).then(() => true).catch(() => false);
|
|
453
|
+
menuClosed = await test.expect(popupElement).toBeHidden({ timeout: 2e3 }).then(() => true).catch(() => false);
|
|
452
454
|
}
|
|
453
455
|
if (!menuClosed && componentContract.selectors.trigger) {
|
|
454
456
|
const triggerElement = page.locator(componentContract.selectors.trigger).first();
|
|
455
457
|
await triggerElement.click();
|
|
456
|
-
await
|
|
457
|
-
menuClosed = await page.waitForFunction(
|
|
458
|
-
(selector) => {
|
|
459
|
-
const popup = document.querySelector(selector);
|
|
460
|
-
return popup && getComputedStyle(popup).display === "none";
|
|
461
|
-
},
|
|
462
|
-
popupSelector,
|
|
463
|
-
{ timeout: 3e3 }
|
|
464
|
-
).then(() => true).catch(() => false);
|
|
458
|
+
menuClosed = await test.expect(popupElement).toBeHidden({ timeout: 2e3 }).then(() => true).catch(() => false);
|
|
465
459
|
}
|
|
466
460
|
if (!menuClosed) {
|
|
467
461
|
await page.mouse.click(10, 10);
|
|
468
|
-
await
|
|
469
|
-
menuClosed = await page.waitForFunction(
|
|
470
|
-
(selector) => {
|
|
471
|
-
const popup = document.querySelector(selector);
|
|
472
|
-
return popup && getComputedStyle(popup).display === "none";
|
|
473
|
-
},
|
|
474
|
-
popupSelector,
|
|
475
|
-
{ timeout: 3e3 }
|
|
476
|
-
).then(() => true).catch(() => false);
|
|
477
|
-
if (menuClosed) {
|
|
478
|
-
console.log("\u{1F3AF} Strategy 3 (Click outside) worked");
|
|
479
|
-
}
|
|
462
|
+
menuClosed = await test.expect(popupElement).toBeHidden({ timeout: 2e3 }).then(() => true).catch(() => false);
|
|
480
463
|
}
|
|
481
464
|
if (!menuClosed) {
|
|
482
|
-
|
|
483
|
-
|
|
465
|
+
if (useNavigation) {
|
|
466
|
+
throw new Error(
|
|
467
|
+
`\u274C FATAL: Cannot close menu between tests. Menu remains visible after trying:
|
|
484
468
|
1. Escape key
|
|
485
469
|
2. Clicking trigger
|
|
486
470
|
3. Clicking outside
|
|
487
471
|
This indicates a problem with the menu component's close functionality.`
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
if (componentName === "menu" && componentContract.selectors.trigger) {
|
|
491
|
-
await page.waitForFunction(
|
|
492
|
-
(selector) => {
|
|
493
|
-
const trigger = document.querySelector(selector);
|
|
494
|
-
return document.activeElement === trigger;
|
|
495
|
-
},
|
|
496
|
-
componentContract.selectors.trigger,
|
|
497
|
-
{ timeout: 2e3 }
|
|
498
|
-
).catch(async () => {
|
|
499
|
-
const triggerElement = page.locator(componentContract.selectors.trigger).first();
|
|
500
|
-
await triggerElement.focus();
|
|
501
|
-
await page.waitForTimeout(200);
|
|
502
|
-
});
|
|
472
|
+
);
|
|
473
|
+
}
|
|
503
474
|
}
|
|
504
|
-
await page.waitForTimeout(500);
|
|
505
475
|
if (componentContract.selectors.input) {
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
476
|
+
await page.locator(componentContract.selectors.input).first().clear();
|
|
477
|
+
}
|
|
478
|
+
if (componentName === "menu" && componentContract.selectors.trigger) {
|
|
479
|
+
const triggerElement = page.locator(componentContract.selectors.trigger).first();
|
|
480
|
+
await triggerElement.focus();
|
|
509
481
|
}
|
|
510
482
|
}
|
|
511
483
|
}
|
|
@@ -549,7 +521,6 @@ This indicates a problem with the menu component's close functionality.`
|
|
|
549
521
|
continue;
|
|
550
522
|
}
|
|
551
523
|
await page.locator(focusSelector).first().focus();
|
|
552
|
-
await page.waitForTimeout(100);
|
|
553
524
|
}
|
|
554
525
|
if (act.type === "type" && act.value) {
|
|
555
526
|
const typeSelector = componentContract.selectors[act.target];
|
|
@@ -558,7 +529,6 @@ This indicates a problem with the menu component's close functionality.`
|
|
|
558
529
|
continue;
|
|
559
530
|
}
|
|
560
531
|
await page.locator(typeSelector).first().fill(act.value);
|
|
561
|
-
await page.waitForTimeout(100);
|
|
562
532
|
}
|
|
563
533
|
if (act.type === "click") {
|
|
564
534
|
if (act.target === "document") {
|
|
@@ -575,7 +545,6 @@ This indicates a problem with the menu component's close functionality.`
|
|
|
575
545
|
continue;
|
|
576
546
|
}
|
|
577
547
|
await relativeElement.click();
|
|
578
|
-
await page.waitForTimeout(componentName === "menu" ? 800 : 200);
|
|
579
548
|
} else {
|
|
580
549
|
const actionSelector = componentContract.selectors[act.target];
|
|
581
550
|
if (!actionSelector) {
|
|
@@ -583,7 +552,6 @@ This indicates a problem with the menu component's close functionality.`
|
|
|
583
552
|
continue;
|
|
584
553
|
}
|
|
585
554
|
await page.locator(actionSelector).first().click();
|
|
586
|
-
await page.waitForTimeout(componentName === "menu" ? 800 : 200);
|
|
587
555
|
}
|
|
588
556
|
}
|
|
589
557
|
if (act.type === "keypress" && act.key) {
|
|
@@ -606,9 +574,7 @@ This indicates a problem with the menu component's close functionality.`
|
|
|
606
574
|
keyValue = keyValue.replace(/ /g, "");
|
|
607
575
|
}
|
|
608
576
|
if (act.target === "focusable" && ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Escape"].includes(keyValue)) {
|
|
609
|
-
await page.waitForTimeout(componentName === "menu" ? 200 : 100);
|
|
610
577
|
await page.keyboard.press(keyValue);
|
|
611
|
-
await page.waitForTimeout(componentName === "menu" ? 300 : 100);
|
|
612
578
|
} else {
|
|
613
579
|
const keypressSelector = componentContract.selectors[act.target];
|
|
614
580
|
if (!keypressSelector) {
|
|
@@ -637,7 +603,6 @@ This indicates a problem with the menu component's close functionality.`
|
|
|
637
603
|
continue;
|
|
638
604
|
}
|
|
639
605
|
await relativeElement.hover();
|
|
640
|
-
await page.waitForTimeout(100);
|
|
641
606
|
} else {
|
|
642
607
|
const hoverSelector = componentContract.selectors[act.target];
|
|
643
608
|
if (!hoverSelector) {
|
|
@@ -645,12 +610,9 @@ This indicates a problem with the menu component's close functionality.`
|
|
|
645
610
|
continue;
|
|
646
611
|
}
|
|
647
612
|
await page.locator(hoverSelector).first().hover();
|
|
648
|
-
await page.waitForTimeout(100);
|
|
649
613
|
}
|
|
650
614
|
}
|
|
651
|
-
await page.waitForTimeout(componentName === "menu" ? 200 : 100);
|
|
652
615
|
}
|
|
653
|
-
await page.waitForTimeout(componentName === "menu" ? 300 : 100);
|
|
654
616
|
for (const assertion of assertions) {
|
|
655
617
|
let target;
|
|
656
618
|
if (assertion.target === "relative") {
|
|
@@ -679,7 +641,7 @@ This indicates a problem with the menu component's close functionality.`
|
|
|
679
641
|
}
|
|
680
642
|
if (assertion.assertion === "toBeVisible") {
|
|
681
643
|
try {
|
|
682
|
-
await
|
|
644
|
+
await test.expect(target).toBeVisible({ timeout: 2e3 });
|
|
683
645
|
passes.push(`${assertion.target} is visible as expected. Test: "${dynamicTest.description}".`);
|
|
684
646
|
} catch {
|
|
685
647
|
const debugState = await page.evaluate((sel) => {
|
|
@@ -693,7 +655,7 @@ This indicates a problem with the menu component's close functionality.`
|
|
|
693
655
|
}
|
|
694
656
|
if (assertion.assertion === "notToBeVisible") {
|
|
695
657
|
try {
|
|
696
|
-
await
|
|
658
|
+
await test.expect(target).toBeHidden({ timeout: 2e3 });
|
|
697
659
|
passes.push(`${assertion.target} is not visible as expected. Test: "${dynamicTest.description}".`);
|
|
698
660
|
} catch {
|
|
699
661
|
const debugState = await page.evaluate((sel) => {
|
|
@@ -715,7 +677,7 @@ This indicates a problem with the menu component's close functionality.`
|
|
|
715
677
|
failures.push(assertion.failureMessage + ` ${assertion.target} "${assertion.attribute}" should not be empty, found "${attributeValue}".`);
|
|
716
678
|
}
|
|
717
679
|
} else {
|
|
718
|
-
await
|
|
680
|
+
await test.expect(target).toHaveAttribute(assertion.attribute, assertion.expectedValue, { timeout: 3e3 });
|
|
719
681
|
passes.push(`${assertion.target} has expected "${assertion.attribute}". Test: "${dynamicTest.description}".`);
|
|
720
682
|
}
|
|
721
683
|
} catch {
|
|
@@ -745,7 +707,7 @@ This indicates a problem with the menu component's close functionality.`
|
|
|
745
707
|
}
|
|
746
708
|
if (assertion.assertion === "toHaveFocus") {
|
|
747
709
|
try {
|
|
748
|
-
await
|
|
710
|
+
await test.expect(target).toBeFocused({ timeout: 5e3 });
|
|
749
711
|
passes.push(`${assertion.target} has focus as expected. Test: "${dynamicTest.description}".`);
|
|
750
712
|
} catch {
|
|
751
713
|
const actualFocus = await page.evaluate(() => {
|
|
@@ -795,15 +757,15 @@ This indicates a problem with the menu component's close functionality.`
|
|
|
795
757
|
}
|
|
796
758
|
}
|
|
797
759
|
} finally {
|
|
798
|
-
if (
|
|
760
|
+
if (page) await page.close();
|
|
799
761
|
}
|
|
800
762
|
return { passes, failures, skipped };
|
|
801
763
|
}
|
|
802
764
|
var init_contractTestRunnerPlaywright = __esm({
|
|
803
765
|
"src/utils/test/contract/contractTestRunnerPlaywright.ts"() {
|
|
804
|
-
init_test();
|
|
805
766
|
init_contract();
|
|
806
767
|
init_ContractReporter();
|
|
768
|
+
init_playwrightTestHarness();
|
|
807
769
|
}
|
|
808
770
|
});
|
|
809
771
|
|
|
@@ -871,60 +833,63 @@ async function runContractTests(componentName, component) {
|
|
|
871
833
|
}
|
|
872
834
|
|
|
873
835
|
// src/utils/test/src/test.ts
|
|
836
|
+
init_playwrightTestHarness();
|
|
874
837
|
async function testUiComponent(componentName, component, url) {
|
|
875
838
|
if (!componentName || typeof componentName !== "string") {
|
|
876
839
|
throw new Error("\u274C testUiComponent requires a valid componentName (string)");
|
|
877
840
|
}
|
|
878
|
-
if (!component || !(component instanceof HTMLElement)) {
|
|
879
|
-
throw new Error("\u274C testUiComponent requires a valid component (HTMLElement)");
|
|
841
|
+
if (!url && (!component || !(component instanceof HTMLElement))) {
|
|
842
|
+
throw new Error("\u274C testUiComponent requires either a valid component (HTMLElement) or a URL");
|
|
880
843
|
}
|
|
881
844
|
if (url && typeof url !== "string") {
|
|
882
845
|
throw new Error("\u274C testUiComponent url parameter must be a string");
|
|
883
846
|
}
|
|
884
847
|
let results;
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
848
|
+
if (component) {
|
|
849
|
+
try {
|
|
850
|
+
results = await jestAxe.axe(component);
|
|
851
|
+
} catch (error) {
|
|
852
|
+
throw new Error(
|
|
853
|
+
`\u274C Axe accessibility scan failed
|
|
890
854
|
Error: ${error instanceof Error ? error.message : String(error)}`
|
|
891
|
-
|
|
855
|
+
);
|
|
856
|
+
}
|
|
857
|
+
} else {
|
|
858
|
+
results = { violations: [] };
|
|
892
859
|
}
|
|
893
|
-
async function checkDevServer(
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
try {
|
|
902
|
-
const response = await fetch(serverUrl, {
|
|
903
|
-
method: "HEAD",
|
|
904
|
-
signal: AbortSignal.timeout(1e3)
|
|
905
|
-
});
|
|
906
|
-
if (response.ok || response.status === 304) {
|
|
907
|
-
return serverUrl;
|
|
908
|
-
}
|
|
909
|
-
} catch {
|
|
910
|
-
return null;
|
|
860
|
+
async function checkDevServer(url2) {
|
|
861
|
+
try {
|
|
862
|
+
const response = await fetch(url2, {
|
|
863
|
+
method: "HEAD",
|
|
864
|
+
signal: AbortSignal.timeout(1e3)
|
|
865
|
+
});
|
|
866
|
+
if (response.ok || response.status === 304) {
|
|
867
|
+
return url2;
|
|
911
868
|
}
|
|
869
|
+
} catch {
|
|
870
|
+
return null;
|
|
912
871
|
}
|
|
913
872
|
return null;
|
|
914
873
|
}
|
|
915
874
|
let contract;
|
|
916
875
|
try {
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
876
|
+
if (url) {
|
|
877
|
+
const devServerUrl = await checkDevServer(url);
|
|
878
|
+
if (devServerUrl) {
|
|
879
|
+
console.log(`\u{1F3AD} Running Playwright tests on ${devServerUrl}`);
|
|
880
|
+
const { runContractTestsPlaywright: runContractTestsPlaywright2 } = await Promise.resolve().then(() => (init_contractTestRunnerPlaywright(), contractTestRunnerPlaywright_exports));
|
|
881
|
+
contract = await runContractTestsPlaywright2(componentName, devServerUrl);
|
|
882
|
+
} else {
|
|
883
|
+
throw new Error(
|
|
884
|
+
`\u274C Dev server not running at ${url}
|
|
885
|
+
Please start your dev server and try again.`
|
|
886
|
+
);
|
|
887
|
+
}
|
|
888
|
+
} else if (component) {
|
|
889
|
+
console.log(`\u{1F3AD} Running component contract tests in JSDOM mode`);
|
|
927
890
|
contract = await runContractTests(componentName, component);
|
|
891
|
+
} else {
|
|
892
|
+
throw new Error("\u274C Either component or URL must be provided");
|
|
928
893
|
}
|
|
929
894
|
} catch (error) {
|
|
930
895
|
if (error instanceof Error) {
|
|
@@ -990,5 +955,9 @@ if (typeof window === "undefined") {
|
|
|
990
955
|
);
|
|
991
956
|
};
|
|
992
957
|
}
|
|
958
|
+
async function cleanupTests() {
|
|
959
|
+
await closeSharedBrowser();
|
|
960
|
+
}
|
|
993
961
|
|
|
962
|
+
exports.cleanupTests = cleanupTests;
|
|
994
963
|
exports.testUiComponent = testUiComponent;
|
|
@@ -8,10 +8,15 @@ interface JestAxeResult {
|
|
|
8
8
|
* Runs static and interactions accessibility test on UI components.
|
|
9
9
|
* @param {string} componentName The name of the component contract to test against
|
|
10
10
|
* @param {HTMLElement} component The UI component to be tested
|
|
11
|
-
* @param {string} url Optional URL to run full Playwright E2E tests
|
|
11
|
+
* @param {string} url Optional URL to run full Playwright E2E tests. If omitted, uses isolated component testing with page.setContent()
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
declare function testUiComponent(componentName: string, component: HTMLElement, url
|
|
14
|
+
declare function testUiComponent(componentName: string, component: HTMLElement | null, url: string | null): Promise<JestAxeResult>;
|
|
15
15
|
declare let runTest: () => Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Cleanup function to close the shared Playwright browser
|
|
18
|
+
* Call this in afterAll() or after all tests complete
|
|
19
|
+
*/
|
|
20
|
+
declare function cleanupTests(): Promise<void>;
|
|
16
21
|
|
|
17
|
-
export { runTest, testUiComponent };
|
|
22
|
+
export { cleanupTests, runTest, testUiComponent };
|
|
@@ -8,10 +8,15 @@ interface JestAxeResult {
|
|
|
8
8
|
* Runs static and interactions accessibility test on UI components.
|
|
9
9
|
* @param {string} componentName The name of the component contract to test against
|
|
10
10
|
* @param {HTMLElement} component The UI component to be tested
|
|
11
|
-
* @param {string} url Optional URL to run full Playwright E2E tests
|
|
11
|
+
* @param {string} url Optional URL to run full Playwright E2E tests. If omitted, uses isolated component testing with page.setContent()
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
declare function testUiComponent(componentName: string, component: HTMLElement, url
|
|
14
|
+
declare function testUiComponent(componentName: string, component: HTMLElement | null, url: string | null): Promise<JestAxeResult>;
|
|
15
15
|
declare let runTest: () => Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Cleanup function to close the shared Playwright browser
|
|
18
|
+
* Call this in afterAll() or after all tests complete
|
|
19
|
+
*/
|
|
20
|
+
declare function cleanupTests(): Promise<void>;
|
|
16
21
|
|
|
17
|
-
export { runTest, testUiComponent };
|
|
22
|
+
export { cleanupTests, runTest, testUiComponent };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ContractReporter, contract_default } from './chunk-
|
|
1
|
+
import { closeSharedBrowser, ContractReporter, contract_default } from './chunk-7RMRFSJL.js';
|
|
2
2
|
import { axe } from 'jest-axe';
|
|
3
3
|
import fs from 'fs/promises';
|
|
4
4
|
|
|
@@ -67,56 +67,58 @@ async function testUiComponent(componentName, component, url) {
|
|
|
67
67
|
if (!componentName || typeof componentName !== "string") {
|
|
68
68
|
throw new Error("\u274C testUiComponent requires a valid componentName (string)");
|
|
69
69
|
}
|
|
70
|
-
if (!component || !(component instanceof HTMLElement)) {
|
|
71
|
-
throw new Error("\u274C testUiComponent requires a valid component (HTMLElement)");
|
|
70
|
+
if (!url && (!component || !(component instanceof HTMLElement))) {
|
|
71
|
+
throw new Error("\u274C testUiComponent requires either a valid component (HTMLElement) or a URL");
|
|
72
72
|
}
|
|
73
73
|
if (url && typeof url !== "string") {
|
|
74
74
|
throw new Error("\u274C testUiComponent url parameter must be a string");
|
|
75
75
|
}
|
|
76
76
|
let results;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
if (component) {
|
|
78
|
+
try {
|
|
79
|
+
results = await axe(component);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
throw new Error(
|
|
82
|
+
`\u274C Axe accessibility scan failed
|
|
82
83
|
Error: ${error instanceof Error ? error.message : String(error)}`
|
|
83
|
-
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
results = { violations: [] };
|
|
84
88
|
}
|
|
85
|
-
async function checkDevServer(
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
try {
|
|
94
|
-
const response = await fetch(serverUrl, {
|
|
95
|
-
method: "HEAD",
|
|
96
|
-
signal: AbortSignal.timeout(1e3)
|
|
97
|
-
});
|
|
98
|
-
if (response.ok || response.status === 304) {
|
|
99
|
-
return serverUrl;
|
|
100
|
-
}
|
|
101
|
-
} catch {
|
|
102
|
-
return null;
|
|
89
|
+
async function checkDevServer(url2) {
|
|
90
|
+
try {
|
|
91
|
+
const response = await fetch(url2, {
|
|
92
|
+
method: "HEAD",
|
|
93
|
+
signal: AbortSignal.timeout(1e3)
|
|
94
|
+
});
|
|
95
|
+
if (response.ok || response.status === 304) {
|
|
96
|
+
return url2;
|
|
103
97
|
}
|
|
98
|
+
} catch {
|
|
99
|
+
return null;
|
|
104
100
|
}
|
|
105
101
|
return null;
|
|
106
102
|
}
|
|
107
103
|
let contract;
|
|
108
104
|
try {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
105
|
+
if (url) {
|
|
106
|
+
const devServerUrl = await checkDevServer(url);
|
|
107
|
+
if (devServerUrl) {
|
|
108
|
+
console.log(`\u{1F3AD} Running Playwright tests on ${devServerUrl}`);
|
|
109
|
+
const { runContractTestsPlaywright } = await import('./contractTestRunnerPlaywright-CREJNINL.js');
|
|
110
|
+
contract = await runContractTestsPlaywright(componentName, devServerUrl);
|
|
111
|
+
} else {
|
|
112
|
+
throw new Error(
|
|
113
|
+
`\u274C Dev server not running at ${url}
|
|
114
|
+
Please start your dev server and try again.`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
} else if (component) {
|
|
118
|
+
console.log(`\u{1F3AD} Running component contract tests in JSDOM mode`);
|
|
119
119
|
contract = await runContractTests(componentName, component);
|
|
120
|
+
} else {
|
|
121
|
+
throw new Error("\u274C Either component or URL must be provided");
|
|
120
122
|
}
|
|
121
123
|
} catch (error) {
|
|
122
124
|
if (error instanceof Error) {
|
|
@@ -182,5 +184,8 @@ if (typeof window === "undefined") {
|
|
|
182
184
|
);
|
|
183
185
|
};
|
|
184
186
|
}
|
|
187
|
+
async function cleanupTests() {
|
|
188
|
+
await closeSharedBrowser();
|
|
189
|
+
}
|
|
185
190
|
|
|
186
|
-
export { runTest, testUiComponent };
|
|
191
|
+
export { cleanupTests, runTest, testUiComponent };
|