aria-ease 6.2.1 → 6.2.2

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.
Files changed (37) hide show
  1. package/README.md +5 -17
  2. package/bin/cli.cjs +227 -115
  3. package/bin/cli.js +1 -1
  4. package/bin/{contractTestRunnerPlaywright-HL2VPEEV.js → contractTestRunnerPlaywright-ACAWN34W.js} +227 -115
  5. package/bin/{test-HH2EW2NM.js → test-A3ESFXOR.js} +1 -1
  6. package/dist/{contractTestRunnerPlaywright-EXEBWWPC.js → contractTestRunnerPlaywright-O7FF7GV4.js} +227 -115
  7. package/dist/index.cjs +229 -116
  8. package/dist/index.d.cts +10 -0
  9. package/dist/index.d.ts +10 -0
  10. package/dist/index.js +3 -2
  11. package/dist/src/{Types.d-CxWrr421.d.ts → Types.d-CRjhbrcw.d.cts} +10 -0
  12. package/dist/src/{Types.d-CxWrr421.d.cts → Types.d-CRjhbrcw.d.ts} +10 -0
  13. package/dist/src/accordion/index.d.cts +1 -1
  14. package/dist/src/accordion/index.d.ts +1 -1
  15. package/dist/src/block/index.d.cts +1 -1
  16. package/dist/src/block/index.d.ts +1 -1
  17. package/dist/src/checkbox/index.d.cts +1 -1
  18. package/dist/src/checkbox/index.d.ts +1 -1
  19. package/dist/src/combobox/index.cjs +1 -1
  20. package/dist/src/combobox/index.d.cts +1 -1
  21. package/dist/src/combobox/index.d.ts +1 -1
  22. package/dist/src/combobox/index.js +1 -1
  23. package/dist/src/menu/index.d.cts +1 -1
  24. package/dist/src/menu/index.d.ts +1 -1
  25. package/dist/src/radio/index.cjs +1 -0
  26. package/dist/src/radio/index.d.cts +1 -1
  27. package/dist/src/radio/index.d.ts +1 -1
  28. package/dist/src/radio/index.js +1 -0
  29. package/dist/src/toggle/index.d.cts +1 -1
  30. package/dist/src/toggle/index.d.ts +1 -1
  31. package/dist/src/utils/test/{contractTestRunnerPlaywright-LJHY3AB4.js → contractTestRunnerPlaywright-7BPRTIN4.js} +227 -115
  32. package/dist/src/utils/test/contracts/AccordionContract.json +1 -0
  33. package/dist/src/utils/test/contracts/ComboboxContract.json +1 -0
  34. package/dist/src/utils/test/contracts/MenuContract.json +1 -0
  35. package/dist/src/utils/test/index.cjs +227 -115
  36. package/dist/src/utils/test/index.js +1 -1
  37. package/package.json +1 -1
package/README.md CHANGED
@@ -128,23 +128,11 @@ menu.refresh();
128
128
  **Required HTML structure:**
129
129
 
130
130
  ```html
131
- <button
132
- id="menu-button"
133
- aria-expanded="false"
134
- aria-controls="dropdown-menu"
135
- aria-haspopup="true"
136
- >
137
- Menu
138
- </button>
139
- <div
140
- id="dropdown-menu"
141
- style="display: none;"
142
- aria-labelledby="menu-button"
143
- role="menu"
144
- >
145
- <a role="menuitem" href="#" class="menu-item">Item 1</a>
146
- <a role="menuitem" href="#" class="menu-item">Item 2</a>
147
- <button role="menuitem" class="menu-item">Item 3</button>
131
+ <button id="menu-button" aria-label="Home example menu">Menu</button>
132
+ <div id="dropdown-menu" style="display: none;">
133
+ <a href="#" class="menu-item">Item 1</a>
134
+ <a href="#" class="menu-item">Item 2</a>
135
+ <button class="menu-item">Item 3</button>
148
136
  </div>
149
137
  ```
150
138
 
package/bin/cli.cjs CHANGED
@@ -673,6 +673,11 @@ __export(contractTestRunnerPlaywright_exports, {
673
673
  });
674
674
  async function runContractTestsPlaywright(componentName, url) {
675
675
  const reporter = new ContractReporter(true);
676
+ const actionTimeoutMs = 400;
677
+ const assertionTimeoutMs = 400;
678
+ function isBrowserClosedError(error) {
679
+ return error instanceof Error && error.message.includes("Target page, context or browser has been closed");
680
+ }
676
681
  const contractTyped = contract_default;
677
682
  const contractPath = contractTyped[componentName]?.path;
678
683
  if (!contractPath) {
@@ -691,17 +696,29 @@ async function runContractTestsPlaywright(componentName, url) {
691
696
  try {
692
697
  page = await createTestPage();
693
698
  if (url) {
694
- await page.goto(url, {
695
- waitUntil: "domcontentloaded",
696
- timeout: 3e4
697
- });
699
+ try {
700
+ await page.goto(url, {
701
+ waitUntil: "domcontentloaded",
702
+ timeout: 3e4
703
+ });
704
+ } catch (error) {
705
+ throw new Error(
706
+ `Failed to navigate to ${url}. Ensure dev server is running and accessible. Original error: ${error instanceof Error ? error.message : String(error)}`
707
+ );
708
+ }
698
709
  await page.addStyleTag({ content: `* { transition: none !important; animation: none !important; }` });
699
710
  }
700
711
  const mainSelector = componentContract.selectors.trigger || componentContract.selectors.input || componentContract.selectors.container;
701
712
  if (!mainSelector) {
702
- throw new Error(`No main selector (trigger, input, or container) found in contract for ${componentName}`);
713
+ throw new Error(`CRITICAL: No main selector (trigger, input, or container) found in contract for ${componentName}`);
714
+ }
715
+ try {
716
+ await page.locator(mainSelector).first().waitFor({ state: "attached", timeout: 3e4 });
717
+ } catch (error) {
718
+ throw new Error(
719
+ `CRITICAL: Component element '${mainSelector}' not found on page within 30s. This usually means the component didn't render or the contract selector is incorrect. Original error: ${error instanceof Error ? error.message : String(error)}`
720
+ );
703
721
  }
704
- await page.locator(mainSelector).first().waitFor({ state: "attached", timeout: 3e4 });
705
722
  if (componentName === "menu" && componentContract.selectors.trigger) {
706
723
  await page.locator(componentContract.selectors.trigger).first().waitFor({
707
724
  state: "visible",
@@ -781,6 +798,13 @@ async function runContractTestsPlaywright(componentName, url) {
781
798
  }
782
799
  }
783
800
  for (const dynamicTest of componentContract.dynamic || []) {
801
+ if (!page || page.isClosed()) {
802
+ console.warn(`
803
+ \u26A0\uFE0F Browser closed - skipping remaining ${componentContract.dynamic.length - componentContract.dynamic.indexOf(dynamicTest)} tests
804
+ `);
805
+ failures.push(`CRITICAL: Browser/page closed before completing all tests. ${componentContract.dynamic.length - componentContract.dynamic.indexOf(dynamicTest)} tests skipped.`);
806
+ break;
807
+ }
784
808
  const { action, assertions } = dynamicTest;
785
809
  const failuresBeforeTest = failures.length;
786
810
  if (componentContract.selectors.popup) {
@@ -800,16 +824,16 @@ async function runContractTestsPlaywright(componentName, url) {
800
824
  const closeElement = page.locator(closeSelector).first();
801
825
  await closeElement.focus();
802
826
  await page.keyboard.press("Escape");
803
- menuClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: 2e3 }).then(() => true).catch(() => false);
827
+ menuClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: assertionTimeoutMs }).then(() => true).catch(() => false);
804
828
  }
805
829
  if (!menuClosed && componentContract.selectors.trigger) {
806
830
  const triggerElement = page.locator(componentContract.selectors.trigger).first();
807
- await triggerElement.click();
808
- menuClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: 2e3 }).then(() => true).catch(() => false);
831
+ await triggerElement.click({ timeout: actionTimeoutMs });
832
+ menuClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: assertionTimeoutMs }).then(() => true).catch(() => false);
809
833
  }
810
834
  if (!menuClosed) {
811
835
  await page.mouse.click(10, 10);
812
- menuClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: 2e3 }).then(() => true).catch(() => false);
836
+ menuClosed = await (0, test_exports.expect)(popupElement).toBeHidden({ timeout: assertionTimeoutMs }).then(() => true).catch(() => false);
813
837
  }
814
838
  if (!menuClosed) {
815
839
  throw new Error(
@@ -838,9 +862,9 @@ This indicates a problem with the menu component's close functionality.`
838
862
  const isExpanded = await trigger.getAttribute("aria-expanded") === "true";
839
863
  const triggerPanel = await trigger.getAttribute("aria-controls");
840
864
  if (isExpanded && triggerPanel) {
841
- await trigger.click();
865
+ await trigger.click({ timeout: actionTimeoutMs });
842
866
  const panel = page.locator(`#${triggerPanel}`);
843
- await (0, test_exports.expect)(panel).toBeHidden({ timeout: 1e3 }).catch(() => {
867
+ await (0, test_exports.expect)(panel).toBeHidden({ timeout: assertionTimeoutMs }).catch(() => {
844
868
  });
845
869
  }
846
870
  }
@@ -879,134 +903,192 @@ This indicates a problem with the menu component's close functionality.`
879
903
  continue;
880
904
  }
881
905
  for (const act of action) {
906
+ if (!page || page.isClosed()) {
907
+ failures.push(`CRITICAL: Browser/page closed during test execution. Remaining actions skipped.`);
908
+ break;
909
+ }
882
910
  if (act.type === "focus") {
883
- const focusSelector = componentContract.selectors[act.target];
884
- if (!focusSelector) {
885
- failures.push(`Selector for focus target ${act.target} not found.`);
911
+ try {
912
+ const focusSelector = componentContract.selectors[act.target];
913
+ if (!focusSelector) {
914
+ failures.push(`Selector for focus target ${act.target} not found.`);
915
+ continue;
916
+ }
917
+ await page.locator(focusSelector).first().focus({ timeout: actionTimeoutMs });
918
+ } catch (error) {
919
+ if (isBrowserClosedError(error)) {
920
+ failures.push(`CRITICAL: Browser/page closed during test execution. Remaining actions skipped.`);
921
+ break;
922
+ }
923
+ failures.push(`Failed to focus ${act.target}: ${error instanceof Error ? error.message : String(error)}`);
886
924
  continue;
887
925
  }
888
- await page.locator(focusSelector).first().focus();
889
926
  }
890
927
  if (act.type === "type" && act.value) {
891
- const typeSelector = componentContract.selectors[act.target];
892
- if (!typeSelector) {
893
- failures.push(`Selector for type target ${act.target} not found.`);
928
+ try {
929
+ const typeSelector = componentContract.selectors[act.target];
930
+ if (!typeSelector) {
931
+ failures.push(`Selector for type target ${act.target} not found.`);
932
+ continue;
933
+ }
934
+ await page.locator(typeSelector).first().fill(act.value, { timeout: actionTimeoutMs });
935
+ } catch (error) {
936
+ if (isBrowserClosedError(error)) {
937
+ failures.push(`CRITICAL: Browser/page closed during test execution. Remaining actions skipped.`);
938
+ break;
939
+ }
940
+ failures.push(`Failed to type into ${act.target}: ${error instanceof Error ? error.message : String(error)}`);
894
941
  continue;
895
942
  }
896
- await page.locator(typeSelector).first().fill(act.value);
897
943
  }
898
944
  if (act.type === "click") {
899
- if (act.target === "document") {
900
- await page.mouse.click(10, 10);
901
- } else if (act.target === "relative" && act.relativeTarget) {
902
- const relativeSelector = componentContract.selectors.relative;
903
- if (!relativeSelector) {
904
- failures.push(`Relative selector not defined for click action.`);
905
- continue;
906
- }
907
- const relativeElement = await resolveRelativeTarget(relativeSelector, act.relativeTarget);
908
- if (!relativeElement) {
909
- failures.push(`Could not resolve relative target ${act.relativeTarget} for click.`);
910
- continue;
945
+ try {
946
+ if (act.target === "document") {
947
+ await page.mouse.click(10, 10);
948
+ } else if (act.target === "relative" && act.relativeTarget) {
949
+ const relativeSelector = componentContract.selectors.relative;
950
+ if (!relativeSelector) {
951
+ failures.push(`Relative selector not defined for click action.`);
952
+ continue;
953
+ }
954
+ const relativeElement = await resolveRelativeTarget(relativeSelector, act.relativeTarget);
955
+ if (!relativeElement) {
956
+ failures.push(`Could not resolve relative target ${act.relativeTarget} for click.`);
957
+ continue;
958
+ }
959
+ await relativeElement.click({ timeout: actionTimeoutMs });
960
+ } else {
961
+ const actionSelector = componentContract.selectors[act.target];
962
+ if (!actionSelector) {
963
+ failures.push(`Selector for action target ${act.target} not found.`);
964
+ continue;
965
+ }
966
+ await page.locator(actionSelector).first().click({ timeout: actionTimeoutMs });
911
967
  }
912
- await relativeElement.click();
913
- } else {
914
- const actionSelector = componentContract.selectors[act.target];
915
- if (!actionSelector) {
916
- failures.push(`Selector for action target ${act.target} not found.`);
917
- continue;
968
+ } catch (error) {
969
+ if (isBrowserClosedError(error)) {
970
+ failures.push(`CRITICAL: Browser/page closed during test execution. Remaining actions skipped.`);
971
+ break;
918
972
  }
919
- await page.locator(actionSelector).first().click();
973
+ failures.push(`Failed to click ${act.target}: ${error instanceof Error ? error.message : String(error)}`);
974
+ continue;
920
975
  }
921
976
  }
922
977
  if (act.type === "keypress" && act.key) {
923
- const keyMap = {
924
- "Space": "Space",
925
- "Enter": "Enter",
926
- "Escape": "Escape",
927
- "Arrow Up": "ArrowUp",
928
- "Arrow Down": "ArrowDown",
929
- "Arrow Left": "ArrowLeft",
930
- "Arrow Right": "ArrowRight",
931
- "Home": "Home",
932
- "End": "End",
933
- "Tab": "Tab"
934
- };
935
- let keyValue = keyMap[act.key] || act.key;
936
- if (keyValue === "Space") {
937
- keyValue = " ";
938
- } else if (keyValue.includes(" ")) {
939
- keyValue = keyValue.replace(/ /g, "");
940
- }
941
- if (act.target === "focusable" && ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Escape"].includes(keyValue)) {
942
- await page.keyboard.press(keyValue);
943
- } else {
944
- const keypressSelector = componentContract.selectors[act.target];
945
- if (!keypressSelector) {
946
- failures.push(`Selector for keypress target ${act.target} not found.`);
947
- continue;
978
+ try {
979
+ const keyMap = {
980
+ "Space": "Space",
981
+ "Enter": "Enter",
982
+ "Escape": "Escape",
983
+ "Arrow Up": "ArrowUp",
984
+ "Arrow Down": "ArrowDown",
985
+ "Arrow Left": "ArrowLeft",
986
+ "Arrow Right": "ArrowRight",
987
+ "Home": "Home",
988
+ "End": "End",
989
+ "Tab": "Tab"
990
+ };
991
+ let keyValue = keyMap[act.key] || act.key;
992
+ if (keyValue === "Space") {
993
+ keyValue = " ";
994
+ } else if (keyValue.includes(" ")) {
995
+ keyValue = keyValue.replace(/ /g, "");
948
996
  }
949
- const target = page.locator(keypressSelector).first();
950
- const elementCount = await target.count();
951
- if (elementCount === 0) {
952
- reporter.reportTest(dynamicTest, "skip", `Skipping test - ${act.target} element not found (optional submenu test)`);
997
+ if (act.target === "focusable" && ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Escape"].includes(keyValue)) {
998
+ await page.keyboard.press(keyValue);
999
+ } else {
1000
+ const keypressSelector = componentContract.selectors[act.target];
1001
+ if (!keypressSelector) {
1002
+ failures.push(`Selector for keypress target ${act.target} not found.`);
1003
+ continue;
1004
+ }
1005
+ const target = page.locator(keypressSelector).first();
1006
+ const elementCount = await target.count();
1007
+ if (elementCount === 0) {
1008
+ reporter.reportTest(dynamicTest, "skip", `Skipping test - ${act.target} element not found (optional submenu test)`);
1009
+ break;
1010
+ }
1011
+ await target.press(keyValue, { timeout: actionTimeoutMs });
1012
+ }
1013
+ } catch (error) {
1014
+ if (isBrowserClosedError(error)) {
1015
+ failures.push(`CRITICAL: Browser/page closed during test execution. Remaining actions skipped.`);
953
1016
  break;
954
1017
  }
955
- await target.press(keyValue);
1018
+ failures.push(`Failed to press ${act.key} on ${act.target}: ${error instanceof Error ? error.message : String(error)}`);
1019
+ continue;
956
1020
  }
957
1021
  }
958
1022
  if (act.type === "hover") {
959
- if (act.target === "relative" && act.relativeTarget) {
1023
+ try {
1024
+ if (act.target === "relative" && act.relativeTarget) {
1025
+ const relativeSelector = componentContract.selectors.relative;
1026
+ if (!relativeSelector) {
1027
+ failures.push(`Relative selector not defined for hover action.`);
1028
+ continue;
1029
+ }
1030
+ const relativeElement = await resolveRelativeTarget(relativeSelector, act.relativeTarget);
1031
+ if (!relativeElement) {
1032
+ failures.push(`Could not resolve relative target ${act.relativeTarget} for hover.`);
1033
+ continue;
1034
+ }
1035
+ await relativeElement.hover({ timeout: actionTimeoutMs });
1036
+ } else {
1037
+ const hoverSelector = componentContract.selectors[act.target];
1038
+ if (!hoverSelector) {
1039
+ failures.push(`Selector for hover target ${act.target} not found.`);
1040
+ continue;
1041
+ }
1042
+ await page.locator(hoverSelector).first().hover({ timeout: actionTimeoutMs });
1043
+ }
1044
+ } catch (error) {
1045
+ if (isBrowserClosedError(error)) {
1046
+ failures.push(`CRITICAL: Browser/page closed during test execution. Remaining actions skipped.`);
1047
+ break;
1048
+ }
1049
+ failures.push(`Failed to hover ${act.target}: ${error instanceof Error ? error.message : String(error)}`);
1050
+ continue;
1051
+ }
1052
+ }
1053
+ }
1054
+ for (const assertion of assertions) {
1055
+ if (!page || page.isClosed()) {
1056
+ failures.push(`CRITICAL: Browser/page closed before completing all tests. Increase test timeout or reduce test complexity.`);
1057
+ break;
1058
+ }
1059
+ let target;
1060
+ try {
1061
+ if (assertion.target === "relative") {
960
1062
  const relativeSelector = componentContract.selectors.relative;
961
1063
  if (!relativeSelector) {
962
- failures.push(`Relative selector not defined for hover action.`);
1064
+ failures.push("Relative selector is not defined in the contract.");
963
1065
  continue;
964
1066
  }
965
- const relativeElement = await resolveRelativeTarget(relativeSelector, act.relativeTarget);
966
- if (!relativeElement) {
967
- failures.push(`Could not resolve relative target ${act.relativeTarget} for hover.`);
1067
+ const relativeTargetValue = assertion.relativeTarget || assertion.expectedValue;
1068
+ if (!relativeTargetValue) {
1069
+ failures.push("Relative target or expected value is not defined.");
968
1070
  continue;
969
1071
  }
970
- await relativeElement.hover();
1072
+ target = await resolveRelativeTarget(relativeSelector, relativeTargetValue);
971
1073
  } else {
972
- const hoverSelector = componentContract.selectors[act.target];
973
- if (!hoverSelector) {
974
- failures.push(`Selector for hover target ${act.target} not found.`);
1074
+ const assertionSelector = componentContract.selectors[assertion.target];
1075
+ if (!assertionSelector) {
1076
+ failures.push(`Selector for assertion target ${assertion.target} not found.`);
975
1077
  continue;
976
1078
  }
977
- await page.locator(hoverSelector).first().hover();
1079
+ target = page.locator(assertionSelector).first();
978
1080
  }
979
- }
980
- }
981
- for (const assertion of assertions) {
982
- let target;
983
- if (assertion.target === "relative") {
984
- const relativeSelector = componentContract.selectors.relative;
985
- if (!relativeSelector) {
986
- failures.push("Relative selector is not defined in the contract.");
987
- continue;
988
- }
989
- const relativeTargetValue = assertion.relativeTarget || assertion.expectedValue;
990
- if (!relativeTargetValue) {
991
- failures.push("Relative target or expected value is not defined.");
1081
+ if (!target) {
1082
+ failures.push(`Target ${assertion.target} not found.`);
992
1083
  continue;
993
1084
  }
994
- target = await resolveRelativeTarget(relativeSelector, relativeTargetValue);
995
- } else {
996
- const assertionSelector = componentContract.selectors[assertion.target];
997
- if (!assertionSelector) {
998
- failures.push(`Selector for assertion target ${assertion.target} not found.`);
999
- continue;
1000
- }
1001
- target = page.locator(assertionSelector).first();
1002
- }
1003
- if (!target) {
1004
- failures.push(`Target ${assertion.target} not found.`);
1085
+ } catch (error) {
1086
+ failures.push(`Failed to resolve target ${assertion.target}: ${error instanceof Error ? error.message : String(error)}`);
1005
1087
  continue;
1006
1088
  }
1007
1089
  if (assertion.assertion === "toBeVisible") {
1008
1090
  try {
1009
- await (0, test_exports.expect)(target).toBeVisible({ timeout: 2e3 });
1091
+ await (0, test_exports.expect)(target).toBeVisible({ timeout: assertionTimeoutMs });
1010
1092
  passes.push(`${assertion.target} is visible as expected. Test: "${dynamicTest.description}".`);
1011
1093
  } catch {
1012
1094
  const debugState = await page.evaluate((sel) => {
@@ -1020,7 +1102,7 @@ This indicates a problem with the menu component's close functionality.`
1020
1102
  }
1021
1103
  if (assertion.assertion === "notToBeVisible") {
1022
1104
  try {
1023
- await (0, test_exports.expect)(target).toBeHidden({ timeout: 2e3 });
1105
+ await (0, test_exports.expect)(target).toBeHidden({ timeout: assertionTimeoutMs });
1024
1106
  passes.push(`${assertion.target} is not visible as expected. Test: "${dynamicTest.description}".`);
1025
1107
  } catch {
1026
1108
  const debugState = await page.evaluate((sel) => {
@@ -1042,7 +1124,7 @@ This indicates a problem with the menu component's close functionality.`
1042
1124
  failures.push(assertion.failureMessage + ` ${assertion.target} "${assertion.attribute}" should not be empty, found "${attributeValue}".`);
1043
1125
  }
1044
1126
  } else {
1045
- await (0, test_exports.expect)(target).toHaveAttribute(assertion.attribute, assertion.expectedValue, { timeout: 3e3 });
1127
+ await (0, test_exports.expect)(target).toHaveAttribute(assertion.attribute, assertion.expectedValue, { timeout: assertionTimeoutMs });
1046
1128
  passes.push(`${assertion.target} has expected "${assertion.attribute}". Test: "${dynamicTest.description}".`);
1047
1129
  }
1048
1130
  } catch {
@@ -1072,7 +1154,7 @@ This indicates a problem with the menu component's close functionality.`
1072
1154
  }
1073
1155
  if (assertion.assertion === "toHaveFocus") {
1074
1156
  try {
1075
- await (0, test_exports.expect)(target).toBeFocused({ timeout: 5e3 });
1157
+ await (0, test_exports.expect)(target).toBeFocused({ timeout: assertionTimeoutMs });
1076
1158
  passes.push(`${assertion.target} has focus as expected. Test: "${dynamicTest.description}".`);
1077
1159
  } catch {
1078
1160
  const actualFocus = await page.evaluate(() => {
@@ -1107,18 +1189,48 @@ This indicates a problem with the menu component's close functionality.`
1107
1189
  reporter.summary(failures);
1108
1190
  } catch (error) {
1109
1191
  if (error instanceof Error) {
1110
- if (error.message.includes("Executable doesn't exist")) {
1111
- console.error("\n\u274C Playwright browsers not found!\n");
1192
+ if (error.message.includes("Executable doesn't exist") || error.message.includes("browserType.launch")) {
1193
+ console.error("\n\u274C CRITICAL: Playwright browsers not found!\n");
1112
1194
  console.log("\u{1F4E6} Run: npx playwright install chromium\n");
1113
- failures.push("Playwright browser not installed. Run: npx playwright install chromium");
1114
- } else if (error.message.includes("net::ERR_CONNECTION_REFUSED")) {
1115
- console.error("\n\u274C Cannot connect to dev server!\n");
1195
+ failures.push("CRITICAL: Playwright browser not installed. Run: npx playwright install chromium");
1196
+ } else if (error.message.includes("net::ERR_CONNECTION_REFUSED") || error.message.includes("NS_ERROR_CONNECTION_REFUSED")) {
1197
+ console.error("\n\u274C CRITICAL: Cannot connect to dev server!\n");
1116
1198
  console.log(` Make sure your dev server is running at ${url}
1117
1199
  `);
1118
- failures.push(`Dev server not running at ${url}`);
1200
+ failures.push(`CRITICAL: Dev server not running at ${url}`);
1201
+ } else if (error.message.includes("Timeout") && error.message.includes("waitFor")) {
1202
+ console.error("\n\u274C CRITICAL: Component not found on page!\n");
1203
+ console.log(` The component selector could not be found within 30 seconds.
1204
+ `);
1205
+ console.log(` This usually means:
1206
+ `);
1207
+ console.log(` - The component didn't render
1208
+ `);
1209
+ console.log(` - The URL is incorrect
1210
+ `);
1211
+ console.log(` - The component selector in the contract is wrong
1212
+ `);
1213
+ failures.push(`CRITICAL: Component element not found on page - ${error.message}`);
1214
+ } else if (error.message.includes("Target page, context or browser has been closed")) {
1215
+ console.error("\n\u274C CRITICAL: Browser/page was closed unexpectedly!\n");
1216
+ console.log(` This usually means:
1217
+ `);
1218
+ console.log(` - The test timeout was too short
1219
+ `);
1220
+ console.log(` - The browser crashed
1221
+ `);
1222
+ console.log(` - An external process killed the browser
1223
+ `);
1224
+ failures.push(`CRITICAL: Browser/page closed unexpectedly - ${error.message}`);
1225
+ } else if (error.message.includes("FATAL")) {
1226
+ console.error(`
1227
+ ${error.message}
1228
+ `);
1229
+ failures.push(error.message);
1119
1230
  } else {
1120
- console.error("\u274C Playwright test error:", error.message);
1121
- failures.push(`Test error: ${error.message}`);
1231
+ console.error("\n\u274C UNEXPECTED ERROR:", error.message);
1232
+ console.error("Stack:", error.stack);
1233
+ failures.push(`UNEXPECTED ERROR: ${error.message}`);
1122
1234
  }
1123
1235
  }
1124
1236
  } finally {
package/bin/cli.js CHANGED
@@ -207,7 +207,7 @@ program.command("audit").description("Run axe-core powered accessibility audit o
207
207
  console.log(chalk.green("\n\u{1F389} All audits completed."));
208
208
  });
209
209
  program.command("test").description("Run core a11y accessibility standard tests on UI components").action(async () => {
210
- const { runTest } = await import("./test-HH2EW2NM.js");
210
+ const { runTest } = await import("./test-A3ESFXOR.js");
211
211
  runTest();
212
212
  });
213
213
  program.command("help").description("Display help information").action(() => {