@cronn/element-snapshot 0.8.0 → 0.9.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 ADDED
@@ -0,0 +1,109 @@
1
+ # Element Snapshot
2
+
3
+ Element Snapshots are a custom snapshot implementation inspired by [Playwright's ARIA Snapshots](https://playwright.dev/docs/aria-snapshots#aria-snapshots) and the [Accessibility Object Model](https://wicg.github.io/aom/explainer.html). They cover additional properties, e.g. validation attributes like `required` or `invalid` on form inputs, and are optimized to be serialized as JSON.
4
+
5
+ Element Snapshots are designed to be used in combination with [playwright-file-snapshots](../playwright-file-snapshots/README.md) for writing Playwright tests.
6
+
7
+ > [!NOTE]
8
+ > Element Snapshots are currently experimental. Not all HTML elements, ARIA roles and attributes are covered. Breaking changes to the snapshot format are possible.
9
+
10
+ ## Getting Started
11
+
12
+ ### Adding the library to your project
13
+
14
+ ```shell
15
+ npm install -D @cronn/element-snapshot
16
+ ```
17
+
18
+ ```shell
19
+ yarn add -D @cronn/element-snapshot
20
+ ```
21
+
22
+ ```shell
23
+ pnpm add -D @cronn/element-snapshot
24
+ ```
25
+
26
+ ## Writing Tests
27
+
28
+ ### General-Purpose Snapshots
29
+
30
+ The function `snapshotElement` provides a general-purpose snapshot including all supported roles and attributes. It can be used to achieve a high test coverage, but can become hard to read for complex HTML structures.
31
+
32
+ ```ts
33
+ import { snapshotElement } from "@cronn/element-snapshot";
34
+ import { defineValidationFileExpect } from "@cronn/playwright-file-snapshots";
35
+
36
+ const expect = defineValidationFileExpect();
37
+
38
+ test("matches element snapshot", async ({ page }) => {
39
+ await expect(snapshotElement(page.getByRole("main"))).toMatchJsonFile();
40
+ });
41
+ ```
42
+
43
+ Element Snapshot Example:
44
+
45
+ ```json
46
+ {
47
+ "main": [
48
+ {
49
+ "heading": {
50
+ "name": "List",
51
+ "level": 1
52
+ }
53
+ },
54
+ {
55
+ "list": [
56
+ {
57
+ "listitem": "Apple"
58
+ },
59
+ {
60
+ "listitem": "Peach"
61
+ }
62
+ ]
63
+ }
64
+ ]
65
+ }
66
+ ```
67
+
68
+ To improve the specificity of certain tests, `snapshotElement` can be called on certain areas of the page only:
69
+
70
+ ```ts
71
+ test("matches navigation snapshot", async ({ page }) => {
72
+ await expect(snapshotElement(page.getByRole("navigation"))).toMatchJsonFile({
73
+ name: "navigation",
74
+ });
75
+ });
76
+ ```
77
+
78
+ #### Snapshot Options
79
+
80
+ Snapshot options can be passed when calling the snapshot function:
81
+
82
+ ```ts
83
+ await expect(
84
+ snapshotElement(page.getByLabel("My select"), {
85
+ includeComboboxOptions: true,
86
+ }),
87
+ ).toMatchJsonFile({
88
+ name: "select options",
89
+ });
90
+ ```
91
+
92
+ ### Custom Snapshots
93
+
94
+ The function `snapshotElementRaw` provides the raw element snapshot in a strictly typed structure. This format is not well suited to be read by humans, but can be utilized to derive custom snapshot formats, e.g. for HTML tables.
95
+
96
+ ```ts
97
+ import { snapshotElementRaw } from "@cronn/element-snapshot";
98
+
99
+ test("matches custom snapshot", async ({ page }) => {
100
+ const tableSnapshot = await snapshotElementRaw(page.getByRole("table"));
101
+ const markdownTable = transformToMarkdownTable(tableSnapshot);
102
+
103
+ await expect(markdownTable).toMatchTextFile({ fileExtension: "md" });
104
+ });
105
+
106
+ function transformToMarkdownTable(snapshot: Array<NodeSnapshot>): string {
107
+ // transform table snapshot to markdown table
108
+ }
109
+ ```
@@ -46,11 +46,6 @@ interface OptionAttributes {
46
46
  selected?: boolean;
47
47
  }
48
48
 
49
- declare const CONTAINER_ROLES: Set<"paragraph" | "list" | "listitem" | "listbox" | "article" | "banner" | "complementary" | "contentinfo" | "form" | "main" | "navigation" | "region" | "search" | "term" | "definition" | "table" | "grid" | "rowgroup" | "row" | "rowheader" | "cell" | "gridcell" | "alert" | "menu" | "tablist" | "tabpanel">;
50
- interface ContainerSnapshot extends GenericElementSnapshot<ContainerRole> {
51
- }
52
- type ContainerRole = SetValues<typeof CONTAINER_ROLES>;
53
-
54
49
  interface DialogSnapshot extends GenericElementSnapshot<DialogRole, DialogAttributes> {
55
50
  }
56
51
  type DialogRole = "dialog" | "alertdialog";
@@ -106,6 +101,7 @@ interface TextSnapshot {
106
101
  name: string;
107
102
  }
108
103
 
104
+ type SnapshotTargetElement = HTMLElement | SVGElement;
109
105
  type NodeRole = ElementRole | "text";
110
106
  type ElementRole = "heading" | "link" | "button" | "option" | "tab" | "menuitem" | "columnheader" | "group" | "radiogroup" | "progressbar" | ContainerRole | InputRole | DialogRole;
111
107
  type NodeSnapshot = ElementSnapshot | TextSnapshot;
@@ -118,4 +114,15 @@ interface GenericElementSnapshot<TRole extends NodeRole = NodeRole, TAttributes
118
114
  }
119
115
  type SetValues<TSet> = TSet extends Set<infer TValue> ? TValue : never;
120
116
 
121
- export type { ButtonSnapshot, ColumnheaderSnapshot, ComboboxSnapshot, ContainerSnapshot, DialogSnapshot, ElementRole, ElementSnapshot, GroupSnapshot, HeadingSnapshot, InputSnapshot, LinkSnapshot, MenuitemSnapshot, NodeRole, NodeSnapshot, OptionSnapshot, ProgressbarSnapshot, TabSnapshot, TextSnapshot };
117
+ declare const CONTAINER_ROLES: Set<"paragraph" | "list" | "listitem" | "listbox" | "article" | "banner" | "complementary" | "contentinfo" | "form" | "main" | "navigation" | "region" | "search" | "term" | "definition" | "table" | "grid" | "rowgroup" | "row" | "rowheader" | "cell" | "gridcell" | "alert" | "menu" | "tablist" | "tabpanel">;
118
+ interface ContainerSnapshot extends GenericElementSnapshot<ContainerRole> {
119
+ }
120
+ type ContainerRole = SetValues<typeof CONTAINER_ROLES>;
121
+
122
+ declare function snapshotElement(element: SnapshotTargetElement): Array<NodeSnapshot>;
123
+
124
+ declare global {
125
+ interface Window {
126
+ snapshotElement: typeof snapshotElement;
127
+ }
128
+ }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  (() => {
3
- // src/snapshots/attribute.ts
3
+ // src/browser/attribute.ts
4
4
  function stringAttribute(value) {
5
5
  return value !== null && value !== "" ? value : void 0;
6
6
  }
@@ -31,13 +31,13 @@
31
31
  return element.ownerDocument.getElementById(referenceId);
32
32
  }
33
33
 
34
- // src/snapshots/children.ts
34
+ // src/browser/children.ts
35
35
  function snapshotChildren(element) {
36
36
  const children = Array.from(element.childNodes).map(snapshotNodeRecursive).filter((childSnapshot) => childSnapshot !== null).flat();
37
37
  return children.length > 0 ? children : void 0;
38
38
  }
39
39
 
40
- // src/snapshots/text.ts
40
+ // src/browser/text.ts
41
41
  function snapshotTextNode(textNode) {
42
42
  const textContent = snapshotTextContent(textNode);
43
43
  if (textContent === void 0) {
@@ -56,7 +56,7 @@
56
56
  return normalizedText !== "" ? normalizedText : void 0;
57
57
  }
58
58
 
59
- // src/snapshots/name.ts
59
+ // src/browser/name.ts
60
60
  function resolveAccessibleName(element, includeTextContent = true) {
61
61
  const labelledByElement = resolveElementReference(element, "aria-labelledby");
62
62
  if (labelledByElement !== null) {
@@ -71,7 +71,7 @@
71
71
  return void 0;
72
72
  }
73
73
 
74
- // src/snapshots/state.ts
74
+ // src/browser/state.ts
75
75
  function disableableAttributes(element) {
76
76
  const supportsHtmlAttribute = isNativeInputElement(element) || element instanceof HTMLButtonElement;
77
77
  const disabled = booleanAttribute(
@@ -103,7 +103,7 @@
103
103
  return element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement;
104
104
  }
105
105
 
106
- // src/snapshots/button.ts
106
+ // src/browser/button.ts
107
107
  var PRESSED_VALUES = /* @__PURE__ */ new Set(["true", "mixed", "false"]);
108
108
  function snapshotButton(element) {
109
109
  return {
@@ -125,7 +125,7 @@
125
125
  return booleanAttribute(pressed === "true");
126
126
  }
127
127
 
128
- // src/snapshots/description.ts
128
+ // src/browser/description.ts
129
129
  function discribableAttributes(element) {
130
130
  return {
131
131
  description: resolveDescription(element)
@@ -145,7 +145,7 @@
145
145
  return void 0;
146
146
  }
147
147
 
148
- // src/snapshots/container.ts
148
+ // src/browser/container.ts
149
149
  var CONTAINER_ROLES = /* @__PURE__ */ new Set([
150
150
  "paragraph",
151
151
  "list",
@@ -186,7 +186,7 @@
186
186
  return CONTAINER_ROLES.has(role);
187
187
  }
188
188
 
189
- // src/snapshots/selector.ts
189
+ // src/browser/selector.ts
190
190
  function selectorList(...selectors) {
191
191
  return selectors.join(",");
192
192
  }
@@ -197,7 +197,7 @@
197
197
  return `[${name}='${value}']`;
198
198
  }
199
199
 
200
- // src/snapshots/utils.ts
200
+ // src/browser/utils.ts
201
201
  function getElementTagName(element) {
202
202
  return element.tagName.toLowerCase();
203
203
  }
@@ -205,7 +205,7 @@
205
205
  return element.closest(containerSelector) !== null;
206
206
  }
207
207
 
208
- // src/snapshots/role.ts
208
+ // src/browser/role.ts
209
209
  var ELEMENT_ROLES = {
210
210
  main: "main",
211
211
  nav: "navigation",
@@ -394,7 +394,7 @@
394
394
  return isWithinElement(element, roleSelector("tablist"));
395
395
  }
396
396
 
397
- // src/snapshots/input.ts
397
+ // src/browser/input.ts
398
398
  function snapshotInput(element) {
399
399
  if (element instanceof HTMLInputElement) {
400
400
  return snapshotInputElement(element);
@@ -477,7 +477,7 @@
477
477
  return stringAttribute(element.placeholder);
478
478
  }
479
479
 
480
- // src/snapshots/combobox.ts
480
+ // src/browser/combobox.ts
481
481
  function snapshotCombobox(element) {
482
482
  if (!isCombobox(element)) {
483
483
  return null;
@@ -546,7 +546,7 @@
546
546
  };
547
547
  }
548
548
 
549
- // src/snapshots/dialog.ts
549
+ // src/browser/dialog.ts
550
550
  function snapshotDialogWithRole(role) {
551
551
  return (element) => snapshotDialog(role, element);
552
552
  }
@@ -562,7 +562,7 @@
562
562
  };
563
563
  }
564
564
 
565
- // src/snapshots/group.ts
565
+ // src/browser/group.ts
566
566
  function snapshotGroup(element) {
567
567
  return {
568
568
  role: "group",
@@ -586,7 +586,7 @@
586
586
  };
587
587
  }
588
588
 
589
- // src/snapshots/heading.ts
589
+ // src/browser/heading.ts
590
590
  var LEVEL_REGEXP = /^H([1-6])$/;
591
591
  function snapshotHeading(element) {
592
592
  if (!(element instanceof HTMLHeadingElement)) {
@@ -606,7 +606,7 @@
606
606
  return numericAttribute(levelAsString);
607
607
  }
608
608
 
609
- // src/snapshots/link.ts
609
+ // src/browser/link.ts
610
610
  function snapshotLink(element) {
611
611
  return {
612
612
  role: "link",
@@ -619,7 +619,7 @@
619
619
  return { url: stringAttribute(element.getAttribute("href")) };
620
620
  }
621
621
 
622
- // src/snapshots/list.ts
622
+ // src/browser/list.ts
623
623
  function snapshotMenuitem(element) {
624
624
  return {
625
625
  role: "menuitem",
@@ -632,7 +632,7 @@
632
632
  };
633
633
  }
634
634
 
635
- // src/snapshots/progressbar.ts
635
+ // src/browser/progressbar.ts
636
636
  function snapshotProgressbar(element) {
637
637
  return {
638
638
  role: "progressbar",
@@ -650,7 +650,7 @@
650
650
  return numericAttribute(element.ariaValueNow);
651
651
  }
652
652
 
653
- // src/snapshots/tab.ts
653
+ // src/browser/tab.ts
654
654
  function snapshotTab(element) {
655
655
  return {
656
656
  role: "tab",
@@ -663,7 +663,7 @@
663
663
  };
664
664
  }
665
665
 
666
- // src/snapshots/table.ts
666
+ // src/browser/table.ts
667
667
  var SORT_ATTRIBUTES = /* @__PURE__ */ new Set(["ascending", "descending", "other"]);
668
668
  function snapshotColumnheader(element) {
669
669
  return {
@@ -676,7 +676,7 @@
676
676
  };
677
677
  }
678
678
 
679
- // src/snapshots/element.ts
679
+ // src/browser/element.ts
680
680
  var ROLE_SNAPSHOTS = {
681
681
  button: snapshotButton,
682
682
  checkbox: snapshotInput,
@@ -761,6 +761,6 @@
761
761
  return cssStyles.display === "none" || cssStyles.visibility === "hidden" || cssStyles.visibility === "collapse";
762
762
  }
763
763
 
764
- // src/index.ts
764
+ // src/browser-lib.ts
765
765
  window.snapshotElement = snapshotElement;
766
766
  })();
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { Locator } from '@playwright/test';
2
+
1
3
  interface DisableableAttributes {
2
4
  disabled?: boolean;
3
5
  }
@@ -46,6 +48,11 @@ interface OptionAttributes {
46
48
  selected?: boolean;
47
49
  }
48
50
 
51
+ declare const CONTAINER_ROLES: Set<"paragraph" | "list" | "listitem" | "listbox" | "article" | "banner" | "complementary" | "contentinfo" | "form" | "main" | "navigation" | "region" | "search" | "term" | "definition" | "table" | "grid" | "rowgroup" | "row" | "rowheader" | "cell" | "gridcell" | "alert" | "menu" | "tablist" | "tabpanel">;
52
+ interface ContainerSnapshot extends GenericElementSnapshot<ContainerRole> {
53
+ }
54
+ type ContainerRole = SetValues<typeof CONTAINER_ROLES>;
55
+
49
56
  interface DialogSnapshot extends GenericElementSnapshot<DialogRole, DialogAttributes> {
50
57
  }
51
58
  type DialogRole = "dialog" | "alertdialog";
@@ -101,7 +108,6 @@ interface TextSnapshot {
101
108
  name: string;
102
109
  }
103
110
 
104
- type SnapshotTargetElement = HTMLElement | SVGElement;
105
111
  type NodeRole = ElementRole | "text";
106
112
  type ElementRole = "heading" | "link" | "button" | "option" | "tab" | "menuitem" | "columnheader" | "group" | "radiogroup" | "progressbar" | ContainerRole | InputRole | DialogRole;
107
113
  type NodeSnapshot = ElementSnapshot | TextSnapshot;
@@ -114,15 +120,31 @@ interface GenericElementSnapshot<TRole extends NodeRole = NodeRole, TAttributes
114
120
  }
115
121
  type SetValues<TSet> = TSet extends Set<infer TValue> ? TValue : never;
116
122
 
117
- declare const CONTAINER_ROLES: Set<"paragraph" | "list" | "listitem" | "listbox" | "article" | "banner" | "complementary" | "contentinfo" | "form" | "main" | "navigation" | "region" | "search" | "term" | "definition" | "table" | "grid" | "rowgroup" | "row" | "rowheader" | "cell" | "gridcell" | "alert" | "menu" | "tablist" | "tabpanel">;
118
- interface ContainerSnapshot extends GenericElementSnapshot<ContainerRole> {
119
- }
120
- type ContainerRole = SetValues<typeof CONTAINER_ROLES>;
121
-
122
- declare function snapshotElement(element: SnapshotTargetElement): Array<NodeSnapshot>;
123
-
124
- declare global {
125
- interface Window {
126
- snapshotElement: typeof snapshotElement;
127
- }
128
- }
123
+ interface ElementSnapshotOptions {
124
+ /**
125
+ * Include combobox options in the snapshot
126
+ *
127
+ * @default false
128
+ */
129
+ includeComboboxOptions?: boolean;
130
+ }
131
+ /**
132
+ * Creates an Element Snapshot of the specified element
133
+ *
134
+ * @example
135
+ * ```ts
136
+ * await expect(snapshotElement(page.getByRole("main"))).toMatchJsonSnapshot();
137
+ * ```
138
+ * @param locator Locator for the element to snapshot
139
+ * @experimental
140
+ */
141
+ declare function snapshotElement(locator: Locator, options?: ElementSnapshotOptions): Promise<unknown>;
142
+ /**
143
+ * Creates an Element Snapshot of the specified element, returning the raw snapshot data for custom transformations
144
+ *
145
+ * @param locator Locator for the element to snapshot
146
+ * @experimental
147
+ */
148
+ declare function snapshotElementRaw(locator: Locator): Promise<Array<NodeSnapshot>>;
149
+
150
+ export { type ButtonSnapshot, type ColumnheaderSnapshot, type ComboboxSnapshot, type ContainerSnapshot, type DialogSnapshot, type ElementRole, type ElementSnapshot, type GroupSnapshot, type HeadingSnapshot, type InputSnapshot, type LinkSnapshot, type MenuitemSnapshot, type NodeRole, type NodeSnapshot, type OptionSnapshot, type ProgressbarSnapshot, type RadiogroupSnapshot, type TabSnapshot, type TextSnapshot, snapshotElement, snapshotElementRaw };
package/dist/index.js ADDED
@@ -0,0 +1,158 @@
1
+ // src/playwright/proxy.ts
2
+ import path from "path";
3
+ import { packageDirectory } from "package-directory";
4
+ var ElementSnapshotProxy = class {
5
+ page;
6
+ constructor(page) {
7
+ this.page = page;
8
+ }
9
+ async snapshotElement(locator) {
10
+ if (!await this.isLibraryLoaded()) {
11
+ await this.loadLibrary();
12
+ }
13
+ return await locator.evaluate((element) => {
14
+ return window.snapshotElement(element);
15
+ });
16
+ }
17
+ async isLibraryLoaded() {
18
+ return await this.page.evaluate(
19
+ () => typeof window.snapshotElement === "function"
20
+ );
21
+ }
22
+ async loadLibrary() {
23
+ const packageRootDir = await this.resolvePackageRootDir();
24
+ const libPath = path.resolve(
25
+ packageRootDir,
26
+ "dist",
27
+ "browser-lib.global.js"
28
+ );
29
+ await this.page.addScriptTag({
30
+ path: libPath
31
+ });
32
+ }
33
+ async resolvePackageRootDir() {
34
+ const packageDir = await packageDirectory({
35
+ cwd: import.meta.dirname
36
+ });
37
+ if (packageDir === void 0) {
38
+ throw new Error("Unable to resolve root directory of package");
39
+ }
40
+ return packageDir;
41
+ }
42
+ };
43
+
44
+ // src/playwright/transformer.ts
45
+ var ElementSnapshotTransformer = class {
46
+ includeComboboxOptions;
47
+ constructor(options = {}) {
48
+ this.includeComboboxOptions = options.includeComboboxOptions ?? false;
49
+ }
50
+ transform(snapshots) {
51
+ const transformedSnapshots = snapshots.map(
52
+ (snapshot) => this.transformSnapshotRecursive(snapshot)
53
+ );
54
+ if (transformedSnapshots.length === 1) {
55
+ return transformedSnapshots.at(0);
56
+ }
57
+ return transformedSnapshots;
58
+ }
59
+ transformSnapshotRecursive(snapshot) {
60
+ if (snapshot.role === "text") {
61
+ return this.simplifyTextSnapshot(snapshot);
62
+ }
63
+ return this.simplifyElementSnapshot(snapshot);
64
+ }
65
+ simplifyTextSnapshot(snapshot) {
66
+ return snapshot.name;
67
+ }
68
+ simplifyElementSnapshot(snapshot) {
69
+ const normalizedSnapshot = this.normalizeElementSnapshot(snapshot);
70
+ if (this.isEmpty(normalizedSnapshot)) {
71
+ const { role: role2 } = normalizedSnapshot;
72
+ return this.transformedSnapshot(role2, "");
73
+ }
74
+ if (this.hasOnlyName(normalizedSnapshot)) {
75
+ const { role: role2, name: name2 } = normalizedSnapshot;
76
+ return this.transformedSnapshot(role2, name2);
77
+ }
78
+ if (this.hasOnlyChildren(normalizedSnapshot)) {
79
+ const { role: role2, children: children2 } = normalizedSnapshot;
80
+ return this.transformedSnapshot(
81
+ role2,
82
+ children2.length === 1 ? children2.at(0) : children2
83
+ );
84
+ }
85
+ if (snapshot.role === "combobox") {
86
+ return this.simplifyComboboxSnapshot(snapshot);
87
+ }
88
+ const { role, name, attributes, children } = normalizedSnapshot;
89
+ return this.transformedSnapshot(role, {
90
+ name,
91
+ ...attributes,
92
+ children
93
+ });
94
+ }
95
+ normalizeElementSnapshot(snapshot) {
96
+ const sparseAttributes = this.removeUndefinedProperties(
97
+ snapshot.attributes ?? {}
98
+ );
99
+ const transformedChildren = snapshot.children?.map(
100
+ (childSnaphot) => this.transformSnapshotRecursive(childSnaphot)
101
+ );
102
+ const nameEqualsChildren = transformedChildren?.length === 1 && snapshot.name === transformedChildren.at(0);
103
+ return {
104
+ role: snapshot.role,
105
+ name: snapshot.name,
106
+ attributes: sparseAttributes,
107
+ children: nameEqualsChildren ? void 0 : transformedChildren
108
+ };
109
+ }
110
+ simplifyComboboxSnapshot(snapshot) {
111
+ const { role, name, attributes } = this.normalizeElementSnapshot(snapshot);
112
+ const options = snapshot.options ?? [];
113
+ const transformedOptions = options.map(
114
+ (optionSnapshot) => this.simplifyElementSnapshot(optionSnapshot)
115
+ );
116
+ return this.transformedSnapshot(role, {
117
+ name,
118
+ ...attributes,
119
+ options: this.includeComboboxOptions && transformedOptions.length > 0 ? transformedOptions : void 0
120
+ });
121
+ }
122
+ isEmpty(snapshot) {
123
+ return snapshot.name === void 0 && (snapshot.attributes === void 0 || Object.keys(snapshot.attributes).length === 0) && (snapshot.children === void 0 || snapshot.children.length === 0);
124
+ }
125
+ hasOnlyName(snapshot) {
126
+ return snapshot.name !== void 0 && snapshot.attributes === void 0 && snapshot.children === void 0;
127
+ }
128
+ hasOnlyChildren(snapshot) {
129
+ return snapshot.name === void 0 && snapshot.attributes === void 0 && snapshot.children !== void 0;
130
+ }
131
+ removeUndefinedProperties(attributes) {
132
+ const sparseAttributes = {};
133
+ Object.entries(attributes).forEach(([key, value]) => {
134
+ if (value !== void 0) {
135
+ sparseAttributes[key] = value;
136
+ }
137
+ });
138
+ return Object.keys(sparseAttributes).length > 0 ? sparseAttributes : void 0;
139
+ }
140
+ transformedSnapshot(role, content) {
141
+ return { [role]: content };
142
+ }
143
+ };
144
+
145
+ // src/playwright/snapshot.ts
146
+ async function snapshotElement(locator, options) {
147
+ const snapshot = await snapshotElementRaw(locator);
148
+ return new ElementSnapshotTransformer(options).transform(snapshot);
149
+ }
150
+ async function snapshotElementRaw(locator) {
151
+ return await new ElementSnapshotProxy(locator.page()).snapshotElement(
152
+ locator
153
+ );
154
+ }
155
+ export {
156
+ snapshotElement,
157
+ snapshotElementRaw
158
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cronn/element-snapshot",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Element snapshots for Playwright",
5
5
  "author": "cronn",
6
6
  "license": "Apache-2.0",
@@ -21,7 +21,7 @@
21
21
  },
22
22
  "packageManager": {
23
23
  "name": "pnpm",
24
- "version": ">=10.21 <11",
24
+ "version": ">=10.27 <11",
25
25
  "onFail": "error"
26
26
  }
27
27
  },
@@ -29,27 +29,31 @@
29
29
  "exports": {
30
30
  ".": {
31
31
  "types": "./dist/index.d.ts",
32
- "default": "./dist/index.global.js"
33
- },
34
- "./types": {
35
- "types": "./dist/types.d.ts",
36
- "default": "./dist/types.js"
32
+ "default": "./dist/index.js"
37
33
  }
38
34
  },
39
35
  "files": [
40
36
  "dist"
41
37
  ],
38
+ "dependencies": {
39
+ "package-directory": "8.1.0"
40
+ },
42
41
  "devDependencies": {
43
42
  "@trivago/prettier-plugin-sort-imports": "6.0.0",
44
- "eslint": "9.39.1",
43
+ "@types/node": "24.10.4",
44
+ "eslint": "9.39.2",
45
45
  "eslint-config-prettier": "10.1.8",
46
46
  "eslint-plugin-unused-imports": "4.3.0",
47
- "prettier": "3.6.2",
47
+ "@playwright/test": "1.56.1",
48
+ "prettier": "3.7.4",
48
49
  "tsup": "8.5.1",
49
50
  "typescript": "5.9.3",
50
- "typescript-eslint": "8.47.0",
51
+ "typescript-eslint": "8.50.1",
51
52
  "@cronn/shared-configs": "0.0.0"
52
53
  },
54
+ "peerDependencies": {
55
+ "@playwright/test": "^1.55"
56
+ },
53
57
  "scripts": {
54
58
  "lint:check": "eslint src/ --max-warnings=0",
55
59
  "lint:fix": "eslint src/ --max-warnings=0 --fix",
package/dist/types.js DELETED
File without changes