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 CHANGED
@@ -175,7 +175,7 @@ useEffect(() => {
175
175
  accordionId: "accordion-container",
176
176
  triggersClass: "accordion-trigger",
177
177
  panelsClass: "accordion-panel",
178
- allowMultiple: false, // Only one panel open at a time (default)
178
+ allowMultipleOpen: false, // Only one panel open at a time (default)
179
179
  });
180
180
 
181
181
  return () => accordion.cleanup();
@@ -214,7 +214,7 @@ makeAccordionAccessible({
214
214
  accordionId: "faq-div",
215
215
  triggersClass: "dropdown-button",
216
216
  panelsClass: "accordion-panel",
217
- allowMultiple: false, // Only one panel open at a time
217
+ allowMultipleOpen: false, // Only one panel open at a time
218
218
  });
219
219
  ```
220
220
 
@@ -428,20 +428,30 @@ blockInstance.current.cleanup();
428
428
  Aria-Ease includes a built-in testing framework for automated accessibility validation:
429
429
 
430
430
  ```javascript
431
- import { testUiComponent } from "aria-ease/test";
431
+ import { describe, test, afterAll } from "vitest";
432
+ import { testUiComponent, cleanupTests } from "aria-ease/test";
433
+ import { render } from "@testing-library/react";
434
+ import ShopifyUserMenu from "../src/components/menus/ShopifyUserMenu";
432
435
 
433
- // In your test file (Vitest, Jest, etc.)
434
- test("combobox is accessible", async () => {
435
- const { container } = render(<Combobox />);
436
+ afterAll(async () => {
437
+ await cleanupTests();
438
+ });
436
439
 
437
- // Runs axe-core + contract tests
438
- const result = await testUiComponent(
439
- "combobox",
440
- container,
441
- "http://localhost:3000", // Optional: full E2E with Playwright
442
- );
440
+ describe("Shopify User Menu Accessibility Test", () => {
441
+ test("renders Shopify user menu without accessibility violation(s)", async () => {
442
+ await testUiComponent(
443
+ "menu",
444
+ null,
445
+ "http://localhost:5173/test-harness?component=menu",
446
+ ); // For full component interaction test. Uses Playwright to test interaction and behaviors
447
+ }, 6000);
448
+ });
443
449
 
444
- expect(result.violations).toHaveLength(0);
450
+ describe("Shopify User Menu Accessibility Test", () => {
451
+ test("renders Shopify user menu without accessibility violation(s)", async () => {
452
+ const { container } = render(<ShopifyUserMenu />);
453
+ await testUiComponent("menu", container, null); // For fast limited static tests. Doesn't test for interaction and behaviors
454
+ });
445
455
  });
446
456
  ```
447
457
 
@@ -7,6 +7,10 @@ var contract_default = {
7
7
  combobox: {
8
8
  path: "./contracts/ComboboxContract.json",
9
9
  component: "combobox"
10
+ },
11
+ accordion: {
12
+ path: "./contracts/AccordionContract.json",
13
+ component: "accordion"
10
14
  }
11
15
  };
12
16
 
@@ -182,7 +186,7 @@ ${"\u2550".repeat(60)}`);
182
186
  } else if (totalFailures === 0) {
183
187
  this.log(`\u2705 ${totalPasses}/${totalRun} required tests passed`);
184
188
  if (this.skipped > 0) {
185
- this.log(`\u25CB ${this.skipped} tests skipped (jsdom limitation)`);
189
+ this.log(`\u25CB ${this.skipped} tests skipped`);
186
190
  }
187
191
  if (this.optionalSuggestions > 0) {
188
192
  this.log(`\u{1F4A1} ${this.optionalSuggestions} optional enhancement${this.optionalSuggestions > 1 ? "s" : ""} suggested`);
@@ -231,7 +235,53 @@ ${"\u2550".repeat(60)}`);
231
235
  }
232
236
  };
233
237
 
238
+ // src/utils/test/contract/playwrightTestHarness.ts
239
+ import { chromium } from "playwright";
240
+ var sharedBrowser = null;
241
+ var sharedContext = null;
242
+ async function getOrCreateBrowser() {
243
+ if (!sharedBrowser) {
244
+ sharedBrowser = await chromium.launch({
245
+ headless: true,
246
+ // Launch with clean browser profile - no extensions, no user data
247
+ args: [
248
+ "--disable-extensions",
249
+ "--disable-blink-features=AutomationControlled"
250
+ ]
251
+ });
252
+ }
253
+ return sharedBrowser;
254
+ }
255
+ async function getOrCreateContext() {
256
+ if (!sharedContext) {
257
+ const browser = await getOrCreateBrowser();
258
+ sharedContext = await browser.newContext({
259
+ // Isolated context - no permissions, no geolocation, etc.
260
+ permissions: [],
261
+ // Ignore HTTPS errors for local dev servers
262
+ ignoreHTTPSErrors: true
263
+ });
264
+ }
265
+ return sharedContext;
266
+ }
267
+ async function createTestPage() {
268
+ const context = await getOrCreateContext();
269
+ return await context.newPage();
270
+ }
271
+ async function closeSharedBrowser() {
272
+ if (sharedContext) {
273
+ await sharedContext.close();
274
+ sharedContext = null;
275
+ }
276
+ if (sharedBrowser) {
277
+ await sharedBrowser.close();
278
+ sharedBrowser = null;
279
+ }
280
+ }
281
+
234
282
  export {
235
283
  contract_default,
236
- ContractReporter
284
+ ContractReporter,
285
+ createTestPage,
286
+ closeSharedBrowser
237
287
  };
package/bin/cli.cjs CHANGED
@@ -283,6 +283,10 @@ var init_contract = __esm({
283
283
  combobox: {
284
284
  path: "./contracts/ComboboxContract.json",
285
285
  component: "combobox"
286
+ },
287
+ accordion: {
288
+ path: "./contracts/AccordionContract.json",
289
+ component: "accordion"
286
290
  }
287
291
  };
288
292
  }
@@ -464,7 +468,7 @@ ${"\u2550".repeat(60)}`);
464
468
  } else if (totalFailures === 0) {
465
469
  this.log(`\u2705 ${totalPasses}/${totalRun} required tests passed`);
466
470
  if (this.skipped > 0) {
467
- this.log(`\u25CB ${this.skipped} tests skipped (jsdom limitation)`);
471
+ this.log(`\u25CB ${this.skipped} tests skipped`);
468
472
  }
469
473
  if (this.optionalSuggestions > 0) {
470
474
  this.log(`\u{1F4A1} ${this.optionalSuggestions} optional enhancement${this.optionalSuggestions > 1 ? "s" : ""} suggested`);
@@ -586,6 +590,56 @@ var init_contractTestRunner = __esm({
586
590
  }
587
591
  });
588
592
 
593
+ // src/utils/test/contract/playwrightTestHarness.ts
594
+ async function getOrCreateBrowser() {
595
+ if (!sharedBrowser) {
596
+ sharedBrowser = await import_playwright3.chromium.launch({
597
+ headless: true,
598
+ // Launch with clean browser profile - no extensions, no user data
599
+ args: [
600
+ "--disable-extensions",
601
+ "--disable-blink-features=AutomationControlled"
602
+ ]
603
+ });
604
+ }
605
+ return sharedBrowser;
606
+ }
607
+ async function getOrCreateContext() {
608
+ if (!sharedContext) {
609
+ const browser = await getOrCreateBrowser();
610
+ sharedContext = await browser.newContext({
611
+ // Isolated context - no permissions, no geolocation, etc.
612
+ permissions: [],
613
+ // Ignore HTTPS errors for local dev servers
614
+ ignoreHTTPSErrors: true
615
+ });
616
+ }
617
+ return sharedContext;
618
+ }
619
+ async function createTestPage() {
620
+ const context = await getOrCreateContext();
621
+ return await context.newPage();
622
+ }
623
+ async function closeSharedBrowser() {
624
+ if (sharedContext) {
625
+ await sharedContext.close();
626
+ sharedContext = null;
627
+ }
628
+ if (sharedBrowser) {
629
+ await sharedBrowser.close();
630
+ sharedBrowser = null;
631
+ }
632
+ }
633
+ var import_playwright3, sharedBrowser, sharedContext;
634
+ var init_playwrightTestHarness = __esm({
635
+ "src/utils/test/contract/playwrightTestHarness.ts"() {
636
+ "use strict";
637
+ import_playwright3 = require("playwright");
638
+ sharedBrowser = null;
639
+ sharedContext = null;
640
+ }
641
+ });
642
+
589
643
  // node_modules/@playwright/test/index.mjs
590
644
  var test_exports = {};
591
645
  __export(test_exports, {
@@ -621,34 +675,35 @@ async function runContractTestsPlaywright(componentName, url) {
621
675
  const failures = [];
622
676
  const passes = [];
623
677
  const skipped = [];
624
- let browser = null;
678
+ let page = null;
679
+ const useNavigation = !!url;
625
680
  try {
626
- browser = await import_playwright3.chromium.launch({ headless: true });
627
- const context = await browser.newContext();
628
- const page = await context.newPage();
629
- await page.goto(url, {
630
- waitUntil: "domcontentloaded",
631
- timeout: 9e4
632
- });
681
+ page = await createTestPage();
682
+ if (url) {
683
+ await page.goto(url, {
684
+ waitUntil: "domcontentloaded",
685
+ timeout: 3e4
686
+ });
687
+ await page.addStyleTag({ content: `* { transition: none !important; animation: none !important; }` });
688
+ }
633
689
  const mainSelector = componentContract.selectors.trigger || componentContract.selectors.input || componentContract.selectors.container;
634
690
  if (!mainSelector) {
635
691
  throw new Error(`No main selector (trigger, input, or container) found in contract for ${componentName}`);
636
692
  }
637
- await page.waitForSelector(mainSelector, { timeout: 9e4 });
693
+ const elementTimeout = useNavigation ? 3e4 : 5e3;
694
+ await page.locator(mainSelector).first().waitFor({ state: "attached", timeout: elementTimeout });
638
695
  if (componentName === "menu" && componentContract.selectors.trigger) {
639
- await page.waitForFunction(
640
- (selector) => {
641
- const trigger = document.querySelector(selector);
642
- return trigger && trigger.getAttribute("data-menu-initialized") === "true";
643
- },
644
- componentContract.selectors.trigger,
645
- { timeout: 1e4 }
646
- ).catch(() => {
647
- console.warn("Menu initialization signal not detected, continuing with tests...");
696
+ await page.locator(componentContract.selectors.trigger).first().waitFor({
697
+ state: "visible",
698
+ timeout: 5e3
699
+ }).catch(() => {
700
+ console.warn("Menu trigger not visible, continuing with tests...");
648
701
  });
649
- await page.waitForTimeout(300);
650
702
  }
651
703
  async function resolveRelativeTarget(selector, relative) {
704
+ if (!page) {
705
+ throw new Error("Page is not initialized");
706
+ }
652
707
  const items = await page.locator(selector).all();
653
708
  switch (relative) {
654
709
  case "first":
@@ -718,11 +773,11 @@ async function runContractTestsPlaywright(componentName, url) {
718
773
  for (const dynamicTest of componentContract.dynamic || []) {
719
774
  const { action, assertions } = dynamicTest;
720
775
  const failuresBeforeTest = failures.length;
721
- if (componentContract.selectors.listbox || componentContract.selectors.container) {
722
- const popupSelector = componentContract.selectors.listbox || componentContract.selectors.container;
776
+ if (componentContract.selectors.popup) {
777
+ const popupSelector = componentContract.selectors.popup;
723
778
  if (!popupSelector) continue;
724
779
  const popupElement = page.locator(popupSelector).first();
725
- const isPopupVisible = await popupElement.isVisible();
780
+ const isPopupVisible = await popupElement.isVisible().catch(() => false);
726
781
  if (isPopupVisible) {
727
782
  let menuClosed = false;
728
783
  let closeSelector = componentContract.selectors.input;
@@ -734,73 +789,35 @@ async function runContractTestsPlaywright(componentName, url) {
734
789
  if (closeSelector) {
735
790
  const closeElement = page.locator(closeSelector).first();
736
791
  await closeElement.focus();
737
- await page.waitForTimeout(200);
738
792
  await page.keyboard.press("Escape");
739
- menuClosed = await page.waitForFunction(
740
- (selector) => {
741
- const popup = document.querySelector(selector);
742
- return popup && getComputedStyle(popup).display === "none";
743
- },
744
- popupSelector,
745
- { timeout: 3e3 }
746
- ).then(() => true).catch(() => false);
793
+ menuClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: 2e3 }).then(() => true).catch(() => false);
747
794
  }
748
795
  if (!menuClosed && componentContract.selectors.trigger) {
749
796
  const triggerElement = page.locator(componentContract.selectors.trigger).first();
750
797
  await triggerElement.click();
751
- await page.waitForTimeout(500);
752
- menuClosed = await page.waitForFunction(
753
- (selector) => {
754
- const popup = document.querySelector(selector);
755
- return popup && getComputedStyle(popup).display === "none";
756
- },
757
- popupSelector,
758
- { timeout: 3e3 }
759
- ).then(() => true).catch(() => false);
798
+ menuClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: 2e3 }).then(() => true).catch(() => false);
760
799
  }
761
800
  if (!menuClosed) {
762
801
  await page.mouse.click(10, 10);
763
- await page.waitForTimeout(500);
764
- menuClosed = await page.waitForFunction(
765
- (selector) => {
766
- const popup = document.querySelector(selector);
767
- return popup && getComputedStyle(popup).display === "none";
768
- },
769
- popupSelector,
770
- { timeout: 3e3 }
771
- ).then(() => true).catch(() => false);
772
- if (menuClosed) {
773
- console.log("\u{1F3AF} Strategy 3 (Click outside) worked");
774
- }
802
+ menuClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: 2e3 }).then(() => true).catch(() => false);
775
803
  }
776
804
  if (!menuClosed) {
777
- throw new Error(
778
- `\u274C FATAL: Cannot close menu between tests. Menu remains visible after trying:
805
+ if (useNavigation) {
806
+ throw new Error(
807
+ `\u274C FATAL: Cannot close menu between tests. Menu remains visible after trying:
779
808
  1. Escape key
780
809
  2. Clicking trigger
781
810
  3. Clicking outside
782
811
  This indicates a problem with the menu component's close functionality.`
783
- );
784
- }
785
- if (componentName === "menu" && componentContract.selectors.trigger) {
786
- await page.waitForFunction(
787
- (selector) => {
788
- const trigger = document.querySelector(selector);
789
- return document.activeElement === trigger;
790
- },
791
- componentContract.selectors.trigger,
792
- { timeout: 2e3 }
793
- ).catch(async () => {
794
- const triggerElement = page.locator(componentContract.selectors.trigger).first();
795
- await triggerElement.focus();
796
- await page.waitForTimeout(200);
797
- });
812
+ );
813
+ }
798
814
  }
799
- await page.waitForTimeout(500);
800
815
  if (componentContract.selectors.input) {
801
- const inputElement = page.locator(componentContract.selectors.input).first();
802
- await inputElement.clear();
803
- await page.waitForTimeout(100);
816
+ await page.locator(componentContract.selectors.input).first().clear();
817
+ }
818
+ if (componentName === "menu" && componentContract.selectors.trigger) {
819
+ const triggerElement = page.locator(componentContract.selectors.trigger).first();
820
+ await triggerElement.focus();
804
821
  }
805
822
  }
806
823
  }
@@ -844,7 +861,6 @@ This indicates a problem with the menu component's close functionality.`
844
861
  continue;
845
862
  }
846
863
  await page.locator(focusSelector).first().focus();
847
- await page.waitForTimeout(100);
848
864
  }
849
865
  if (act.type === "type" && act.value) {
850
866
  const typeSelector = componentContract.selectors[act.target];
@@ -853,7 +869,6 @@ This indicates a problem with the menu component's close functionality.`
853
869
  continue;
854
870
  }
855
871
  await page.locator(typeSelector).first().fill(act.value);
856
- await page.waitForTimeout(100);
857
872
  }
858
873
  if (act.type === "click") {
859
874
  if (act.target === "document") {
@@ -870,7 +885,6 @@ This indicates a problem with the menu component's close functionality.`
870
885
  continue;
871
886
  }
872
887
  await relativeElement.click();
873
- await page.waitForTimeout(componentName === "menu" ? 800 : 200);
874
888
  } else {
875
889
  const actionSelector = componentContract.selectors[act.target];
876
890
  if (!actionSelector) {
@@ -878,7 +892,6 @@ This indicates a problem with the menu component's close functionality.`
878
892
  continue;
879
893
  }
880
894
  await page.locator(actionSelector).first().click();
881
- await page.waitForTimeout(componentName === "menu" ? 800 : 200);
882
895
  }
883
896
  }
884
897
  if (act.type === "keypress" && act.key) {
@@ -901,9 +914,7 @@ This indicates a problem with the menu component's close functionality.`
901
914
  keyValue = keyValue.replace(/ /g, "");
902
915
  }
903
916
  if (act.target === "focusable" && ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Escape"].includes(keyValue)) {
904
- await page.waitForTimeout(componentName === "menu" ? 200 : 100);
905
917
  await page.keyboard.press(keyValue);
906
- await page.waitForTimeout(componentName === "menu" ? 300 : 100);
907
918
  } else {
908
919
  const keypressSelector = componentContract.selectors[act.target];
909
920
  if (!keypressSelector) {
@@ -932,7 +943,6 @@ This indicates a problem with the menu component's close functionality.`
932
943
  continue;
933
944
  }
934
945
  await relativeElement.hover();
935
- await page.waitForTimeout(100);
936
946
  } else {
937
947
  const hoverSelector = componentContract.selectors[act.target];
938
948
  if (!hoverSelector) {
@@ -940,12 +950,9 @@ This indicates a problem with the menu component's close functionality.`
940
950
  continue;
941
951
  }
942
952
  await page.locator(hoverSelector).first().hover();
943
- await page.waitForTimeout(100);
944
953
  }
945
954
  }
946
- await page.waitForTimeout(componentName === "menu" ? 200 : 100);
947
955
  }
948
- await page.waitForTimeout(componentName === "menu" ? 300 : 100);
949
956
  for (const assertion of assertions) {
950
957
  let target;
951
958
  if (assertion.target === "relative") {
@@ -974,7 +981,7 @@ This indicates a problem with the menu component's close functionality.`
974
981
  }
975
982
  if (assertion.assertion === "toBeVisible") {
976
983
  try {
977
- await (0, test_exports.expect)(target).toBeVisible({ timeout: 3e3 });
984
+ await (0, test_exports.expect)(target).toBeVisible({ timeout: 2e3 });
978
985
  passes.push(`${assertion.target} is visible as expected. Test: "${dynamicTest.description}".`);
979
986
  } catch {
980
987
  const debugState = await page.evaluate((sel) => {
@@ -988,7 +995,7 @@ This indicates a problem with the menu component's close functionality.`
988
995
  }
989
996
  if (assertion.assertion === "notToBeVisible") {
990
997
  try {
991
- await (0, test_exports.expect)(target).toBeHidden({ timeout: 5e3 });
998
+ await (0, test_exports.expect)(target).toBeHidden({ timeout: 2e3 });
992
999
  passes.push(`${assertion.target} is not visible as expected. Test: "${dynamicTest.description}".`);
993
1000
  } catch {
994
1001
  const debugState = await page.evaluate((sel) => {
@@ -1090,19 +1097,19 @@ This indicates a problem with the menu component's close functionality.`
1090
1097
  }
1091
1098
  }
1092
1099
  } finally {
1093
- if (browser) await browser.close();
1100
+ if (page) await page.close();
1094
1101
  }
1095
1102
  return { passes, failures, skipped };
1096
1103
  }
1097
- var import_playwright3, import_fs, import_meta2;
1104
+ var import_fs, import_meta2;
1098
1105
  var init_contractTestRunnerPlaywright = __esm({
1099
1106
  "src/utils/test/contract/contractTestRunnerPlaywright.ts"() {
1100
1107
  "use strict";
1101
- import_playwright3 = require("playwright");
1102
1108
  init_test();
1103
1109
  import_fs = require("fs");
1104
1110
  init_contract();
1105
1111
  init_ContractReporter();
1112
+ init_playwrightTestHarness();
1106
1113
  import_meta2 = {};
1107
1114
  }
1108
1115
  });
@@ -1112,56 +1119,58 @@ async function testUiComponent(componentName, component, url) {
1112
1119
  if (!componentName || typeof componentName !== "string") {
1113
1120
  throw new Error("\u274C testUiComponent requires a valid componentName (string)");
1114
1121
  }
1115
- if (!component || !(component instanceof HTMLElement)) {
1116
- throw new Error("\u274C testUiComponent requires a valid component (HTMLElement)");
1122
+ if (!url && (!component || !(component instanceof HTMLElement))) {
1123
+ throw new Error("\u274C testUiComponent requires either a valid component (HTMLElement) or a URL");
1117
1124
  }
1118
1125
  if (url && typeof url !== "string") {
1119
1126
  throw new Error("\u274C testUiComponent url parameter must be a string");
1120
1127
  }
1121
1128
  let results;
1122
- try {
1123
- results = await (0, import_jest_axe.axe)(component);
1124
- } catch (error) {
1125
- throw new Error(
1126
- `\u274C Axe accessibility scan failed
1129
+ if (component) {
1130
+ try {
1131
+ results = await (0, import_jest_axe.axe)(component);
1132
+ } catch (error) {
1133
+ throw new Error(
1134
+ `\u274C Axe accessibility scan failed
1127
1135
  Error: ${error instanceof Error ? error.message : String(error)}`
1128
- );
1136
+ );
1137
+ }
1138
+ } else {
1139
+ results = { violations: [] };
1129
1140
  }
1130
- async function checkDevServer(testUrl) {
1131
- const urlsToTry = testUrl ? [testUrl] : [
1132
- "http://localhost:5173",
1133
- "http://localhost:3000",
1134
- "http://localhost:8080",
1135
- "http://localhost:4173"
1136
- ];
1137
- for (const serverUrl of urlsToTry) {
1138
- try {
1139
- const response = await fetch(serverUrl, {
1140
- method: "HEAD",
1141
- signal: AbortSignal.timeout(1e3)
1142
- });
1143
- if (response.ok || response.status === 304) {
1144
- return serverUrl;
1145
- }
1146
- } catch {
1147
- return null;
1141
+ async function checkDevServer(url2) {
1142
+ try {
1143
+ const response = await fetch(url2, {
1144
+ method: "HEAD",
1145
+ signal: AbortSignal.timeout(1e3)
1146
+ });
1147
+ if (response.ok || response.status === 304) {
1148
+ return url2;
1148
1149
  }
1150
+ } catch {
1151
+ return null;
1149
1152
  }
1150
1153
  return null;
1151
1154
  }
1152
1155
  let contract;
1153
1156
  try {
1154
- const devServerUrl = await checkDevServer(url);
1155
- if (devServerUrl) {
1156
- console.log(`\u{1F3AD} Running Playwright E2E tests on ${devServerUrl}`);
1157
- const { runContractTestsPlaywright: runContractTestsPlaywright2 } = await Promise.resolve().then(() => (init_contractTestRunnerPlaywright(), contractTestRunnerPlaywright_exports));
1158
- contract = await runContractTestsPlaywright2(componentName, devServerUrl);
1159
- } else {
1160
- console.log(`\u{1F9EA} Running jsdom tests (limited event handling)`);
1161
- console.log(`\u26A0\uFE0F No dev server detected. Some tests may be skipped.
1162
- For full coverage start your dev server and provide a URL.
1163
- `);
1157
+ if (url) {
1158
+ const devServerUrl = await checkDevServer(url);
1159
+ if (devServerUrl) {
1160
+ console.log(`\u{1F3AD} Running Playwright tests on ${devServerUrl}`);
1161
+ const { runContractTestsPlaywright: runContractTestsPlaywright2 } = await Promise.resolve().then(() => (init_contractTestRunnerPlaywright(), contractTestRunnerPlaywright_exports));
1162
+ contract = await runContractTestsPlaywright2(componentName, devServerUrl);
1163
+ } else {
1164
+ throw new Error(
1165
+ `\u274C Dev server not running at ${url}
1166
+ Please start your dev server and try again.`
1167
+ );
1168
+ }
1169
+ } else if (component) {
1170
+ console.log(`\u{1F3AD} Running component contract tests in JSDOM mode`);
1164
1171
  contract = await runContractTests(componentName, component);
1172
+ } else {
1173
+ throw new Error("\u274C Either component or URL must be provided");
1165
1174
  }
1166
1175
  } catch (error) {
1167
1176
  if (error instanceof Error) {
@@ -1203,12 +1212,16 @@ ${violationDetails}
1203
1212
  }
1204
1213
  return result;
1205
1214
  }
1215
+ async function cleanupTests() {
1216
+ await closeSharedBrowser();
1217
+ }
1206
1218
  var import_jest_axe, runTest;
1207
1219
  var init_test2 = __esm({
1208
1220
  "src/utils/test/src/test.ts"() {
1209
1221
  "use strict";
1210
1222
  import_jest_axe = require("jest-axe");
1211
1223
  init_contractTestRunner();
1224
+ init_playwrightTestHarness();
1212
1225
  runTest = async () => {
1213
1226
  };
1214
1227
  if (typeof window === "undefined") {
@@ -1239,6 +1252,7 @@ var init_test2 = __esm({
1239
1252
  // src/utils/test/index.ts
1240
1253
  var test_exports2 = {};
1241
1254
  __export(test_exports2, {
1255
+ cleanupTests: () => cleanupTests,
1242
1256
  runTest: () => runTest,
1243
1257
  testUiComponent: () => testUiComponent
1244
1258
  });
package/bin/cli.js CHANGED
@@ -204,7 +204,7 @@ program.command("audit").description("Run axe-core powered accessibility audit o
204
204
  console.log(chalk.green("\n\u{1F389} All audits completed."));
205
205
  });
206
206
  program.command("test").description("Run core a11y accessibility standard tests on UI components").action(async () => {
207
- const { runTest } = await import("./test-RHQ2LJVG.js");
207
+ const { runTest } = await import("./test-X6K2LCMO.js");
208
208
  runTest();
209
209
  });
210
210
  program.command("help").description("Display help information").action(() => {