aria-ease 6.9.1 → 6.10.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.
Files changed (43) hide show
  1. package/README.md +3 -3
  2. package/bin/{buildContracts-GBOY7UXG.js → buildContracts-S22V7AGV.js} +28 -0
  3. package/bin/{chunk-LMSKLN5O.js → chunk-NI3MQCAS.js} +34 -0
  4. package/bin/cli.cjs +235 -20
  5. package/bin/cli.js +4 -4
  6. package/bin/{configLoader-Q6A4JLKW.js → configLoader-UJZHQBYS.js} +1 -1
  7. package/{dist/contractTestRunnerPlaywright-XBWJZMR3.js → bin/contractTestRunnerPlaywright-QDXSK3FE.js} +173 -20
  8. package/bin/{test-OND56UUL.js → test-O3J4ZPQR.js} +2 -2
  9. package/dist/{configLoader-WTGJAP4Z.js → configLoader-DWHOHXHL.js} +34 -0
  10. package/{bin/contractTestRunnerPlaywright-ZZNWDUYP.js → dist/contractTestRunnerPlaywright-WNWQYSXZ.js} +173 -20
  11. package/dist/index.cjs +492 -298
  12. package/dist/index.d.cts +53 -53
  13. package/dist/index.d.ts +53 -53
  14. package/dist/index.js +289 -282
  15. package/dist/src/{Types.d-DYfYR3Vc.d.cts → Types.d-yGC2bBaB.d.cts} +1 -1
  16. package/dist/src/{Types.d-DYfYR3Vc.d.ts → Types.d-yGC2bBaB.d.ts} +1 -1
  17. package/dist/src/accordion/index.d.cts +1 -1
  18. package/dist/src/accordion/index.d.ts +1 -1
  19. package/dist/src/block/index.d.cts +1 -1
  20. package/dist/src/block/index.d.ts +1 -1
  21. package/dist/src/checkbox/index.d.cts +1 -1
  22. package/dist/src/checkbox/index.d.ts +1 -1
  23. package/dist/src/combobox/index.cjs +21 -7
  24. package/dist/src/combobox/index.d.cts +1 -1
  25. package/dist/src/combobox/index.d.ts +1 -1
  26. package/dist/src/combobox/index.js +21 -7
  27. package/dist/src/menu/index.d.cts +1 -1
  28. package/dist/src/menu/index.d.ts +1 -1
  29. package/dist/src/radio/index.d.cts +1 -1
  30. package/dist/src/radio/index.d.ts +1 -1
  31. package/dist/src/tabs/index.d.cts +1 -1
  32. package/dist/src/tabs/index.d.ts +1 -1
  33. package/dist/src/toggle/index.d.cts +1 -1
  34. package/dist/src/toggle/index.d.ts +1 -1
  35. package/dist/src/utils/test/{configLoader-YE2CYGDG.js → configLoader-SHJSRG2A.js} +34 -0
  36. package/dist/src/utils/test/{contractTestRunnerPlaywright-LC5OAVXB.js → contractTestRunnerPlaywright-Z2AHXSNM.js} +173 -20
  37. package/dist/src/utils/test/dsl/index.cjs +263 -270
  38. package/dist/src/utils/test/dsl/index.d.cts +53 -53
  39. package/dist/src/utils/test/dsl/index.d.ts +53 -53
  40. package/dist/src/utils/test/dsl/index.js +263 -270
  41. package/dist/src/utils/test/index.cjs +207 -20
  42. package/dist/src/utils/test/index.js +2 -2
  43. package/package.json +1 -1
@@ -1,4 +1,148 @@
1
- // src/utils/test/dsl/index.ts
1
+ // src/utils/test/dsl/src/state-packs/comboboxStatePack.ts
2
+ var COMBOBOX_STATES = {
3
+ "listbox.open": {
4
+ setup: openCombobox(),
5
+ assertion: isComboboxOpen()
6
+ },
7
+ "listbox.closed": {
8
+ setup: closeCombobox(),
9
+ assertion: isComboboxClosed()
10
+ },
11
+ "input.focused": {
12
+ setup: focusInput(),
13
+ assertion: [
14
+ ...isInputFocused()
15
+ ]
16
+ },
17
+ "input.filled": {
18
+ setup: fillInput(),
19
+ assertion: [
20
+ ...isInputFilled()
21
+ ]
22
+ },
23
+ "activeOption.first": {
24
+ requires: ["listbox.open"],
25
+ setup: [
26
+ { type: "keypress", target: "input", key: "ArrowDown" }
27
+ ],
28
+ assertion: [
29
+ ...isActiveDescendantNotEmpty()
30
+ ]
31
+ },
32
+ "activeOption.last": {
33
+ requires: ["activeOption.first"],
34
+ setup: [
35
+ { type: "keypress", target: "input", key: "ArrowUp" }
36
+ ],
37
+ assertion: [
38
+ ...isActiveDescendantNotEmpty()
39
+ ]
40
+ },
41
+ "selectedOption.first": {
42
+ requires: ["listbox.open"],
43
+ setup: [
44
+ { type: "click", target: "relative", relativeTarget: "first" }
45
+ ],
46
+ assertion: [
47
+ ...isAriaSelected("first")
48
+ ]
49
+ },
50
+ "selectedOption.last": {
51
+ requires: ["listbox.open"],
52
+ setup: [
53
+ { type: "click", target: "relative", relativeTarget: "last" }
54
+ ],
55
+ assertion: [
56
+ ...isAriaSelected("first")
57
+ ]
58
+ }
59
+ };
60
+ function openCombobox() {
61
+ return [
62
+ { type: "keypress", target: "input", key: "ArrowDown" }
63
+ ];
64
+ }
65
+ function closeCombobox() {
66
+ return [
67
+ { type: "keypress", target: "input", key: "Escape" }
68
+ ];
69
+ }
70
+ function focusInput() {
71
+ return [
72
+ { type: "focus", target: "input" }
73
+ ];
74
+ }
75
+ function fillInput() {
76
+ return [
77
+ { type: "type", target: "input", value: "test" }
78
+ ];
79
+ }
80
+ function isComboboxOpen() {
81
+ return [
82
+ {
83
+ target: "listbox",
84
+ assertion: "toBeVisible",
85
+ failureMessage: "Expected listbox to be visible"
86
+ }
87
+ ];
88
+ }
89
+ function isComboboxClosed() {
90
+ return [
91
+ {
92
+ target: "listbox",
93
+ assertion: "notToBeVisible",
94
+ failureMessage: "Expected listbox to be closed"
95
+ }
96
+ ];
97
+ }
98
+ function isActiveDescendantNotEmpty() {
99
+ return [
100
+ {
101
+ target: "input",
102
+ assertion: "toHaveAttribute",
103
+ attribute: "aria-activedescendant",
104
+ expectedValue: "!empty",
105
+ failureMessage: "Expected aria-activedescendant to not be empty"
106
+ }
107
+ ];
108
+ }
109
+ function isAriaSelected(index) {
110
+ return [
111
+ {
112
+ target: "relative",
113
+ relativeTarget: index,
114
+ assertion: "toHaveAttribute",
115
+ attribute: "aria-selected",
116
+ expectedValue: "true",
117
+ failureMessage: `Expected aria-selected on ${index} option to be true`
118
+ }
119
+ ];
120
+ }
121
+ function isInputFocused() {
122
+ return [
123
+ {
124
+ target: "input",
125
+ assertion: "toHaveFocus",
126
+ failureMessage: "Expected input to be focused"
127
+ }
128
+ ];
129
+ }
130
+ function isInputFilled() {
131
+ return [
132
+ {
133
+ target: "input",
134
+ assertion: "toHaveValue",
135
+ expectedValue: "test",
136
+ failureMessage: "Expected input to have the value 'test'"
137
+ }
138
+ ];
139
+ }
140
+
141
+ // src/utils/test/dsl/src/contractBuilder.ts
142
+ var STATE_PACKS = {
143
+ "combobox.listbox": COMBOBOX_STATES
144
+ // Add more mappings as needed
145
+ };
2
146
  var FluentContract = class {
3
147
  constructor(jsonContract) {
4
148
  this.jsonContract = jsonContract;
@@ -7,306 +151,155 @@ var FluentContract = class {
7
151
  return this.jsonContract;
8
152
  }
9
153
  };
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;
154
+ var ContractBuilder = class {
155
+ constructor(componentName) {
156
+ this.componentName = componentName;
157
+ this.statePack = STATE_PACKS[componentName] || {};
58
158
  }
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
- }
159
+ metaValue = {};
160
+ selectorsValue = {};
161
+ relationshipInvariants = [];
162
+ staticAssertions = [];
163
+ dynamicTests = [];
164
+ statePack;
165
+ meta(meta) {
166
+ this.metaValue = meta;
82
167
  return this;
83
168
  }
84
- visible(target) {
85
- this.assertions.push({ target, assertion: "toBeVisible" });
169
+ selectors(selectors) {
170
+ this.selectorsValue = selectors;
86
171
  return this;
87
172
  }
88
- hidden(target) {
89
- this.assertions.push({ target, assertion: "notToBeVisible" });
173
+ relationships(fn) {
174
+ const api = {
175
+ ariaReference: (from, attribute, to) => ({
176
+ required: () => this.relationshipInvariants.push({ type: "aria-reference", from, attribute, to, level: "required" }),
177
+ optional: () => this.relationshipInvariants.push({ type: "aria-reference", from, attribute, to, level: "optional" })
178
+ }),
179
+ contains: (parent, child) => ({
180
+ required: () => this.relationshipInvariants.push({ type: "contains", parent, child, level: "required" }),
181
+ optional: () => this.relationshipInvariants.push({ type: "contains", parent, child, level: "optional" })
182
+ })
183
+ };
184
+ fn(api);
90
185
  return this;
91
186
  }
92
- has(target, attribute, expectedValue) {
93
- this.assertions.push({
94
- target,
95
- assertion: "toHaveAttribute",
96
- attribute,
97
- expectedValue
98
- });
187
+ static(fn) {
188
+ const api = {
189
+ target: (target) => ({
190
+ has: (attribute, expectedValue) => ({
191
+ required: () => this.staticAssertions.push({ target, attribute, expectedValue, failureMessage: "", level: "required" }),
192
+ optional: () => this.staticAssertions.push({ target, attribute, expectedValue, failureMessage: "", level: "optional" })
193
+ })
194
+ })
195
+ };
196
+ fn(api);
99
197
  return this;
100
198
  }
101
- required() {
102
- this.finalize("required");
103
- }
104
- recommended() {
105
- this.finalize("recommended");
199
+ when(event) {
200
+ return new DynamicTestBuilder(this, this.statePack, event);
106
201
  }
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
- });
202
+ addDynamicTest(test) {
203
+ this.dynamicTests.push(test);
121
204
  }
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 };
205
+ build() {
206
+ return {
207
+ meta: this.metaValue,
208
+ selectors: this.selectorsValue,
209
+ relationships: this.relationshipInvariants.length ? this.relationshipInvariants : void 0,
210
+ static: this.staticAssertions.length ? [{ assertions: this.staticAssertions }] : [],
211
+ dynamic: this.dynamicTests
212
+ };
128
213
  }
129
214
  };
130
- var ContractBuilder = class {
131
- constructor(componentName) {
132
- this.componentName = componentName;
215
+ var DynamicTestBuilder = class {
216
+ constructor(parent, statePack, event) {
217
+ this.parent = parent;
218
+ this.statePack = statePack;
219
+ this.event = event;
133
220
  }
134
- metaValue = {};
135
- selectorsValue = {};
136
- relationshipInvariants = [];
137
- staticAssertions = [];
138
- dynamicTests = [];
139
- meta(meta) {
140
- this.metaValue = { ...this.metaValue, ...meta };
221
+ _as;
222
+ _on;
223
+ _given = [];
224
+ _then = [];
225
+ _desc = "";
226
+ _level = "required";
227
+ as(actionType) {
228
+ this._as = actionType;
141
229
  return this;
142
230
  }
143
- selectors(selectors) {
144
- this.selectorsValue = { ...this.selectorsValue, ...selectors };
231
+ on(target) {
232
+ this._on = target;
145
233
  return this;
146
234
  }
147
- relationship(invariant) {
148
- this.relationshipInvariants.push(invariant);
235
+ given(states) {
236
+ this._given = Array.isArray(states) ? states : [states];
149
237
  return this;
150
238
  }
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
- });
239
+ then(states) {
240
+ this._then = Array.isArray(states) ? states : [states];
185
241
  return this;
186
242
  }
187
- static(builderFn) {
188
- builderFn(new StaticBuilder(this.staticAssertions));
243
+ describe(desc) {
244
+ this._desc = desc;
189
245
  return this;
190
246
  }
191
- when(key) {
192
- return new DynamicChain(key, this.dynamicTests, this.selectorsValue);
247
+ required() {
248
+ this._level = "required";
249
+ this._finalize();
250
+ return this.parent;
193
251
  }
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}"`);
252
+ optional() {
253
+ this._level = "optional";
254
+ this._finalize();
255
+ return this.parent;
256
+ }
257
+ recommended() {
258
+ this._level = "recommended";
259
+ this._finalize();
260
+ return this.parent;
261
+ }
262
+ _finalize() {
263
+ const resolveSetup = (stateName, visited = /* @__PURE__ */ new Set()) => {
264
+ if (visited.has(stateName)) return [];
265
+ visited.add(stateName);
266
+ const s = this.statePack[stateName];
267
+ if (!s) return [];
268
+ let actions = [];
269
+ if (Array.isArray(s.requires)) {
270
+ for (const req of s.requires) {
271
+ actions = actions.concat(resolveSetup(req, visited));
217
272
  }
218
273
  }
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
- );
274
+ if (s.setup) actions = actions.concat(s.setup);
275
+ return actions;
276
+ };
277
+ const setup = [];
278
+ for (const state of this._given) {
279
+ setup.push(...resolveSetup(state));
229
280
  }
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`);
281
+ const assertions = [];
282
+ for (const state of this._then) {
283
+ const s = this.statePack[state];
284
+ if (s && s.assertion) {
285
+ if (Array.isArray(s.assertion)) assertions.push(...s.assertion);
286
+ else assertions.push(s.assertion);
238
287
  }
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
288
  }
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
- });
289
+ const action = [
290
+ {
291
+ type: this._as,
292
+ target: this._on,
293
+ key: this._as === "keypress" ? this.event : void 0
294
+ }
295
+ ];
296
+ this.parent.addDynamicTest({
297
+ description: this._desc || "",
298
+ level: this._level,
299
+ action,
300
+ assertions,
301
+ ...setup.length ? { setup } : {}
280
302
  });
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
303
  }
311
304
  };
312
305
  function createContract(componentName, define) {