@cronn/element-snapshot 0.17.0 → 0.19.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/README.md +2 -2
- package/dist/browser-lib.iife.js +161 -118
- package/dist/index.d.mts +48 -29
- package/dist/index.mjs +65 -37
- package/package.json +37 -38
package/README.md
CHANGED
|
@@ -27,9 +27,9 @@ yarn add -D @cronn/element-snapshot
|
|
|
27
27
|
|
|
28
28
|
```ts
|
|
29
29
|
import { semanticSnapshot } from "@cronn/element-snapshot";
|
|
30
|
-
import {
|
|
30
|
+
import { defineFileSnapshotMatchers } from "@cronn/playwright-file-snapshots";
|
|
31
31
|
|
|
32
|
-
const expect =
|
|
32
|
+
const expect = defineFileSnapshotMatchers();
|
|
33
33
|
|
|
34
34
|
test("matches element snapshot", async ({ page }) => {
|
|
35
35
|
await page.setContent(`
|
package/dist/browser-lib.iife.js
CHANGED
|
@@ -119,89 +119,6 @@
|
|
|
119
119
|
}, []);
|
|
120
120
|
}
|
|
121
121
|
//#endregion
|
|
122
|
-
//#region src/browser/text.ts
|
|
123
|
-
function snapshotTextNode(textNode) {
|
|
124
|
-
if (textNode.textContent === null) return null;
|
|
125
|
-
const normalizedText = normalizeText(textNode.textContent);
|
|
126
|
-
if (normalizedText.length === 0) return null;
|
|
127
|
-
return textSnapshot(normalizedText);
|
|
128
|
-
}
|
|
129
|
-
function snapshotPresentationalChildren(node) {
|
|
130
|
-
const accessibleTextContent = resolveAccessibleTextContent(node);
|
|
131
|
-
if (accessibleTextContent === void 0 || accessibleTextContent.length === 0) return [];
|
|
132
|
-
return [textSnapshot(accessibleTextContent)];
|
|
133
|
-
}
|
|
134
|
-
function resolveAccessibleTextContent(node, excludedNodes = []) {
|
|
135
|
-
const children = snapshotChildren(node, excludedNodes);
|
|
136
|
-
if (children === void 0) return;
|
|
137
|
-
const textContent = getTextContent(children);
|
|
138
|
-
return textContent.length > 0 ? textContent : void 0;
|
|
139
|
-
}
|
|
140
|
-
//#endregion
|
|
141
|
-
//#region src/browser/name.ts
|
|
142
|
-
function resolveAccessibleName(element, includeTextContent = true) {
|
|
143
|
-
const labelledByElement = resolveElementReference(element, "aria-labelledby");
|
|
144
|
-
if (labelledByElement !== null) return resolveAccessibleTextContent(labelledByElement);
|
|
145
|
-
if (element.ariaLabel !== null) return element.ariaLabel;
|
|
146
|
-
if (includeTextContent) return resolveAccessibleTextContent(element);
|
|
147
|
-
}
|
|
148
|
-
//#endregion
|
|
149
|
-
//#region src/browser/state.ts
|
|
150
|
-
function disableableAttributes(element) {
|
|
151
|
-
return { disabled: booleanAttribute(isNativeInputElement(element) || element instanceof HTMLButtonElement || element instanceof HTMLOptionElement ? element.hasAttribute("disabled") : false) ?? booleanAttribute(element.ariaDisabled) };
|
|
152
|
-
}
|
|
153
|
-
function selectableAttributes(element) {
|
|
154
|
-
return { selected: booleanAttribute(element instanceof HTMLOptionElement ? element.hasAttribute("selected") : false) ?? booleanAttribute(element.ariaSelected) };
|
|
155
|
-
}
|
|
156
|
-
function inputStateAttributes(element) {
|
|
157
|
-
const supportsHtmlAttributes = isNativeInputElement(element);
|
|
158
|
-
const readonly = booleanAttribute(supportsHtmlAttributes ? element.hasAttribute("readonly") : false);
|
|
159
|
-
const required = booleanAttribute(supportsHtmlAttributes ? element.hasAttribute("required") : false);
|
|
160
|
-
return {
|
|
161
|
-
readonly: readonly ?? booleanAttribute(element.ariaReadOnly),
|
|
162
|
-
...disableableAttributes(element),
|
|
163
|
-
required: required ?? booleanAttribute(element.ariaRequired),
|
|
164
|
-
invalid: booleanAttribute(element.ariaInvalid)
|
|
165
|
-
};
|
|
166
|
-
}
|
|
167
|
-
function isNativeInputElement(element) {
|
|
168
|
-
return element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement;
|
|
169
|
-
}
|
|
170
|
-
//#endregion
|
|
171
|
-
//#region src/browser/button.ts
|
|
172
|
-
const PRESSED_VALUES = new Set([
|
|
173
|
-
"true",
|
|
174
|
-
"mixed",
|
|
175
|
-
"false"
|
|
176
|
-
]);
|
|
177
|
-
function snapshotButton(element) {
|
|
178
|
-
return {
|
|
179
|
-
role: "button",
|
|
180
|
-
name: resolveAccessibleName(element),
|
|
181
|
-
attributes: {
|
|
182
|
-
...disableableAttributes(element),
|
|
183
|
-
expanded: booleanAttribute(element.ariaExpanded),
|
|
184
|
-
pressed: resolvePressedAttribute(element)
|
|
185
|
-
},
|
|
186
|
-
children: snapshotChildren(element)
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
function resolvePressedAttribute(element) {
|
|
190
|
-
const pressed = enumAttribute(element.ariaPressed, PRESSED_VALUES);
|
|
191
|
-
if (pressed === "mixed") return pressed;
|
|
192
|
-
return booleanAttribute(pressed === "true");
|
|
193
|
-
}
|
|
194
|
-
//#endregion
|
|
195
|
-
//#region src/browser/description.ts
|
|
196
|
-
function discribableAttributes(element) {
|
|
197
|
-
return { description: resolveDescription(element) };
|
|
198
|
-
}
|
|
199
|
-
function resolveDescription(element) {
|
|
200
|
-
const describedByElement = resolveElementReference(element, "aria-describedby");
|
|
201
|
-
if (describedByElement !== null) return resolveAccessibleTextContent(describedByElement);
|
|
202
|
-
if (element.ariaDescription !== null) return element.ariaDescription;
|
|
203
|
-
}
|
|
204
|
-
//#endregion
|
|
205
122
|
//#region src/types/elements/container.ts
|
|
206
123
|
const CONTAINER_ROLES = new Set([
|
|
207
124
|
"paragraph",
|
|
@@ -215,7 +132,6 @@
|
|
|
215
132
|
"form",
|
|
216
133
|
"main",
|
|
217
134
|
"navigation",
|
|
218
|
-
"region",
|
|
219
135
|
"search",
|
|
220
136
|
"descriptionlist",
|
|
221
137
|
"term",
|
|
@@ -235,12 +151,11 @@
|
|
|
235
151
|
]);
|
|
236
152
|
//#endregion
|
|
237
153
|
//#region src/browser/container.ts
|
|
238
|
-
const NAMEABLE_CONTAINER_ROLES = new Set(["label"]);
|
|
239
154
|
function snapshotContainer(role, element) {
|
|
240
155
|
const children = snapshotChildren(element);
|
|
241
156
|
return elementSnapshot({
|
|
242
157
|
role,
|
|
243
|
-
name: resolveAccessibleName(element
|
|
158
|
+
name: resolveAccessibleName(element),
|
|
244
159
|
children
|
|
245
160
|
});
|
|
246
161
|
}
|
|
@@ -319,7 +234,6 @@
|
|
|
319
234
|
gridcell: isWithinGridRow,
|
|
320
235
|
listitem: isWithinList,
|
|
321
236
|
menuitem: isWithinMenu,
|
|
322
|
-
region: hasAccessibleName,
|
|
323
237
|
row: isWithinTableOrGrid,
|
|
324
238
|
rowgroup: isWithinTableOrGrid,
|
|
325
239
|
rowheader: isWithinTableRowOrGridRow,
|
|
@@ -345,7 +259,7 @@
|
|
|
345
259
|
const resolvedElementRole = resolveElementRole(element);
|
|
346
260
|
if (resolvedElementRole === void 0) return;
|
|
347
261
|
const isValidInContext = CONTEXT_DEPENDENT_ROLES[resolvedElementRole];
|
|
348
|
-
if (isValidInContext !== void 0 && !isValidInContext(element)) return;
|
|
262
|
+
if (isValidInContext !== void 0 && !isValidInContext(element, resolvedElementRole)) return;
|
|
349
263
|
return resolvedElementRole;
|
|
350
264
|
}
|
|
351
265
|
function resolveElementRole(element) {
|
|
@@ -384,9 +298,6 @@
|
|
|
384
298
|
function isTopLevelBanner(element) {
|
|
385
299
|
return !isWithinElement(element, selectorList(...DISALLOWED_BANNER_CONTAINER_ELEMENTS, ...DISALLOWED_BANNER_CONTAINER_ROLES.map(roleSelector)));
|
|
386
300
|
}
|
|
387
|
-
function hasAccessibleName(element) {
|
|
388
|
-
return resolveAccessibleName(element, false) !== void 0;
|
|
389
|
-
}
|
|
390
301
|
function isWithinDescriptionList(element) {
|
|
391
302
|
return isWithinElement(element, "dl");
|
|
392
303
|
}
|
|
@@ -428,6 +339,144 @@
|
|
|
428
339
|
return isWithinElement(element, roleSelector("tablist"));
|
|
429
340
|
}
|
|
430
341
|
//#endregion
|
|
342
|
+
//#region src/browser/text.ts
|
|
343
|
+
function snapshotTextNode(textNode) {
|
|
344
|
+
if (textNode.textContent === null) return null;
|
|
345
|
+
const normalizedText = normalizeText(textNode.textContent);
|
|
346
|
+
if (normalizedText.length === 0) return null;
|
|
347
|
+
return textSnapshot(normalizedText);
|
|
348
|
+
}
|
|
349
|
+
function snapshotPresentationalChildren(node) {
|
|
350
|
+
const accessibleTextContent = resolveAccessibleTextContent(node);
|
|
351
|
+
if (accessibleTextContent === void 0 || accessibleTextContent.length === 0) return [];
|
|
352
|
+
return [textSnapshot(accessibleTextContent)];
|
|
353
|
+
}
|
|
354
|
+
function resolveAccessibleTextContent(node, excludedNodes = []) {
|
|
355
|
+
const children = snapshotChildren(node, excludedNodes);
|
|
356
|
+
if (children === void 0) return;
|
|
357
|
+
const textContent = getTextContent(children);
|
|
358
|
+
return textContent.length > 0 ? textContent : void 0;
|
|
359
|
+
}
|
|
360
|
+
//#endregion
|
|
361
|
+
//#region src/browser/name.ts
|
|
362
|
+
const prohibitsNaming = new Set([
|
|
363
|
+
"label",
|
|
364
|
+
"listitem",
|
|
365
|
+
"paragraph",
|
|
366
|
+
"rowgroup",
|
|
367
|
+
"term"
|
|
368
|
+
]);
|
|
369
|
+
const supportsNamingByLabel = new Set([
|
|
370
|
+
"checkbox",
|
|
371
|
+
"combobox",
|
|
372
|
+
"progressbar",
|
|
373
|
+
"radio",
|
|
374
|
+
"searchbox",
|
|
375
|
+
"slider",
|
|
376
|
+
"spinbutton",
|
|
377
|
+
"textbox"
|
|
378
|
+
]);
|
|
379
|
+
const supportsNamingFromChildContent = new Set([
|
|
380
|
+
"button",
|
|
381
|
+
"cell",
|
|
382
|
+
"columnheader",
|
|
383
|
+
"gridcell",
|
|
384
|
+
"heading",
|
|
385
|
+
"link",
|
|
386
|
+
"menuitem",
|
|
387
|
+
"option",
|
|
388
|
+
"rowheader",
|
|
389
|
+
"tab"
|
|
390
|
+
]);
|
|
391
|
+
const contextBasedNameResolvers = [resolveImageName, resolveLegendName];
|
|
392
|
+
function resolveAccessibleName(element) {
|
|
393
|
+
const role = parseElementRole(element);
|
|
394
|
+
if (role === void 0 || prohibitsNaming.has(role)) return;
|
|
395
|
+
const labelledByElement = resolveElementReference(element, "aria-labelledby");
|
|
396
|
+
if (labelledByElement !== null) return resolveAccessibleTextContent(labelledByElement);
|
|
397
|
+
if (element.ariaLabel !== null) return element.ariaLabel;
|
|
398
|
+
for (const resolveName of contextBasedNameResolvers) {
|
|
399
|
+
const name = resolveName(element, role);
|
|
400
|
+
if (name !== void 0) return name;
|
|
401
|
+
}
|
|
402
|
+
if (supportsNamingByLabel.has(role)) return resolveLabelName(element);
|
|
403
|
+
if (supportsNamingFromChildContent.has(role)) return resolveAccessibleTextContent(element);
|
|
404
|
+
}
|
|
405
|
+
function resolveLabelName(element) {
|
|
406
|
+
if (element.id !== null) {
|
|
407
|
+
const referencedElement = element.ownerDocument.querySelector(attributeSelector("for", element.id));
|
|
408
|
+
if (referencedElement !== null) return resolveAccessibleTextContent(referencedElement);
|
|
409
|
+
}
|
|
410
|
+
const closestLabel = element.closest("label");
|
|
411
|
+
if (closestLabel !== null) return resolveAccessibleTextContent(closestLabel, [element]);
|
|
412
|
+
}
|
|
413
|
+
function resolveLegendName(element) {
|
|
414
|
+
if (!(element instanceof HTMLFieldSetElement)) return;
|
|
415
|
+
const legendElement = element.querySelector("legend");
|
|
416
|
+
if (legendElement === null) return;
|
|
417
|
+
return resolveAccessibleTextContent(legendElement);
|
|
418
|
+
}
|
|
419
|
+
function resolveImageName(element, role) {
|
|
420
|
+
if (element instanceof HTMLImageElement) return stringAttribute(element.alt);
|
|
421
|
+
if (role === "img") return resolveAccessibleTextContent(element);
|
|
422
|
+
}
|
|
423
|
+
//#endregion
|
|
424
|
+
//#region src/browser/state.ts
|
|
425
|
+
function disableableAttributes(element) {
|
|
426
|
+
return { disabled: booleanAttribute(isNativeInputElement(element) || element instanceof HTMLButtonElement || element instanceof HTMLOptionElement ? element.hasAttribute("disabled") : false) ?? booleanAttribute(element.ariaDisabled) };
|
|
427
|
+
}
|
|
428
|
+
function selectableAttributes(element) {
|
|
429
|
+
return { selected: booleanAttribute(element instanceof HTMLOptionElement ? element.hasAttribute("selected") : false) ?? booleanAttribute(element.ariaSelected) };
|
|
430
|
+
}
|
|
431
|
+
function inputStateAttributes(element) {
|
|
432
|
+
const supportsHtmlAttributes = isNativeInputElement(element);
|
|
433
|
+
const readonly = booleanAttribute(supportsHtmlAttributes ? element.hasAttribute("readonly") : false);
|
|
434
|
+
const required = booleanAttribute(supportsHtmlAttributes ? element.hasAttribute("required") : false);
|
|
435
|
+
return {
|
|
436
|
+
readonly: readonly ?? booleanAttribute(element.ariaReadOnly),
|
|
437
|
+
...disableableAttributes(element),
|
|
438
|
+
required: required ?? booleanAttribute(element.ariaRequired),
|
|
439
|
+
invalid: booleanAttribute(element.ariaInvalid)
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
function isNativeInputElement(element) {
|
|
443
|
+
return element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement;
|
|
444
|
+
}
|
|
445
|
+
//#endregion
|
|
446
|
+
//#region src/browser/button.ts
|
|
447
|
+
const PRESSED_VALUES = new Set([
|
|
448
|
+
"true",
|
|
449
|
+
"mixed",
|
|
450
|
+
"false"
|
|
451
|
+
]);
|
|
452
|
+
function snapshotButton(element) {
|
|
453
|
+
return {
|
|
454
|
+
role: "button",
|
|
455
|
+
name: resolveAccessibleName(element),
|
|
456
|
+
attributes: {
|
|
457
|
+
...disableableAttributes(element),
|
|
458
|
+
expanded: booleanAttribute(element.ariaExpanded),
|
|
459
|
+
pressed: resolvePressedAttribute(element)
|
|
460
|
+
},
|
|
461
|
+
children: snapshotChildren(element)
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
function resolvePressedAttribute(element) {
|
|
465
|
+
const pressed = enumAttribute(element.ariaPressed, PRESSED_VALUES);
|
|
466
|
+
if (pressed === "mixed") return pressed;
|
|
467
|
+
return booleanAttribute(pressed === "true");
|
|
468
|
+
}
|
|
469
|
+
//#endregion
|
|
470
|
+
//#region src/browser/description.ts
|
|
471
|
+
function discribableAttributes(element) {
|
|
472
|
+
return { description: resolveDescription(element) };
|
|
473
|
+
}
|
|
474
|
+
function resolveDescription(element) {
|
|
475
|
+
const describedByElement = resolveElementReference(element, "aria-describedby");
|
|
476
|
+
if (describedByElement !== null) return resolveAccessibleTextContent(describedByElement);
|
|
477
|
+
if (element.ariaDescription !== null) return element.ariaDescription;
|
|
478
|
+
}
|
|
479
|
+
//#endregion
|
|
431
480
|
//#region src/browser/input.ts
|
|
432
481
|
function snapshotInput(element) {
|
|
433
482
|
if (element instanceof HTMLInputElement) return snapshotInputElement(element);
|
|
@@ -439,7 +488,7 @@
|
|
|
439
488
|
if (inputRole === void 0 || inputRole === "button" || inputRole === "combobox") return null;
|
|
440
489
|
return elementSnapshot({
|
|
441
490
|
role: inputRole,
|
|
442
|
-
name:
|
|
491
|
+
name: resolveAccessibleName(element),
|
|
443
492
|
attributes: {
|
|
444
493
|
value: resolveInputValue(element),
|
|
445
494
|
checked: resolveChecked(element),
|
|
@@ -450,7 +499,7 @@
|
|
|
450
499
|
function snapshotTextareaElement(element) {
|
|
451
500
|
return elementSnapshot({
|
|
452
501
|
role: "textbox",
|
|
453
|
-
name:
|
|
502
|
+
name: resolveAccessibleName(element),
|
|
454
503
|
attributes: {
|
|
455
504
|
value: resolveInputValue(element),
|
|
456
505
|
...snapshotCommonInputAttributes(element)
|
|
@@ -473,16 +522,6 @@
|
|
|
473
522
|
if (!(element instanceof HTMLInputElement)) return;
|
|
474
523
|
return element.checked ? true : void 0;
|
|
475
524
|
}
|
|
476
|
-
function resolveInputLabel(element) {
|
|
477
|
-
const accessibleName = resolveAccessibleName(element, false);
|
|
478
|
-
if (accessibleName !== void 0) return accessibleName;
|
|
479
|
-
if (element.id !== null) {
|
|
480
|
-
const referencedElement = element.ownerDocument.querySelector(`[for='${element.id}']`);
|
|
481
|
-
if (referencedElement !== null) return resolveAccessibleTextContent(referencedElement);
|
|
482
|
-
}
|
|
483
|
-
const closestLabel = element.closest("label");
|
|
484
|
-
if (closestLabel !== null) return resolveAccessibleTextContent(closestLabel, [element]);
|
|
485
|
-
}
|
|
486
525
|
function resolvePlaceholder(element) {
|
|
487
526
|
if (element instanceof HTMLSelectElement || element instanceof HTMLButtonElement) return;
|
|
488
527
|
return stringAttribute(element.placeholder);
|
|
@@ -494,7 +533,7 @@
|
|
|
494
533
|
const options = snapshotOptions(element);
|
|
495
534
|
return {
|
|
496
535
|
role: "combobox",
|
|
497
|
-
name:
|
|
536
|
+
name: resolveAccessibleName(element),
|
|
498
537
|
attributes: {
|
|
499
538
|
value: resolveValue$1(element),
|
|
500
539
|
...snapshotCommonInputAttributes(element),
|
|
@@ -546,7 +585,7 @@
|
|
|
546
585
|
function snapshotDialog(role, element) {
|
|
547
586
|
return {
|
|
548
587
|
role,
|
|
549
|
-
name: resolveAccessibleName(element
|
|
588
|
+
name: resolveAccessibleName(element),
|
|
550
589
|
attributes: {
|
|
551
590
|
...discribableAttributes(element),
|
|
552
591
|
modal: booleanAttribute(element.ariaModal)
|
|
@@ -559,19 +598,14 @@
|
|
|
559
598
|
function snapshotGroup(element) {
|
|
560
599
|
return elementSnapshot({
|
|
561
600
|
role: "group",
|
|
562
|
-
name:
|
|
601
|
+
name: resolveAccessibleName(element),
|
|
563
602
|
children: snapshotChildren(element)
|
|
564
603
|
});
|
|
565
604
|
}
|
|
566
|
-
function resolveGroupName(element) {
|
|
567
|
-
const legendElement = element instanceof HTMLFieldSetElement ? element.querySelector("legend") : null;
|
|
568
|
-
if (legendElement !== null) return resolveAccessibleTextContent(legendElement);
|
|
569
|
-
return resolveAccessibleName(element, false);
|
|
570
|
-
}
|
|
571
605
|
function snapshotRadioGroup(element) {
|
|
572
606
|
return {
|
|
573
607
|
role: "radiogroup",
|
|
574
|
-
name: resolveAccessibleName(element
|
|
608
|
+
name: resolveAccessibleName(element),
|
|
575
609
|
attributes: discribableAttributes(element),
|
|
576
610
|
children: snapshotChildren(element)
|
|
577
611
|
};
|
|
@@ -594,17 +628,13 @@
|
|
|
594
628
|
//#endregion
|
|
595
629
|
//#region src/browser/image.ts
|
|
596
630
|
function snapshotImage(element) {
|
|
597
|
-
const imageName =
|
|
631
|
+
const imageName = resolveAccessibleName(element);
|
|
598
632
|
if (imageName === void 0) return null;
|
|
599
633
|
return elementSnapshot({
|
|
600
634
|
role: "img",
|
|
601
635
|
name: imageName
|
|
602
636
|
});
|
|
603
637
|
}
|
|
604
|
-
function resolveImageName(element) {
|
|
605
|
-
if (element instanceof HTMLImageElement) return stringAttribute(element.alt);
|
|
606
|
-
return resolveAccessibleName(element, true);
|
|
607
|
-
}
|
|
608
638
|
//#endregion
|
|
609
639
|
//#region src/browser/link.ts
|
|
610
640
|
function snapshotLink(element) {
|
|
@@ -636,7 +666,7 @@
|
|
|
636
666
|
function snapshotProgressbar(element) {
|
|
637
667
|
return {
|
|
638
668
|
role: "progressbar",
|
|
639
|
-
name: resolveAccessibleName(element
|
|
669
|
+
name: resolveAccessibleName(element),
|
|
640
670
|
attributes: { value: resolveValue(element) },
|
|
641
671
|
children: snapshotPresentationalChildren(element)
|
|
642
672
|
};
|
|
@@ -646,6 +676,18 @@
|
|
|
646
676
|
return numericAttribute(element.ariaValueNow);
|
|
647
677
|
}
|
|
648
678
|
//#endregion
|
|
679
|
+
//#region src/browser/region.ts
|
|
680
|
+
function snapshotRegion(element) {
|
|
681
|
+
const name = resolveAccessibleName(element);
|
|
682
|
+
const children = snapshotChildren(element);
|
|
683
|
+
if (name === void 0) return children;
|
|
684
|
+
return elementSnapshot({
|
|
685
|
+
role: "region",
|
|
686
|
+
name,
|
|
687
|
+
children
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
//#endregion
|
|
649
691
|
//#region src/browser/separator.ts
|
|
650
692
|
function snapshotSeparator(element) {
|
|
651
693
|
return elementSnapshot({
|
|
@@ -701,6 +743,7 @@
|
|
|
701
743
|
link: snapshotLink,
|
|
702
744
|
radio: snapshotInput,
|
|
703
745
|
radiogroup: snapshotRadioGroup,
|
|
746
|
+
region: snapshotRegion,
|
|
704
747
|
searchbox: snapshotInput,
|
|
705
748
|
separator: snapshotSeparator,
|
|
706
749
|
slider: snapshotInput,
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
|
-
import { Locator } from "@playwright/test";
|
|
1
|
+
import { Expect, Locator, MatcherReturnType } from "@playwright/test";
|
|
2
|
+
import { PlaywrightMatchJsonFileOptions, PlaywrightMatchTextFileOptions, PlaywrightValidationFileMatcherConfig } from "@cronn/playwright-file-snapshots";
|
|
2
3
|
|
|
4
|
+
//#region src/playwright/markdown-table.d.ts
|
|
5
|
+
interface MarkdownTableSnapshotOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Show sort indicator for column headers
|
|
8
|
+
*
|
|
9
|
+
* @default true
|
|
10
|
+
*/
|
|
11
|
+
showSortIndicator?: boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Creates a Markdown table snapshot from a table or grid element
|
|
15
|
+
*/
|
|
16
|
+
declare function markdownTableSnapshot(locator: Locator, options?: MarkdownTableSnapshotOptions): Promise<string>;
|
|
17
|
+
//#endregion
|
|
3
18
|
//#region src/types/attributes.d.ts
|
|
4
19
|
interface DisableableAttributes {
|
|
5
20
|
disabled?: boolean;
|
|
@@ -24,6 +39,15 @@ interface ButtonAttributes extends DisableableAttributes {
|
|
|
24
39
|
}
|
|
25
40
|
type PressedValue = true | "mixed";
|
|
26
41
|
//#endregion
|
|
42
|
+
//#region src/types/utils.d.ts
|
|
43
|
+
type SetValues<TSet> = TSet extends Set<infer TValue> ? TValue : never;
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/types/elements/container.d.ts
|
|
46
|
+
declare const CONTAINER_ROLES: Set<"paragraph" | "list" | "listitem" | "listbox" | "article" | "banner" | "complementary" | "contentinfo" | "form" | "main" | "navigation" | "search" | "descriptionlist" | "term" | "definition" | "table" | "grid" | "rowgroup" | "row" | "rowheader" | "cell" | "gridcell" | "alert" | "menu" | "tablist" | "tabpanel" | "label">;
|
|
47
|
+
interface ContainerSnapshot extends GenericElementSnapshot<ContainerRole> {}
|
|
48
|
+
type ContainerRole = SetValues<typeof CONTAINER_ROLES>;
|
|
49
|
+
interface RegionSnapshot extends GenericElementSnapshot<"region"> {}
|
|
50
|
+
//#endregion
|
|
27
51
|
//#region src/types/elements/dialog.d.ts
|
|
28
52
|
interface DialogSnapshot extends GenericElementSnapshot<DialogRole, DialogAttributes> {}
|
|
29
53
|
type DialogRole = "dialog" | "alertdialog";
|
|
@@ -87,9 +111,6 @@ interface SeparatorSnapshot extends GenericElementSnapshot<"separator"> {}
|
|
|
87
111
|
interface TabSnapshot extends GenericElementSnapshot<"tab", TabAttributes> {}
|
|
88
112
|
interface TabAttributes extends DisableableAttributes, SelectableAttributes {}
|
|
89
113
|
//#endregion
|
|
90
|
-
//#region src/types/utils.d.ts
|
|
91
|
-
type SetValues<TSet> = TSet extends Set<infer TValue> ? TValue : never;
|
|
92
|
-
//#endregion
|
|
93
114
|
//#region src/types/elements/table.d.ts
|
|
94
115
|
declare const SORT_TYPES: Set<"ascending" | "descending" | "other">;
|
|
95
116
|
interface ColumnHeaderSnapshot extends GenericElementSnapshot<"columnheader", ColumnheaderAttributes> {}
|
|
@@ -104,6 +125,10 @@ interface TextSnapshot {
|
|
|
104
125
|
name: string;
|
|
105
126
|
}
|
|
106
127
|
//#endregion
|
|
128
|
+
//#region src/types/role.d.ts
|
|
129
|
+
type TextRole = "text";
|
|
130
|
+
type ElementRole = "button" | "columnheader" | "group" | "heading" | "img" | "link" | "menuitem" | "option" | "progressbar" | "radiogroup" | "region" | "separator" | "tab" | ContainerRole | DialogRole | InputRole;
|
|
131
|
+
//#endregion
|
|
107
132
|
//#region src/types/snapshot.d.ts
|
|
108
133
|
type NodeRole = ElementRole | TextRole;
|
|
109
134
|
type NodeSnapshot = ElementSnapshot | TextSnapshot;
|
|
@@ -116,30 +141,7 @@ interface GenericElementSnapshot<TRole extends NodeRole = NodeRole, TAttributes
|
|
|
116
141
|
attributes: TAttributes;
|
|
117
142
|
children: Array<NodeSnapshot>;
|
|
118
143
|
}
|
|
119
|
-
type ElementSnapshot = ButtonSnapshot | ColumnHeaderSnapshot | ComboboxSnapshot | ContainerSnapshot | DialogSnapshot | GroupSnapshot | HeadingSnapshot | ImageSnapshot | InputSnapshot | LinkSnapshot | OptionSnapshot | ProgressbarSnapshot | TabSnapshot | MenuItemSnapshot | RadioGroupSnapshot | SeparatorSnapshot;
|
|
120
|
-
//#endregion
|
|
121
|
-
//#region src/types/elements/container.d.ts
|
|
122
|
-
declare const CONTAINER_ROLES: Set<"paragraph" | "list" | "listitem" | "listbox" | "article" | "banner" | "complementary" | "contentinfo" | "form" | "main" | "navigation" | "region" | "search" | "descriptionlist" | "term" | "definition" | "table" | "grid" | "rowgroup" | "row" | "rowheader" | "cell" | "gridcell" | "alert" | "menu" | "tablist" | "tabpanel" | "label">;
|
|
123
|
-
interface ContainerSnapshot extends GenericElementSnapshot<ContainerRole> {}
|
|
124
|
-
type ContainerRole = SetValues<typeof CONTAINER_ROLES>;
|
|
125
|
-
//#endregion
|
|
126
|
-
//#region src/types/role.d.ts
|
|
127
|
-
type TextRole = "text";
|
|
128
|
-
type ElementRole = "button" | "columnheader" | "group" | "heading" | "img" | "link" | "menuitem" | "option" | "progressbar" | "radiogroup" | "separator" | "tab" | ContainerRole | DialogRole | InputRole;
|
|
129
|
-
//#endregion
|
|
130
|
-
//#region src/playwright/markdown-table.d.ts
|
|
131
|
-
interface MarkdownTableSnapshotOptions {
|
|
132
|
-
/**
|
|
133
|
-
* Show sort indicator for column headers
|
|
134
|
-
*
|
|
135
|
-
* @default true
|
|
136
|
-
*/
|
|
137
|
-
showSortIndicator?: boolean;
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Creates a Markdown table snapshot from a table or grid element
|
|
141
|
-
*/
|
|
142
|
-
declare function markdownTableSnapshot(locator: Locator, options?: MarkdownTableSnapshotOptions): Promise<string>;
|
|
144
|
+
type ElementSnapshot = ButtonSnapshot | ColumnHeaderSnapshot | ComboboxSnapshot | ContainerSnapshot | DialogSnapshot | GroupSnapshot | HeadingSnapshot | ImageSnapshot | InputSnapshot | LinkSnapshot | OptionSnapshot | ProgressbarSnapshot | RegionSnapshot | TabSnapshot | MenuItemSnapshot | RadioGroupSnapshot | SeparatorSnapshot;
|
|
143
145
|
//#endregion
|
|
144
146
|
//#region src/utils/filter.d.ts
|
|
145
147
|
type FilterPredicate = (snapshot: NodeSnapshot) => boolean;
|
|
@@ -227,6 +229,23 @@ declare function semanticSnapshot(locator: Locator, options?: SemanticSnapshotOp
|
|
|
227
229
|
*/
|
|
228
230
|
declare function rawSnapshot(locator: Locator): Promise<Array<NodeSnapshot>>;
|
|
229
231
|
//#endregion
|
|
232
|
+
//#region src/types/matchers.d.ts
|
|
233
|
+
interface ElementSnapshotMatchers {
|
|
234
|
+
toMatchSemanticSnapshotFile: (actual: Locator, options?: MatchSemanticSnapshotFileOptions) => Promise<MatcherReturnType>;
|
|
235
|
+
toMatchMarkdownTableSnapshotFile: (actual: Locator, options?: MatchMarkdownTableSnapshotFileOptions) => Promise<MatcherReturnType>;
|
|
236
|
+
}
|
|
237
|
+
interface MatchSemanticSnapshotFileOptions extends PlaywrightMatchJsonFileOptions, SemanticSnapshotOptions {}
|
|
238
|
+
interface MatchMarkdownTableSnapshotFileOptions extends Omit<PlaywrightMatchTextFileOptions, "fileExtension">, MarkdownTableSnapshotOptions {}
|
|
239
|
+
//#endregion
|
|
240
|
+
//#region src/playwright/matchers.d.ts
|
|
241
|
+
/**
|
|
242
|
+
* Defines a custom Playwright expect instance with element snapshot matchers for validating DOM elements against stored snapshots.
|
|
243
|
+
*
|
|
244
|
+
* @param {PlaywrightValidationFileMatcherConfig} config - Configuration options for file matching behavior
|
|
245
|
+
* @return {Expect<ElementSnapshotMatchers>} An extended expect instance that includes matcher methods for element snapshot validation.
|
|
246
|
+
*/
|
|
247
|
+
declare function defineElementSnapshotMatchers(config?: PlaywrightValidationFileMatcherConfig): Expect<ElementSnapshotMatchers>;
|
|
248
|
+
//#endregion
|
|
230
249
|
//#region src/utils/predicates.d.ts
|
|
231
250
|
/**
|
|
232
251
|
* Include only elements with the specified role
|
|
@@ -243,4 +262,4 @@ declare function excludeRole<TRole extends NodeRole>(role: TRole | Array<TRole>)
|
|
|
243
262
|
*/
|
|
244
263
|
declare function getTextContent(snapshots: Array<NodeSnapshot>): string;
|
|
245
264
|
//#endregion
|
|
246
|
-
export { type ButtonSnapshot, type ColumnHeaderSnapshot, type ComboboxSnapshot, type ContainerSnapshot, type DialogSnapshot, type ElementRole, type ElementSnapshot, type GroupSnapshot, type HeadingSnapshot, type ImageSnapshot, type InputSnapshot, type LinkSnapshot, type MarkdownTableSnapshotOptions, type MenuItemSnapshot, type NodeRole, type NodeSnapshot, type OptionSnapshot, type ProgressbarSnapshot, type RadioGroupSnapshot, type SemanticSnapshotOptions, type SeparatorSnapshot, type SnapshotByRole, type TabSnapshot, type TextSnapshot, excludeRole, filter, filterByRole, getTextContent, includeRole, markdownTableSnapshot, rawSnapshot, semanticSnapshot };
|
|
265
|
+
export { type ButtonSnapshot, type ColumnHeaderSnapshot, type ComboboxSnapshot, type ContainerSnapshot, type DialogSnapshot, type ElementRole, type ElementSnapshot, type ElementSnapshotMatchers, type GroupSnapshot, type HeadingSnapshot, type ImageSnapshot, type InputSnapshot, type LinkSnapshot, type MarkdownTableSnapshotOptions, type MatchMarkdownTableSnapshotFileOptions, type MatchSemanticSnapshotFileOptions, type MenuItemSnapshot, type NodeRole, type NodeSnapshot, type OptionSnapshot, type ProgressbarSnapshot, type RadioGroupSnapshot, type RegionSnapshot, type SemanticSnapshotOptions, type SeparatorSnapshot, type SnapshotByRole, type TabSnapshot, type TextSnapshot, defineElementSnapshotMatchers, excludeRole, filter, filterByRole, getTextContent, includeRole, markdownTableSnapshot, rawSnapshot, semanticSnapshot };
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { expect } from "@playwright/test";
|
|
2
|
+
import { defineJsonFileMatcher, defineTextFileMatcher } from "@cronn/playwright-file-snapshots";
|
|
1
3
|
import { MarkdownTableSerializer } from "@cronn/lib-file-snapshots";
|
|
2
4
|
import path from "node:path";
|
|
3
5
|
import { packageDirectory } from "package-directory";
|
|
@@ -62,23 +64,6 @@ function hasChildren(snapshot) {
|
|
|
62
64
|
return "children" in snapshot && snapshot.children.length > 0;
|
|
63
65
|
}
|
|
64
66
|
//#endregion
|
|
65
|
-
//#region src/utils/text.ts
|
|
66
|
-
/**
|
|
67
|
-
* Aggregates and normalizes the text content of all provided snapshots
|
|
68
|
-
*/
|
|
69
|
-
function getTextContent(snapshots) {
|
|
70
|
-
return mergeTexts(filter({
|
|
71
|
-
snapshots,
|
|
72
|
-
predicate: isTextSnapshot
|
|
73
|
-
}));
|
|
74
|
-
}
|
|
75
|
-
function normalizeText(text) {
|
|
76
|
-
return text.replaceAll(/\s+/g, " ").trim();
|
|
77
|
-
}
|
|
78
|
-
function mergeTexts(texts) {
|
|
79
|
-
return normalizeText(texts.map((textNode) => textNode.name).join(" "));
|
|
80
|
-
}
|
|
81
|
-
//#endregion
|
|
82
67
|
//#region src/playwright/proxy.ts
|
|
83
68
|
var ElementSnapshotProxy = class {
|
|
84
69
|
page;
|
|
@@ -154,7 +139,6 @@ var SemanticSnapshotTransformer = class {
|
|
|
154
139
|
const { role, children } = normalizedSnapshot;
|
|
155
140
|
return this.transformedSnapshot(role, children.length === 1 ? children.at(0) : children);
|
|
156
141
|
}
|
|
157
|
-
if (snapshot.role === "combobox") return this.simplifyComboboxSnapshot(snapshot);
|
|
158
142
|
const { role, name, attributes, children } = normalizedSnapshot;
|
|
159
143
|
return this.transformedSnapshot(role, {
|
|
160
144
|
name: name.length === 0 ? void 0 : name,
|
|
@@ -162,27 +146,18 @@ var SemanticSnapshotTransformer = class {
|
|
|
162
146
|
children: children.length === 0 ? void 0 : children
|
|
163
147
|
});
|
|
164
148
|
}
|
|
165
|
-
normalizeElementSnapshot(snapshot
|
|
149
|
+
normalizeElementSnapshot(snapshot) {
|
|
166
150
|
const normalizedName = snapshot.name ?? "";
|
|
167
|
-
const
|
|
151
|
+
const transformedAttributes = this.transformAttributes(snapshot);
|
|
168
152
|
const transformedChildren = this.transformSnapshots(snapshot.children);
|
|
169
153
|
const nameEqualsChildren = transformedChildren.length === 1 && normalizedName === transformedChildren.at(0);
|
|
170
154
|
return {
|
|
171
155
|
role: snapshot.role,
|
|
172
156
|
name: normalizedName,
|
|
173
|
-
attributes:
|
|
157
|
+
attributes: transformedAttributes,
|
|
174
158
|
children: nameEqualsChildren ? [] : transformedChildren
|
|
175
159
|
};
|
|
176
160
|
}
|
|
177
|
-
simplifyComboboxSnapshot(snapshot) {
|
|
178
|
-
const { role, name, attributes } = this.normalizeElementSnapshot(snapshot, ["options"]);
|
|
179
|
-
const transformedOptions = snapshot.attributes.options.map((optionSnapshot) => this.simplifyElementSnapshot(optionSnapshot));
|
|
180
|
-
return this.transformedSnapshot(role, {
|
|
181
|
-
name,
|
|
182
|
-
...attributes,
|
|
183
|
-
options: this.includeComboboxOptions && transformedOptions.length > 0 ? transformedOptions : void 0
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
161
|
isEmpty(snapshot) {
|
|
187
162
|
return isEmpty(snapshot.name) && isEmpty(snapshot.attributes) && isEmpty(snapshot.children);
|
|
188
163
|
}
|
|
@@ -192,14 +167,24 @@ var SemanticSnapshotTransformer = class {
|
|
|
192
167
|
hasOnlyChildren(snapshot) {
|
|
193
168
|
return isEmpty(snapshot.name) && isEmpty(snapshot.attributes) && !isEmpty(snapshot.children);
|
|
194
169
|
}
|
|
195
|
-
|
|
170
|
+
transformAttributes(snapshot) {
|
|
171
|
+
const { attributes } = snapshot;
|
|
196
172
|
const filteredAttributes = {};
|
|
197
|
-
Object.
|
|
198
|
-
|
|
199
|
-
|
|
173
|
+
Object.keys(attributes).forEach((attributeName) => {
|
|
174
|
+
const transformedAttribute = this.transformAttribute(attributeName, snapshot);
|
|
175
|
+
if (transformedAttribute === void 0) return;
|
|
176
|
+
filteredAttributes[attributeName] = transformedAttribute;
|
|
200
177
|
});
|
|
201
178
|
return filteredAttributes;
|
|
202
179
|
}
|
|
180
|
+
transformAttribute(name, snapshot) {
|
|
181
|
+
const { role, attributes } = snapshot;
|
|
182
|
+
if (role === "combobox" && name === "options") {
|
|
183
|
+
const transformedOptions = attributes.options.map((optionSnapshot) => this.simplifyElementSnapshot(optionSnapshot));
|
|
184
|
+
return this.includeComboboxOptions && transformedOptions.length > 0 ? transformedOptions : void 0;
|
|
185
|
+
}
|
|
186
|
+
return attributes[name];
|
|
187
|
+
}
|
|
203
188
|
transformedSnapshot(role, content) {
|
|
204
189
|
return { [role]: content };
|
|
205
190
|
}
|
|
@@ -271,7 +256,7 @@ function parseTable(snapshot, options) {
|
|
|
271
256
|
};
|
|
272
257
|
}
|
|
273
258
|
function getColumnHeaderText(columnHeader, showSortIndicator) {
|
|
274
|
-
const headerText =
|
|
259
|
+
const headerText = getNameOrDefault(columnHeader);
|
|
275
260
|
const sortType = columnHeader.attributes.sort;
|
|
276
261
|
if (!showSortIndicator || sortType === void 0) return headerText;
|
|
277
262
|
return `${headerText} ${sortIndicators[sortType]}`;
|
|
@@ -280,7 +265,50 @@ function getCellTexts(row) {
|
|
|
280
265
|
return filter({
|
|
281
266
|
predicate: includeRole(cellRoles),
|
|
282
267
|
snapshots: row.children
|
|
283
|
-
}).map(
|
|
268
|
+
}).map(getNameOrDefault);
|
|
269
|
+
}
|
|
270
|
+
function getNameOrDefault(snapshot) {
|
|
271
|
+
return snapshot.name ?? "";
|
|
272
|
+
}
|
|
273
|
+
//#endregion
|
|
274
|
+
//#region src/playwright/matchers.ts
|
|
275
|
+
/**
|
|
276
|
+
* Defines a custom Playwright expect instance with element snapshot matchers for validating DOM elements against stored snapshots.
|
|
277
|
+
*
|
|
278
|
+
* @param {PlaywrightValidationFileMatcherConfig} config - Configuration options for file matching behavior
|
|
279
|
+
* @return {Expect<ElementSnapshotMatchers>} An extended expect instance that includes matcher methods for element snapshot validation.
|
|
280
|
+
*/
|
|
281
|
+
function defineElementSnapshotMatchers(config = {}) {
|
|
282
|
+
async function toMatchSemanticSnapshotFile(actual, options = {}) {
|
|
283
|
+
return await defineJsonFileMatcher("toMatchSemanticSnapshotFile", config).bind(this)(() => semanticSnapshot(actual, options), options);
|
|
284
|
+
}
|
|
285
|
+
async function toMatchMarkdownTableSnapshotFile(actual, options = {}) {
|
|
286
|
+
return await defineTextFileMatcher("toMatchMarkdownTableSnapshotFile", config).bind(this)(() => markdownTableSnapshot(actual, options), {
|
|
287
|
+
...options,
|
|
288
|
+
fileExtension: "md"
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
return expect.extend({
|
|
292
|
+
toMatchSemanticSnapshotFile,
|
|
293
|
+
toMatchMarkdownTableSnapshotFile
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
//#endregion
|
|
297
|
+
//#region src/utils/text.ts
|
|
298
|
+
/**
|
|
299
|
+
* Aggregates and normalizes the text content of all provided snapshots
|
|
300
|
+
*/
|
|
301
|
+
function getTextContent(snapshots) {
|
|
302
|
+
return mergeTexts(filter({
|
|
303
|
+
snapshots,
|
|
304
|
+
predicate: isTextSnapshot
|
|
305
|
+
}));
|
|
306
|
+
}
|
|
307
|
+
function normalizeText(text) {
|
|
308
|
+
return text.replaceAll(/\s+/g, " ").trim();
|
|
309
|
+
}
|
|
310
|
+
function mergeTexts(texts) {
|
|
311
|
+
return normalizeText(texts.map((textNode) => textNode.name).join(" "));
|
|
284
312
|
}
|
|
285
313
|
//#endregion
|
|
286
|
-
export { excludeRole, filter, filterByRole, getTextContent, includeRole, markdownTableSnapshot, rawSnapshot, semanticSnapshot };
|
|
314
|
+
export { defineElementSnapshotMatchers, excludeRole, filter, filterByRole, getTextContent, includeRole, markdownTableSnapshot, rawSnapshot, semanticSnapshot };
|
package/package.json
CHANGED
|
@@ -1,33 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cronn/element-snapshot",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "Element snapshots for Playwright",
|
|
5
|
+
"homepage": "https://cronn.github.io/file-snapshots/playwright/element-snapshots/",
|
|
5
6
|
"bugs": {
|
|
6
7
|
"url": "https://github.com/cronn/file-snapshots/issues"
|
|
7
8
|
},
|
|
8
|
-
"author": "cronn",
|
|
9
9
|
"license": "Apache-2.0",
|
|
10
|
+
"author": "cronn",
|
|
10
11
|
"repository": {
|
|
11
12
|
"type": "git",
|
|
12
13
|
"url": "git+https://github.com/cronn/file-snapshots.git",
|
|
13
14
|
"directory": "packages/element-snapshot"
|
|
14
15
|
},
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
},
|
|
19
|
-
"devEngines": {
|
|
20
|
-
"runtime": {
|
|
21
|
-
"name": "node",
|
|
22
|
-
"version": ">=24.14.1 <25",
|
|
23
|
-
"onFail": "error"
|
|
24
|
-
},
|
|
25
|
-
"packageManager": {
|
|
26
|
-
"name": "pnpm",
|
|
27
|
-
"version": ">=10.33.0 <11",
|
|
28
|
-
"onFail": "error"
|
|
29
|
-
}
|
|
30
|
-
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
31
19
|
"type": "module",
|
|
32
20
|
"exports": {
|
|
33
21
|
"./package.json": "./package.json",
|
|
@@ -36,47 +24,58 @@
|
|
|
36
24
|
"default": "./dist/index.mjs"
|
|
37
25
|
}
|
|
38
26
|
},
|
|
39
|
-
"files": [
|
|
40
|
-
"dist"
|
|
41
|
-
],
|
|
42
27
|
"dependencies": {
|
|
43
28
|
"package-directory": "8.2.0",
|
|
44
|
-
"@cronn/lib-file-snapshots": "1.1.
|
|
29
|
+
"@cronn/lib-file-snapshots": "1.1.1",
|
|
30
|
+
"@cronn/playwright-file-snapshots": "2.0.0"
|
|
45
31
|
},
|
|
46
32
|
"devDependencies": {
|
|
47
33
|
"@arethetypeswrong/core": "0.18.2",
|
|
48
34
|
"@playwright/test": "1.59.1",
|
|
49
|
-
"@trivago/prettier-plugin-sort-imports": "6.0.2",
|
|
50
35
|
"@types/node": "24.12.2",
|
|
51
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
52
|
-
"@vitest/coverage-v8": "4.1.
|
|
53
|
-
"eslint": "10.2.
|
|
36
|
+
"@typescript/native-preview": "7.0.0-dev.20260427.1",
|
|
37
|
+
"@vitest/coverage-v8": "4.1.5",
|
|
38
|
+
"eslint": "10.2.1",
|
|
54
39
|
"eslint-config-prettier": "10.1.8",
|
|
55
40
|
"eslint-plugin-check-file": "3.3.1",
|
|
56
41
|
"eslint-plugin-unused-imports": "4.4.1",
|
|
57
|
-
"prettier": "3.8.1",
|
|
58
42
|
"publint": "0.3.18",
|
|
59
43
|
"rimraf": "6.1.3",
|
|
60
|
-
"tsdown": "0.21.
|
|
61
|
-
"typescript-eslint": "8.
|
|
62
|
-
"vitest": "4.1.
|
|
63
|
-
"
|
|
44
|
+
"tsdown": "0.21.10",
|
|
45
|
+
"typescript-eslint": "8.59.0",
|
|
46
|
+
"vitest": "4.1.5",
|
|
47
|
+
"node": "runtime:>=24.14.1 <25",
|
|
64
48
|
"@cronn/shared-configs": "0.0.0",
|
|
65
49
|
"@cronn/test-utils": "0.0.0",
|
|
66
|
-
"@cronn/vitest-file-snapshots": "
|
|
50
|
+
"@cronn/vitest-file-snapshots": "2.0.0"
|
|
67
51
|
},
|
|
68
52
|
"peerDependencies": {
|
|
69
53
|
"@playwright/test": "^1.55"
|
|
70
54
|
},
|
|
55
|
+
"devEngines": {
|
|
56
|
+
"packageManager": {
|
|
57
|
+
"name": "pnpm",
|
|
58
|
+
"version": "11.0.7",
|
|
59
|
+
"onFail": "download"
|
|
60
|
+
},
|
|
61
|
+
"runtime": {
|
|
62
|
+
"name": "node",
|
|
63
|
+
"version": ">=24.14.1 <25",
|
|
64
|
+
"onFail": "download"
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"engines": {
|
|
68
|
+
"node": "^20 || ^22 || >=24"
|
|
69
|
+
},
|
|
71
70
|
"scripts": {
|
|
71
|
+
"build": "tsdown",
|
|
72
|
+
"clean": "rimraf .turbo dist playwright-report test-results coverage",
|
|
73
|
+
"compile": "tsgo",
|
|
72
74
|
"lint:check": "eslint src/ tests/ --max-warnings=0",
|
|
73
75
|
"lint:fix": "eslint src/ tests/ --max-warnings=0 --fix",
|
|
74
|
-
"test:unit": "vitest run",
|
|
75
|
-
"test:unit:coverage": "vitest run --coverage",
|
|
76
|
-
"test:integration": "playwright test",
|
|
77
76
|
"playwright:install": "playwright install chromium",
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
"
|
|
77
|
+
"test:integration": "playwright test",
|
|
78
|
+
"test:unit": "vitest run",
|
|
79
|
+
"test:unit:coverage": "vitest run --coverage"
|
|
81
80
|
}
|
|
82
81
|
}
|