@cronn/element-snapshot 0.4.0 → 0.6.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/index.d.ts CHANGED
@@ -4,12 +4,19 @@ interface DisableableAttributes {
4
4
  interface SelectableAttributes {
5
5
  selected?: boolean;
6
6
  }
7
+ interface InputStateAttributes extends DisableableAttributes {
8
+ readonly?: boolean;
9
+ required?: boolean;
10
+ invalid?: boolean;
11
+ }
7
12
 
8
13
  interface ButtonSnapshot extends GenericElementSnapshot<"button", ButtonAttributes> {
9
14
  }
10
15
  interface ButtonAttributes extends DisableableAttributes {
11
16
  expanded?: boolean;
17
+ pressed?: PressedValue;
12
18
  }
19
+ type PressedValue = true | "mixed";
13
20
 
14
21
  interface InputSnapshot extends GenericElementSnapshot<CommonInputRole, InputAttributes> {
15
22
  }
@@ -19,12 +26,9 @@ interface InputAttributes extends CommonInputAttributes {
19
26
  value?: string;
20
27
  checked?: boolean;
21
28
  }
22
- interface CommonInputAttributes extends DisableableAttributes {
29
+ interface CommonInputAttributes extends InputStateAttributes {
23
30
  description?: string;
24
31
  placeholder?: string;
25
- readonly?: boolean;
26
- required?: boolean;
27
- invalid?: boolean;
28
32
  }
29
33
 
30
34
  interface ComboboxSnapshot extends GenericElementSnapshot<"combobox", ComboboxAttributes> {
@@ -47,6 +51,9 @@ interface DialogAttributes {
47
51
  modal?: boolean;
48
52
  }
49
53
 
54
+ interface GroupSnapshot extends GenericElementSnapshot<"group"> {
55
+ }
56
+
50
57
  interface HeadingSnapshot extends GenericElementSnapshot<"heading", HeadingAttributes> {
51
58
  }
52
59
  interface HeadingAttributes {
@@ -84,9 +91,9 @@ interface TextSnapshot {
84
91
 
85
92
  type SnapshotTargetElement = HTMLElement | SVGElement;
86
93
  type NodeRole = ElementRole | "text";
87
- type ElementRole = "heading" | "link" | "button" | "option" | "tab" | "menuitem" | "columnheader" | ContainerRole | InputRole | DialogRole;
94
+ type ElementRole = "heading" | "link" | "button" | "option" | "tab" | "menuitem" | "columnheader" | "group" | ContainerRole | InputRole | DialogRole;
88
95
  type NodeSnapshot = ElementSnapshot | TextSnapshot;
89
- type ElementSnapshot = ContainerSnapshot | HeadingSnapshot | LinkSnapshot | ButtonSnapshot | InputSnapshot | ComboboxSnapshot | OptionSnapshot | DialogSnapshot | TabSnapshot | MenuitemSnapshot | ColumnheaderSnapshot;
96
+ type ElementSnapshot = ContainerSnapshot | HeadingSnapshot | LinkSnapshot | ButtonSnapshot | InputSnapshot | ComboboxSnapshot | OptionSnapshot | DialogSnapshot | TabSnapshot | MenuitemSnapshot | ColumnheaderSnapshot | GroupSnapshot;
90
97
  interface GenericElementSnapshot<TRole extends NodeRole = NodeRole, TAttributes = unknown> {
91
98
  role: TRole;
92
99
  name?: string;
@@ -72,30 +72,58 @@
72
72
  }
73
73
 
74
74
  // src/snapshots/state.ts
75
- function disableableAttributes(element, ariaOnly = false) {
76
- if (ariaOnly) {
77
- return { disabled: booleanAttribute(element.ariaDisabled) };
78
- }
75
+ function disableableAttributes(element) {
76
+ const supportsHtmlAttribute = isNativeInputElement(element) || element instanceof HTMLButtonElement;
77
+ const disabled = booleanAttribute(
78
+ supportsHtmlAttribute ? element.hasAttribute("disabled") : false
79
+ );
79
80
  return {
80
- disabled: booleanAttribute(element.hasAttribute("disabled")) ?? booleanAttribute(element.ariaDisabled)
81
+ disabled: disabled ?? booleanAttribute(element.ariaDisabled)
81
82
  };
82
83
  }
83
84
  function selectableAttributes(element) {
84
85
  return { selected: booleanAttribute(element.ariaSelected) };
85
86
  }
87
+ function inputStateAttributes(element) {
88
+ const supportsHtmlAttributes = isNativeInputElement(element);
89
+ const readonly = booleanAttribute(
90
+ supportsHtmlAttributes ? element.hasAttribute("readonly") : false
91
+ );
92
+ const required = booleanAttribute(
93
+ supportsHtmlAttributes ? element.hasAttribute("required") : false
94
+ );
95
+ return {
96
+ readonly: readonly ?? booleanAttribute(element.ariaReadOnly),
97
+ ...disableableAttributes(element),
98
+ required: required ?? booleanAttribute(element.ariaRequired),
99
+ invalid: booleanAttribute(element.ariaInvalid)
100
+ };
101
+ }
102
+ function isNativeInputElement(element) {
103
+ return element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement;
104
+ }
86
105
 
87
106
  // src/snapshots/button.ts
107
+ var PRESSED_VALUES = /* @__PURE__ */ new Set(["true", "mixed", "false"]);
88
108
  function snapshotButton(element) {
89
109
  return {
90
110
  role: "button",
91
111
  name: resolveAccessibleName(element),
92
112
  attributes: {
93
113
  ...disableableAttributes(element),
94
- expanded: booleanAttribute(element.ariaExpanded)
114
+ expanded: booleanAttribute(element.ariaExpanded),
115
+ pressed: resolvePressedAttribute(element)
95
116
  },
96
117
  children: snapshotChildren(element)
97
118
  };
98
119
  }
120
+ function resolvePressedAttribute(element) {
121
+ const pressed = enumAttribute(element.ariaPressed, PRESSED_VALUES);
122
+ if (pressed === "mixed") {
123
+ return pressed;
124
+ }
125
+ return booleanAttribute(pressed === "true");
126
+ }
99
127
 
100
128
  // src/snapshots/description.ts
101
129
  function resolveDescription(element) {
@@ -207,7 +235,8 @@
207
235
  tfoot: "rowgroup",
208
236
  tr: "row",
209
237
  th: resolveTableHeaderCellRole,
210
- td: "cell"
238
+ td: "cell",
239
+ fieldset: "group"
211
240
  };
212
241
  var CONTEXT_DEPENDENT_ROLES = {
213
242
  banner: isTopLevelBanner,
@@ -400,10 +429,7 @@
400
429
  return {
401
430
  description: resolveDescription(element),
402
431
  placeholder: isEmpty ? resolvePlaceholder(element) : void 0,
403
- readonly: booleanAttribute(element.hasAttribute("readonly")),
404
- ...disableableAttributes(element),
405
- required: booleanAttribute(element.required),
406
- invalid: booleanAttribute(element.ariaInvalid)
432
+ ...inputStateAttributes(element)
407
433
  };
408
434
  }
409
435
  function resolveInputValue(element) {
@@ -438,7 +464,7 @@
438
464
  return void 0;
439
465
  }
440
466
  function resolvePlaceholder(element) {
441
- if (element instanceof HTMLSelectElement) {
467
+ if (element instanceof HTMLSelectElement || element instanceof HTMLButtonElement) {
442
468
  return void 0;
443
469
  }
444
470
  return stringAttribute(element.placeholder);
@@ -465,7 +491,7 @@
465
491
  if (element instanceof HTMLSelectElement) {
466
492
  return element.role === null || element.role === "combobox";
467
493
  }
468
- if (element instanceof HTMLInputElement) {
494
+ if (element instanceof HTMLInputElement || element instanceof HTMLButtonElement) {
469
495
  return element.role === "combobox";
470
496
  }
471
497
  return false;
@@ -525,6 +551,22 @@
525
551
  };
526
552
  }
527
553
 
554
+ // src/snapshots/group.ts
555
+ function snapshotGroup(element) {
556
+ return {
557
+ role: "group",
558
+ name: resolveGroupName(element),
559
+ children: snapshotChildren(element)
560
+ };
561
+ }
562
+ function resolveGroupName(element) {
563
+ const legendElement = element instanceof HTMLFieldSetElement ? element.querySelector("legend") : null;
564
+ if (legendElement !== null) {
565
+ return snapshotTextContent(legendElement);
566
+ }
567
+ return resolveAccessibleName(element, false);
568
+ }
569
+
528
570
  // src/snapshots/heading.ts
529
571
  var LEVEL_REGEXP = /^H([1-6])$/;
530
572
  function snapshotHeading(element) {
@@ -565,7 +607,7 @@
565
607
  name: resolveAccessibleName(element),
566
608
  attributes: {
567
609
  ...linkAttributes(element),
568
- ...disableableAttributes(element, true)
610
+ ...disableableAttributes(element)
569
611
  },
570
612
  children: snapshotChildren(element)
571
613
  };
@@ -614,7 +656,8 @@
614
656
  alertdialog: snapshotDialogWithRole("alertdialog"),
615
657
  tab: snapshotTab,
616
658
  menuitem: snapshotMenuitem,
617
- columnheader: snapshotColumnheader
659
+ columnheader: snapshotColumnheader,
660
+ group: snapshotGroup
618
661
  };
619
662
  function snapshotElement(element) {
620
663
  return snapshotNodeRecursive(element);
package/dist/types.d.ts CHANGED
@@ -4,12 +4,19 @@ interface DisableableAttributes {
4
4
  interface SelectableAttributes {
5
5
  selected?: boolean;
6
6
  }
7
+ interface InputStateAttributes extends DisableableAttributes {
8
+ readonly?: boolean;
9
+ required?: boolean;
10
+ invalid?: boolean;
11
+ }
7
12
 
8
13
  interface ButtonSnapshot extends GenericElementSnapshot<"button", ButtonAttributes> {
9
14
  }
10
15
  interface ButtonAttributes extends DisableableAttributes {
11
16
  expanded?: boolean;
17
+ pressed?: PressedValue;
12
18
  }
19
+ type PressedValue = true | "mixed";
13
20
 
14
21
  interface InputSnapshot extends GenericElementSnapshot<CommonInputRole, InputAttributes> {
15
22
  }
@@ -19,12 +26,9 @@ interface InputAttributes extends CommonInputAttributes {
19
26
  value?: string;
20
27
  checked?: boolean;
21
28
  }
22
- interface CommonInputAttributes extends DisableableAttributes {
29
+ interface CommonInputAttributes extends InputStateAttributes {
23
30
  description?: string;
24
31
  placeholder?: string;
25
- readonly?: boolean;
26
- required?: boolean;
27
- invalid?: boolean;
28
32
  }
29
33
 
30
34
  interface ComboboxSnapshot extends GenericElementSnapshot<"combobox", ComboboxAttributes> {
@@ -52,6 +56,9 @@ interface DialogAttributes {
52
56
  modal?: boolean;
53
57
  }
54
58
 
59
+ interface GroupSnapshot extends GenericElementSnapshot<"group"> {
60
+ }
61
+
55
62
  interface HeadingSnapshot extends GenericElementSnapshot<"heading", HeadingAttributes> {
56
63
  }
57
64
  interface HeadingAttributes {
@@ -88,9 +95,9 @@ interface TextSnapshot {
88
95
  }
89
96
 
90
97
  type NodeRole = ElementRole | "text";
91
- type ElementRole = "heading" | "link" | "button" | "option" | "tab" | "menuitem" | "columnheader" | ContainerRole | InputRole | DialogRole;
98
+ type ElementRole = "heading" | "link" | "button" | "option" | "tab" | "menuitem" | "columnheader" | "group" | ContainerRole | InputRole | DialogRole;
92
99
  type NodeSnapshot = ElementSnapshot | TextSnapshot;
93
- type ElementSnapshot = ContainerSnapshot | HeadingSnapshot | LinkSnapshot | ButtonSnapshot | InputSnapshot | ComboboxSnapshot | OptionSnapshot | DialogSnapshot | TabSnapshot | MenuitemSnapshot | ColumnheaderSnapshot;
100
+ type ElementSnapshot = ContainerSnapshot | HeadingSnapshot | LinkSnapshot | ButtonSnapshot | InputSnapshot | ComboboxSnapshot | OptionSnapshot | DialogSnapshot | TabSnapshot | MenuitemSnapshot | ColumnheaderSnapshot | GroupSnapshot;
94
101
  interface GenericElementSnapshot<TRole extends NodeRole = NodeRole, TAttributes = unknown> {
95
102
  role: TRole;
96
103
  name?: string;
@@ -99,4 +106,4 @@ interface GenericElementSnapshot<TRole extends NodeRole = NodeRole, TAttributes
99
106
  }
100
107
  type SetValues<TSet> = TSet extends Set<infer TValue> ? TValue : never;
101
108
 
102
- export type { ButtonSnapshot, ColumnheaderSnapshot, ComboboxSnapshot, ContainerSnapshot, DialogSnapshot, ElementRole, ElementSnapshot, HeadingSnapshot, InputSnapshot, LinkSnapshot, MenuitemSnapshot, NodeRole, NodeSnapshot, OptionSnapshot, TabSnapshot, TextSnapshot };
109
+ export type { ButtonSnapshot, ColumnheaderSnapshot, ComboboxSnapshot, ContainerSnapshot, DialogSnapshot, ElementRole, ElementSnapshot, GroupSnapshot, HeadingSnapshot, InputSnapshot, LinkSnapshot, MenuitemSnapshot, NodeRole, NodeSnapshot, OptionSnapshot, TabSnapshot, TextSnapshot };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cronn/element-snapshot",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "Element snapshots for Playwright",
5
5
  "author": "cronn",
6
6
  "license": "Apache-2.0",
@@ -11,8 +11,19 @@
11
11
  },
12
12
  "homepage": "https://github.com/cronn/file-snapshots",
13
13
  "engines": {
14
- "node": ">=22.18",
15
- "pnpm": ">=10"
14
+ "node": "^20 || ^22 || >=24"
15
+ },
16
+ "devEngines": {
17
+ "runtime": {
18
+ "name": "node",
19
+ "version": ">=24.11 <25",
20
+ "onFail": "error"
21
+ },
22
+ "packageManager": {
23
+ "name": "pnpm",
24
+ "version": ">=10.21 <11",
25
+ "onFail": "error"
26
+ }
16
27
  },
17
28
  "type": "module",
18
29
  "exports": {
@@ -34,9 +45,9 @@
34
45
  "eslint-config-prettier": "10.1.8",
35
46
  "eslint-plugin-unused-imports": "4.3.0",
36
47
  "prettier": "3.6.2",
37
- "tsup": "8.5.0",
48
+ "tsup": "8.5.1",
38
49
  "typescript": "5.9.3",
39
- "typescript-eslint": "8.46.3",
50
+ "typescript-eslint": "8.47.0",
40
51
  "@cronn/shared-configs": "0.0.0"
41
52
  },
42
53
  "scripts": {