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.
- package/README.md +68 -6
- package/bin/AccordionComponentStrategy-4ZEIQ2V6.js +42 -0
- package/bin/ComboboxComponentStrategy-OGRVZXAF.js +64 -0
- package/bin/MenuComponentStrategy-JAMTCSNF.js +81 -0
- package/bin/TabsComponentStrategy-3SQURPMX.js +29 -0
- package/bin/buildContracts-GBOY7UXG.js +437 -0
- package/bin/{chunk-VPBHLMAS.js → chunk-LMSKLN5O.js} +21 -0
- package/bin/chunk-PK5L2SAF.js +17 -0
- package/bin/{chunk-2TOYEY5L.js → chunk-XERMSYEH.js} +12 -3
- package/bin/cli.cjs +991 -128
- package/bin/cli.js +33 -2
- package/bin/{configLoader-XRF6VM4J.js → configLoader-Q6A4JLKW.js} +1 -1
- package/{dist/contractTestRunnerPlaywright-UAOFNS7Z.js → bin/contractTestRunnerPlaywright-ZZNWDUYP.js} +270 -219
- package/bin/{test-WRIJHN6H.js → test-OND56UUL.js} +97 -10
- package/dist/AccordionComponentStrategy-4ZEIQ2V6.js +42 -0
- package/dist/ComboboxComponentStrategy-OGRVZXAF.js +64 -0
- package/dist/MenuComponentStrategy-JAMTCSNF.js +81 -0
- package/dist/TabsComponentStrategy-3SQURPMX.js +29 -0
- package/dist/chunk-PK5L2SAF.js +17 -0
- package/dist/{chunk-2TOYEY5L.js → chunk-XERMSYEH.js} +12 -3
- package/dist/{configLoader-IT4PWCJB.js → configLoader-WTGJAP4Z.js} +21 -0
- package/{bin/contractTestRunnerPlaywright-UAOFNS7Z.js → dist/contractTestRunnerPlaywright-XBWJZMR3.js} +270 -219
- package/dist/index.cjs +794 -90
- package/dist/index.d.cts +136 -1
- package/dist/index.d.ts +136 -1
- package/dist/index.js +415 -10
- package/dist/src/utils/test/AccordionComponentStrategy-WRHZOEN6.js +38 -0
- package/dist/src/utils/test/ComboboxComponentStrategy-5AECQSRN.js +60 -0
- package/dist/src/utils/test/MenuComponentStrategy-VKZQYLBE.js +77 -0
- package/dist/src/utils/test/TabsComponentStrategy-BKG53SEV.js +26 -0
- package/dist/src/utils/test/{chunk-2TOYEY5L.js → chunk-XERMSYEH.js} +12 -3
- package/dist/src/utils/test/{configLoader-LD4RV2WQ.js → configLoader-YE2CYGDG.js} +21 -0
- package/dist/src/utils/test/{contractTestRunnerPlaywright-IRJOAEMT.js → contractTestRunnerPlaywright-LC5OAVXB.js} +262 -200
- package/dist/src/utils/test/dsl/index.cjs +320 -0
- package/dist/src/utils/test/dsl/index.d.cts +136 -0
- package/dist/src/utils/test/dsl/index.d.ts +136 -0
- package/dist/src/utils/test/dsl/index.js +318 -0
- package/dist/src/utils/test/index.cjs +472 -88
- package/dist/src/utils/test/index.js +97 -12
- package/package.json +9 -3
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/utils/test/dsl/index.ts
|
|
4
|
+
var FluentContract = class {
|
|
5
|
+
constructor(jsonContract) {
|
|
6
|
+
this.jsonContract = jsonContract;
|
|
7
|
+
}
|
|
8
|
+
toJSON() {
|
|
9
|
+
return this.jsonContract;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
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;
|
|
60
|
+
}
|
|
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
|
+
}
|
|
84
|
+
return this;
|
|
85
|
+
}
|
|
86
|
+
visible(target) {
|
|
87
|
+
this.assertions.push({ target, assertion: "toBeVisible" });
|
|
88
|
+
return this;
|
|
89
|
+
}
|
|
90
|
+
hidden(target) {
|
|
91
|
+
this.assertions.push({ target, assertion: "notToBeVisible" });
|
|
92
|
+
return this;
|
|
93
|
+
}
|
|
94
|
+
has(target, attribute, expectedValue) {
|
|
95
|
+
this.assertions.push({
|
|
96
|
+
target,
|
|
97
|
+
assertion: "toHaveAttribute",
|
|
98
|
+
attribute,
|
|
99
|
+
expectedValue
|
|
100
|
+
});
|
|
101
|
+
return this;
|
|
102
|
+
}
|
|
103
|
+
required() {
|
|
104
|
+
this.finalize("required");
|
|
105
|
+
}
|
|
106
|
+
recommended() {
|
|
107
|
+
this.finalize("recommended");
|
|
108
|
+
}
|
|
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
|
+
});
|
|
123
|
+
}
|
|
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 };
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
var ContractBuilder = class {
|
|
133
|
+
constructor(componentName) {
|
|
134
|
+
this.componentName = componentName;
|
|
135
|
+
}
|
|
136
|
+
metaValue = {};
|
|
137
|
+
selectorsValue = {};
|
|
138
|
+
relationshipInvariants = [];
|
|
139
|
+
staticAssertions = [];
|
|
140
|
+
dynamicTests = [];
|
|
141
|
+
meta(meta) {
|
|
142
|
+
this.metaValue = { ...this.metaValue, ...meta };
|
|
143
|
+
return this;
|
|
144
|
+
}
|
|
145
|
+
selectors(selectors) {
|
|
146
|
+
this.selectorsValue = { ...this.selectorsValue, ...selectors };
|
|
147
|
+
return this;
|
|
148
|
+
}
|
|
149
|
+
relationship(invariant) {
|
|
150
|
+
this.relationshipInvariants.push(invariant);
|
|
151
|
+
return this;
|
|
152
|
+
}
|
|
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
|
+
});
|
|
187
|
+
return this;
|
|
188
|
+
}
|
|
189
|
+
static(builderFn) {
|
|
190
|
+
builderFn(new StaticBuilder(this.staticAssertions));
|
|
191
|
+
return this;
|
|
192
|
+
}
|
|
193
|
+
when(key) {
|
|
194
|
+
return new DynamicChain(key, this.dynamicTests, this.selectorsValue);
|
|
195
|
+
}
|
|
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}"`);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
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
|
+
);
|
|
231
|
+
}
|
|
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`);
|
|
240
|
+
}
|
|
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
|
+
}
|
|
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
|
+
});
|
|
282
|
+
});
|
|
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
|
+
}
|
|
313
|
+
};
|
|
314
|
+
function createContract(componentName, define) {
|
|
315
|
+
const builder = new ContractBuilder(componentName);
|
|
316
|
+
define(builder);
|
|
317
|
+
return new FluentContract(builder.build());
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
exports.createContract = createContract;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
type Level = "required" | "recommended" | "optional";
|
|
2
|
+
type ContractMeta = {
|
|
3
|
+
id?: string;
|
|
4
|
+
version?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
source?: {
|
|
7
|
+
apg?: string;
|
|
8
|
+
wcag?: string[];
|
|
9
|
+
};
|
|
10
|
+
W3CName?: string;
|
|
11
|
+
};
|
|
12
|
+
type SelectorsMap = Record<string, string>;
|
|
13
|
+
type RelationshipInvariant = {
|
|
14
|
+
type: "aria-reference";
|
|
15
|
+
from: string;
|
|
16
|
+
attribute: string;
|
|
17
|
+
to: string;
|
|
18
|
+
level?: Level;
|
|
19
|
+
} | {
|
|
20
|
+
type: "contains";
|
|
21
|
+
parent: string;
|
|
22
|
+
child: string;
|
|
23
|
+
level?: Level;
|
|
24
|
+
};
|
|
25
|
+
type StaticAssertion = {
|
|
26
|
+
target: string;
|
|
27
|
+
attribute: string;
|
|
28
|
+
expectedValue?: string;
|
|
29
|
+
failureMessage: string;
|
|
30
|
+
level: Level;
|
|
31
|
+
};
|
|
32
|
+
type DynamicAction = {
|
|
33
|
+
type: "focus" | "type" | "click" | "keypress" | "hover";
|
|
34
|
+
target: string;
|
|
35
|
+
key?: string;
|
|
36
|
+
value?: string;
|
|
37
|
+
relativeTarget?: string;
|
|
38
|
+
};
|
|
39
|
+
type DynamicAssertion = {
|
|
40
|
+
target: string;
|
|
41
|
+
assertion: "toBeVisible" | "notToBeVisible" | "toHaveAttribute" | "toHaveValue" | "toHaveFocus" | "toHaveRole";
|
|
42
|
+
attribute?: string;
|
|
43
|
+
expectedValue?: string;
|
|
44
|
+
failureMessage?: string;
|
|
45
|
+
relativeTarget?: string;
|
|
46
|
+
level?: Level;
|
|
47
|
+
};
|
|
48
|
+
type DynamicTest = {
|
|
49
|
+
description: string;
|
|
50
|
+
level?: Level;
|
|
51
|
+
action: DynamicAction[];
|
|
52
|
+
assertions: DynamicAssertion[];
|
|
53
|
+
};
|
|
54
|
+
type JsonContract = {
|
|
55
|
+
meta?: ContractMeta;
|
|
56
|
+
selectors: SelectorsMap;
|
|
57
|
+
relationships?: RelationshipInvariant[];
|
|
58
|
+
static: Array<{
|
|
59
|
+
assertions: StaticAssertion[];
|
|
60
|
+
}>;
|
|
61
|
+
dynamic: DynamicTest[];
|
|
62
|
+
};
|
|
63
|
+
declare class FluentContract {
|
|
64
|
+
private readonly jsonContract;
|
|
65
|
+
constructor(jsonContract: JsonContract);
|
|
66
|
+
toJSON(): JsonContract;
|
|
67
|
+
}
|
|
68
|
+
declare class StaticTargetBuilder {
|
|
69
|
+
private readonly targetName;
|
|
70
|
+
private readonly sink;
|
|
71
|
+
constructor(targetName: string, sink: StaticAssertion[]);
|
|
72
|
+
has(attribute: string, expectedValue?: string): {
|
|
73
|
+
required: () => void;
|
|
74
|
+
recommended: () => void;
|
|
75
|
+
optional: () => void;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
declare class StaticBuilder {
|
|
79
|
+
private readonly sink;
|
|
80
|
+
constructor(sink: StaticAssertion[]);
|
|
81
|
+
target(targetName: string): StaticTargetBuilder;
|
|
82
|
+
}
|
|
83
|
+
declare class DynamicChain {
|
|
84
|
+
private readonly key;
|
|
85
|
+
private readonly testsSink;
|
|
86
|
+
private readonly selectors;
|
|
87
|
+
private selectorTarget;
|
|
88
|
+
private readonly actions;
|
|
89
|
+
private readonly assertions;
|
|
90
|
+
private explicitDescription;
|
|
91
|
+
constructor(key: string, testsSink: DynamicTest[], selectors: SelectorsMap);
|
|
92
|
+
on(target: string): this;
|
|
93
|
+
describe(description: string): this;
|
|
94
|
+
focus(targetExpression: string): this;
|
|
95
|
+
visible(target: string): this;
|
|
96
|
+
hidden(target: string): this;
|
|
97
|
+
has(target: string, attribute: string, expectedValue?: string): this;
|
|
98
|
+
required(): void;
|
|
99
|
+
recommended(): void;
|
|
100
|
+
optional(): void;
|
|
101
|
+
private finalize;
|
|
102
|
+
private parseRelativeExpression;
|
|
103
|
+
}
|
|
104
|
+
declare class ContractBuilder {
|
|
105
|
+
private readonly componentName;
|
|
106
|
+
private metaValue;
|
|
107
|
+
private selectorsValue;
|
|
108
|
+
private readonly relationshipInvariants;
|
|
109
|
+
private readonly staticAssertions;
|
|
110
|
+
private readonly dynamicTests;
|
|
111
|
+
constructor(componentName: string);
|
|
112
|
+
meta(meta: ContractMeta): this;
|
|
113
|
+
selectors(selectors: SelectorsMap): this;
|
|
114
|
+
relationship(invariant: RelationshipInvariant): this;
|
|
115
|
+
relationships(builderFn: (r: {
|
|
116
|
+
ariaReference: (from: string, attribute: string, to: string) => {
|
|
117
|
+
required: () => void;
|
|
118
|
+
recommended: () => void;
|
|
119
|
+
optional: () => void;
|
|
120
|
+
};
|
|
121
|
+
contains: (parent: string, child: string) => {
|
|
122
|
+
required: () => void;
|
|
123
|
+
recommended: () => void;
|
|
124
|
+
optional: () => void;
|
|
125
|
+
};
|
|
126
|
+
}) => void): this;
|
|
127
|
+
static(builderFn: (s: StaticBuilder) => void): this;
|
|
128
|
+
when(key: string): DynamicChain;
|
|
129
|
+
private validateRelationshipInvariants;
|
|
130
|
+
private validateStaticTargets;
|
|
131
|
+
private validateDynamicTargets;
|
|
132
|
+
build(): JsonContract;
|
|
133
|
+
}
|
|
134
|
+
declare function createContract(componentName: string, define: (c: ContractBuilder) => void): FluentContract;
|
|
135
|
+
|
|
136
|
+
export { ContractBuilder, type JsonContract, type RelationshipInvariant, createContract };
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
type Level = "required" | "recommended" | "optional";
|
|
2
|
+
type ContractMeta = {
|
|
3
|
+
id?: string;
|
|
4
|
+
version?: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
source?: {
|
|
7
|
+
apg?: string;
|
|
8
|
+
wcag?: string[];
|
|
9
|
+
};
|
|
10
|
+
W3CName?: string;
|
|
11
|
+
};
|
|
12
|
+
type SelectorsMap = Record<string, string>;
|
|
13
|
+
type RelationshipInvariant = {
|
|
14
|
+
type: "aria-reference";
|
|
15
|
+
from: string;
|
|
16
|
+
attribute: string;
|
|
17
|
+
to: string;
|
|
18
|
+
level?: Level;
|
|
19
|
+
} | {
|
|
20
|
+
type: "contains";
|
|
21
|
+
parent: string;
|
|
22
|
+
child: string;
|
|
23
|
+
level?: Level;
|
|
24
|
+
};
|
|
25
|
+
type StaticAssertion = {
|
|
26
|
+
target: string;
|
|
27
|
+
attribute: string;
|
|
28
|
+
expectedValue?: string;
|
|
29
|
+
failureMessage: string;
|
|
30
|
+
level: Level;
|
|
31
|
+
};
|
|
32
|
+
type DynamicAction = {
|
|
33
|
+
type: "focus" | "type" | "click" | "keypress" | "hover";
|
|
34
|
+
target: string;
|
|
35
|
+
key?: string;
|
|
36
|
+
value?: string;
|
|
37
|
+
relativeTarget?: string;
|
|
38
|
+
};
|
|
39
|
+
type DynamicAssertion = {
|
|
40
|
+
target: string;
|
|
41
|
+
assertion: "toBeVisible" | "notToBeVisible" | "toHaveAttribute" | "toHaveValue" | "toHaveFocus" | "toHaveRole";
|
|
42
|
+
attribute?: string;
|
|
43
|
+
expectedValue?: string;
|
|
44
|
+
failureMessage?: string;
|
|
45
|
+
relativeTarget?: string;
|
|
46
|
+
level?: Level;
|
|
47
|
+
};
|
|
48
|
+
type DynamicTest = {
|
|
49
|
+
description: string;
|
|
50
|
+
level?: Level;
|
|
51
|
+
action: DynamicAction[];
|
|
52
|
+
assertions: DynamicAssertion[];
|
|
53
|
+
};
|
|
54
|
+
type JsonContract = {
|
|
55
|
+
meta?: ContractMeta;
|
|
56
|
+
selectors: SelectorsMap;
|
|
57
|
+
relationships?: RelationshipInvariant[];
|
|
58
|
+
static: Array<{
|
|
59
|
+
assertions: StaticAssertion[];
|
|
60
|
+
}>;
|
|
61
|
+
dynamic: DynamicTest[];
|
|
62
|
+
};
|
|
63
|
+
declare class FluentContract {
|
|
64
|
+
private readonly jsonContract;
|
|
65
|
+
constructor(jsonContract: JsonContract);
|
|
66
|
+
toJSON(): JsonContract;
|
|
67
|
+
}
|
|
68
|
+
declare class StaticTargetBuilder {
|
|
69
|
+
private readonly targetName;
|
|
70
|
+
private readonly sink;
|
|
71
|
+
constructor(targetName: string, sink: StaticAssertion[]);
|
|
72
|
+
has(attribute: string, expectedValue?: string): {
|
|
73
|
+
required: () => void;
|
|
74
|
+
recommended: () => void;
|
|
75
|
+
optional: () => void;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
declare class StaticBuilder {
|
|
79
|
+
private readonly sink;
|
|
80
|
+
constructor(sink: StaticAssertion[]);
|
|
81
|
+
target(targetName: string): StaticTargetBuilder;
|
|
82
|
+
}
|
|
83
|
+
declare class DynamicChain {
|
|
84
|
+
private readonly key;
|
|
85
|
+
private readonly testsSink;
|
|
86
|
+
private readonly selectors;
|
|
87
|
+
private selectorTarget;
|
|
88
|
+
private readonly actions;
|
|
89
|
+
private readonly assertions;
|
|
90
|
+
private explicitDescription;
|
|
91
|
+
constructor(key: string, testsSink: DynamicTest[], selectors: SelectorsMap);
|
|
92
|
+
on(target: string): this;
|
|
93
|
+
describe(description: string): this;
|
|
94
|
+
focus(targetExpression: string): this;
|
|
95
|
+
visible(target: string): this;
|
|
96
|
+
hidden(target: string): this;
|
|
97
|
+
has(target: string, attribute: string, expectedValue?: string): this;
|
|
98
|
+
required(): void;
|
|
99
|
+
recommended(): void;
|
|
100
|
+
optional(): void;
|
|
101
|
+
private finalize;
|
|
102
|
+
private parseRelativeExpression;
|
|
103
|
+
}
|
|
104
|
+
declare class ContractBuilder {
|
|
105
|
+
private readonly componentName;
|
|
106
|
+
private metaValue;
|
|
107
|
+
private selectorsValue;
|
|
108
|
+
private readonly relationshipInvariants;
|
|
109
|
+
private readonly staticAssertions;
|
|
110
|
+
private readonly dynamicTests;
|
|
111
|
+
constructor(componentName: string);
|
|
112
|
+
meta(meta: ContractMeta): this;
|
|
113
|
+
selectors(selectors: SelectorsMap): this;
|
|
114
|
+
relationship(invariant: RelationshipInvariant): this;
|
|
115
|
+
relationships(builderFn: (r: {
|
|
116
|
+
ariaReference: (from: string, attribute: string, to: string) => {
|
|
117
|
+
required: () => void;
|
|
118
|
+
recommended: () => void;
|
|
119
|
+
optional: () => void;
|
|
120
|
+
};
|
|
121
|
+
contains: (parent: string, child: string) => {
|
|
122
|
+
required: () => void;
|
|
123
|
+
recommended: () => void;
|
|
124
|
+
optional: () => void;
|
|
125
|
+
};
|
|
126
|
+
}) => void): this;
|
|
127
|
+
static(builderFn: (s: StaticBuilder) => void): this;
|
|
128
|
+
when(key: string): DynamicChain;
|
|
129
|
+
private validateRelationshipInvariants;
|
|
130
|
+
private validateStaticTargets;
|
|
131
|
+
private validateDynamicTargets;
|
|
132
|
+
build(): JsonContract;
|
|
133
|
+
}
|
|
134
|
+
declare function createContract(componentName: string, define: (c: ContractBuilder) => void): FluentContract;
|
|
135
|
+
|
|
136
|
+
export { ContractBuilder, type JsonContract, type RelationshipInvariant, createContract };
|