aria-ease 6.8.0 → 6.9.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.
Files changed (40) hide show
  1. package/README.md +68 -6
  2. package/bin/AccordionComponentStrategy-4ZEIQ2V6.js +42 -0
  3. package/bin/ComboboxComponentStrategy-OGRVZXAF.js +64 -0
  4. package/bin/MenuComponentStrategy-JAMTCSNF.js +81 -0
  5. package/bin/TabsComponentStrategy-3SQURPMX.js +29 -0
  6. package/bin/buildContracts-GBOY7UXG.js +437 -0
  7. package/bin/{chunk-VPBHLMAS.js → chunk-LMSKLN5O.js} +21 -0
  8. package/bin/chunk-PK5L2SAF.js +17 -0
  9. package/bin/{chunk-2TOYEY5L.js → chunk-XERMSYEH.js} +12 -3
  10. package/bin/cli.cjs +991 -128
  11. package/bin/cli.js +33 -2
  12. package/bin/{configLoader-XRF6VM4J.js → configLoader-Q6A4JLKW.js} +1 -1
  13. package/{dist/contractTestRunnerPlaywright-UAOFNS7Z.js → bin/contractTestRunnerPlaywright-ZZNWDUYP.js} +270 -219
  14. package/bin/{test-WRIJHN6H.js → test-OND56UUL.js} +97 -10
  15. package/dist/AccordionComponentStrategy-4ZEIQ2V6.js +42 -0
  16. package/dist/ComboboxComponentStrategy-OGRVZXAF.js +64 -0
  17. package/dist/MenuComponentStrategy-JAMTCSNF.js +81 -0
  18. package/dist/TabsComponentStrategy-3SQURPMX.js +29 -0
  19. package/dist/chunk-PK5L2SAF.js +17 -0
  20. package/dist/{chunk-2TOYEY5L.js → chunk-XERMSYEH.js} +12 -3
  21. package/dist/{configLoader-IT4PWCJB.js → configLoader-WTGJAP4Z.js} +21 -0
  22. package/{bin/contractTestRunnerPlaywright-UAOFNS7Z.js → dist/contractTestRunnerPlaywright-XBWJZMR3.js} +270 -219
  23. package/dist/index.cjs +794 -90
  24. package/dist/index.d.cts +136 -1
  25. package/dist/index.d.ts +136 -1
  26. package/dist/index.js +415 -10
  27. package/dist/src/utils/test/AccordionComponentStrategy-WRHZOEN6.js +38 -0
  28. package/dist/src/utils/test/ComboboxComponentStrategy-5AECQSRN.js +60 -0
  29. package/dist/src/utils/test/MenuComponentStrategy-VKZQYLBE.js +77 -0
  30. package/dist/src/utils/test/TabsComponentStrategy-BKG53SEV.js +26 -0
  31. package/dist/src/utils/test/{chunk-2TOYEY5L.js → chunk-XERMSYEH.js} +12 -3
  32. package/dist/src/utils/test/{configLoader-LD4RV2WQ.js → configLoader-YE2CYGDG.js} +21 -0
  33. package/dist/src/utils/test/{contractTestRunnerPlaywright-IRJOAEMT.js → contractTestRunnerPlaywright-LC5OAVXB.js} +262 -200
  34. package/dist/src/utils/test/dsl/index.cjs +320 -0
  35. package/dist/src/utils/test/dsl/index.d.cts +136 -0
  36. package/dist/src/utils/test/dsl/index.d.ts +136 -0
  37. package/dist/src/utils/test/dsl/index.js +318 -0
  38. package/dist/src/utils/test/index.cjs +472 -88
  39. package/dist/src/utils/test/index.js +97 -12
  40. package/package.json +9 -3
@@ -0,0 +1,318 @@
1
+ // src/utils/test/dsl/index.ts
2
+ var FluentContract = class {
3
+ constructor(jsonContract) {
4
+ this.jsonContract = jsonContract;
5
+ }
6
+ toJSON() {
7
+ return this.jsonContract;
8
+ }
9
+ };
10
+ var StaticTargetBuilder = class {
11
+ constructor(targetName, sink) {
12
+ this.targetName = targetName;
13
+ this.sink = sink;
14
+ }
15
+ has(attribute, expectedValue) {
16
+ const create = (level) => {
17
+ this.sink.push({
18
+ target: this.targetName,
19
+ attribute,
20
+ expectedValue,
21
+ failureMessage: `Expected ${this.targetName} to have ${attribute}${expectedValue !== void 0 ? `=${expectedValue}` : ""}.`,
22
+ level
23
+ });
24
+ };
25
+ return {
26
+ required: () => create("required"),
27
+ recommended: () => create("recommended"),
28
+ optional: () => create("optional")
29
+ };
30
+ }
31
+ };
32
+ var StaticBuilder = class {
33
+ constructor(sink) {
34
+ this.sink = sink;
35
+ }
36
+ target(targetName) {
37
+ return new StaticTargetBuilder(targetName, this.sink);
38
+ }
39
+ };
40
+ var DynamicChain = class {
41
+ constructor(key, testsSink, selectors) {
42
+ this.key = key;
43
+ this.testsSink = testsSink;
44
+ this.selectors = selectors;
45
+ }
46
+ selectorTarget = "";
47
+ actions = [];
48
+ assertions = [];
49
+ explicitDescription = "";
50
+ on(target) {
51
+ this.selectorTarget = target;
52
+ this.actions.push({ type: "keypress", target, key: this.key });
53
+ return this;
54
+ }
55
+ describe(description) {
56
+ this.explicitDescription = description;
57
+ return this;
58
+ }
59
+ focus(targetExpression) {
60
+ const parsed = this.parseRelativeExpression(targetExpression);
61
+ if (parsed) {
62
+ if (!this.selectors[parsed.selectorKey]) {
63
+ const availableSelectors = Object.keys(this.selectors).sort().join(", ") || "(none)";
64
+ throw new Error(
65
+ `Invalid focus target expression "${targetExpression}": selector "${parsed.selectorKey}" is not defined. Available selectors: ${availableSelectors}`
66
+ );
67
+ }
68
+ if (!this.selectors.relative && this.selectors[parsed.selectorKey]) {
69
+ this.selectors.relative = this.selectors[parsed.selectorKey];
70
+ }
71
+ this.assertions.push({
72
+ target: "relative",
73
+ assertion: "toHaveFocus",
74
+ relativeTarget: parsed.relativeTarget
75
+ });
76
+ } else {
77
+ this.assertions.push({
78
+ target: targetExpression,
79
+ assertion: "toHaveFocus"
80
+ });
81
+ }
82
+ return this;
83
+ }
84
+ visible(target) {
85
+ this.assertions.push({ target, assertion: "toBeVisible" });
86
+ return this;
87
+ }
88
+ hidden(target) {
89
+ this.assertions.push({ target, assertion: "notToBeVisible" });
90
+ return this;
91
+ }
92
+ has(target, attribute, expectedValue) {
93
+ this.assertions.push({
94
+ target,
95
+ assertion: "toHaveAttribute",
96
+ attribute,
97
+ expectedValue
98
+ });
99
+ return this;
100
+ }
101
+ required() {
102
+ this.finalize("required");
103
+ }
104
+ recommended() {
105
+ this.finalize("recommended");
106
+ }
107
+ optional() {
108
+ this.finalize("optional");
109
+ }
110
+ finalize(level) {
111
+ if (!this.selectorTarget) {
112
+ throw new Error("Dynamic contract chain requires .on(<selectorKey>) before level terminator.");
113
+ }
114
+ const description = this.explicitDescription || `Pressing ${this.key} on ${this.selectorTarget} satisfies expected behavior.`;
115
+ this.testsSink.push({
116
+ description,
117
+ level,
118
+ action: this.actions,
119
+ assertions: this.assertions.map((a) => ({ ...a, level }))
120
+ });
121
+ }
122
+ parseRelativeExpression(input) {
123
+ const match = input.match(/^(next|previous|first|last)\(([^)]+)\)$/);
124
+ if (!match) return null;
125
+ const relativeTarget = match[1];
126
+ const selectorKey = match[2].trim();
127
+ return { relativeTarget, selectorKey };
128
+ }
129
+ };
130
+ var ContractBuilder = class {
131
+ constructor(componentName) {
132
+ this.componentName = componentName;
133
+ }
134
+ metaValue = {};
135
+ selectorsValue = {};
136
+ relationshipInvariants = [];
137
+ staticAssertions = [];
138
+ dynamicTests = [];
139
+ meta(meta) {
140
+ this.metaValue = { ...this.metaValue, ...meta };
141
+ return this;
142
+ }
143
+ selectors(selectors) {
144
+ this.selectorsValue = { ...this.selectorsValue, ...selectors };
145
+ return this;
146
+ }
147
+ relationship(invariant) {
148
+ this.relationshipInvariants.push(invariant);
149
+ return this;
150
+ }
151
+ relationships(builderFn) {
152
+ builderFn({
153
+ ariaReference: (from, attribute, to) => {
154
+ const create = (level) => {
155
+ this.relationshipInvariants.push({
156
+ type: "aria-reference",
157
+ from,
158
+ attribute,
159
+ to,
160
+ level
161
+ });
162
+ };
163
+ return {
164
+ required: () => create("required"),
165
+ recommended: () => create("recommended"),
166
+ optional: () => create("optional")
167
+ };
168
+ },
169
+ contains: (parent, child) => {
170
+ const create = (level) => {
171
+ this.relationshipInvariants.push({
172
+ type: "contains",
173
+ parent,
174
+ child,
175
+ level
176
+ });
177
+ };
178
+ return {
179
+ required: () => create("required"),
180
+ recommended: () => create("recommended"),
181
+ optional: () => create("optional")
182
+ };
183
+ }
184
+ });
185
+ return this;
186
+ }
187
+ static(builderFn) {
188
+ builderFn(new StaticBuilder(this.staticAssertions));
189
+ return this;
190
+ }
191
+ when(key) {
192
+ return new DynamicChain(key, this.dynamicTests, this.selectorsValue);
193
+ }
194
+ validateRelationshipInvariants() {
195
+ if (this.relationshipInvariants.length === 0) {
196
+ return;
197
+ }
198
+ const selectorKeys = new Set(Object.keys(this.selectorsValue));
199
+ const available = Object.keys(this.selectorsValue).sort().join(", ");
200
+ const errors = [];
201
+ this.relationshipInvariants.forEach((invariant, index) => {
202
+ const prefix = `relationships[${index}] (${invariant.type})`;
203
+ if (invariant.type === "aria-reference") {
204
+ if (!selectorKeys.has(invariant.from)) {
205
+ errors.push(`${prefix}: "from" references unknown selector "${invariant.from}"`);
206
+ }
207
+ if (!selectorKeys.has(invariant.to)) {
208
+ errors.push(`${prefix}: "to" references unknown selector "${invariant.to}"`);
209
+ }
210
+ }
211
+ if (invariant.type === "contains") {
212
+ if (!selectorKeys.has(invariant.parent)) {
213
+ errors.push(`${prefix}: "parent" references unknown selector "${invariant.parent}"`);
214
+ }
215
+ if (!selectorKeys.has(invariant.child)) {
216
+ errors.push(`${prefix}: "child" references unknown selector "${invariant.child}"`);
217
+ }
218
+ }
219
+ });
220
+ if (errors.length > 0) {
221
+ const availableSelectorsMessage = available.length > 0 ? available : "(none)";
222
+ throw new Error(
223
+ [
224
+ `Contract invariant validation failed for component "${this.componentName}".`,
225
+ ...errors.map((error) => `- ${error}`),
226
+ `Available selectors: ${availableSelectorsMessage}`
227
+ ].join("\n")
228
+ );
229
+ }
230
+ }
231
+ validateStaticTargets() {
232
+ const selectorKeys = new Set(Object.keys(this.selectorsValue));
233
+ const available = Object.keys(this.selectorsValue).sort().join(", ") || "(none)";
234
+ const errors = [];
235
+ this.staticAssertions.forEach((assertion, index) => {
236
+ if (!selectorKeys.has(assertion.target)) {
237
+ errors.push(`static.assertions[${index}]: target "${assertion.target}" is not defined in selectors`);
238
+ }
239
+ });
240
+ if (errors.length > 0) {
241
+ throw new Error(
242
+ [
243
+ `Contract static target validation failed for component "${this.componentName}".`,
244
+ ...errors.map((error) => `- ${error}`),
245
+ `Available selectors: ${available}`
246
+ ].join("\n")
247
+ );
248
+ }
249
+ }
250
+ validateDynamicTargets() {
251
+ const selectorKeys = new Set(Object.keys(this.selectorsValue));
252
+ const available = Object.keys(this.selectorsValue).sort().join(", ") || "(none)";
253
+ const errors = [];
254
+ const isValidActionTarget = (target) => {
255
+ return selectorKeys.has(target) || target === "document" || target === "relative";
256
+ };
257
+ const isValidAssertionTarget = (target) => {
258
+ return selectorKeys.has(target) || target === "relative";
259
+ };
260
+ this.dynamicTests.forEach((test, testIndex) => {
261
+ test.action.forEach((action, actionIndex) => {
262
+ if (!isValidActionTarget(action.target)) {
263
+ errors.push(
264
+ `dynamic[${testIndex}].action[${actionIndex}]: target "${action.target}" is not defined in selectors`
265
+ );
266
+ }
267
+ });
268
+ test.assertions.forEach((assertion, assertionIndex) => {
269
+ if (!isValidAssertionTarget(assertion.target)) {
270
+ errors.push(
271
+ `dynamic[${testIndex}].assertions[${assertionIndex}]: target "${assertion.target}" is not defined in selectors`
272
+ );
273
+ }
274
+ if (assertion.target === "relative" && !this.selectorsValue.relative) {
275
+ errors.push(
276
+ `dynamic[${testIndex}].assertions[${assertionIndex}]: target "relative" requires selectors.relative to be defined`
277
+ );
278
+ }
279
+ });
280
+ });
281
+ if (errors.length > 0) {
282
+ throw new Error(
283
+ [
284
+ `Contract dynamic target validation failed for component "${this.componentName}".`,
285
+ ...errors.map((error) => `- ${error}`),
286
+ `Available selectors: ${available}`,
287
+ `Allowed special targets: document, relative`
288
+ ].join("\n")
289
+ );
290
+ }
291
+ }
292
+ build() {
293
+ this.validateRelationshipInvariants();
294
+ this.validateStaticTargets();
295
+ this.validateDynamicTargets();
296
+ const fallbackId = this.metaValue.id || `aria-ease.contract.${this.componentName}`;
297
+ return {
298
+ meta: {
299
+ id: fallbackId,
300
+ version: this.metaValue.version || "1.0.0",
301
+ description: this.metaValue.description || `Fluent contract for ${this.componentName}`,
302
+ source: this.metaValue.source,
303
+ W3CName: this.metaValue.W3CName
304
+ },
305
+ selectors: this.selectorsValue,
306
+ relationships: this.relationshipInvariants,
307
+ static: [{ assertions: this.staticAssertions }],
308
+ dynamic: this.dynamicTests
309
+ };
310
+ }
311
+ };
312
+ function createContract(componentName, define) {
313
+ const builder = new ContractBuilder(componentName);
314
+ define(builder);
315
+ return new FluentContract(builder.build());
316
+ }
317
+
318
+ export { createContract };