aria-ease 5.0.3 → 6.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/README.md CHANGED
@@ -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
 
@@ -186,7 +186,7 @@ ${"\u2550".repeat(60)}`);
186
186
  } else if (totalFailures === 0) {
187
187
  this.log(`\u2705 ${totalPasses}/${totalRun} required tests passed`);
188
188
  if (this.skipped > 0) {
189
- this.log(`\u25CB ${this.skipped} tests skipped (jsdom limitation)`);
189
+ this.log(`\u25CB ${this.skipped} tests skipped`);
190
190
  }
191
191
  if (this.optionalSuggestions > 0) {
192
192
  this.log(`\u{1F4A1} ${this.optionalSuggestions} optional enhancement${this.optionalSuggestions > 1 ? "s" : ""} suggested`);
@@ -235,4 +235,53 @@ ${"\u2550".repeat(60)}`);
235
235
  }
236
236
  };
237
237
 
238
- export { ContractReporter, contract_default };
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
+
282
+ export {
283
+ contract_default,
284
+ ContractReporter,
285
+ createTestPage,
286
+ closeSharedBrowser
287
+ };
package/bin/cli.cjs CHANGED
@@ -468,7 +468,7 @@ ${"\u2550".repeat(60)}`);
468
468
  } else if (totalFailures === 0) {
469
469
  this.log(`\u2705 ${totalPasses}/${totalRun} required tests passed`);
470
470
  if (this.skipped > 0) {
471
- this.log(`\u25CB ${this.skipped} tests skipped (jsdom limitation)`);
471
+ this.log(`\u25CB ${this.skipped} tests skipped`);
472
472
  }
473
473
  if (this.optionalSuggestions > 0) {
474
474
  this.log(`\u{1F4A1} ${this.optionalSuggestions} optional enhancement${this.optionalSuggestions > 1 ? "s" : ""} suggested`);
@@ -590,6 +590,56 @@ var init_contractTestRunner = __esm({
590
590
  }
591
591
  });
592
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
+
593
643
  // node_modules/@playwright/test/index.mjs
594
644
  var test_exports = {};
595
645
  __export(test_exports, {
@@ -625,30 +675,33 @@ async function runContractTestsPlaywright(componentName, url) {
625
675
  const failures = [];
626
676
  const passes = [];
627
677
  const skipped = [];
628
- let browser = null;
678
+ let page = null;
629
679
  try {
630
- browser = await import_playwright3.chromium.launch({ headless: true });
631
- const context = await browser.newContext();
632
- const page = await context.newPage();
633
- await page.goto(url, {
634
- waitUntil: "domcontentloaded",
635
- timeout: 9e5
636
- });
637
- await page.addStyleTag({ content: `* { transition: none !important; animation: none !important; }` });
680
+ page = await createTestPage();
681
+ if (url) {
682
+ await page.goto(url, {
683
+ waitUntil: "domcontentloaded",
684
+ timeout: 3e4
685
+ });
686
+ await page.addStyleTag({ content: `* { transition: none !important; animation: none !important; }` });
687
+ }
638
688
  const mainSelector = componentContract.selectors.trigger || componentContract.selectors.input || componentContract.selectors.container;
639
689
  if (!mainSelector) {
640
690
  throw new Error(`No main selector (trigger, input, or container) found in contract for ${componentName}`);
641
691
  }
642
- await page.locator(mainSelector).first().waitFor({ state: "attached", timeout: 9e5 });
692
+ await page.locator(mainSelector).first().waitFor({ state: "attached", timeout: 3e4 });
643
693
  if (componentName === "menu" && componentContract.selectors.trigger) {
644
694
  await page.locator(componentContract.selectors.trigger).first().waitFor({
645
695
  state: "visible",
646
- timeout: 1e4
696
+ timeout: 5e3
647
697
  }).catch(() => {
648
698
  console.warn("Menu trigger not visible, continuing with tests...");
649
699
  });
650
700
  }
651
701
  async function resolveRelativeTarget(selector, relative) {
702
+ if (!page) {
703
+ throw new Error("Page is not initialized");
704
+ }
652
705
  const items = await page.locator(selector).all();
653
706
  switch (relative) {
654
707
  case "first":
@@ -718,8 +771,8 @@ async function runContractTestsPlaywright(componentName, url) {
718
771
  for (const dynamicTest of componentContract.dynamic || []) {
719
772
  const { action, assertions } = dynamicTest;
720
773
  const failuresBeforeTest = failures.length;
721
- if (componentContract.selectors.listbox || componentContract.selectors.container) {
722
- const popupSelector = componentContract.selectors.listbox || componentContract.selectors.container;
774
+ if (componentContract.selectors.popup) {
775
+ const popupSelector = componentContract.selectors.popup;
723
776
  if (!popupSelector) continue;
724
777
  const popupElement = page.locator(popupSelector).first();
725
778
  const isPopupVisible = await popupElement.isVisible().catch(() => false);
@@ -735,16 +788,16 @@ async function runContractTestsPlaywright(componentName, url) {
735
788
  const closeElement = page.locator(closeSelector).first();
736
789
  await closeElement.focus();
737
790
  await page.keyboard.press("Escape");
738
- menuClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: 3e3 }).then(() => true).catch(() => false);
791
+ menuClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: 2e3 }).then(() => true).catch(() => false);
739
792
  }
740
793
  if (!menuClosed && componentContract.selectors.trigger) {
741
794
  const triggerElement = page.locator(componentContract.selectors.trigger).first();
742
795
  await triggerElement.click();
743
- menuClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: 3e3 }).then(() => true).catch(() => false);
796
+ menuClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: 2e3 }).then(() => true).catch(() => false);
744
797
  }
745
798
  if (!menuClosed) {
746
799
  await page.mouse.click(10, 10);
747
- menuClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: 3e3 }).then(() => true).catch(() => false);
800
+ menuClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: 2e3 }).then(() => true).catch(() => false);
748
801
  }
749
802
  if (!menuClosed) {
750
803
  throw new Error(
@@ -764,6 +817,23 @@ This indicates a problem with the menu component's close functionality.`
764
817
  }
765
818
  }
766
819
  }
820
+ if (componentContract.selectors.panel && componentContract.selectors.trigger && !componentContract.selectors.popup) {
821
+ const triggerSelector = componentContract.selectors.trigger;
822
+ const panelSelector = componentContract.selectors.panel;
823
+ if (triggerSelector && panelSelector) {
824
+ const allTriggers = await page.locator(triggerSelector).all();
825
+ for (const trigger of allTriggers) {
826
+ const isExpanded = await trigger.getAttribute("aria-expanded") === "true";
827
+ const triggerPanel = await trigger.getAttribute("aria-controls");
828
+ if (isExpanded && triggerPanel) {
829
+ await trigger.click();
830
+ const panel = page.locator(`#${triggerPanel}`);
831
+ await (0, test_exports.expect)(panel).toBeHidden({ timeout: 1e3 }).catch(() => {
832
+ });
833
+ }
834
+ }
835
+ }
836
+ }
767
837
  let shouldSkipTest = false;
768
838
  for (const act of action) {
769
839
  if (act.type === "keypress" && (act.target === "submenuTrigger" || act.target === "submenu")) {
@@ -924,7 +994,7 @@ This indicates a problem with the menu component's close functionality.`
924
994
  }
925
995
  if (assertion.assertion === "toBeVisible") {
926
996
  try {
927
- await (0, test_exports.expect)(target).toBeVisible({ timeout: 3e3 });
997
+ await (0, test_exports.expect)(target).toBeVisible({ timeout: 2e3 });
928
998
  passes.push(`${assertion.target} is visible as expected. Test: "${dynamicTest.description}".`);
929
999
  } catch {
930
1000
  const debugState = await page.evaluate((sel) => {
@@ -938,7 +1008,7 @@ This indicates a problem with the menu component's close functionality.`
938
1008
  }
939
1009
  if (assertion.assertion === "notToBeVisible") {
940
1010
  try {
941
- await (0, test_exports.expect)(target).toBeHidden({ timeout: 5e3 });
1011
+ await (0, test_exports.expect)(target).toBeHidden({ timeout: 2e3 });
942
1012
  passes.push(`${assertion.target} is not visible as expected. Test: "${dynamicTest.description}".`);
943
1013
  } catch {
944
1014
  const debugState = await page.evaluate((sel) => {
@@ -1040,19 +1110,19 @@ This indicates a problem with the menu component's close functionality.`
1040
1110
  }
1041
1111
  }
1042
1112
  } finally {
1043
- if (browser) await browser.close();
1113
+ if (page) await page.close();
1044
1114
  }
1045
1115
  return { passes, failures, skipped };
1046
1116
  }
1047
- var import_playwright3, import_fs, import_meta2;
1117
+ var import_fs, import_meta2;
1048
1118
  var init_contractTestRunnerPlaywright = __esm({
1049
1119
  "src/utils/test/contract/contractTestRunnerPlaywright.ts"() {
1050
1120
  "use strict";
1051
- import_playwright3 = require("playwright");
1052
1121
  init_test();
1053
1122
  import_fs = require("fs");
1054
1123
  init_contract();
1055
1124
  init_ContractReporter();
1125
+ init_playwrightTestHarness();
1056
1126
  import_meta2 = {};
1057
1127
  }
1058
1128
  });
@@ -1062,56 +1132,58 @@ async function testUiComponent(componentName, component, url) {
1062
1132
  if (!componentName || typeof componentName !== "string") {
1063
1133
  throw new Error("\u274C testUiComponent requires a valid componentName (string)");
1064
1134
  }
1065
- if (!component || !(component instanceof HTMLElement)) {
1066
- throw new Error("\u274C testUiComponent requires a valid component (HTMLElement)");
1135
+ if (!url && (!component || !(component instanceof HTMLElement))) {
1136
+ throw new Error("\u274C testUiComponent requires either a valid component (HTMLElement) or a URL");
1067
1137
  }
1068
1138
  if (url && typeof url !== "string") {
1069
1139
  throw new Error("\u274C testUiComponent url parameter must be a string");
1070
1140
  }
1071
1141
  let results;
1072
- try {
1073
- results = await (0, import_jest_axe.axe)(component);
1074
- } catch (error) {
1075
- throw new Error(
1076
- `\u274C Axe accessibility scan failed
1142
+ if (component) {
1143
+ try {
1144
+ results = await (0, import_jest_axe.axe)(component);
1145
+ } catch (error) {
1146
+ throw new Error(
1147
+ `\u274C Axe accessibility scan failed
1077
1148
  Error: ${error instanceof Error ? error.message : String(error)}`
1078
- );
1149
+ );
1150
+ }
1151
+ } else {
1152
+ results = { violations: [] };
1079
1153
  }
1080
- async function checkDevServer(testUrl) {
1081
- const urlsToTry = testUrl ? [testUrl] : [
1082
- "http://localhost:5173",
1083
- "http://localhost:3000",
1084
- "http://localhost:8080",
1085
- "http://localhost:4173"
1086
- ];
1087
- for (const serverUrl of urlsToTry) {
1088
- try {
1089
- const response = await fetch(serverUrl, {
1090
- method: "HEAD",
1091
- signal: AbortSignal.timeout(1e3)
1092
- });
1093
- if (response.ok || response.status === 304) {
1094
- return serverUrl;
1095
- }
1096
- } catch {
1097
- return null;
1154
+ async function checkDevServer(url2) {
1155
+ try {
1156
+ const response = await fetch(url2, {
1157
+ method: "HEAD",
1158
+ signal: AbortSignal.timeout(1e3)
1159
+ });
1160
+ if (response.ok || response.status === 304) {
1161
+ return url2;
1098
1162
  }
1163
+ } catch {
1164
+ return null;
1099
1165
  }
1100
1166
  return null;
1101
1167
  }
1102
1168
  let contract;
1103
1169
  try {
1104
- const devServerUrl = await checkDevServer(url);
1105
- if (devServerUrl) {
1106
- console.log(`\u{1F3AD} Running Playwright E2E tests on ${devServerUrl}`);
1107
- const { runContractTestsPlaywright: runContractTestsPlaywright2 } = await Promise.resolve().then(() => (init_contractTestRunnerPlaywright(), contractTestRunnerPlaywright_exports));
1108
- contract = await runContractTestsPlaywright2(componentName, devServerUrl);
1109
- } else {
1110
- console.log(`\u{1F9EA} Running jsdom tests (limited event handling)`);
1111
- console.log(`\u26A0\uFE0F No dev server detected. Some tests may be skipped.
1112
- For full coverage start your dev server and provide a URL.
1113
- `);
1170
+ if (url) {
1171
+ const devServerUrl = await checkDevServer(url);
1172
+ if (devServerUrl) {
1173
+ console.log(`\u{1F3AD} Running Playwright tests on ${devServerUrl}`);
1174
+ const { runContractTestsPlaywright: runContractTestsPlaywright2 } = await Promise.resolve().then(() => (init_contractTestRunnerPlaywright(), contractTestRunnerPlaywright_exports));
1175
+ contract = await runContractTestsPlaywright2(componentName, devServerUrl);
1176
+ } else {
1177
+ throw new Error(
1178
+ `\u274C Dev server not running at ${url}
1179
+ Please start your dev server and try again.`
1180
+ );
1181
+ }
1182
+ } else if (component) {
1183
+ console.log(`\u{1F3AD} Running component contract tests in JSDOM mode`);
1114
1184
  contract = await runContractTests(componentName, component);
1185
+ } else {
1186
+ throw new Error("\u274C Either component or URL must be provided");
1115
1187
  }
1116
1188
  } catch (error) {
1117
1189
  if (error instanceof Error) {
@@ -1153,12 +1225,16 @@ ${violationDetails}
1153
1225
  }
1154
1226
  return result;
1155
1227
  }
1228
+ async function cleanupTests() {
1229
+ await closeSharedBrowser();
1230
+ }
1156
1231
  var import_jest_axe, runTest;
1157
1232
  var init_test2 = __esm({
1158
1233
  "src/utils/test/src/test.ts"() {
1159
1234
  "use strict";
1160
1235
  import_jest_axe = require("jest-axe");
1161
1236
  init_contractTestRunner();
1237
+ init_playwrightTestHarness();
1162
1238
  runTest = async () => {
1163
1239
  };
1164
1240
  if (typeof window === "undefined") {
@@ -1189,6 +1265,7 @@ var init_test2 = __esm({
1189
1265
  // src/utils/test/index.ts
1190
1266
  var test_exports2 = {};
1191
1267
  __export(test_exports2, {
1268
+ cleanupTests: () => cleanupTests,
1192
1269
  runTest: () => runTest,
1193
1270
  testUiComponent: () => testUiComponent
1194
1271
  });
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-JNQFZBJA.js");
207
+ const { runTest } = await import("./test-HH2EW2NM.js");
208
208
  runTest();
209
209
  });
210
210
  program.command("help").description("Display help information").action(() => {
@@ -1,15 +1,13 @@
1
1
  import {
2
2
  ContractReporter,
3
- contract_default
4
- } from "./chunk-TUWQNVQJ.js";
3
+ contract_default,
4
+ createTestPage
5
+ } from "./chunk-7RMRFSJL.js";
5
6
  import {
6
7
  __export,
7
8
  __reExport
8
9
  } from "./chunk-I2KLQ2HA.js";
9
10
 
10
- // src/utils/test/contract/contractTestRunnerPlaywright.ts
11
- import { chromium } from "playwright";
12
-
13
11
  // node_modules/@playwright/test/index.mjs
14
12
  var test_exports = {};
15
13
  __export(test_exports, {
@@ -37,30 +35,33 @@ async function runContractTestsPlaywright(componentName, url) {
37
35
  const failures = [];
38
36
  const passes = [];
39
37
  const skipped = [];
40
- let browser = null;
38
+ let page = null;
41
39
  try {
42
- browser = await chromium.launch({ headless: true });
43
- const context = await browser.newContext();
44
- const page = await context.newPage();
45
- await page.goto(url, {
46
- waitUntil: "domcontentloaded",
47
- timeout: 9e5
48
- });
49
- await page.addStyleTag({ content: `* { transition: none !important; animation: none !important; }` });
40
+ page = await createTestPage();
41
+ if (url) {
42
+ await page.goto(url, {
43
+ waitUntil: "domcontentloaded",
44
+ timeout: 3e4
45
+ });
46
+ await page.addStyleTag({ content: `* { transition: none !important; animation: none !important; }` });
47
+ }
50
48
  const mainSelector = componentContract.selectors.trigger || componentContract.selectors.input || componentContract.selectors.container;
51
49
  if (!mainSelector) {
52
50
  throw new Error(`No main selector (trigger, input, or container) found in contract for ${componentName}`);
53
51
  }
54
- await page.locator(mainSelector).first().waitFor({ state: "attached", timeout: 9e5 });
52
+ await page.locator(mainSelector).first().waitFor({ state: "attached", timeout: 3e4 });
55
53
  if (componentName === "menu" && componentContract.selectors.trigger) {
56
54
  await page.locator(componentContract.selectors.trigger).first().waitFor({
57
55
  state: "visible",
58
- timeout: 1e4
56
+ timeout: 5e3
59
57
  }).catch(() => {
60
58
  console.warn("Menu trigger not visible, continuing with tests...");
61
59
  });
62
60
  }
63
61
  async function resolveRelativeTarget(selector, relative) {
62
+ if (!page) {
63
+ throw new Error("Page is not initialized");
64
+ }
64
65
  const items = await page.locator(selector).all();
65
66
  switch (relative) {
66
67
  case "first":
@@ -130,8 +131,8 @@ async function runContractTestsPlaywright(componentName, url) {
130
131
  for (const dynamicTest of componentContract.dynamic || []) {
131
132
  const { action, assertions } = dynamicTest;
132
133
  const failuresBeforeTest = failures.length;
133
- if (componentContract.selectors.listbox || componentContract.selectors.container) {
134
- const popupSelector = componentContract.selectors.listbox || componentContract.selectors.container;
134
+ if (componentContract.selectors.popup) {
135
+ const popupSelector = componentContract.selectors.popup;
135
136
  if (!popupSelector) continue;
136
137
  const popupElement = page.locator(popupSelector).first();
137
138
  const isPopupVisible = await popupElement.isVisible().catch(() => false);
@@ -147,16 +148,16 @@ async function runContractTestsPlaywright(componentName, url) {
147
148
  const closeElement = page.locator(closeSelector).first();
148
149
  await closeElement.focus();
149
150
  await page.keyboard.press("Escape");
150
- menuClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: 3e3 }).then(() => true).catch(() => false);
151
+ menuClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: 2e3 }).then(() => true).catch(() => false);
151
152
  }
152
153
  if (!menuClosed && componentContract.selectors.trigger) {
153
154
  const triggerElement = page.locator(componentContract.selectors.trigger).first();
154
155
  await triggerElement.click();
155
- menuClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: 3e3 }).then(() => true).catch(() => false);
156
+ menuClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: 2e3 }).then(() => true).catch(() => false);
156
157
  }
157
158
  if (!menuClosed) {
158
159
  await page.mouse.click(10, 10);
159
- menuClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: 3e3 }).then(() => true).catch(() => false);
160
+ menuClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: 2e3 }).then(() => true).catch(() => false);
160
161
  }
161
162
  if (!menuClosed) {
162
163
  throw new Error(
@@ -176,6 +177,23 @@ This indicates a problem with the menu component's close functionality.`
176
177
  }
177
178
  }
178
179
  }
180
+ if (componentContract.selectors.panel && componentContract.selectors.trigger && !componentContract.selectors.popup) {
181
+ const triggerSelector = componentContract.selectors.trigger;
182
+ const panelSelector = componentContract.selectors.panel;
183
+ if (triggerSelector && panelSelector) {
184
+ const allTriggers = await page.locator(triggerSelector).all();
185
+ for (const trigger of allTriggers) {
186
+ const isExpanded = await trigger.getAttribute("aria-expanded") === "true";
187
+ const triggerPanel = await trigger.getAttribute("aria-controls");
188
+ if (isExpanded && triggerPanel) {
189
+ await trigger.click();
190
+ const panel = page.locator(`#${triggerPanel}`);
191
+ await (0, test_exports.expect)(panel).toBeHidden({ timeout: 1e3 }).catch(() => {
192
+ });
193
+ }
194
+ }
195
+ }
196
+ }
179
197
  let shouldSkipTest = false;
180
198
  for (const act of action) {
181
199
  if (act.type === "keypress" && (act.target === "submenuTrigger" || act.target === "submenu")) {
@@ -336,7 +354,7 @@ This indicates a problem with the menu component's close functionality.`
336
354
  }
337
355
  if (assertion.assertion === "toBeVisible") {
338
356
  try {
339
- await (0, test_exports.expect)(target).toBeVisible({ timeout: 3e3 });
357
+ await (0, test_exports.expect)(target).toBeVisible({ timeout: 2e3 });
340
358
  passes.push(`${assertion.target} is visible as expected. Test: "${dynamicTest.description}".`);
341
359
  } catch {
342
360
  const debugState = await page.evaluate((sel) => {
@@ -350,7 +368,7 @@ This indicates a problem with the menu component's close functionality.`
350
368
  }
351
369
  if (assertion.assertion === "notToBeVisible") {
352
370
  try {
353
- await (0, test_exports.expect)(target).toBeHidden({ timeout: 5e3 });
371
+ await (0, test_exports.expect)(target).toBeHidden({ timeout: 2e3 });
354
372
  passes.push(`${assertion.target} is not visible as expected. Test: "${dynamicTest.description}".`);
355
373
  } catch {
356
374
  const debugState = await page.evaluate((sel) => {
@@ -452,7 +470,7 @@ This indicates a problem with the menu component's close functionality.`
452
470
  }
453
471
  }
454
472
  } finally {
455
- if (browser) await browser.close();
473
+ if (page) await page.close();
456
474
  }
457
475
  return { passes, failures, skipped };
458
476
  }