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,6 +1,150 @@
1
1
  'use strict';
2
2
 
3
- // src/utils/test/dsl/index.ts
3
+ // src/utils/test/dsl/src/state-packs/comboboxStatePack.ts
4
+ var COMBOBOX_STATES = {
5
+ "listbox.open": {
6
+ setup: openCombobox(),
7
+ assertion: isComboboxOpen()
8
+ },
9
+ "listbox.closed": {
10
+ setup: closeCombobox(),
11
+ assertion: isComboboxClosed()
12
+ },
13
+ "input.focused": {
14
+ setup: focusInput(),
15
+ assertion: [
16
+ ...isInputFocused()
17
+ ]
18
+ },
19
+ "input.filled": {
20
+ setup: fillInput(),
21
+ assertion: [
22
+ ...isInputFilled()
23
+ ]
24
+ },
25
+ "activeOption.first": {
26
+ requires: ["listbox.open"],
27
+ setup: [
28
+ { type: "keypress", target: "input", key: "ArrowDown" }
29
+ ],
30
+ assertion: [
31
+ ...isActiveDescendantNotEmpty()
32
+ ]
33
+ },
34
+ "activeOption.last": {
35
+ requires: ["activeOption.first"],
36
+ setup: [
37
+ { type: "keypress", target: "input", key: "ArrowUp" }
38
+ ],
39
+ assertion: [
40
+ ...isActiveDescendantNotEmpty()
41
+ ]
42
+ },
43
+ "selectedOption.first": {
44
+ requires: ["listbox.open"],
45
+ setup: [
46
+ { type: "click", target: "relative", relativeTarget: "first" }
47
+ ],
48
+ assertion: [
49
+ ...isAriaSelected("first")
50
+ ]
51
+ },
52
+ "selectedOption.last": {
53
+ requires: ["listbox.open"],
54
+ setup: [
55
+ { type: "click", target: "relative", relativeTarget: "last" }
56
+ ],
57
+ assertion: [
58
+ ...isAriaSelected("first")
59
+ ]
60
+ }
61
+ };
62
+ function openCombobox() {
63
+ return [
64
+ { type: "keypress", target: "input", key: "ArrowDown" }
65
+ ];
66
+ }
67
+ function closeCombobox() {
68
+ return [
69
+ { type: "keypress", target: "input", key: "Escape" }
70
+ ];
71
+ }
72
+ function focusInput() {
73
+ return [
74
+ { type: "focus", target: "input" }
75
+ ];
76
+ }
77
+ function fillInput() {
78
+ return [
79
+ { type: "type", target: "input", value: "test" }
80
+ ];
81
+ }
82
+ function isComboboxOpen() {
83
+ return [
84
+ {
85
+ target: "listbox",
86
+ assertion: "toBeVisible",
87
+ failureMessage: "Expected listbox to be visible"
88
+ }
89
+ ];
90
+ }
91
+ function isComboboxClosed() {
92
+ return [
93
+ {
94
+ target: "listbox",
95
+ assertion: "notToBeVisible",
96
+ failureMessage: "Expected listbox to be closed"
97
+ }
98
+ ];
99
+ }
100
+ function isActiveDescendantNotEmpty() {
101
+ return [
102
+ {
103
+ target: "input",
104
+ assertion: "toHaveAttribute",
105
+ attribute: "aria-activedescendant",
106
+ expectedValue: "!empty",
107
+ failureMessage: "Expected aria-activedescendant to not be empty"
108
+ }
109
+ ];
110
+ }
111
+ function isAriaSelected(index) {
112
+ return [
113
+ {
114
+ target: "relative",
115
+ relativeTarget: index,
116
+ assertion: "toHaveAttribute",
117
+ attribute: "aria-selected",
118
+ expectedValue: "true",
119
+ failureMessage: `Expected aria-selected on ${index} option to be true`
120
+ }
121
+ ];
122
+ }
123
+ function isInputFocused() {
124
+ return [
125
+ {
126
+ target: "input",
127
+ assertion: "toHaveFocus",
128
+ failureMessage: "Expected input to be focused"
129
+ }
130
+ ];
131
+ }
132
+ function isInputFilled() {
133
+ return [
134
+ {
135
+ target: "input",
136
+ assertion: "toHaveValue",
137
+ expectedValue: "test",
138
+ failureMessage: "Expected input to have the value 'test'"
139
+ }
140
+ ];
141
+ }
142
+
143
+ // src/utils/test/dsl/src/contractBuilder.ts
144
+ var STATE_PACKS = {
145
+ "combobox.listbox": COMBOBOX_STATES
146
+ // Add more mappings as needed
147
+ };
4
148
  var FluentContract = class {
5
149
  constructor(jsonContract) {
6
150
  this.jsonContract = jsonContract;
@@ -9,306 +153,155 @@ var FluentContract = class {
9
153
  return this.jsonContract;
10
154
  }
11
155
  };
12
- var StaticTargetBuilder = class {
13
- constructor(targetName, sink) {
14
- this.targetName = targetName;
15
- this.sink = sink;
16
- }
17
- has(attribute, expectedValue) {
18
- const create = (level) => {
19
- this.sink.push({
20
- target: this.targetName,
21
- attribute,
22
- expectedValue,
23
- failureMessage: `Expected ${this.targetName} to have ${attribute}${expectedValue !== void 0 ? `=${expectedValue}` : ""}.`,
24
- level
25
- });
26
- };
27
- return {
28
- required: () => create("required"),
29
- recommended: () => create("recommended"),
30
- optional: () => create("optional")
31
- };
32
- }
33
- };
34
- var StaticBuilder = class {
35
- constructor(sink) {
36
- this.sink = sink;
37
- }
38
- target(targetName) {
39
- return new StaticTargetBuilder(targetName, this.sink);
40
- }
41
- };
42
- var DynamicChain = class {
43
- constructor(key, testsSink, selectors) {
44
- this.key = key;
45
- this.testsSink = testsSink;
46
- this.selectors = selectors;
47
- }
48
- selectorTarget = "";
49
- actions = [];
50
- assertions = [];
51
- explicitDescription = "";
52
- on(target) {
53
- this.selectorTarget = target;
54
- this.actions.push({ type: "keypress", target, key: this.key });
55
- return this;
56
- }
57
- describe(description) {
58
- this.explicitDescription = description;
59
- return this;
156
+ var ContractBuilder = class {
157
+ constructor(componentName) {
158
+ this.componentName = componentName;
159
+ this.statePack = STATE_PACKS[componentName] || {};
60
160
  }
61
- focus(targetExpression) {
62
- const parsed = this.parseRelativeExpression(targetExpression);
63
- if (parsed) {
64
- if (!this.selectors[parsed.selectorKey]) {
65
- const availableSelectors = Object.keys(this.selectors).sort().join(", ") || "(none)";
66
- throw new Error(
67
- `Invalid focus target expression "${targetExpression}": selector "${parsed.selectorKey}" is not defined. Available selectors: ${availableSelectors}`
68
- );
69
- }
70
- if (!this.selectors.relative && this.selectors[parsed.selectorKey]) {
71
- this.selectors.relative = this.selectors[parsed.selectorKey];
72
- }
73
- this.assertions.push({
74
- target: "relative",
75
- assertion: "toHaveFocus",
76
- relativeTarget: parsed.relativeTarget
77
- });
78
- } else {
79
- this.assertions.push({
80
- target: targetExpression,
81
- assertion: "toHaveFocus"
82
- });
83
- }
161
+ metaValue = {};
162
+ selectorsValue = {};
163
+ relationshipInvariants = [];
164
+ staticAssertions = [];
165
+ dynamicTests = [];
166
+ statePack;
167
+ meta(meta) {
168
+ this.metaValue = meta;
84
169
  return this;
85
170
  }
86
- visible(target) {
87
- this.assertions.push({ target, assertion: "toBeVisible" });
171
+ selectors(selectors) {
172
+ this.selectorsValue = selectors;
88
173
  return this;
89
174
  }
90
- hidden(target) {
91
- this.assertions.push({ target, assertion: "notToBeVisible" });
175
+ relationships(fn) {
176
+ const api = {
177
+ ariaReference: (from, attribute, to) => ({
178
+ required: () => this.relationshipInvariants.push({ type: "aria-reference", from, attribute, to, level: "required" }),
179
+ optional: () => this.relationshipInvariants.push({ type: "aria-reference", from, attribute, to, level: "optional" })
180
+ }),
181
+ contains: (parent, child) => ({
182
+ required: () => this.relationshipInvariants.push({ type: "contains", parent, child, level: "required" }),
183
+ optional: () => this.relationshipInvariants.push({ type: "contains", parent, child, level: "optional" })
184
+ })
185
+ };
186
+ fn(api);
92
187
  return this;
93
188
  }
94
- has(target, attribute, expectedValue) {
95
- this.assertions.push({
96
- target,
97
- assertion: "toHaveAttribute",
98
- attribute,
99
- expectedValue
100
- });
189
+ static(fn) {
190
+ const api = {
191
+ target: (target) => ({
192
+ has: (attribute, expectedValue) => ({
193
+ required: () => this.staticAssertions.push({ target, attribute, expectedValue, failureMessage: "", level: "required" }),
194
+ optional: () => this.staticAssertions.push({ target, attribute, expectedValue, failureMessage: "", level: "optional" })
195
+ })
196
+ })
197
+ };
198
+ fn(api);
101
199
  return this;
102
200
  }
103
- required() {
104
- this.finalize("required");
105
- }
106
- recommended() {
107
- this.finalize("recommended");
201
+ when(event) {
202
+ return new DynamicTestBuilder(this, this.statePack, event);
108
203
  }
109
- optional() {
110
- this.finalize("optional");
111
- }
112
- finalize(level) {
113
- if (!this.selectorTarget) {
114
- throw new Error("Dynamic contract chain requires .on(<selectorKey>) before level terminator.");
115
- }
116
- const description = this.explicitDescription || `Pressing ${this.key} on ${this.selectorTarget} satisfies expected behavior.`;
117
- this.testsSink.push({
118
- description,
119
- level,
120
- action: this.actions,
121
- assertions: this.assertions.map((a) => ({ ...a, level }))
122
- });
204
+ addDynamicTest(test) {
205
+ this.dynamicTests.push(test);
123
206
  }
124
- parseRelativeExpression(input) {
125
- const match = input.match(/^(next|previous|first|last)\(([^)]+)\)$/);
126
- if (!match) return null;
127
- const relativeTarget = match[1];
128
- const selectorKey = match[2].trim();
129
- return { relativeTarget, selectorKey };
207
+ build() {
208
+ return {
209
+ meta: this.metaValue,
210
+ selectors: this.selectorsValue,
211
+ relationships: this.relationshipInvariants.length ? this.relationshipInvariants : void 0,
212
+ static: this.staticAssertions.length ? [{ assertions: this.staticAssertions }] : [],
213
+ dynamic: this.dynamicTests
214
+ };
130
215
  }
131
216
  };
132
- var ContractBuilder = class {
133
- constructor(componentName) {
134
- this.componentName = componentName;
217
+ var DynamicTestBuilder = class {
218
+ constructor(parent, statePack, event) {
219
+ this.parent = parent;
220
+ this.statePack = statePack;
221
+ this.event = event;
135
222
  }
136
- metaValue = {};
137
- selectorsValue = {};
138
- relationshipInvariants = [];
139
- staticAssertions = [];
140
- dynamicTests = [];
141
- meta(meta) {
142
- this.metaValue = { ...this.metaValue, ...meta };
223
+ _as;
224
+ _on;
225
+ _given = [];
226
+ _then = [];
227
+ _desc = "";
228
+ _level = "required";
229
+ as(actionType) {
230
+ this._as = actionType;
143
231
  return this;
144
232
  }
145
- selectors(selectors) {
146
- this.selectorsValue = { ...this.selectorsValue, ...selectors };
233
+ on(target) {
234
+ this._on = target;
147
235
  return this;
148
236
  }
149
- relationship(invariant) {
150
- this.relationshipInvariants.push(invariant);
237
+ given(states) {
238
+ this._given = Array.isArray(states) ? states : [states];
151
239
  return this;
152
240
  }
153
- relationships(builderFn) {
154
- builderFn({
155
- ariaReference: (from, attribute, to) => {
156
- const create = (level) => {
157
- this.relationshipInvariants.push({
158
- type: "aria-reference",
159
- from,
160
- attribute,
161
- to,
162
- level
163
- });
164
- };
165
- return {
166
- required: () => create("required"),
167
- recommended: () => create("recommended"),
168
- optional: () => create("optional")
169
- };
170
- },
171
- contains: (parent, child) => {
172
- const create = (level) => {
173
- this.relationshipInvariants.push({
174
- type: "contains",
175
- parent,
176
- child,
177
- level
178
- });
179
- };
180
- return {
181
- required: () => create("required"),
182
- recommended: () => create("recommended"),
183
- optional: () => create("optional")
184
- };
185
- }
186
- });
241
+ then(states) {
242
+ this._then = Array.isArray(states) ? states : [states];
187
243
  return this;
188
244
  }
189
- static(builderFn) {
190
- builderFn(new StaticBuilder(this.staticAssertions));
245
+ describe(desc) {
246
+ this._desc = desc;
191
247
  return this;
192
248
  }
193
- when(key) {
194
- return new DynamicChain(key, this.dynamicTests, this.selectorsValue);
249
+ required() {
250
+ this._level = "required";
251
+ this._finalize();
252
+ return this.parent;
195
253
  }
196
- validateRelationshipInvariants() {
197
- if (this.relationshipInvariants.length === 0) {
198
- return;
199
- }
200
- const selectorKeys = new Set(Object.keys(this.selectorsValue));
201
- const available = Object.keys(this.selectorsValue).sort().join(", ");
202
- const errors = [];
203
- this.relationshipInvariants.forEach((invariant, index) => {
204
- const prefix = `relationships[${index}] (${invariant.type})`;
205
- if (invariant.type === "aria-reference") {
206
- if (!selectorKeys.has(invariant.from)) {
207
- errors.push(`${prefix}: "from" references unknown selector "${invariant.from}"`);
208
- }
209
- if (!selectorKeys.has(invariant.to)) {
210
- errors.push(`${prefix}: "to" references unknown selector "${invariant.to}"`);
211
- }
212
- }
213
- if (invariant.type === "contains") {
214
- if (!selectorKeys.has(invariant.parent)) {
215
- errors.push(`${prefix}: "parent" references unknown selector "${invariant.parent}"`);
216
- }
217
- if (!selectorKeys.has(invariant.child)) {
218
- errors.push(`${prefix}: "child" references unknown selector "${invariant.child}"`);
254
+ optional() {
255
+ this._level = "optional";
256
+ this._finalize();
257
+ return this.parent;
258
+ }
259
+ recommended() {
260
+ this._level = "recommended";
261
+ this._finalize();
262
+ return this.parent;
263
+ }
264
+ _finalize() {
265
+ const resolveSetup = (stateName, visited = /* @__PURE__ */ new Set()) => {
266
+ if (visited.has(stateName)) return [];
267
+ visited.add(stateName);
268
+ const s = this.statePack[stateName];
269
+ if (!s) return [];
270
+ let actions = [];
271
+ if (Array.isArray(s.requires)) {
272
+ for (const req of s.requires) {
273
+ actions = actions.concat(resolveSetup(req, visited));
219
274
  }
220
275
  }
221
- });
222
- if (errors.length > 0) {
223
- const availableSelectorsMessage = available.length > 0 ? available : "(none)";
224
- throw new Error(
225
- [
226
- `Contract invariant validation failed for component "${this.componentName}".`,
227
- ...errors.map((error) => `- ${error}`),
228
- `Available selectors: ${availableSelectorsMessage}`
229
- ].join("\n")
230
- );
276
+ if (s.setup) actions = actions.concat(s.setup);
277
+ return actions;
278
+ };
279
+ const setup = [];
280
+ for (const state of this._given) {
281
+ setup.push(...resolveSetup(state));
231
282
  }
232
- }
233
- validateStaticTargets() {
234
- const selectorKeys = new Set(Object.keys(this.selectorsValue));
235
- const available = Object.keys(this.selectorsValue).sort().join(", ") || "(none)";
236
- const errors = [];
237
- this.staticAssertions.forEach((assertion, index) => {
238
- if (!selectorKeys.has(assertion.target)) {
239
- errors.push(`static.assertions[${index}]: target "${assertion.target}" is not defined in selectors`);
283
+ const assertions = [];
284
+ for (const state of this._then) {
285
+ const s = this.statePack[state];
286
+ if (s && s.assertion) {
287
+ if (Array.isArray(s.assertion)) assertions.push(...s.assertion);
288
+ else assertions.push(s.assertion);
240
289
  }
241
- });
242
- if (errors.length > 0) {
243
- throw new Error(
244
- [
245
- `Contract static target validation failed for component "${this.componentName}".`,
246
- ...errors.map((error) => `- ${error}`),
247
- `Available selectors: ${available}`
248
- ].join("\n")
249
- );
250
290
  }
251
- }
252
- validateDynamicTargets() {
253
- const selectorKeys = new Set(Object.keys(this.selectorsValue));
254
- const available = Object.keys(this.selectorsValue).sort().join(", ") || "(none)";
255
- const errors = [];
256
- const isValidActionTarget = (target) => {
257
- return selectorKeys.has(target) || target === "document" || target === "relative";
258
- };
259
- const isValidAssertionTarget = (target) => {
260
- return selectorKeys.has(target) || target === "relative";
261
- };
262
- this.dynamicTests.forEach((test, testIndex) => {
263
- test.action.forEach((action, actionIndex) => {
264
- if (!isValidActionTarget(action.target)) {
265
- errors.push(
266
- `dynamic[${testIndex}].action[${actionIndex}]: target "${action.target}" is not defined in selectors`
267
- );
268
- }
269
- });
270
- test.assertions.forEach((assertion, assertionIndex) => {
271
- if (!isValidAssertionTarget(assertion.target)) {
272
- errors.push(
273
- `dynamic[${testIndex}].assertions[${assertionIndex}]: target "${assertion.target}" is not defined in selectors`
274
- );
275
- }
276
- if (assertion.target === "relative" && !this.selectorsValue.relative) {
277
- errors.push(
278
- `dynamic[${testIndex}].assertions[${assertionIndex}]: target "relative" requires selectors.relative to be defined`
279
- );
280
- }
281
- });
291
+ const action = [
292
+ {
293
+ type: this._as,
294
+ target: this._on,
295
+ key: this._as === "keypress" ? this.event : void 0
296
+ }
297
+ ];
298
+ this.parent.addDynamicTest({
299
+ description: this._desc || "",
300
+ level: this._level,
301
+ action,
302
+ assertions,
303
+ ...setup.length ? { setup } : {}
282
304
  });
283
- if (errors.length > 0) {
284
- throw new Error(
285
- [
286
- `Contract dynamic target validation failed for component "${this.componentName}".`,
287
- ...errors.map((error) => `- ${error}`),
288
- `Available selectors: ${available}`,
289
- `Allowed special targets: document, relative`
290
- ].join("\n")
291
- );
292
- }
293
- }
294
- build() {
295
- this.validateRelationshipInvariants();
296
- this.validateStaticTargets();
297
- this.validateDynamicTargets();
298
- const fallbackId = this.metaValue.id || `aria-ease.contract.${this.componentName}`;
299
- return {
300
- meta: {
301
- id: fallbackId,
302
- version: this.metaValue.version || "1.0.0",
303
- description: this.metaValue.description || `Fluent contract for ${this.componentName}`,
304
- source: this.metaValue.source,
305
- W3CName: this.metaValue.W3CName
306
- },
307
- selectors: this.selectorsValue,
308
- relationships: this.relationshipInvariants,
309
- static: [{ assertions: this.staticAssertions }],
310
- dynamic: this.dynamicTests
311
- };
312
305
  }
313
306
  };
314
307
  function createContract(componentName, define) {