aria-ease 5.0.1 → 5.0.3

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.
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  // src/accordion/src/makeAccordionAccessible/makeAccordionAccessible.ts
4
- function makeAccordionAccessible({ accordionId, triggersClass, panelsClass, allowMultiple = false }) {
4
+ function makeAccordionAccessible({ accordionId, triggersClass, panelsClass, allowMultipleOpen = false }) {
5
5
  const accordionContainer = document.querySelector(`#${accordionId}`);
6
6
  if (!accordionContainer) {
7
7
  console.error(`[aria-ease] Element with id="${accordionId}" not found. Make sure the accordion container exists before calling makeAccordionAccessible.`);
@@ -69,7 +69,7 @@ function makeAccordionAccessible({ accordionId, triggersClass, panelsClass, allo
69
69
  if (isExpanded) {
70
70
  collapseItem(index);
71
71
  } else {
72
- if (!allowMultiple) {
72
+ if (!allowMultipleOpen) {
73
73
  triggers.forEach((_, i) => {
74
74
  if (i !== index) {
75
75
  collapseItem(i);
@@ -6,15 +6,15 @@ import { A as AccessibilityInstance } from '../Types.d-COr5IFp5.cjs';
6
6
  * @param {string} accordionId - The id of the accordion container.
7
7
  * @param {string} triggersClass - The shared class of all accordion trigger buttons.
8
8
  * @param {string} panelsClass - The shared class of all accordion panels.
9
- * @param {boolean} allowMultiple - Whether multiple panels can be open simultaneously (default: false).
9
+ * @param {boolean} allowMultipleOpen - Whether multiple panels can be open simultaneously (default: false).
10
10
  */
11
11
 
12
12
  interface AccordionConfig {
13
13
  accordionId: string;
14
14
  triggersClass: string;
15
15
  panelsClass: string;
16
- allowMultiple?: boolean;
16
+ allowMultipleOpen?: boolean;
17
17
  }
18
- declare function makeAccordionAccessible({ accordionId, triggersClass, panelsClass, allowMultiple }: AccordionConfig): AccessibilityInstance;
18
+ declare function makeAccordionAccessible({ accordionId, triggersClass, panelsClass, allowMultipleOpen }: AccordionConfig): AccessibilityInstance;
19
19
 
20
20
  export { makeAccordionAccessible };
@@ -6,15 +6,15 @@ import { A as AccessibilityInstance } from '../Types.d-COr5IFp5.js';
6
6
  * @param {string} accordionId - The id of the accordion container.
7
7
  * @param {string} triggersClass - The shared class of all accordion trigger buttons.
8
8
  * @param {string} panelsClass - The shared class of all accordion panels.
9
- * @param {boolean} allowMultiple - Whether multiple panels can be open simultaneously (default: false).
9
+ * @param {boolean} allowMultipleOpen - Whether multiple panels can be open simultaneously (default: false).
10
10
  */
11
11
 
12
12
  interface AccordionConfig {
13
13
  accordionId: string;
14
14
  triggersClass: string;
15
15
  panelsClass: string;
16
- allowMultiple?: boolean;
16
+ allowMultipleOpen?: boolean;
17
17
  }
18
- declare function makeAccordionAccessible({ accordionId, triggersClass, panelsClass, allowMultiple }: AccordionConfig): AccessibilityInstance;
18
+ declare function makeAccordionAccessible({ accordionId, triggersClass, panelsClass, allowMultipleOpen }: AccordionConfig): AccessibilityInstance;
19
19
 
20
20
  export { makeAccordionAccessible };
@@ -1,5 +1,5 @@
1
1
  // src/accordion/src/makeAccordionAccessible/makeAccordionAccessible.ts
2
- function makeAccordionAccessible({ accordionId, triggersClass, panelsClass, allowMultiple = false }) {
2
+ function makeAccordionAccessible({ accordionId, triggersClass, panelsClass, allowMultipleOpen = false }) {
3
3
  const accordionContainer = document.querySelector(`#${accordionId}`);
4
4
  if (!accordionContainer) {
5
5
  console.error(`[aria-ease] Element with id="${accordionId}" not found. Make sure the accordion container exists before calling makeAccordionAccessible.`);
@@ -67,7 +67,7 @@ function makeAccordionAccessible({ accordionId, triggersClass, panelsClass, allo
67
67
  if (isExpanded) {
68
68
  collapseItem(index);
69
69
  } else {
70
- if (!allowMultiple) {
70
+ if (!allowMultipleOpen) {
71
71
  triggers.forEach((_, i) => {
72
72
  if (i !== index) {
73
73
  collapseItem(i);
@@ -1,34 +1,3 @@
1
- var __create = Object.create;
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __commonJS = (cb, mod) => function __require() {
8
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
- };
10
- var __export = (target, all) => {
11
- for (var name in all)
12
- __defProp(target, name, { get: all[name], enumerable: true });
13
- };
14
- var __copyProps = (to, from, except, desc) => {
15
- if (from && typeof from === "object" || typeof from === "function") {
16
- for (let key of __getOwnPropNames(from))
17
- if (!__hasOwnProp.call(to, key) && key !== except)
18
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
19
- }
20
- return to;
21
- };
22
- var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
23
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
24
- // If the importer is in node compatibility mode or this is not an ESM
25
- // file that has been converted to a CommonJS file using a Babel-
26
- // compatible transform (i.e. "__esModule" has not been set), then set
27
- // "default" to the CommonJS "module.exports" for node compatibility.
28
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
29
- mod
30
- ));
31
-
32
1
  // src/utils/test/contract/contract.json
33
2
  var contract_default = {
34
3
  menu: {
@@ -38,6 +7,10 @@ var contract_default = {
38
7
  combobox: {
39
8
  path: "./contracts/ComboboxContract.json",
40
9
  component: "combobox"
10
+ },
11
+ accordion: {
12
+ path: "./contracts/AccordionContract.json",
13
+ component: "accordion"
41
14
  }
42
15
  };
43
16
 
@@ -50,17 +23,22 @@ var ContractReporter = class {
50
23
  dynamicResults = [];
51
24
  totalTests = 0;
52
25
  skipped = 0;
26
+ optionalSuggestions = 0;
53
27
  isPlaywright = false;
28
+ apgUrl = "https://www.w3.org/WAI/ARIA/apg/";
54
29
  constructor(isPlaywright = false) {
55
30
  this.isPlaywright = isPlaywright;
56
31
  }
57
32
  log(message) {
58
33
  process.stderr.write(message + "\n");
59
34
  }
60
- start(componentName, totalTests) {
35
+ start(componentName, totalTests, apgUrl) {
61
36
  this.startTime = Date.now();
62
37
  this.componentName = componentName;
63
38
  this.totalTests = totalTests;
39
+ if (apgUrl) {
40
+ this.apgUrl = apgUrl;
41
+ }
64
42
  const mode = this.isPlaywright ? "Playwright (Real Browser)" : "jsdom (Fast)";
65
43
  this.log(`
66
44
  ${"\u2550".repeat(60)}`);
@@ -73,10 +51,21 @@ ${"\u2550".repeat(60)}`);
73
51
  this.staticFailures = failures;
74
52
  const icon = failures === 0 ? "\u2705" : "\u274C";
75
53
  const status = failures === 0 ? "PASS" : "FAIL";
54
+ this.log("");
76
55
  this.log(`${icon} Static ARIA Tests: ${status}`);
77
56
  this.log(` ${passes}/${passes + failures} required attributes present
78
57
  `);
79
58
  }
59
+ /**
60
+ * Report individual static test pass
61
+ */
62
+ reportStaticTest(description, passed, failureMessage) {
63
+ const icon = passed ? "\u2713" : "\u2717";
64
+ this.log(` ${icon} ${description}`);
65
+ if (!passed && failureMessage) {
66
+ this.log(` \u21B3 ${failureMessage}`);
67
+ }
68
+ }
80
69
  /**
81
70
  * Report individual dynamic test result
82
71
  */
@@ -84,20 +73,25 @@ ${"\u2550".repeat(60)}`);
84
73
  const result = {
85
74
  description: test.description,
86
75
  status,
87
- failureMessage
76
+ failureMessage,
77
+ isOptional: test.isOptional
88
78
  };
89
79
  if (status === "skip" && test.requiresBrowser) {
90
80
  result.skipReason = "Requires real browser (addEventListener events)";
91
81
  }
92
82
  this.dynamicResults.push(result);
93
- const icons = { pass: "\u2713", fail: "\u2717", skip: "\u25CB" };
94
- this.log(` ${icons[status]} ${test.description}`);
83
+ const icons = { pass: "\u2713", fail: "\u2717", skip: "\u25CB", "optional-fail": "\u25CB" };
84
+ const prefix = test.isOptional ? "[OPTIONAL] " : "";
85
+ this.log(` ${icons[status]} ${prefix}${test.description}`);
95
86
  if (status === "skip" && !this.isPlaywright) {
96
87
  this.log(` \u21B3 Skipped in jsdom (runs in Playwright)`);
97
88
  }
98
- if (status === "fail" && failureMessage) {
89
+ if (status === "fail" && failureMessage && !test.isOptional) {
99
90
  this.log(` \u21B3 ${failureMessage}`);
100
91
  }
92
+ if (status === "optional-fail") {
93
+ this.log(` \u21B3 Not implemented (recommended for enhanced UX)`);
94
+ }
101
95
  }
102
96
  /**
103
97
  * Report all failures with actionable context
@@ -120,6 +114,30 @@ ${"\u2500".repeat(60)}`);
120
114
  this.log("");
121
115
  });
122
116
  }
117
+ /**
118
+ * Report optional features that aren't implemented
119
+ */
120
+ reportOptionalSuggestions() {
121
+ const suggestions = this.dynamicResults.filter((r) => r.status === "optional-fail");
122
+ if (suggestions.length === 0) return;
123
+ this.log(`
124
+ ${"\u2500".repeat(60)}`);
125
+ this.log(`\u{1F4A1} Optional Enhancements (${suggestions.length}):
126
+ `);
127
+ this.log(`These features are optional per APG guidelines but recommended`);
128
+ this.log(`for improved user experience and keyboard navigation:
129
+ `);
130
+ suggestions.forEach((test, index) => {
131
+ this.log(`${index + 1}. ${test.description}`);
132
+ if (test.failureMessage) {
133
+ this.log(` \u21B3 ${test.failureMessage}`);
134
+ }
135
+ });
136
+ this.log(`
137
+ \u2728 Consider implementing these for better accessibility`);
138
+ this.log(` Reference: ${this.apgUrl}
139
+ `);
140
+ }
123
141
  /**
124
142
  * Report skipped tests with helpful context
125
143
  */
@@ -149,30 +167,40 @@ ${"\u2500".repeat(60)}`);
149
167
  const dynamicPasses = this.dynamicResults.filter((r) => r.status === "pass").length;
150
168
  const dynamicFailures = this.dynamicResults.filter((r) => r.status === "fail").length;
151
169
  this.skipped = this.dynamicResults.filter((r) => r.status === "skip").length;
170
+ this.optionalSuggestions = this.dynamicResults.filter((r) => r.status === "optional-fail").length;
152
171
  const totalPasses = this.staticPasses + dynamicPasses;
153
172
  const totalFailures = this.staticFailures + dynamicFailures;
154
173
  const totalRun = totalPasses + totalFailures;
155
174
  if (failures.length > 0) {
156
175
  this.reportFailures(failures);
157
176
  }
177
+ this.reportOptionalSuggestions();
158
178
  this.reportSkipped();
159
179
  this.log(`
160
180
  ${"\u2550".repeat(60)}`);
161
181
  this.log(`\u{1F4CA} Summary
162
182
  `);
163
- if (totalFailures === 0 && this.skipped === 0) {
183
+ if (totalFailures === 0 && this.skipped === 0 && this.optionalSuggestions === 0) {
164
184
  this.log(`\u2705 All ${totalRun} tests passed!`);
165
185
  this.log(` ${this.componentName} component meets APG and WCAG guidelines \u2713`);
166
186
  } else if (totalFailures === 0) {
167
- this.log(`\u2705 ${totalPasses}/${totalRun} tests passed`);
168
- this.log(`\u25CB ${this.skipped} tests skipped (jsdom limitation)`);
169
- this.log(` ${this.componentName} component works correctly`);
187
+ this.log(`\u2705 ${totalPasses}/${totalRun} required tests passed`);
188
+ if (this.skipped > 0) {
189
+ this.log(`\u25CB ${this.skipped} tests skipped (jsdom limitation)`);
190
+ }
191
+ if (this.optionalSuggestions > 0) {
192
+ this.log(`\u{1F4A1} ${this.optionalSuggestions} optional enhancement${this.optionalSuggestions > 1 ? "s" : ""} suggested`);
193
+ }
194
+ this.log(` ${this.componentName} component meets required standards \u2713`);
170
195
  } else {
171
196
  this.log(`\u274C ${totalFailures} test${totalFailures > 1 ? "s" : ""} failed`);
172
197
  this.log(`\u2705 ${totalPasses} test${totalPasses > 1 ? "s" : ""} passed`);
173
198
  if (this.skipped > 0) {
174
199
  this.log(`\u25CB ${this.skipped} test${this.skipped > 1 ? "s" : ""} skipped`);
175
200
  }
201
+ if (this.optionalSuggestions > 0) {
202
+ this.log(`\u{1F4A1} ${this.optionalSuggestions} optional enhancement${this.optionalSuggestions > 1 ? "s" : ""} suggested`);
203
+ }
176
204
  }
177
205
  this.log(`\u23F1\uFE0F Duration: ${duration}ms`);
178
206
  this.log(`${"\u2550".repeat(60)}
@@ -207,4 +235,4 @@ ${"\u2550".repeat(60)}`);
207
235
  }
208
236
  };
209
237
 
210
- export { ContractReporter, __commonJS, __export, __reExport, __toESM, contract_default };
238
+ export { ContractReporter, contract_default };
@@ -1,15 +1,8 @@
1
- import { __export, __reExport, ContractReporter, contract_default } from './chunk-IPJYOFRK.js';
1
+ import { ContractReporter, contract_default } from './chunk-TUWQNVQJ.js';
2
2
  import { chromium } from 'playwright';
3
- import * as default2 from 'playwright/test';
4
- import default2__default from 'playwright/test';
3
+ import { expect } from '@playwright/test';
5
4
  import { readFileSync } from 'fs';
6
5
 
7
- // node_modules/@playwright/test/index.mjs
8
- var test_exports = {};
9
- __export(test_exports, {
10
- default: () => default2__default
11
- });
12
- __reExport(test_exports, default2);
13
6
  async function runContractTestsPlaywright(componentName, url) {
14
7
  const reporter = new ContractReporter(true);
15
8
  const contractTyped = contract_default;
@@ -21,7 +14,8 @@ async function runContractTestsPlaywright(componentName, url) {
21
14
  const contractData = readFileSync(resolvedPath, "utf-8");
22
15
  const componentContract = JSON.parse(contractData);
23
16
  const totalTests = componentContract.static[0].assertions.length + componentContract.dynamic.length;
24
- reporter.start(componentName, totalTests);
17
+ const apgUrl = componentContract.meta?.source?.apg;
18
+ reporter.start(componentName, totalTests, apgUrl);
25
19
  const failures = [];
26
20
  const passes = [];
27
21
  const skipped = [];
@@ -32,25 +26,21 @@ async function runContractTestsPlaywright(componentName, url) {
32
26
  const page = await context.newPage();
33
27
  await page.goto(url, {
34
28
  waitUntil: "domcontentloaded",
35
- timeout: 9e4
29
+ timeout: 9e5
36
30
  });
31
+ await page.addStyleTag({ content: `* { transition: none !important; animation: none !important; }` });
37
32
  const mainSelector = componentContract.selectors.trigger || componentContract.selectors.input || componentContract.selectors.container;
38
33
  if (!mainSelector) {
39
34
  throw new Error(`No main selector (trigger, input, or container) found in contract for ${componentName}`);
40
35
  }
41
- await page.waitForSelector(mainSelector, { timeout: 9e4 });
36
+ await page.locator(mainSelector).first().waitFor({ state: "attached", timeout: 9e5 });
42
37
  if (componentName === "menu" && componentContract.selectors.trigger) {
43
- await page.waitForFunction(
44
- (selector) => {
45
- const trigger = document.querySelector(selector);
46
- return trigger && trigger.getAttribute("data-menu-initialized") === "true";
47
- },
48
- componentContract.selectors.trigger,
49
- { timeout: 1e4 }
50
- ).catch(() => {
51
- console.warn("Menu initialization signal not detected, continuing with tests...");
38
+ await page.locator(componentContract.selectors.trigger).first().waitFor({
39
+ state: "visible",
40
+ timeout: 1e4
41
+ }).catch(() => {
42
+ console.warn("Menu trigger not visible, continuing with tests...");
52
43
  });
53
- await page.waitForTimeout(300);
54
44
  }
55
45
  async function resolveRelativeTarget(selector, relative) {
56
46
  const items = await page.locator(selector).all();
@@ -126,7 +116,7 @@ async function runContractTestsPlaywright(componentName, url) {
126
116
  const popupSelector = componentContract.selectors.listbox || componentContract.selectors.container;
127
117
  if (!popupSelector) continue;
128
118
  const popupElement = page.locator(popupSelector).first();
129
- const isPopupVisible = await popupElement.isVisible();
119
+ const isPopupVisible = await popupElement.isVisible().catch(() => false);
130
120
  if (isPopupVisible) {
131
121
  let menuClosed = false;
132
122
  let closeSelector = componentContract.selectors.input;
@@ -138,44 +128,17 @@ async function runContractTestsPlaywright(componentName, url) {
138
128
  if (closeSelector) {
139
129
  const closeElement = page.locator(closeSelector).first();
140
130
  await closeElement.focus();
141
- await page.waitForTimeout(200);
142
131
  await page.keyboard.press("Escape");
143
- menuClosed = await page.waitForFunction(
144
- (selector) => {
145
- const popup = document.querySelector(selector);
146
- return popup && getComputedStyle(popup).display === "none";
147
- },
148
- popupSelector,
149
- { timeout: 3e3 }
150
- ).then(() => true).catch(() => false);
132
+ menuClosed = await expect(popupElement).toBeHidden({ timeout: 3e3 }).then(() => true).catch(() => false);
151
133
  }
152
134
  if (!menuClosed && componentContract.selectors.trigger) {
153
135
  const triggerElement = page.locator(componentContract.selectors.trigger).first();
154
136
  await triggerElement.click();
155
- await page.waitForTimeout(500);
156
- menuClosed = await page.waitForFunction(
157
- (selector) => {
158
- const popup = document.querySelector(selector);
159
- return popup && getComputedStyle(popup).display === "none";
160
- },
161
- popupSelector,
162
- { timeout: 3e3 }
163
- ).then(() => true).catch(() => false);
137
+ menuClosed = await expect(popupElement).toBeHidden({ timeout: 3e3 }).then(() => true).catch(() => false);
164
138
  }
165
139
  if (!menuClosed) {
166
140
  await page.mouse.click(10, 10);
167
- await page.waitForTimeout(500);
168
- menuClosed = await page.waitForFunction(
169
- (selector) => {
170
- const popup = document.querySelector(selector);
171
- return popup && getComputedStyle(popup).display === "none";
172
- },
173
- popupSelector,
174
- { timeout: 3e3 }
175
- ).then(() => true).catch(() => false);
176
- if (menuClosed) {
177
- console.log("\u{1F3AF} Strategy 3 (Click outside) worked");
178
- }
141
+ menuClosed = await expect(popupElement).toBeHidden({ timeout: 3e3 }).then(() => true).catch(() => false);
179
142
  }
180
143
  if (!menuClosed) {
181
144
  throw new Error(
@@ -186,25 +149,12 @@ async function runContractTestsPlaywright(componentName, url) {
186
149
  This indicates a problem with the menu component's close functionality.`
187
150
  );
188
151
  }
189
- if (componentName === "menu" && componentContract.selectors.trigger) {
190
- await page.waitForFunction(
191
- (selector) => {
192
- const trigger = document.querySelector(selector);
193
- return document.activeElement === trigger;
194
- },
195
- componentContract.selectors.trigger,
196
- { timeout: 2e3 }
197
- ).catch(async () => {
198
- const triggerElement = page.locator(componentContract.selectors.trigger).first();
199
- await triggerElement.focus();
200
- await page.waitForTimeout(200);
201
- });
202
- }
203
- await page.waitForTimeout(500);
204
152
  if (componentContract.selectors.input) {
205
- const inputElement = page.locator(componentContract.selectors.input).first();
206
- await inputElement.clear();
207
- await page.waitForTimeout(100);
153
+ await page.locator(componentContract.selectors.input).first().clear();
154
+ }
155
+ if (componentName === "menu" && componentContract.selectors.trigger) {
156
+ const triggerElement = page.locator(componentContract.selectors.trigger).first();
157
+ await triggerElement.focus();
208
158
  }
209
159
  }
210
160
  }
@@ -248,7 +198,6 @@ This indicates a problem with the menu component's close functionality.`
248
198
  continue;
249
199
  }
250
200
  await page.locator(focusSelector).first().focus();
251
- await page.waitForTimeout(100);
252
201
  }
253
202
  if (act.type === "type" && act.value) {
254
203
  const typeSelector = componentContract.selectors[act.target];
@@ -257,7 +206,6 @@ This indicates a problem with the menu component's close functionality.`
257
206
  continue;
258
207
  }
259
208
  await page.locator(typeSelector).first().fill(act.value);
260
- await page.waitForTimeout(100);
261
209
  }
262
210
  if (act.type === "click") {
263
211
  if (act.target === "document") {
@@ -274,7 +222,6 @@ This indicates a problem with the menu component's close functionality.`
274
222
  continue;
275
223
  }
276
224
  await relativeElement.click();
277
- await page.waitForTimeout(componentName === "menu" ? 800 : 200);
278
225
  } else {
279
226
  const actionSelector = componentContract.selectors[act.target];
280
227
  if (!actionSelector) {
@@ -282,7 +229,6 @@ This indicates a problem with the menu component's close functionality.`
282
229
  continue;
283
230
  }
284
231
  await page.locator(actionSelector).first().click();
285
- await page.waitForTimeout(componentName === "menu" ? 800 : 200);
286
232
  }
287
233
  }
288
234
  if (act.type === "keypress" && act.key) {
@@ -305,9 +251,7 @@ This indicates a problem with the menu component's close functionality.`
305
251
  keyValue = keyValue.replace(/ /g, "");
306
252
  }
307
253
  if (act.target === "focusable" && ["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight", "Escape"].includes(keyValue)) {
308
- await page.waitForTimeout(componentName === "menu" ? 200 : 100);
309
254
  await page.keyboard.press(keyValue);
310
- await page.waitForTimeout(componentName === "menu" ? 300 : 100);
311
255
  } else {
312
256
  const keypressSelector = componentContract.selectors[act.target];
313
257
  if (!keypressSelector) {
@@ -336,7 +280,6 @@ This indicates a problem with the menu component's close functionality.`
336
280
  continue;
337
281
  }
338
282
  await relativeElement.hover();
339
- await page.waitForTimeout(100);
340
283
  } else {
341
284
  const hoverSelector = componentContract.selectors[act.target];
342
285
  if (!hoverSelector) {
@@ -344,12 +287,9 @@ This indicates a problem with the menu component's close functionality.`
344
287
  continue;
345
288
  }
346
289
  await page.locator(hoverSelector).first().hover();
347
- await page.waitForTimeout(100);
348
290
  }
349
291
  }
350
- await page.waitForTimeout(componentName === "menu" ? 200 : 100);
351
292
  }
352
- await page.waitForTimeout(componentName === "menu" ? 300 : 100);
353
293
  for (const assertion of assertions) {
354
294
  let target;
355
295
  if (assertion.target === "relative") {
@@ -378,7 +318,7 @@ This indicates a problem with the menu component's close functionality.`
378
318
  }
379
319
  if (assertion.assertion === "toBeVisible") {
380
320
  try {
381
- await (0, test_exports.expect)(target).toBeVisible({ timeout: 3e3 });
321
+ await expect(target).toBeVisible({ timeout: 3e3 });
382
322
  passes.push(`${assertion.target} is visible as expected. Test: "${dynamicTest.description}".`);
383
323
  } catch {
384
324
  const debugState = await page.evaluate((sel) => {
@@ -392,7 +332,7 @@ This indicates a problem with the menu component's close functionality.`
392
332
  }
393
333
  if (assertion.assertion === "notToBeVisible") {
394
334
  try {
395
- await (0, test_exports.expect)(target).toBeHidden({ timeout: 5e3 });
335
+ await expect(target).toBeHidden({ timeout: 5e3 });
396
336
  passes.push(`${assertion.target} is not visible as expected. Test: "${dynamicTest.description}".`);
397
337
  } catch {
398
338
  const debugState = await page.evaluate((sel) => {
@@ -414,7 +354,7 @@ This indicates a problem with the menu component's close functionality.`
414
354
  failures.push(assertion.failureMessage + ` ${assertion.target} "${assertion.attribute}" should not be empty, found "${attributeValue}".`);
415
355
  }
416
356
  } else {
417
- await (0, test_exports.expect)(target).toHaveAttribute(assertion.attribute, assertion.expectedValue, { timeout: 3e3 });
357
+ await expect(target).toHaveAttribute(assertion.attribute, assertion.expectedValue, { timeout: 3e3 });
418
358
  passes.push(`${assertion.target} has expected "${assertion.attribute}". Test: "${dynamicTest.description}".`);
419
359
  }
420
360
  } catch {
@@ -444,7 +384,7 @@ This indicates a problem with the menu component's close functionality.`
444
384
  }
445
385
  if (assertion.assertion === "toHaveFocus") {
446
386
  try {
447
- await (0, test_exports.expect)(target).toBeFocused({ timeout: 5e3 });
387
+ await expect(target).toBeFocused({ timeout: 5e3 });
448
388
  passes.push(`${assertion.target} has focus as expected. Test: "${dynamicTest.description}".`);
449
389
  } catch {
450
390
  const actualFocus = await page.evaluate(() => {
@@ -466,7 +406,12 @@ This indicates a problem with the menu component's close functionality.`
466
406
  const failuresAfterTest = failures.length;
467
407
  const testPassed = failuresAfterTest === failuresBeforeTest;
468
408
  const failureMessage = testPassed ? void 0 : failures[failures.length - 1];
469
- reporter.reportTest(dynamicTest, testPassed ? "pass" : "fail", failureMessage);
409
+ if (dynamicTest.isOptional === true && !testPassed) {
410
+ failures.pop();
411
+ reporter.reportTest(dynamicTest, "optional-fail", failureMessage);
412
+ } else {
413
+ reporter.reportTest(dynamicTest, testPassed ? "pass" : "fail", failureMessage);
414
+ }
470
415
  }
471
416
  const staticPassed = componentContract.static[0].assertions.length;
472
417
  const staticFailed = 0;