@cronn/element-snapshot 0.19.2 → 0.21.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.
@@ -15,6 +15,10 @@
15
15
  if (value === null || !supportedValues.has(value)) return;
16
16
  return value;
17
17
  }
18
+ function booleanOrEnumAttribute(value, supportedStringValues) {
19
+ if (value === "true" || value === "false") return booleanAttribute(value);
20
+ return enumAttribute(value, supportedStringValues);
21
+ }
18
22
  function resolveElementReference(element, attributeName) {
19
23
  const referenceId = element.getAttribute(attributeName);
20
24
  if (referenceId === null) return null;
@@ -140,9 +144,6 @@
140
144
  "grid",
141
145
  "rowgroup",
142
146
  "row",
143
- "rowheader",
144
- "cell",
145
- "gridcell",
146
147
  "alert",
147
148
  "menu",
148
149
  "tablist",
@@ -304,11 +305,20 @@
304
305
  function resolveTableHeaderCellRole(element) {
305
306
  if (!(element instanceof HTMLTableCellElement)) return;
306
307
  switch (element.scope) {
307
- case "col": return "columnheader";
308
- case "row": return "rowheader";
309
- default: return;
308
+ case "col":
309
+ case "colgroup": return "columnheader";
310
+ case "row":
311
+ case "rowgroup": return "rowheader";
312
+ default: return resolveTableHeaderCellRoleFromContext(element);
310
313
  }
311
314
  }
315
+ function resolveTableHeaderCellRoleFromContext(element) {
316
+ const row = element.closest("tr");
317
+ if (row === null) return;
318
+ const nextElementSibling = getNextElementSibling(element);
319
+ if (row.rowIndex === 0 && (nextElementSibling === null || resolveElementRole(nextElementSibling) === "columnheader")) return "columnheader";
320
+ if (element.cellIndex === 0 && nextElementSibling !== null && resolveElementRole(nextElementSibling) === "cell") return "rowheader";
321
+ }
312
322
  function isWithinTableOrGrid(element) {
313
323
  return isWithinTable(element) || isWithinGrid(element);
314
324
  }
@@ -444,11 +454,7 @@
444
454
  }
445
455
  //#endregion
446
456
  //#region src/browser/button.ts
447
- const PRESSED_VALUES = new Set([
448
- "true",
449
- "mixed",
450
- "false"
451
- ]);
457
+ const pressedValues = new Set(["mixed"]);
452
458
  function snapshotButton(element) {
453
459
  return {
454
460
  role: "button",
@@ -456,16 +462,11 @@
456
462
  attributes: {
457
463
  ...disableableAttributes(element),
458
464
  expanded: booleanAttribute(element.ariaExpanded),
459
- pressed: resolvePressedAttribute(element)
465
+ pressed: booleanOrEnumAttribute(element.ariaPressed, pressedValues)
460
466
  },
461
467
  children: snapshotChildren(element)
462
468
  };
463
469
  }
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
470
  //#endregion
470
471
  //#region src/browser/description.ts
471
472
  function discribableAttributes(element) {
@@ -637,6 +638,7 @@
637
638
  }
638
639
  //#endregion
639
640
  //#region src/browser/link.ts
641
+ const currentValues = new Set(["page", "step"]);
640
642
  function snapshotLink(element) {
641
643
  return {
642
644
  role: "link",
@@ -646,7 +648,10 @@
646
648
  };
647
649
  }
648
650
  function linkAttributes(element) {
649
- return { url: stringAttribute(element.getAttribute("href")) };
651
+ return {
652
+ url: stringAttribute(element.getAttribute("href")),
653
+ current: booleanOrEnumAttribute(element.ariaCurrent, currentValues)
654
+ };
650
655
  }
651
656
  //#endregion
652
657
  //#region src/browser/list.ts
@@ -718,22 +723,54 @@
718
723
  //#endregion
719
724
  //#region src/browser/table.ts
720
725
  function snapshotColumnHeader(element) {
726
+ const cell = snapshotCell("columnheader", element);
721
727
  return {
722
728
  role: "columnheader",
729
+ name: cell.name,
730
+ attributes: {
731
+ ...cell.attributes,
732
+ sort: enumAttribute(element.ariaSort, SORT_TYPES)
733
+ },
734
+ children: cell.children
735
+ };
736
+ }
737
+ function snapshotCellWithRole(role) {
738
+ return (element) => snapshotCell(role, element);
739
+ }
740
+ function snapshotCell(role, element) {
741
+ return {
742
+ role,
723
743
  name: resolveAccessibleName(element),
724
- attributes: { sort: enumAttribute(element.ariaSort, SORT_TYPES) },
744
+ attributes: cellAttributes(element),
725
745
  children: snapshotChildren(element)
726
746
  };
727
747
  }
748
+ function cellAttributes(element) {
749
+ if (element instanceof HTMLTableCellElement) return {
750
+ colSpan: resolveSpan(element.colSpan),
751
+ rowSpan: resolveSpan(element.rowSpan)
752
+ };
753
+ return {
754
+ colSpan: resolveSpan(element.ariaColSpan),
755
+ rowSpan: resolveSpan(element.ariaRowSpan)
756
+ };
757
+ }
758
+ function resolveSpan(value) {
759
+ if (typeof value === "string") value = numericAttribute(value) ?? null;
760
+ if (value === null || value === 1) return;
761
+ return value;
762
+ }
728
763
  //#endregion
729
764
  //#region src/browser/element.ts
730
765
  const ROLE_SNAPSHOTS = {
731
766
  alertdialog: snapshotDialogWithRole("alertdialog"),
732
767
  button: snapshotButton,
768
+ cell: snapshotCellWithRole("cell"),
733
769
  checkbox: snapshotInput,
734
770
  columnheader: snapshotColumnHeader,
735
771
  combobox: snapshotCombobox,
736
772
  dialog: snapshotDialogWithRole("dialog"),
773
+ gridcell: snapshotCellWithRole("gridcell"),
737
774
  group: snapshotGroup,
738
775
  heading: snapshotHeading,
739
776
  img: snapshotImage,
@@ -744,6 +781,7 @@
744
781
  radio: snapshotInput,
745
782
  radiogroup: snapshotRadioGroup,
746
783
  region: snapshotRegion,
784
+ rowheader: snapshotCellWithRole("rowheader"),
747
785
  searchbox: snapshotInput,
748
786
  separator: snapshotSeparator,
749
787
  slider: snapshotInput,
@@ -796,6 +834,12 @@
796
834
  const cssStyles = window.getComputedStyle(element);
797
835
  return cssStyles.display === "none" || cssStyles.visibility === "hidden" || cssStyles.visibility === "collapse";
798
836
  }
837
+ function getNextElementSibling(element) {
838
+ const nextElementSibling = element.nextElementSibling;
839
+ if (nextElementSibling === null) return null;
840
+ if (!isSupportedElement(nextElementSibling)) return getNextElementSibling(nextElementSibling);
841
+ return nextElementSibling;
842
+ }
799
843
  //#endregion
800
844
  //#region src/browser-lib.ts
801
845
  window.snapshotElement = snapshotElement;
package/dist/index.d.mts CHANGED
@@ -43,7 +43,7 @@ type PressedValue = true | "mixed";
43
43
  type SetValues<TSet> = TSet extends Set<infer TValue> ? TValue : never;
44
44
  //#endregion
45
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">;
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" | "alert" | "menu" | "tablist" | "tabpanel" | "label">;
47
47
  interface ContainerSnapshot extends GenericElementSnapshot<ContainerRole> {}
48
48
  type ContainerRole = SetValues<typeof CONTAINER_ROLES>;
49
49
  interface RegionSnapshot extends GenericElementSnapshot<"region"> {}
@@ -92,7 +92,9 @@ interface OptionAttributes extends SelectableAttributes, DisableableAttributes {
92
92
  interface LinkSnapshot extends GenericElementSnapshot<"link", LinkAttributes> {}
93
93
  interface LinkAttributes {
94
94
  url?: string;
95
+ current?: CurrentValue;
95
96
  }
97
+ type CurrentValue = true | "page" | "step";
96
98
  //#endregion
97
99
  //#region src/types/elements/list.d.ts
98
100
  interface MenuItemSnapshot extends GenericElementSnapshot<"menuitem", MenuitemAttributes> {}
@@ -113,11 +115,17 @@ interface TabAttributes extends DisableableAttributes, SelectableAttributes {}
113
115
  //#endregion
114
116
  //#region src/types/elements/table.d.ts
115
117
  declare const SORT_TYPES: Set<"ascending" | "descending" | "other">;
116
- interface ColumnHeaderSnapshot extends GenericElementSnapshot<"columnheader", ColumnheaderAttributes> {}
117
- interface ColumnheaderAttributes {
118
+ interface ColumnHeaderSnapshot extends GenericElementSnapshot<"columnheader", ColumnHeaderAttributes> {}
119
+ interface ColumnHeaderAttributes extends CellAttributes {
118
120
  sort?: SortType;
119
121
  }
120
122
  type SortType = SetValues<typeof SORT_TYPES>;
123
+ interface CellSnapshot extends GenericElementSnapshot<CellRole, CellAttributes> {}
124
+ type CellRole = "columnheader" | "rowheader" | "cell" | "gridcell";
125
+ interface CellAttributes {
126
+ colSpan?: number;
127
+ rowSpan?: number;
128
+ }
121
129
  //#endregion
122
130
  //#region src/types/elements/text.d.ts
123
131
  interface TextSnapshot {
@@ -127,7 +135,7 @@ interface TextSnapshot {
127
135
  //#endregion
128
136
  //#region src/types/role.d.ts
129
137
  type TextRole = "text";
130
- type ElementRole = "button" | "columnheader" | "group" | "heading" | "img" | "link" | "menuitem" | "option" | "progressbar" | "radiogroup" | "region" | "separator" | "tab" | ContainerRole | DialogRole | InputRole;
138
+ type ElementRole = "button" | "group" | "heading" | "img" | "link" | "menuitem" | "option" | "progressbar" | "radiogroup" | "region" | "separator" | "tab" | CellRole | ContainerRole | DialogRole | InputRole;
131
139
  //#endregion
132
140
  //#region src/types/snapshot.d.ts
133
141
  type NodeRole = ElementRole | TextRole;
@@ -141,7 +149,7 @@ interface GenericElementSnapshot<TRole extends NodeRole = NodeRole, TAttributes
141
149
  attributes: TAttributes;
142
150
  children: Array<NodeSnapshot>;
143
151
  }
144
- type ElementSnapshot = ButtonSnapshot | ColumnHeaderSnapshot | ComboboxSnapshot | ContainerSnapshot | DialogSnapshot | GroupSnapshot | HeadingSnapshot | ImageSnapshot | InputSnapshot | LinkSnapshot | OptionSnapshot | ProgressbarSnapshot | RegionSnapshot | TabSnapshot | MenuItemSnapshot | RadioGroupSnapshot | SeparatorSnapshot;
152
+ type ElementSnapshot = ButtonSnapshot | CellSnapshot | ColumnHeaderSnapshot | ComboboxSnapshot | ContainerSnapshot | DialogSnapshot | GroupSnapshot | HeadingSnapshot | ImageSnapshot | InputSnapshot | LinkSnapshot | OptionSnapshot | ProgressbarSnapshot | RegionSnapshot | TabSnapshot | MenuItemSnapshot | RadioGroupSnapshot | SeparatorSnapshot;
145
153
  //#endregion
146
154
  //#region src/utils/filter.d.ts
147
155
  type FilterPredicate = (snapshot: NodeSnapshot) => boolean;
@@ -262,4 +270,4 @@ declare function excludeRole<TRole extends NodeRole>(role: TRole | Array<TRole>)
262
270
  */
263
271
  declare function getTextContent(snapshots: Array<NodeSnapshot>): string;
264
272
  //#endregion
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 };
273
+ export { type ButtonSnapshot, type CellSnapshot, 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cronn/element-snapshot",
3
- "version": "0.19.2",
3
+ "version": "0.21.0",
4
4
  "description": "Element snapshots for Playwright",
5
5
  "homepage": "https://cronn.github.io/file-snapshots/playwright/element-snapshots/",
6
6
  "bugs": {
@@ -27,27 +27,27 @@
27
27
  "dependencies": {
28
28
  "package-directory": "8.2.0",
29
29
  "@cronn/lib-file-snapshots": "1.2.0",
30
- "@cronn/playwright-file-snapshots": "2.1.0"
30
+ "@cronn/playwright-file-snapshots": "2.2.0"
31
31
  },
32
32
  "devDependencies": {
33
- "@arethetypeswrong/core": "0.18.2",
33
+ "@arethetypeswrong/core": "0.18.3",
34
34
  "@playwright/test": "1.60.0",
35
35
  "@types/node": "24.12.4",
36
- "@typescript/native-preview": "7.0.0-dev.20260518.1",
37
- "@vitest/coverage-v8": "4.1.6",
38
- "eslint": "10.4.0",
36
+ "@typescript/native-preview": "7.0.0-dev.20260527.2",
37
+ "@vitest/coverage-v8": "4.1.7",
38
+ "eslint": "10.4.1",
39
39
  "eslint-config-prettier": "10.1.8",
40
40
  "eslint-plugin-check-file": "3.3.1",
41
41
  "eslint-plugin-unused-imports": "4.4.1",
42
42
  "publint": "0.3.21",
43
43
  "rimraf": "6.1.3",
44
- "tsdown": "0.22.0",
45
- "typescript-eslint": "8.59.4",
46
- "vitest": "4.1.6",
44
+ "tsdown": "0.22.1",
45
+ "typescript-eslint": "8.60.0",
46
+ "vitest": "4.1.7",
47
47
  "node": "runtime:>=24.14.1 <25",
48
- "@cronn/shared-configs": "0.0.0",
49
48
  "@cronn/test-utils": "0.0.0",
50
- "@cronn/vitest-file-snapshots": "2.1.0"
49
+ "@cronn/vitest-file-snapshots": "2.1.1",
50
+ "@cronn/shared-configs": "0.0.0"
51
51
  },
52
52
  "peerDependencies": {
53
53
  "@playwright/test": "^1.55"
@@ -55,7 +55,7 @@
55
55
  "devEngines": {
56
56
  "packageManager": {
57
57
  "name": "pnpm",
58
- "version": "11.3.0",
58
+ "version": "11.5.2",
59
59
  "onFail": "download"
60
60
  },
61
61
  "runtime": {