@stackoverflow/stacks 2.5.8 → 2.7.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.
- package/dist/css/stacks.css +91 -65
- package/dist/css/stacks.min.css +1 -1
- package/dist/js/stacks.js +2 -5
- package/lib/components/badge/badge.less +269 -258
- package/lib/components/button/button.less +35 -5
- package/lib/components/expandable/expandable.ts +238 -238
- package/lib/components/input_textarea/input_textarea.less +150 -150
- package/lib/components/link/link.less +136 -136
- package/lib/components/pagination/pagination.less +77 -65
- package/lib/components/sidebar-widget/sidebar-widget.less +34 -73
- package/lib/components/table/table.less +309 -307
- package/lib/components/uploader/uploader.ts +207 -207
- package/lib/exports/color-sets.less +711 -711
- package/lib/exports/color.less +65 -65
- package/lib/stacks.ts +113 -113
- package/lib/test/a11y-test-utils.ts +94 -94
- package/lib/test/test-utils.ts +364 -364
- package/package.json +12 -12
package/lib/test/test-utils.ts
CHANGED
|
@@ -1,364 +1,364 @@
|
|
|
1
|
-
import { html, unsafeStatic } from "@open-wc/testing";
|
|
2
|
-
|
|
3
|
-
type TestVariationArgs = {
|
|
4
|
-
/**
|
|
5
|
-
* Base class of the component
|
|
6
|
-
* (e.g. "s-component")
|
|
7
|
-
*/
|
|
8
|
-
baseClass: string;
|
|
9
|
-
/**
|
|
10
|
-
* Additional html attributes applied to the test element
|
|
11
|
-
* (e.g. { role: "button", id: "id" } -> <element role="button" id="id"> )
|
|
12
|
-
*/
|
|
13
|
-
attributes?: Record<string, string>;
|
|
14
|
-
/**
|
|
15
|
-
* Child elements to render inside the test element
|
|
16
|
-
* (if key `default` is used, the testid will not include the child name)
|
|
17
|
-
*/
|
|
18
|
-
children?: {
|
|
19
|
-
[key: string]: string;
|
|
20
|
-
};
|
|
21
|
-
/**
|
|
22
|
-
* testids of tests to exclude from testing
|
|
23
|
-
*/
|
|
24
|
-
excludedTestids?: (string | RegExp)[];
|
|
25
|
-
/**
|
|
26
|
-
* testids of tests to skip
|
|
27
|
-
*/
|
|
28
|
-
skippedTestids?: (string | RegExp)[];
|
|
29
|
-
/**
|
|
30
|
-
* HTML tag name of the test element
|
|
31
|
-
*/
|
|
32
|
-
tag?: string;
|
|
33
|
-
/**
|
|
34
|
-
* Function that returns a template for the test element
|
|
35
|
-
* used to wrap the component test element in a container
|
|
36
|
-
*/
|
|
37
|
-
template?: (args: {
|
|
38
|
-
component: unknown;
|
|
39
|
-
tag?: string;
|
|
40
|
-
testid: string;
|
|
41
|
-
}) => ReturnType<typeof html>;
|
|
42
|
-
/**
|
|
43
|
-
* Variants of the component
|
|
44
|
-
* (e.g. ["primary", "secondary"])
|
|
45
|
-
*/
|
|
46
|
-
variants?: string[];
|
|
47
|
-
/**
|
|
48
|
-
* Modifiers of the component
|
|
49
|
-
* (e.g. { primary: ["filled", "outlined"], secondary: ["xs", "sm", "md"] })
|
|
50
|
-
*/
|
|
51
|
-
modifiers?: Modifiers;
|
|
52
|
-
/**
|
|
53
|
-
* Options for the test
|
|
54
|
-
*/
|
|
55
|
-
options?: Partial<TestOptions>;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
type Modifiers = {
|
|
59
|
-
/**
|
|
60
|
-
* Primary grouping of modifiers to test
|
|
61
|
-
* The base class will be used as a prefix for these modifiers
|
|
62
|
-
*/
|
|
63
|
-
primary?: string[];
|
|
64
|
-
/**
|
|
65
|
-
* Secondary grouping of modifiers to test
|
|
66
|
-
* The base class will be used as a prefix for these modifiers
|
|
67
|
-
*/
|
|
68
|
-
secondary?: string[];
|
|
69
|
-
/**
|
|
70
|
-
* Grouping of modifers to test that will not be prefixed with the base class
|
|
71
|
-
*/
|
|
72
|
-
global?: string[];
|
|
73
|
-
/**
|
|
74
|
-
* Modifiers to test individually
|
|
75
|
-
* The base class will be used as a prefix for these modifiers
|
|
76
|
-
*/
|
|
77
|
-
standalone?: string[];
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
type TestOptions = {
|
|
81
|
-
/**
|
|
82
|
-
* Enable tests for all color themes
|
|
83
|
-
* default: true
|
|
84
|
-
*/
|
|
85
|
-
testColorThemes: boolean;
|
|
86
|
-
/**
|
|
87
|
-
* Enable tests for high contrast
|
|
88
|
-
* default: true
|
|
89
|
-
*/
|
|
90
|
-
testHighContrast: boolean;
|
|
91
|
-
/**
|
|
92
|
-
* Provide a custom testid suffix
|
|
93
|
-
* default: undefined
|
|
94
|
-
*/
|
|
95
|
-
testidSuffix?: string;
|
|
96
|
-
/**
|
|
97
|
-
* Include tests for the component without any variants applied
|
|
98
|
-
* default: true
|
|
99
|
-
*/
|
|
100
|
-
includeNullVariant: boolean;
|
|
101
|
-
/**
|
|
102
|
-
* Include tests for the component without any modifiers applied
|
|
103
|
-
* default: true
|
|
104
|
-
*/
|
|
105
|
-
includeNullModifier: boolean;
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
export const DEFAULT_OPTIONS = {
|
|
109
|
-
testColorThemes: true,
|
|
110
|
-
testHighContrast: true,
|
|
111
|
-
includeNullVariant: true,
|
|
112
|
-
includeNullModifier: true,
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
// TODO: refactor using MODES as opposed to THEMES
|
|
116
|
-
const COLOR_THEMES = ["dark", "light"];
|
|
117
|
-
const BASE_THEMES = ["", "highcontrast"];
|
|
118
|
-
type Themes = ["light" | "dark" | "highcontrast" | ""];
|
|
119
|
-
|
|
120
|
-
const attrObjToString = (attrs: Record<string, string>): string => {
|
|
121
|
-
const attrString = Object.keys(attrs).map((key) => {
|
|
122
|
-
return `${key}="${attrs[key]}"
|
|
123
|
-
});
|
|
124
|
-
return attrString.join(" ") || "";
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
const matchTestidByPattern = ({
|
|
128
|
-
testid,
|
|
129
|
-
pattern,
|
|
130
|
-
}: {
|
|
131
|
-
testid: string;
|
|
132
|
-
pattern: string | RegExp;
|
|
133
|
-
}): boolean => {
|
|
134
|
-
if (pattern instanceof RegExp) {
|
|
135
|
-
return pattern.test(testid);
|
|
136
|
-
} else {
|
|
137
|
-
return pattern === testid;
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
const buildTestid = (arr: string[]) => arr.filter(Boolean).join("-");
|
|
142
|
-
|
|
143
|
-
const buildClasses = ({
|
|
144
|
-
baseClass,
|
|
145
|
-
prefixed = [],
|
|
146
|
-
unprefixed = [],
|
|
147
|
-
}: {
|
|
148
|
-
baseClass: string;
|
|
149
|
-
prefixed?: string[];
|
|
150
|
-
unprefixed?: string[];
|
|
151
|
-
}) =>
|
|
152
|
-
[
|
|
153
|
-
baseClass,
|
|
154
|
-
...prefixed.filter((x) => x).map((suffix) => `${baseClass}__${suffix}`),
|
|
155
|
-
...unprefixed.filter((x) => x),
|
|
156
|
-
].join(" ");
|
|
157
|
-
|
|
158
|
-
const buildTestElement = ({
|
|
159
|
-
attributes = {},
|
|
160
|
-
children = "",
|
|
161
|
-
tag = "div",
|
|
162
|
-
testid,
|
|
163
|
-
}: {
|
|
164
|
-
attributes?: Record<string, string>;
|
|
165
|
-
children?: string;
|
|
166
|
-
tag?: string;
|
|
167
|
-
testid: string;
|
|
168
|
-
}) => {
|
|
169
|
-
const unsafe = {
|
|
170
|
-
tag: unsafeStatic(tag),
|
|
171
|
-
attributes: unsafeStatic(attrObjToString(attributes).toString()),
|
|
172
|
-
children: unsafeStatic(children),
|
|
173
|
-
};
|
|
174
|
-
|
|
175
|
-
return html`
|
|
176
|
-
<${unsafe.tag}
|
|
177
|
-
${unsafe.attributes}
|
|
178
|
-
data-testid="${testid}"
|
|
179
|
-
>${unsafe.children}</${unsafe.tag}>
|
|
180
|
-
`;
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
type PrimitiveVariation = {
|
|
184
|
-
classes: string;
|
|
185
|
-
testid: string;
|
|
186
|
-
theme: Themes;
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
type PrimitiveVariationArgs = Pick<
|
|
190
|
-
TestVariationArgs,
|
|
191
|
-
"baseClass" | "variants" | "modifiers" | "options"
|
|
192
|
-
>;
|
|
193
|
-
|
|
194
|
-
const generatePrimitiveVariations = ({
|
|
195
|
-
baseClass,
|
|
196
|
-
variants = [],
|
|
197
|
-
modifiers,
|
|
198
|
-
options = {},
|
|
199
|
-
}: PrimitiveVariationArgs): PrimitiveVariation[] => {
|
|
200
|
-
const primitiveVariations: PrimitiveVariation[] = [];
|
|
201
|
-
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
202
|
-
// Test default, high contrast themes
|
|
203
|
-
[...(opts.testHighContrast ? BASE_THEMES : [""])].forEach((baseTheme) => {
|
|
204
|
-
// Test light, dark theme
|
|
205
|
-
[...(opts.testColorThemes ? COLOR_THEMES : [""])].forEach(
|
|
206
|
-
(colorTheme) => {
|
|
207
|
-
const theme = [baseTheme, colorTheme].filter(Boolean) as Themes;
|
|
208
|
-
const testidBase = buildTestid([baseClass, ...theme]);
|
|
209
|
-
const allVariants = opts.includeNullVariant
|
|
210
|
-
? ["", ...variants]
|
|
211
|
-
: variants;
|
|
212
|
-
const primaryModifiers = modifiers?.primary
|
|
213
|
-
? opts.includeNullModifier
|
|
214
|
-
? ["", ...(<[]>modifiers.primary)]
|
|
215
|
-
: modifiers.primary
|
|
216
|
-
: [""];
|
|
217
|
-
const secondaryModifiers = modifiers?.secondary
|
|
218
|
-
? opts.includeNullModifier
|
|
219
|
-
? ["", ...(<[]>modifiers.secondary)]
|
|
220
|
-
: modifiers.secondary
|
|
221
|
-
: [""];
|
|
222
|
-
const globalModifiers = modifiers?.global
|
|
223
|
-
? opts.includeNullModifier
|
|
224
|
-
? ["", ...(<[]>modifiers.global)]
|
|
225
|
-
: modifiers.global
|
|
226
|
-
: [""];
|
|
227
|
-
|
|
228
|
-
primaryModifiers.forEach((primaryModifier) => {
|
|
229
|
-
secondaryModifiers.forEach((secondaryModifier) => {
|
|
230
|
-
globalModifiers.forEach((globalModifier) => {
|
|
231
|
-
allVariants.forEach((variant) => {
|
|
232
|
-
primitiveVariations.push({
|
|
233
|
-
classes: buildClasses({
|
|
234
|
-
baseClass,
|
|
235
|
-
prefixed: [
|
|
236
|
-
variant,
|
|
237
|
-
primaryModifier,
|
|
238
|
-
secondaryModifier,
|
|
239
|
-
],
|
|
240
|
-
unprefixed: [globalModifier],
|
|
241
|
-
}),
|
|
242
|
-
testid: buildTestid([
|
|
243
|
-
testidBase,
|
|
244
|
-
variant,
|
|
245
|
-
[
|
|
246
|
-
primaryModifier,
|
|
247
|
-
secondaryModifier,
|
|
248
|
-
globalModifier,
|
|
249
|
-
]
|
|
250
|
-
.filter(Boolean)
|
|
251
|
-
.join("-"),
|
|
252
|
-
]),
|
|
253
|
-
theme,
|
|
254
|
-
});
|
|
255
|
-
});
|
|
256
|
-
});
|
|
257
|
-
});
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
// create standalone modifiers test props
|
|
261
|
-
modifiers?.standalone?.forEach((standaloneModifier) => {
|
|
262
|
-
primitiveVariations.push({
|
|
263
|
-
testid: buildTestid([testidBase, standaloneModifier]),
|
|
264
|
-
classes: buildClasses({
|
|
265
|
-
baseClass,
|
|
266
|
-
prefixed: [standaloneModifier],
|
|
267
|
-
}),
|
|
268
|
-
theme,
|
|
269
|
-
});
|
|
270
|
-
});
|
|
271
|
-
}
|
|
272
|
-
);
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
// Sorting for readability
|
|
276
|
-
return primitiveVariations.sort((a, b) => a.testid.localeCompare(b.testid));
|
|
277
|
-
};
|
|
278
|
-
|
|
279
|
-
type TestVariation = {
|
|
280
|
-
testid: string;
|
|
281
|
-
element: ReturnType<typeof html>;
|
|
282
|
-
skipped: boolean;
|
|
283
|
-
theme: Themes;
|
|
284
|
-
};
|
|
285
|
-
|
|
286
|
-
const generateTestVariations = ({
|
|
287
|
-
baseClass,
|
|
288
|
-
variants = [],
|
|
289
|
-
modifiers,
|
|
290
|
-
options = DEFAULT_OPTIONS,
|
|
291
|
-
attributes,
|
|
292
|
-
children,
|
|
293
|
-
excludedTestids = [],
|
|
294
|
-
skippedTestids = [],
|
|
295
|
-
tag,
|
|
296
|
-
template,
|
|
297
|
-
}: TestVariationArgs): TestVariation[] => {
|
|
298
|
-
return generatePrimitiveVariations({
|
|
299
|
-
baseClass,
|
|
300
|
-
variants,
|
|
301
|
-
modifiers,
|
|
302
|
-
options,
|
|
303
|
-
}).flatMap(({ testid, classes, theme }) => {
|
|
304
|
-
const allChildren: {
|
|
305
|
-
[key: string]: string;
|
|
306
|
-
} = children ? { ...children } : { default: "" };
|
|
307
|
-
const { testidSuffix } = options;
|
|
308
|
-
|
|
309
|
-
return Object.keys(allChildren)
|
|
310
|
-
.map((key) => {
|
|
311
|
-
let testidModified = (
|
|
312
|
-
key !== "default" ? `${testid}-${key}` : testid
|
|
313
|
-
).replace(" ", "-");
|
|
314
|
-
testidModified = testidSuffix
|
|
315
|
-
? `${testidModified}-${testidSuffix}`
|
|
316
|
-
: testidModified;
|
|
317
|
-
|
|
318
|
-
const children = allChildren[key];
|
|
319
|
-
|
|
320
|
-
const element = template
|
|
321
|
-
? html`${template({
|
|
322
|
-
testid: testidModified,
|
|
323
|
-
component: buildTestElement({
|
|
324
|
-
attributes: {
|
|
325
|
-
...attributes,
|
|
326
|
-
class: `${classes} ${attributes?.class || ""}`,
|
|
327
|
-
},
|
|
328
|
-
children,
|
|
329
|
-
testid: `${testidModified}-nested`,
|
|
330
|
-
tag,
|
|
331
|
-
}),
|
|
332
|
-
})}`
|
|
333
|
-
: buildTestElement({
|
|
334
|
-
attributes: {
|
|
335
|
-
...attributes,
|
|
336
|
-
class: `${classes} ${attributes?.class || ""}`,
|
|
337
|
-
},
|
|
338
|
-
children,
|
|
339
|
-
testid: testidModified,
|
|
340
|
-
tag,
|
|
341
|
-
});
|
|
342
|
-
|
|
343
|
-
const skipped = skippedTestids.some((pattern) =>
|
|
344
|
-
matchTestidByPattern({ testid: testidModified, pattern })
|
|
345
|
-
);
|
|
346
|
-
|
|
347
|
-
return {
|
|
348
|
-
element,
|
|
349
|
-
testid: testidModified,
|
|
350
|
-
theme,
|
|
351
|
-
skipped,
|
|
352
|
-
};
|
|
353
|
-
})
|
|
354
|
-
.filter(
|
|
355
|
-
({ testid }) =>
|
|
356
|
-
!excludedTestids.some((pattern) =>
|
|
357
|
-
matchTestidByPattern({ testid, pattern })
|
|
358
|
-
)
|
|
359
|
-
);
|
|
360
|
-
});
|
|
361
|
-
};
|
|
362
|
-
|
|
363
|
-
export type { TestVariationArgs, TestVariation };
|
|
364
|
-
export { generateTestVariations };
|
|
1
|
+
import { html, unsafeStatic } from "@open-wc/testing";
|
|
2
|
+
|
|
3
|
+
type TestVariationArgs = {
|
|
4
|
+
/**
|
|
5
|
+
* Base class of the component
|
|
6
|
+
* (e.g. "s-component")
|
|
7
|
+
*/
|
|
8
|
+
baseClass: string;
|
|
9
|
+
/**
|
|
10
|
+
* Additional html attributes applied to the test element
|
|
11
|
+
* (e.g. { role: "button", id: "id" } -> <element role="button" id="id"> )
|
|
12
|
+
*/
|
|
13
|
+
attributes?: Record<string, string>;
|
|
14
|
+
/**
|
|
15
|
+
* Child elements to render inside the test element
|
|
16
|
+
* (if key `default` is used, the testid will not include the child name)
|
|
17
|
+
*/
|
|
18
|
+
children?: {
|
|
19
|
+
[key: string]: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* testids of tests to exclude from testing
|
|
23
|
+
*/
|
|
24
|
+
excludedTestids?: (string | RegExp)[];
|
|
25
|
+
/**
|
|
26
|
+
* testids of tests to skip
|
|
27
|
+
*/
|
|
28
|
+
skippedTestids?: (string | RegExp)[];
|
|
29
|
+
/**
|
|
30
|
+
* HTML tag name of the test element
|
|
31
|
+
*/
|
|
32
|
+
tag?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Function that returns a template for the test element
|
|
35
|
+
* used to wrap the component test element in a container
|
|
36
|
+
*/
|
|
37
|
+
template?: (args: {
|
|
38
|
+
component: unknown;
|
|
39
|
+
tag?: string;
|
|
40
|
+
testid: string;
|
|
41
|
+
}) => ReturnType<typeof html>;
|
|
42
|
+
/**
|
|
43
|
+
* Variants of the component
|
|
44
|
+
* (e.g. ["primary", "secondary"])
|
|
45
|
+
*/
|
|
46
|
+
variants?: string[];
|
|
47
|
+
/**
|
|
48
|
+
* Modifiers of the component
|
|
49
|
+
* (e.g. { primary: ["filled", "outlined"], secondary: ["xs", "sm", "md"] })
|
|
50
|
+
*/
|
|
51
|
+
modifiers?: Modifiers;
|
|
52
|
+
/**
|
|
53
|
+
* Options for the test
|
|
54
|
+
*/
|
|
55
|
+
options?: Partial<TestOptions>;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
type Modifiers = {
|
|
59
|
+
/**
|
|
60
|
+
* Primary grouping of modifiers to test
|
|
61
|
+
* The base class will be used as a prefix for these modifiers
|
|
62
|
+
*/
|
|
63
|
+
primary?: string[];
|
|
64
|
+
/**
|
|
65
|
+
* Secondary grouping of modifiers to test
|
|
66
|
+
* The base class will be used as a prefix for these modifiers
|
|
67
|
+
*/
|
|
68
|
+
secondary?: string[];
|
|
69
|
+
/**
|
|
70
|
+
* Grouping of modifers to test that will not be prefixed with the base class
|
|
71
|
+
*/
|
|
72
|
+
global?: string[];
|
|
73
|
+
/**
|
|
74
|
+
* Modifiers to test individually
|
|
75
|
+
* The base class will be used as a prefix for these modifiers
|
|
76
|
+
*/
|
|
77
|
+
standalone?: string[];
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
type TestOptions = {
|
|
81
|
+
/**
|
|
82
|
+
* Enable tests for all color themes
|
|
83
|
+
* default: true
|
|
84
|
+
*/
|
|
85
|
+
testColorThemes: boolean;
|
|
86
|
+
/**
|
|
87
|
+
* Enable tests for high contrast
|
|
88
|
+
* default: true
|
|
89
|
+
*/
|
|
90
|
+
testHighContrast: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Provide a custom testid suffix
|
|
93
|
+
* default: undefined
|
|
94
|
+
*/
|
|
95
|
+
testidSuffix?: string;
|
|
96
|
+
/**
|
|
97
|
+
* Include tests for the component without any variants applied
|
|
98
|
+
* default: true
|
|
99
|
+
*/
|
|
100
|
+
includeNullVariant: boolean;
|
|
101
|
+
/**
|
|
102
|
+
* Include tests for the component without any modifiers applied
|
|
103
|
+
* default: true
|
|
104
|
+
*/
|
|
105
|
+
includeNullModifier: boolean;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
export const DEFAULT_OPTIONS = {
|
|
109
|
+
testColorThemes: true,
|
|
110
|
+
testHighContrast: true,
|
|
111
|
+
includeNullVariant: true,
|
|
112
|
+
includeNullModifier: true,
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// TODO: refactor using MODES as opposed to THEMES
|
|
116
|
+
const COLOR_THEMES = ["dark", "light"];
|
|
117
|
+
const BASE_THEMES = ["", "highcontrast"];
|
|
118
|
+
type Themes = ["light" | "dark" | "highcontrast" | ""];
|
|
119
|
+
|
|
120
|
+
const attrObjToString = (attrs: Record<string, string>): string => {
|
|
121
|
+
const attrString = Object.keys(attrs).map((key) => {
|
|
122
|
+
return `${key}="${attrs[key]}"`;
|
|
123
|
+
});
|
|
124
|
+
return attrString.join(" ") || "";
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const matchTestidByPattern = ({
|
|
128
|
+
testid,
|
|
129
|
+
pattern,
|
|
130
|
+
}: {
|
|
131
|
+
testid: string;
|
|
132
|
+
pattern: string | RegExp;
|
|
133
|
+
}): boolean => {
|
|
134
|
+
if (pattern instanceof RegExp) {
|
|
135
|
+
return pattern.test(testid);
|
|
136
|
+
} else {
|
|
137
|
+
return pattern === testid;
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const buildTestid = (arr: string[]) => arr.filter(Boolean).join("-");
|
|
142
|
+
|
|
143
|
+
const buildClasses = ({
|
|
144
|
+
baseClass,
|
|
145
|
+
prefixed = [],
|
|
146
|
+
unprefixed = [],
|
|
147
|
+
}: {
|
|
148
|
+
baseClass: string;
|
|
149
|
+
prefixed?: string[];
|
|
150
|
+
unprefixed?: string[];
|
|
151
|
+
}) =>
|
|
152
|
+
[
|
|
153
|
+
baseClass,
|
|
154
|
+
...prefixed.filter((x) => x).map((suffix) => `${baseClass}__${suffix}`),
|
|
155
|
+
...unprefixed.filter((x) => x),
|
|
156
|
+
].join(" ");
|
|
157
|
+
|
|
158
|
+
const buildTestElement = ({
|
|
159
|
+
attributes = {},
|
|
160
|
+
children = "",
|
|
161
|
+
tag = "div",
|
|
162
|
+
testid,
|
|
163
|
+
}: {
|
|
164
|
+
attributes?: Record<string, string>;
|
|
165
|
+
children?: string;
|
|
166
|
+
tag?: string;
|
|
167
|
+
testid: string;
|
|
168
|
+
}) => {
|
|
169
|
+
const unsafe = {
|
|
170
|
+
tag: unsafeStatic(tag),
|
|
171
|
+
attributes: unsafeStatic(attrObjToString(attributes).toString()),
|
|
172
|
+
children: unsafeStatic(children),
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
return html`
|
|
176
|
+
<${unsafe.tag}
|
|
177
|
+
${unsafe.attributes}
|
|
178
|
+
data-testid="${testid}"
|
|
179
|
+
>${unsafe.children}</${unsafe.tag}>
|
|
180
|
+
`;
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
type PrimitiveVariation = {
|
|
184
|
+
classes: string;
|
|
185
|
+
testid: string;
|
|
186
|
+
theme: Themes;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
type PrimitiveVariationArgs = Pick<
|
|
190
|
+
TestVariationArgs,
|
|
191
|
+
"baseClass" | "variants" | "modifiers" | "options"
|
|
192
|
+
>;
|
|
193
|
+
|
|
194
|
+
const generatePrimitiveVariations = ({
|
|
195
|
+
baseClass,
|
|
196
|
+
variants = [],
|
|
197
|
+
modifiers,
|
|
198
|
+
options = {},
|
|
199
|
+
}: PrimitiveVariationArgs): PrimitiveVariation[] => {
|
|
200
|
+
const primitiveVariations: PrimitiveVariation[] = [];
|
|
201
|
+
const opts = { ...DEFAULT_OPTIONS, ...options };
|
|
202
|
+
// Test default, high contrast themes
|
|
203
|
+
[...(opts.testHighContrast ? BASE_THEMES : [""])].forEach((baseTheme) => {
|
|
204
|
+
// Test light, dark theme
|
|
205
|
+
[...(opts.testColorThemes ? COLOR_THEMES : [""])].forEach(
|
|
206
|
+
(colorTheme) => {
|
|
207
|
+
const theme = [baseTheme, colorTheme].filter(Boolean) as Themes;
|
|
208
|
+
const testidBase = buildTestid([baseClass, ...theme]);
|
|
209
|
+
const allVariants = opts.includeNullVariant
|
|
210
|
+
? ["", ...variants]
|
|
211
|
+
: variants;
|
|
212
|
+
const primaryModifiers = modifiers?.primary
|
|
213
|
+
? opts.includeNullModifier
|
|
214
|
+
? ["", ...(<[]>modifiers.primary)]
|
|
215
|
+
: modifiers.primary
|
|
216
|
+
: [""];
|
|
217
|
+
const secondaryModifiers = modifiers?.secondary
|
|
218
|
+
? opts.includeNullModifier
|
|
219
|
+
? ["", ...(<[]>modifiers.secondary)]
|
|
220
|
+
: modifiers.secondary
|
|
221
|
+
: [""];
|
|
222
|
+
const globalModifiers = modifiers?.global
|
|
223
|
+
? opts.includeNullModifier
|
|
224
|
+
? ["", ...(<[]>modifiers.global)]
|
|
225
|
+
: modifiers.global
|
|
226
|
+
: [""];
|
|
227
|
+
|
|
228
|
+
primaryModifiers.forEach((primaryModifier) => {
|
|
229
|
+
secondaryModifiers.forEach((secondaryModifier) => {
|
|
230
|
+
globalModifiers.forEach((globalModifier) => {
|
|
231
|
+
allVariants.forEach((variant) => {
|
|
232
|
+
primitiveVariations.push({
|
|
233
|
+
classes: buildClasses({
|
|
234
|
+
baseClass,
|
|
235
|
+
prefixed: [
|
|
236
|
+
variant,
|
|
237
|
+
primaryModifier,
|
|
238
|
+
secondaryModifier,
|
|
239
|
+
],
|
|
240
|
+
unprefixed: [globalModifier],
|
|
241
|
+
}),
|
|
242
|
+
testid: buildTestid([
|
|
243
|
+
testidBase,
|
|
244
|
+
variant,
|
|
245
|
+
[
|
|
246
|
+
primaryModifier,
|
|
247
|
+
secondaryModifier,
|
|
248
|
+
globalModifier,
|
|
249
|
+
]
|
|
250
|
+
.filter(Boolean)
|
|
251
|
+
.join("-"),
|
|
252
|
+
]),
|
|
253
|
+
theme,
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// create standalone modifiers test props
|
|
261
|
+
modifiers?.standalone?.forEach((standaloneModifier) => {
|
|
262
|
+
primitiveVariations.push({
|
|
263
|
+
testid: buildTestid([testidBase, standaloneModifier]),
|
|
264
|
+
classes: buildClasses({
|
|
265
|
+
baseClass,
|
|
266
|
+
prefixed: [standaloneModifier],
|
|
267
|
+
}),
|
|
268
|
+
theme,
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
);
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
// Sorting for readability
|
|
276
|
+
return primitiveVariations.sort((a, b) => a.testid.localeCompare(b.testid));
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
type TestVariation = {
|
|
280
|
+
testid: string;
|
|
281
|
+
element: ReturnType<typeof html>;
|
|
282
|
+
skipped: boolean;
|
|
283
|
+
theme: Themes;
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
const generateTestVariations = ({
|
|
287
|
+
baseClass,
|
|
288
|
+
variants = [],
|
|
289
|
+
modifiers,
|
|
290
|
+
options = DEFAULT_OPTIONS,
|
|
291
|
+
attributes,
|
|
292
|
+
children,
|
|
293
|
+
excludedTestids = [],
|
|
294
|
+
skippedTestids = [],
|
|
295
|
+
tag,
|
|
296
|
+
template,
|
|
297
|
+
}: TestVariationArgs): TestVariation[] => {
|
|
298
|
+
return generatePrimitiveVariations({
|
|
299
|
+
baseClass,
|
|
300
|
+
variants,
|
|
301
|
+
modifiers,
|
|
302
|
+
options,
|
|
303
|
+
}).flatMap(({ testid, classes, theme }) => {
|
|
304
|
+
const allChildren: {
|
|
305
|
+
[key: string]: string;
|
|
306
|
+
} = children ? { ...children } : { default: "" };
|
|
307
|
+
const { testidSuffix } = options;
|
|
308
|
+
|
|
309
|
+
return Object.keys(allChildren)
|
|
310
|
+
.map((key) => {
|
|
311
|
+
let testidModified = (
|
|
312
|
+
key !== "default" ? `${testid}-${key}` : testid
|
|
313
|
+
).replace(" ", "-");
|
|
314
|
+
testidModified = testidSuffix
|
|
315
|
+
? `${testidModified}-${testidSuffix}`
|
|
316
|
+
: testidModified;
|
|
317
|
+
|
|
318
|
+
const children = allChildren[key];
|
|
319
|
+
|
|
320
|
+
const element = template
|
|
321
|
+
? html`${template({
|
|
322
|
+
testid: testidModified,
|
|
323
|
+
component: buildTestElement({
|
|
324
|
+
attributes: {
|
|
325
|
+
...attributes,
|
|
326
|
+
class: `${classes} ${attributes?.class || ""}`,
|
|
327
|
+
},
|
|
328
|
+
children,
|
|
329
|
+
testid: `${testidModified}-nested`,
|
|
330
|
+
tag,
|
|
331
|
+
}),
|
|
332
|
+
})}`
|
|
333
|
+
: buildTestElement({
|
|
334
|
+
attributes: {
|
|
335
|
+
...attributes,
|
|
336
|
+
class: `${classes} ${attributes?.class || ""}`,
|
|
337
|
+
},
|
|
338
|
+
children,
|
|
339
|
+
testid: testidModified,
|
|
340
|
+
tag,
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
const skipped = skippedTestids.some((pattern) =>
|
|
344
|
+
matchTestidByPattern({ testid: testidModified, pattern })
|
|
345
|
+
);
|
|
346
|
+
|
|
347
|
+
return {
|
|
348
|
+
element,
|
|
349
|
+
testid: testidModified,
|
|
350
|
+
theme,
|
|
351
|
+
skipped,
|
|
352
|
+
};
|
|
353
|
+
})
|
|
354
|
+
.filter(
|
|
355
|
+
({ testid }) =>
|
|
356
|
+
!excludedTestids.some((pattern) =>
|
|
357
|
+
matchTestidByPattern({ testid, pattern })
|
|
358
|
+
)
|
|
359
|
+
);
|
|
360
|
+
});
|
|
361
|
+
};
|
|
362
|
+
|
|
363
|
+
export type { TestVariationArgs, TestVariation };
|
|
364
|
+
export { generateTestVariations };
|