playwright-clipboard-testing 0.2.0 → 0.4.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 CHANGED
@@ -4,6 +4,7 @@
4
4
 
5
5
  Effortless clipboard testing for Playwright. Features custom fixtures, smart polling matchers, and auto-managed permissions.
6
6
 
7
+ [![Tests](https://github.com/sergoleksenko/playwright-clipboard-testing/actions/workflows/tests.yml/badge.svg)](https://github.com/sergoleksenko/playwright-clipboard-testing/actions/workflows/tests.yml)
7
8
  [![npm version](https://img.shields.io/npm/v/playwright-clipboard-testing.svg?style=flat&color=blue)](https://www.npmjs.com/package/playwright-clipboard-testing)
8
9
  [![npm downloads](https://img.shields.io/npm/dw/playwright-clipboard-testing.svg?color=blue)](https://www.npmjs.com/package/playwright-clipboard-testing)
9
10
  [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg?style=flat&color=blue)](LICENSE)
@@ -14,7 +15,7 @@ Testing the Clipboard API in Playwright usually requires boilerplate code to man
14
15
  **playwright-clipboard-testing** simplifies this with:
15
16
  - 🔌 **Zero configuration** — Chromium permissions are granted automatically under the hood (Firefox requires a 1-line config setup).
16
17
  - 🔄 **Built-in Auto-retries & Polling** — Uses Playwright's native `expect` polling to wait until the clipboard updates asynchronously.
17
- - 📦 **TypeScript Ready** — Out-of-the-box support for JSON objects with full type safety (`readJSON<T>()`).
18
+ - 📦 **TypeScript Ready** — Full type safety for JSON objects with `readJSON<T>()`.
18
19
 
19
20
  ## Table of Contents
20
21
  - [Why?](#why)
@@ -24,7 +25,9 @@ Testing the Clipboard API in Playwright usually requires boilerplate code to man
24
25
  - [Direct Usage](#direct-usage)
25
26
  - [Extended Usage](#extended-usage)
26
27
  - [API](#api)
27
- - [Clipboard Fixture](#clipboard-fixture)
28
+ - [Clipboard Fixtures](#clipboard-fixtures)
29
+ - [toHaveTextContent Matcher](#tohavetextcontent-matcher)
30
+ - [toHaveJSONContent Matcher](#tohavejsoncontent-matcher)
28
31
  - [toHaveData Matcher](#tohavedata-matcher)
29
32
  - [Author](#author)
30
33
  - [License](#license)
@@ -81,38 +84,70 @@ test('should copy text to clipboard', async ({ page, clipboard }) => {
81
84
  await page.goto('https://example.com');
82
85
  await page.locator('#copy-button').click();
83
86
 
84
- await expect(clipboard).toHaveData('Hello, World!');
87
+ await expect(clipboard).toHaveTextContent('Hello, World!');
85
88
  });
86
89
  ```
87
90
 
88
91
  ### Extended Usage
89
92
 
90
- If you already have a custom test fixture file, extend Playwright's `test` and `expect` with `clipboardFixture` and `clipboardMatchers`:
93
+ If you already have a custom test fixture file, extend Playwright's `test` and `expect` with `clipboardFixtures` and `clipboardMatchers`:
91
94
  ```ts
92
95
  import { expect as baseExpect, test as baseTest } from '@playwright/test';
93
96
  import {
94
97
  type ClipboardHandler,
95
- clipboardFixture,
98
+ clipboardFixtures,
96
99
  clipboardMatchers,
97
100
  } from 'playwright-clipboard-testing';
98
101
 
99
- export const test = baseTest.extend<{ clipboard: ClipboardHandler }>({
100
- clipboard: clipboardFixture,
101
- });
102
+ export const test = baseTest.extend<{ clipboard: ClipboardHandler }>(clipboardFixtures);
102
103
 
103
104
  export const expect = baseExpect.extend(clipboardMatchers);
104
-
105
105
  ```
106
106
 
107
107
  ## API
108
- ### Clipboard Fixture
109
- The `clipboard` fixture provides direct access to the browser clipboard during tests:
110
- - `clipboard.read(): Promise<string>` - reads the current plain text content from the clipboard.
111
- - `clipboard.readJSON<T>(): Promise<T>` - reads the current clipboard content and parses it as a JSON object of type `T`. Throws an error if the content is not valid JSON.
108
+ ### Clipboard Fixtures
109
+ The package exports `clipboardFixtures` (containing `context` and `clipboard` fixtures) as well as individual fixtures `clipboardFixture` and `contextFixture`:
110
+
111
+ - `clipboardFixtures` — Object containing both `context` and `clipboard` fixtures for simple fixture extension.
112
+ - `contextFixture` (`context`) — Automatically grants `clipboard-read` and `clipboard-write` permissions to Chromium browser contexts.
113
+ - `clipboardFixture` (`clipboard`) — Provides direct access to the `ClipboardHandler` instance during tests:
114
+ - `clipboard.read(): Promise<string>` — reads the current plain text content from the clipboard.
115
+ - `clipboard.readJSON<T>(): Promise<T>` — reads the current clipboard content and parses it as a JSON object of type `T`. Throws an error if the content is not valid JSON.
112
116
 
113
- ![NOTE](https://img.shields.io/badge/NOTE-For%20your%20tests%20we%20recommend%20using%20the%20toHaveData%20matcher-yellow)
117
+ ![NOTE](https://img.shields.io/badge/NOTE-For%20your%20tests%20we%20recommend%20using%20existing%20matchers%20to%20assert%20clipboard%20content-yellow)
118
+
119
+ ### toHaveTextContent Matcher
120
+ `expect(clipboard).toHaveTextContent(expected, options?)`
121
+
122
+ Asserts that the clipboard content matches the expected string. Uses Playwright's smart polling mechanism to wait for the clipboard to update.
123
+ - `expected: string` — Expected text to compare against.
124
+ - `options.timeout: number (optional, default: 10000ms)` — Time in milliseconds to wait for the clipboard content to match.
125
+ ```ts
126
+ // assert that the clipboard contains the expected text
127
+ await expect(clipboard).toHaveTextContent('Hello, World!');
128
+ ```
129
+ ```ts
130
+ // Custom timeout
131
+ await expect(clipboard).toHaveTextContent('Async copied value', { timeout: 5000 });
132
+ ```
133
+
134
+ ### toHaveJSONContent Matcher
135
+ `expect(clipboard).toHaveJSONContent(expected, options?)`
136
+ Asserts that the clipboard content matches the expected JSON value. Uses Playwright's smart polling mechanism to wait for the clipboard to update.
137
+ - `expected: unknown` — Expected JSON value to compare against.
138
+ - `options.timeout: number (optional, default: 10000ms)` — Time in milliseconds to wait for the clipboard content to match.
139
+ ```ts
140
+ // assert that the clipboard contains the expected JSON data
141
+ await expect(clipboard).toHaveJSONContent({ message: 'Hello, World!' });
142
+ ```
143
+ ```ts
144
+ // Custom timeout
145
+ await expect(clipboard).toHaveJSONContent({ message: 'Async copied value' }, { timeout: 5000 });
146
+ ```
114
147
 
115
148
  ### toHaveData Matcher
149
+ ![NOTE](https://img.shields.io/badge/NOTE-Matcher%20is%20deprecated%20in%20favor%20of%20toHaveTextContent%20and%20toHaveJSONContent-yellow)
150
+
116
151
  `expect(clipboard).toHaveData(expected, options?)`
117
152
 
118
153
  Asserts that the clipboard content matches the expected string or JSON object. Uses Playwright's smart polling mechanism to wait for the clipboard to update.
package/dist/index.cjs CHANGED
@@ -22,8 +22,10 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  ClipboardHandler: () => ClipboardHandler,
24
24
  clipboardFixture: () => clipboardFixture,
25
+ clipboardFixtures: () => clipboardFixtures,
25
26
  clipboardMatchers: () => clipboardMatchers,
26
- expect: () => expect2,
27
+ contextFixture: () => contextFixture,
28
+ expect: () => expect3,
27
29
  firefoxClipboardPrefs: () => firefoxClipboardPrefs,
28
30
  test: () => test
29
31
  });
@@ -40,28 +42,10 @@ var firefoxClipboardPrefs = {
40
42
 
41
43
  // src/utils/clipboardHandler.ts
42
44
  var ClipboardHandler = class {
43
- constructor(page, context, browserName = "chromium") {
45
+ constructor(page) {
44
46
  this.page = page;
45
- this.context = context;
46
- this.browserName = browserName;
47
- this.isPermissionGranted = false;
48
47
  }
49
48
  page;
50
- context;
51
- browserName;
52
- isPermissionGranted;
53
- /**
54
- * Grants clipboard permissions to the Chromium browser context if not already granted.
55
- * @private
56
- */
57
- async grantPermissions() {
58
- if (this.browserName === "chromium") {
59
- if (!this.isPermissionGranted) {
60
- await this.context.grantPermissions(["clipboard-read", "clipboard-write"]);
61
- this.isPermissionGranted = true;
62
- }
63
- }
64
- }
65
49
  /**
66
50
  * Reads the current text content from the browser clipboard.
67
51
  * If the content is a JSON-encoded string (e.g., has extra quotes),
@@ -70,7 +54,6 @@ var ClipboardHandler = class {
70
54
  * @returns A promise that resolves to the clipboard string content.
71
55
  */
72
56
  async read() {
73
- await this.grantPermissions();
74
57
  return await this.page.evaluate(() => navigator.clipboard.readText());
75
58
  }
76
59
  /**
@@ -92,21 +75,35 @@ var ClipboardHandler = class {
92
75
  };
93
76
 
94
77
  // src/fixtures/clipboardFixture.ts
95
- var clipboardFixture = async ({ page, context, browserName }, use) => {
78
+ var clipboardFixture = async ({ page, browserName }, use) => {
96
79
  if (browserName === "webkit") {
97
80
  throw new Error(
98
81
  `[playwright-clipboard] Browser '${browserName}' is not supported. Clipboard API testing is currently supported only in Chromium-based and Firefox browsers.
99
82
  Add test.skip(browserName === 'webkit', 'Clipboard API is only supported in Chromium and Firefox'); to your test body.`
100
83
  );
101
84
  }
102
- const handler = new ClipboardHandler(page, context, browserName);
85
+ const handler = new ClipboardHandler(page);
103
86
  await use(handler);
104
87
  };
105
88
 
89
+ // src/fixtures/contextFixture.ts
90
+ var contextFixture = async ({ context, browserName }, use) => {
91
+ if (browserName === "chromium") {
92
+ await context.grantPermissions(["clipboard-read", "clipboard-write"]);
93
+ }
94
+ await use(context);
95
+ };
96
+
97
+ // src/fixtures/index.ts
98
+ var clipboardFixtures = {
99
+ context: contextFixture,
100
+ clipboard: clipboardFixture
101
+ };
102
+
106
103
  // src/fixtures.ts
107
- var import_test2 = require("@playwright/test");
104
+ var import_test3 = require("@playwright/test");
108
105
 
109
- // src/matchers/toHaveData.ts
106
+ // src/matchers/toHaveJSONContent.ts
110
107
  var import_test = require("@playwright/test");
111
108
 
112
109
  // src/utils/matcherUtils.ts
@@ -125,23 +122,68 @@ ${error.message}`;
125
122
  Received: ${this.utils.printReceived(actual)}`;
126
123
  }
127
124
 
128
- // src/matchers/toHaveData.ts
129
- async function toHaveData(clipboard, expected, options = {}) {
130
- const name = "toHaveData";
125
+ // src/matchers/toHaveJSONContent.ts
126
+ async function toHaveJSONContent(clipboard, expected, options = {}) {
127
+ const name = "toHaveJSONContent";
131
128
  let pass;
132
129
  let actual;
130
+ let errorReason = null;
133
131
  const { timeout = 1e4 } = options;
134
132
  const poll = import_test.expect.poll(
135
133
  async () => {
136
134
  try {
137
135
  actual = await clipboard.readJSON();
138
- } catch {
139
- actual = await clipboard.read();
136
+ errorReason = null;
137
+ return actual;
138
+ } catch (error) {
139
+ errorReason = error instanceof Error ? error : new Error(String(error));
140
+ try {
141
+ actual = await clipboard.read();
142
+ } catch {
143
+ actual = void 0;
144
+ }
145
+ throw errorReason;
140
146
  }
141
- if (typeof expected === "string" && actual !== null && actual !== void 0) {
142
- return String(actual);
147
+ },
148
+ { timeout }
149
+ );
150
+ try {
151
+ const expectation = this.isNot ? poll.not : poll;
152
+ await expectation.toEqual(expected);
153
+ pass = true;
154
+ } catch {
155
+ pass = false;
156
+ }
157
+ if (this.isNot) pass = !pass;
158
+ const matcherReturn = {
159
+ message: getErrorMessage.call(this, name, expected, actual, errorReason),
160
+ pass,
161
+ name,
162
+ expected,
163
+ actual
164
+ };
165
+ return matcherReturn;
166
+ }
167
+
168
+ // src/matchers/toHaveTextContent.ts
169
+ var import_test2 = require("@playwright/test");
170
+ async function toHaveTextContent(clipboard, expected, options = {}) {
171
+ const name = "toHaveTextContent";
172
+ let pass;
173
+ let actual;
174
+ let errorReason = null;
175
+ const { timeout = 1e4 } = options;
176
+ const poll = import_test2.expect.poll(
177
+ async () => {
178
+ try {
179
+ actual = await clipboard.read();
180
+ errorReason = null;
181
+ return actual;
182
+ } catch (error) {
183
+ errorReason = error instanceof Error ? error : new Error(String(error));
184
+ actual = void 0;
185
+ throw errorReason;
143
186
  }
144
- return actual;
145
187
  },
146
188
  { timeout }
147
189
  );
@@ -154,7 +196,7 @@ async function toHaveData(clipboard, expected, options = {}) {
154
196
  }
155
197
  if (this.isNot) pass = !pass;
156
198
  const matcherReturn = {
157
- message: getErrorMessage.call(this, name, expected, actual),
199
+ message: getErrorMessage.call(this, name, expected, actual, errorReason),
158
200
  pass,
159
201
  name,
160
202
  expected,
@@ -163,25 +205,42 @@ async function toHaveData(clipboard, expected, options = {}) {
163
205
  return matcherReturn;
164
206
  }
165
207
 
208
+ // src/matchers/toHaveData.ts
209
+ async function toHaveData(clipboard, expected, options = {}) {
210
+ const name = "toHaveData";
211
+ let matcherReturn = null;
212
+ if (typeof expected === "string") {
213
+ matcherReturn = await toHaveTextContent.call(this, clipboard, expected, options);
214
+ } else {
215
+ matcherReturn = await toHaveJSONContent.call(this, clipboard, expected, options);
216
+ }
217
+ return {
218
+ ...matcherReturn,
219
+ name,
220
+ message: () => {
221
+ const originalMessage = matcherReturn.message();
222
+ return originalMessage.replace("toHaveText", name).replace("toHaveJSON", name);
223
+ }
224
+ };
225
+ }
226
+
166
227
  // src/matchers/clipboardMatchers.ts
167
228
  var clipboardMatchers = {
229
+ toHaveTextContent,
230
+ toHaveJSONContent,
168
231
  toHaveData
169
232
  };
170
233
 
171
234
  // src/fixtures.ts
172
- var test = import_test2.test.extend({
173
- /**
174
- * A fixture that provides an instance of the Clipboard utility for interacting with the system clipboard.
175
- * It allows reading from the clipboard during tests.
176
- */
177
- clipboard: clipboardFixture
178
- });
179
- var expect2 = import_test2.expect.extend({ ...clipboardMatchers });
235
+ var test = import_test3.test.extend(clipboardFixtures);
236
+ var expect3 = import_test3.expect.extend({ ...clipboardMatchers });
180
237
  // Annotate the CommonJS export names for ESM import in node:
181
238
  0 && (module.exports = {
182
239
  ClipboardHandler,
183
240
  clipboardFixture,
241
+ clipboardFixtures,
184
242
  clipboardMatchers,
243
+ contextFixture,
185
244
  expect,
186
245
  firefoxClipboardPrefs,
187
246
  test
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/utils/clipboardHandler.ts","../src/fixtures/clipboardFixture.ts","../src/fixtures.ts","../src/matchers/toHaveData.ts","../src/utils/matcherUtils.ts","../src/matchers/clipboardMatchers.ts"],"sourcesContent":["export { firefoxClipboardPrefs } from './constants.js';\nexport { clipboardFixture } from './fixtures/clipboardFixture.js';\nexport { expect, test } from './fixtures.js';\nexport { clipboardMatchers } from './matchers/clipboardMatchers.js';\nexport { ClipboardHandler } from './utils/clipboardHandler.js';\n","export const firefoxClipboardPrefs = {\n 'dom.events.testing.asyncClipboard': true,\n 'dom.events.asyncClipboard.readText': true,\n 'dom.events.asyncClipboard.writeText': true,\n 'permissions.default.clipboard-read': 1,\n 'permissions.default.clipboard-write': 1,\n};\n","/**\n * Playwright-compatible Clipboard utilities.\n *\n * Core functions for interacting with the browser clipboard within Playwright tests.\n * Provides wrappers for reading plain text and JSON.\n *\n * @remarks\n * These utilities require 'clipboard-read' and 'clipboard-write' permissions\n * to be granted in the browser context.\n */\n\nimport type { BrowserContext, Page } from '@playwright/test';\nimport type { BrowserName } from '../types.js';\n\nexport class ClipboardHandler {\n private readonly browserName: BrowserName;\n private isPermissionGranted: boolean;\n\n constructor(\n private readonly page: Page,\n private readonly context: BrowserContext,\n browserName: BrowserName = 'chromium',\n ) {\n this.browserName = browserName;\n this.isPermissionGranted = false;\n }\n\n /**\n * Grants clipboard permissions to the Chromium browser context if not already granted.\n * @private\n */\n private async grantPermissions() {\n if (this.browserName === 'chromium') {\n if (!this.isPermissionGranted) {\n await this.context.grantPermissions(['clipboard-read', 'clipboard-write']);\n this.isPermissionGranted = true;\n }\n }\n }\n\n /**\n * Reads the current text content from the browser clipboard.\n * If the content is a JSON-encoded string (e.g., has extra quotes),\n * it will be returned as is. Use readJSON for automatic parsing.\n *\n * @returns A promise that resolves to the clipboard string content.\n */\n async read(): Promise<string> {\n await this.grantPermissions();\n return await this.page.evaluate(() => navigator.clipboard.readText());\n }\n\n /**\n * Reads the clipboard content and parses it as JSON.\n * If the content is a string literal (e.g., '\"value\"'), it returns the unwrapped string ('value').\n *\n * @template T - The expected type of the parsed JSON object.\n * @returns A promise that resolves to the parsed JSON object of type T.\n * @throws {Error} If the clipboard content is not a valid JSON string.\n */\n async readJSON<T = unknown>(): Promise<T> {\n const text = await this.read();\n try {\n return JSON.parse(text);\n } catch {\n throw new Error(`Clipboard content is not a valid JSON: ${JSON.stringify(text)}`);\n }\n }\n}\n","import type { BrowserContext, Page, TestFixture } from '@playwright/test';\nimport type { BrowserName } from '../types.js';\nimport { ClipboardHandler } from '../utils/clipboardHandler.js';\n\n/**\n * A fixture that provides an instance of the Clipboard utility for interacting with the system clipboard.\n * It allows reading from the clipboard during tests.\n */\nexport const clipboardFixture: TestFixture<\n ClipboardHandler,\n { page: Page; context: BrowserContext; browserName: BrowserName }\n> = async ({ page, context, browserName }, use) => {\n if (browserName === 'webkit') {\n throw new Error(\n `[playwright-clipboard] Browser '${browserName}' is not supported. ` +\n 'Clipboard API testing is currently supported only in Chromium-based and Firefox browsers.\\n' +\n `Add test.skip(browserName === 'webkit', 'Clipboard API is only supported in Chromium and Firefox'); to your test body.`,\n );\n }\n\n const handler = new ClipboardHandler(page, context, browserName);\n await use(handler);\n};\n","import { expect as baseExpect, test as baseTest } from '@playwright/test';\nimport { clipboardFixture } from './fixtures/clipboardFixture.js';\nimport { clipboardMatchers } from './matchers/clipboardMatchers.js';\nimport type { ClipboardHandler } from './utils/clipboardHandler.js';\n\nexport const test = baseTest.extend<{\n clipboard: ClipboardHandler;\n}>({\n /**\n * A fixture that provides an instance of the Clipboard utility for interacting with the system clipboard.\n * It allows reading from the clipboard during tests.\n */\n clipboard: clipboardFixture,\n});\n\nexport const expect = baseExpect.extend({ ...clipboardMatchers });\n","import { type ExpectMatcherState, expect, type MatcherReturnType } from '@playwright/test';\nimport type { ClipboardHandler } from '../utils/clipboardHandler.js';\nimport { getErrorMessage } from '../utils/matcherUtils.js';\nimport type { MatcherOptions } from './types.js';\n\n/**\n * Asserts that the clipboard content matches the expected value.\n *\n * @this ExpectMatcherState\n * @param clipboard The Clipboard utility instance.\n * @param expected The string or object to compare against the clipboard content.\n * @param options Optional settings for the matcher, such as timeout.\n * @returns A Promise that resolves to a MatcherReturnType object.\n */\nexport async function toHaveData(\n this: ExpectMatcherState,\n clipboard: ClipboardHandler,\n expected: unknown,\n options: MatcherOptions = {},\n) {\n const name = 'toHaveData';\n let pass: boolean;\n let actual: unknown;\n\n const { timeout = 10_000 } = options;\n\n const poll = expect.poll(\n async () => {\n try {\n actual = await clipboard.readJSON();\n } catch {\n actual = await clipboard.read();\n }\n\n if (typeof expected === 'string' && actual !== null && actual !== undefined) {\n return String(actual);\n }\n\n return actual;\n },\n { timeout },\n );\n\n try {\n const expectation = this.isNot ? poll.not : poll;\n await expectation.toEqual(expected);\n pass = true;\n } catch {\n pass = false;\n }\n\n if (this.isNot) pass = !pass;\n\n const matcherReturn: MatcherReturnType = {\n message: getErrorMessage.call(this, name, expected, actual),\n pass,\n name,\n expected,\n actual,\n };\n\n return matcherReturn;\n}\n","import type { ExpectMatcherState } from '@playwright/test';\n\n/**\n * Generates an error message for a custom matcher.\n *\n * @this ExpectMatcherState\n * @param name The name of the matcher.\n * @param expected The expected value.\n * @param actual The actual value.\n * @param error An optional error object.\n * @param errorMessage An optional error message string.\n * @returns A function that returns the error message string.\n */\nexport function getErrorMessage(\n this: ExpectMatcherState,\n name: string,\n expected: unknown,\n actual: unknown,\n error?: Error | null,\n errorMessage?: string | undefined | null,\n): () => string {\n const message = `${this.utils.matcherHint(name, undefined, undefined, { isNot: this.isNot })}\\n\\n`;\n\n if (error) {\n return () => `${message}An unexpected error occurred:\\n${error.message}`;\n }\n\n if (errorMessage) {\n return () => `${message}${errorMessage}`;\n }\n\n return () =>\n message +\n `Expected: ${this.isNot ? 'not ' : ''}${this.utils.printExpected(expected)}\\n` +\n `Received: ${this.utils.printReceived(actual)}`;\n}\n","import { toHaveData } from './toHaveData.js';\n\n/**\n * Export an object containing all the custom clipboard matchers for Playwright.\n */\nexport const clipboardMatchers = {\n toHaveData,\n};\n"],"mappings":"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","names":["expect","import_test","baseTest","expect","baseExpect"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/utils/clipboardHandler.ts","../src/fixtures/clipboardFixture.ts","../src/fixtures/contextFixture.ts","../src/fixtures/index.ts","../src/fixtures.ts","../src/matchers/toHaveJSONContent.ts","../src/utils/matcherUtils.ts","../src/matchers/toHaveTextContent.ts","../src/matchers/toHaveData.ts","../src/matchers/clipboardMatchers.ts"],"sourcesContent":["export { firefoxClipboardPrefs } from './constants.js';\nexport { clipboardFixture, clipboardFixtures, contextFixture } from './fixtures/index.js';\nexport { expect, test } from './fixtures.js';\nexport { clipboardMatchers } from './matchers/index.js';\nexport { ClipboardHandler } from './utils/index.js';\n","export const firefoxClipboardPrefs = {\n 'dom.events.testing.asyncClipboard': true,\n 'dom.events.asyncClipboard.readText': true,\n 'dom.events.asyncClipboard.writeText': true,\n 'permissions.default.clipboard-read': 1,\n 'permissions.default.clipboard-write': 1,\n};\n","/**\n * Playwright-compatible Clipboard utilities.\n *\n * Core functions for interacting with the browser clipboard within Playwright tests.\n * Provides wrappers for reading plain text and JSON.\n *\n * @remarks\n * These utilities require 'clipboard-read' and 'clipboard-write' permissions\n * to be granted in the browser context.\n */\n\nimport type { Page } from '@playwright/test';\n\nexport class ClipboardHandler {\n constructor(private readonly page: Page) {}\n\n /**\n * Reads the current text content from the browser clipboard.\n * If the content is a JSON-encoded string (e.g., has extra quotes),\n * it will be returned as is. Use readJSON for automatic parsing.\n *\n * @returns A promise that resolves to the clipboard string content.\n */\n async read(): Promise<string> {\n return await this.page.evaluate(() => navigator.clipboard.readText());\n }\n\n /**\n * Reads the clipboard content and parses it as JSON.\n * If the content is a string literal (e.g., '\"value\"'), it returns the unwrapped string ('value').\n *\n * @template T - The expected type of the parsed JSON object.\n * @returns A promise that resolves to the parsed JSON object of type T.\n * @throws {Error} If the clipboard content is not a valid JSON string.\n */\n async readJSON<T = unknown>(): Promise<T> {\n const text = await this.read();\n try {\n return JSON.parse(text);\n } catch {\n throw new Error(`Clipboard content is not a valid JSON: ${JSON.stringify(text)}`);\n }\n }\n}\n","import type { Page, TestFixture } from '@playwright/test';\nimport type { BrowserName } from '../types.js';\nimport { ClipboardHandler } from '../utils/index.js';\n\n/**\n * A fixture that provides an instance of the Clipboard utility for interacting with the system clipboard.\n * It allows reading from the clipboard during tests.\n */\nexport const clipboardFixture: TestFixture<\n ClipboardHandler,\n { page: Page; browserName: BrowserName }\n> = async ({ page, browserName }, use) => {\n if (browserName === 'webkit') {\n throw new Error(\n `[playwright-clipboard] Browser '${browserName}' is not supported. ` +\n 'Clipboard API testing is currently supported only in Chromium-based and Firefox browsers.\\n' +\n `Add test.skip(browserName === 'webkit', 'Clipboard API is only supported in Chromium and Firefox'); to your test body.`,\n );\n }\n\n const handler = new ClipboardHandler(page);\n await use(handler);\n};\n","import type { BrowserContext, TestFixture } from '@playwright/test';\nimport type { BrowserName } from '../types.js';\n\n/**\n * A fixture that provides a BrowserContext with clipboard permissions granted for Chromium browsers.\n */\nexport const contextFixture: TestFixture<\n BrowserContext,\n { context: BrowserContext; browserName: BrowserName }\n> = async ({ context, browserName }, use) => {\n if (browserName === 'chromium') {\n await context.grantPermissions(['clipboard-read', 'clipboard-write']);\n }\n\n await use(context);\n};\n","import { clipboardFixture } from './clipboardFixture.js';\nimport { contextFixture } from './contextFixture.js';\n\n/**\n * A collection of fixtures related to clipboard testing, including the clipboard fixture and context fixture.\n * These fixtures can be used in Playwright tests to facilitate clipboard interactions and context management.\n */\nexport const clipboardFixtures = {\n context: contextFixture,\n clipboard: clipboardFixture,\n};\n\nexport { clipboardFixture, contextFixture };\n","import { expect as baseExpect, test as baseTest } from '@playwright/test';\nimport { clipboardFixtures } from './fixtures/index.js';\nimport { clipboardMatchers } from './matchers/index.js';\nimport type { ClipboardHandler } from './utils/index.js';\n\nexport const test = baseTest.extend<{\n clipboard: ClipboardHandler;\n}>(clipboardFixtures);\n\nexport const expect = baseExpect.extend({ ...clipboardMatchers });\n","import type { ExpectMatcherState, MatcherReturnType } from '@playwright/test';\nimport { expect } from '@playwright/test';\nimport type { ClipboardHandler } from '../utils/clipboardHandler.js';\nimport { getErrorMessage } from '../utils/matcherUtils.js';\nimport type { MatcherOptions } from './types.js';\n\n/**\n * Asserts that the clipboard content matches the expected JSON value.\n *\n * @this ExpectMatcherState\n * @param clipboard The Clipboard utility instance.\n * @param expected The expected JSON value.\n * @param options Matcher options.\n * @returns A Promise that resolves to a MatcherReturnType object.\n */\nexport async function toHaveJSONContent(\n this: ExpectMatcherState,\n clipboard: ClipboardHandler,\n expected: unknown,\n options: MatcherOptions = {},\n) {\n const name = 'toHaveJSONContent';\n let pass: boolean;\n let actual: unknown;\n let errorReason: Error | null = null;\n\n const { timeout = 10_000 } = options;\n\n const poll = expect.poll(\n async () => {\n try {\n actual = await clipboard.readJSON();\n errorReason = null;\n return actual;\n } catch (error) {\n errorReason = error instanceof Error ? error : new Error(String(error));\n\n try {\n actual = await clipboard.read();\n } catch {\n actual = undefined;\n }\n\n throw errorReason;\n }\n },\n { timeout },\n );\n\n try {\n const expectation = this.isNot ? poll.not : poll;\n await expectation.toEqual(expected);\n pass = true;\n } catch {\n pass = false;\n }\n\n if (this.isNot) pass = !pass;\n\n const matcherReturn: MatcherReturnType = {\n message: getErrorMessage.call(this, name, expected, actual, errorReason),\n pass,\n name,\n expected,\n actual,\n };\n\n return matcherReturn;\n}\n","import type { ExpectMatcherState } from '@playwright/test';\n\n/**\n * Generates an error message for a custom matcher.\n *\n * @this ExpectMatcherState\n * @param name The name of the matcher.\n * @param expected The expected value.\n * @param actual The actual value.\n * @param error An optional error object.\n * @param errorMessage An optional error message string.\n * @returns A function that returns the error message string.\n */\nexport function getErrorMessage(\n this: ExpectMatcherState,\n name: string,\n expected: unknown,\n actual: unknown,\n error?: Error | null,\n errorMessage?: string | undefined | null,\n): () => string {\n const message = `${this.utils.matcherHint(name, undefined, undefined, { isNot: this.isNot })}\\n\\n`;\n\n if (error) {\n return () => `${message}An unexpected error occurred:\\n${error.message}`;\n }\n\n if (errorMessage) {\n return () => `${message}${errorMessage}`;\n }\n\n return () =>\n message +\n `Expected: ${this.isNot ? 'not ' : ''}${this.utils.printExpected(expected)}\\n` +\n `Received: ${this.utils.printReceived(actual)}`;\n}\n","import { type ExpectMatcherState, expect, type MatcherReturnType } from '@playwright/test';\nimport type { ClipboardHandler } from '../utils/clipboardHandler.js';\nimport { getErrorMessage } from '../utils/matcherUtils.js';\nimport type { MatcherOptions } from './types.js';\n\n/**\n * Asserts that the clipboard content matches the expected text value.\n *\n * @this ExpectMatcherState\n * @param clipboard The Clipboard utility instance.\n * @param expected The expected text value.\n * @param options Matcher options.\n * @returns A Promise that resolves to a MatcherReturnType object.\n */\nexport async function toHaveTextContent(\n this: ExpectMatcherState,\n clipboard: ClipboardHandler,\n expected: string,\n options: MatcherOptions = {},\n) {\n const name = 'toHaveTextContent';\n let pass: boolean;\n let actual: unknown;\n let errorReason: Error | null = null;\n\n const { timeout = 10_000 } = options;\n\n const poll = expect.poll(\n async () => {\n try {\n actual = await clipboard.read();\n errorReason = null;\n return actual;\n } catch (error) {\n errorReason = error instanceof Error ? error : new Error(String(error));\n actual = undefined;\n\n throw errorReason;\n }\n },\n { timeout },\n );\n\n try {\n const expectation = this.isNot ? poll.not : poll;\n await expectation.toEqual(expected);\n pass = true;\n } catch {\n pass = false;\n }\n\n if (this.isNot) pass = !pass;\n\n const matcherReturn: MatcherReturnType = {\n message: getErrorMessage.call(this, name, expected, actual, errorReason),\n pass,\n name,\n expected,\n actual,\n };\n\n return matcherReturn;\n}\n","import type { ExpectMatcherState, MatcherReturnType } from '@playwright/test';\nimport type { ClipboardHandler } from '../utils/clipboardHandler.js';\nimport { toHaveJSONContent } from './toHaveJSONContent.js';\nimport { toHaveTextContent } from './toHaveTextContent.js';\nimport type { MatcherOptions } from './types.js';\n\n/**\n * Asserts that the clipboard content matches the expected value.\n * Uses smart polling to wait for the clipboard to be updated.\n * If the `expected` value is an object, it attempts to parse the clipboard\n * content as JSON before comparing.\n *\n * @this ExpectMatcherState\n * @param clipboard The Clipboard utility instance.\n * @param expected The string or object to compare against the clipboard content.\n * @param options Optional settings for the matcher, such as timeout.\n * @returns A Promise that resolves to a MatcherReturnType object.\n */\nexport async function toHaveData(\n this: ExpectMatcherState,\n clipboard: ClipboardHandler,\n expected: unknown,\n options: MatcherOptions = {},\n) {\n const name = 'toHaveData';\n let matcherReturn: MatcherReturnType | null = null;\n\n if (typeof expected === 'string') {\n matcherReturn = await toHaveTextContent.call(this, clipboard, expected, options);\n } else {\n matcherReturn = await toHaveJSONContent.call(this, clipboard, expected, options);\n }\n\n return {\n ...matcherReturn,\n name,\n message: () => {\n const originalMessage = matcherReturn.message();\n return originalMessage.replace('toHaveText', name).replace('toHaveJSON', name);\n },\n };\n}\n","import { toHaveData } from './toHaveData.js';\nimport { toHaveJSONContent } from './toHaveJSONContent.js';\nimport { toHaveTextContent } from './toHaveTextContent.js';\n\n/**\n * Export an object containing all the custom clipboard matchers for Playwright.\n */\nexport const clipboardMatchers = {\n toHaveTextContent,\n toHaveJSONContent,\n toHaveData,\n};\n"],"mappings":"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","names":["expect","import_test","import_test","baseTest","expect","baseExpect"]}
package/dist/index.d.cts CHANGED
@@ -1,5 +1,7 @@
1
+ import * as playwright_test from 'playwright/test';
2
+ import * as playwright_core from 'playwright-core';
1
3
  import * as _playwright_test from '@playwright/test';
2
- import { Page, BrowserContext, TestFixture, ExpectMatcherState, MatcherReturnType } from '@playwright/test';
4
+ import { Page, TestFixture, BrowserContext, ExpectMatcherState, MatcherReturnType } from '@playwright/test';
3
5
 
4
6
  declare const firefoxClipboardPrefs: {
5
7
  'dom.events.testing.asyncClipboard': boolean;
@@ -24,15 +26,7 @@ type BrowserName = 'chromium' | 'firefox' | 'webkit';
24
26
 
25
27
  declare class ClipboardHandler {
26
28
  private readonly page;
27
- private readonly context;
28
- private readonly browserName;
29
- private isPermissionGranted;
30
- constructor(page: Page, context: BrowserContext, browserName?: BrowserName);
31
- /**
32
- * Grants clipboard permissions to the Chromium browser context if not already granted.
33
- * @private
34
- */
35
- private grantPermissions;
29
+ constructor(page: Page);
36
30
  /**
37
31
  * Reads the current text content from the browser clipboard.
38
32
  * If the content is a JSON-encoded string (e.g., has extra quotes),
@@ -58,22 +52,70 @@ declare class ClipboardHandler {
58
52
  */
59
53
  declare const clipboardFixture: TestFixture<ClipboardHandler, {
60
54
  page: Page;
55
+ browserName: BrowserName;
56
+ }>;
57
+
58
+ /**
59
+ * A fixture that provides a BrowserContext with clipboard permissions granted for Chromium browsers.
60
+ */
61
+ declare const contextFixture: TestFixture<BrowserContext, {
61
62
  context: BrowserContext;
62
63
  browserName: BrowserName;
63
64
  }>;
64
65
 
66
+ /**
67
+ * A collection of fixtures related to clipboard testing, including the clipboard fixture and context fixture.
68
+ * These fixtures can be used in Playwright tests to facilitate clipboard interactions and context management.
69
+ */
70
+ declare const clipboardFixtures: {
71
+ context: playwright_test.TestFixture<playwright_core.BrowserContext, {
72
+ context: playwright_core.BrowserContext;
73
+ browserName: BrowserName;
74
+ }>;
75
+ clipboard: playwright_test.TestFixture<ClipboardHandler, {
76
+ page: playwright_core.Page;
77
+ browserName: BrowserName;
78
+ }>;
79
+ };
80
+
65
81
  type MatcherOptions = {
66
82
  timeout?: number;
67
83
  };
68
84
  declare global {
69
85
  namespace PlaywrightTest {
70
86
  interface Matchers<R> {
87
+ /**
88
+ * Asserts that the clipboard content matches the expected text.
89
+ * Uses smart polling to wait for the clipboard to be updated.
90
+ *
91
+ * @param expected The string to compare against the clipboard content.
92
+ * @param options Matcher options.
93
+ * @returns A Promise that resolves when the assertion completes.
94
+ *
95
+ * @example
96
+ * await expect(clipboard).toHaveText('Copied value');
97
+ */
98
+ toHaveTextContent(expected: string, options?: MatcherOptions): Promise<R>;
99
+ /**
100
+ * Asserts that the clipboard content matches the expected JSON value.
101
+ * Uses smart polling to wait for the clipboard to be updated.
102
+ *
103
+ * @param expected The JSON value to compare against the clipboard content.
104
+ * @param options Matcher options.
105
+ * @returns A Promise that resolves when the assertion completes.
106
+ *
107
+ * @example
108
+ * await expect(clipboard).toHaveJSON({ id: 123, status: 'success' });
109
+ */
110
+ toHaveJSONContent(expected: unknown, options?: MatcherOptions): Promise<R>;
71
111
  /**
72
112
  * Asserts that the clipboard content matches the expected value.
73
113
  * Uses smart polling to wait for the clipboard to be updated.
74
114
  * If the `expected` value is an object, it attempts to parse the clipboard
75
115
  * content as JSON before comparing.
76
116
  *
117
+ * @deprecated Use `toHaveText` or `toHaveJSON` instead. This matcher will be removed in future versions.
118
+ *
77
119
  * @param expected The string or object to compare against the clipboard content.
78
120
  * @param options Optional settings for the matcher, such as timeout.
79
121
  * @returns A Promise that resolves when the assertion completes.
@@ -89,6 +131,9 @@ declare global {
89
131
 
90
132
  /**
91
133
  * Asserts that the clipboard content matches the expected value.
134
+ * Uses smart polling to wait for the clipboard to be updated.
135
+ * If the `expected` value is an object, it attempts to parse the clipboard
136
+ * content as JSON before comparing.
92
137
  *
93
138
  * @this ExpectMatcherState
94
139
  * @param clipboard The Clipboard utility instance.
@@ -96,12 +141,44 @@ declare global {
96
141
  * @param options Optional settings for the matcher, such as timeout.
97
142
  * @returns A Promise that resolves to a MatcherReturnType object.
98
143
  */
99
- declare function toHaveData(this: ExpectMatcherState, clipboard: ClipboardHandler, expected: unknown, options?: MatcherOptions): Promise<MatcherReturnType>;
144
+ declare function toHaveData(this: ExpectMatcherState, clipboard: ClipboardHandler, expected: unknown, options?: MatcherOptions): Promise<{
145
+ name: string;
146
+ message: () => string;
147
+ pass: boolean;
148
+ expected?: unknown;
149
+ actual?: any;
150
+ log?: string[];
151
+ timeout?: number;
152
+ }>;
153
+
154
+ /**
155
+ * Asserts that the clipboard content matches the expected JSON value.
156
+ *
157
+ * @this ExpectMatcherState
158
+ * @param clipboard The Clipboard utility instance.
159
+ * @param expected The expected JSON value.
160
+ * @param options Matcher options.
161
+ * @returns A Promise that resolves to a MatcherReturnType object.
162
+ */
163
+ declare function toHaveJSONContent(this: ExpectMatcherState, clipboard: ClipboardHandler, expected: unknown, options?: MatcherOptions): Promise<MatcherReturnType>;
164
+
165
+ /**
166
+ * Asserts that the clipboard content matches the expected text value.
167
+ *
168
+ * @this ExpectMatcherState
169
+ * @param clipboard The Clipboard utility instance.
170
+ * @param expected The expected text value.
171
+ * @param options Matcher options.
172
+ * @returns A Promise that resolves to a MatcherReturnType object.
173
+ */
174
+ declare function toHaveTextContent(this: ExpectMatcherState, clipboard: ClipboardHandler, expected: string, options?: MatcherOptions): Promise<MatcherReturnType>;
100
175
 
101
176
  declare const test: _playwright_test.TestType<_playwright_test.PlaywrightTestArgs & _playwright_test.PlaywrightTestOptions & {
102
177
  clipboard: ClipboardHandler;
103
178
  }, _playwright_test.PlaywrightWorkerArgs & _playwright_test.PlaywrightWorkerOptions>;
104
179
  declare const expect: _playwright_test.Expect<{
180
+ toHaveTextContent: typeof toHaveTextContent;
181
+ toHaveJSONContent: typeof toHaveJSONContent;
105
182
  toHaveData: typeof toHaveData;
106
183
  }>;
107
184
 
@@ -109,7 +186,9 @@ declare const expect: _playwright_test.Expect<{
109
186
  * Export an object containing all the custom clipboard matchers for Playwright.
110
187
  */
111
188
  declare const clipboardMatchers: {
189
+ toHaveTextContent: typeof toHaveTextContent;
190
+ toHaveJSONContent: typeof toHaveJSONContent;
112
191
  toHaveData: typeof toHaveData;
113
192
  };
114
193
 
115
- export { ClipboardHandler, clipboardFixture, clipboardMatchers, expect, firefoxClipboardPrefs, test };
194
+ export { ClipboardHandler, clipboardFixture, clipboardFixtures, clipboardMatchers, contextFixture, expect, firefoxClipboardPrefs, test };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,7 @@
1
+ import * as playwright_test from 'playwright/test';
2
+ import * as playwright_core from 'playwright-core';
1
3
  import * as _playwright_test from '@playwright/test';
2
- import { Page, BrowserContext, TestFixture, ExpectMatcherState, MatcherReturnType } from '@playwright/test';
4
+ import { Page, TestFixture, BrowserContext, ExpectMatcherState, MatcherReturnType } from '@playwright/test';
3
5
 
4
6
  declare const firefoxClipboardPrefs: {
5
7
  'dom.events.testing.asyncClipboard': boolean;
@@ -24,15 +26,7 @@ type BrowserName = 'chromium' | 'firefox' | 'webkit';
24
26
 
25
27
  declare class ClipboardHandler {
26
28
  private readonly page;
27
- private readonly context;
28
- private readonly browserName;
29
- private isPermissionGranted;
30
- constructor(page: Page, context: BrowserContext, browserName?: BrowserName);
31
- /**
32
- * Grants clipboard permissions to the Chromium browser context if not already granted.
33
- * @private
34
- */
35
- private grantPermissions;
29
+ constructor(page: Page);
36
30
  /**
37
31
  * Reads the current text content from the browser clipboard.
38
32
  * If the content is a JSON-encoded string (e.g., has extra quotes),
@@ -58,22 +52,70 @@ declare class ClipboardHandler {
58
52
  */
59
53
  declare const clipboardFixture: TestFixture<ClipboardHandler, {
60
54
  page: Page;
55
+ browserName: BrowserName;
56
+ }>;
57
+
58
+ /**
59
+ * A fixture that provides a BrowserContext with clipboard permissions granted for Chromium browsers.
60
+ */
61
+ declare const contextFixture: TestFixture<BrowserContext, {
61
62
  context: BrowserContext;
62
63
  browserName: BrowserName;
63
64
  }>;
64
65
 
66
+ /**
67
+ * A collection of fixtures related to clipboard testing, including the clipboard fixture and context fixture.
68
+ * These fixtures can be used in Playwright tests to facilitate clipboard interactions and context management.
69
+ */
70
+ declare const clipboardFixtures: {
71
+ context: playwright_test.TestFixture<playwright_core.BrowserContext, {
72
+ context: playwright_core.BrowserContext;
73
+ browserName: BrowserName;
74
+ }>;
75
+ clipboard: playwright_test.TestFixture<ClipboardHandler, {
76
+ page: playwright_core.Page;
77
+ browserName: BrowserName;
78
+ }>;
79
+ };
80
+
65
81
  type MatcherOptions = {
66
82
  timeout?: number;
67
83
  };
68
84
  declare global {
69
85
  namespace PlaywrightTest {
70
86
  interface Matchers<R> {
87
+ /**
88
+ * Asserts that the clipboard content matches the expected text.
89
+ * Uses smart polling to wait for the clipboard to be updated.
90
+ *
91
+ * @param expected The string to compare against the clipboard content.
92
+ * @param options Matcher options.
93
+ * @returns A Promise that resolves when the assertion completes.
94
+ *
95
+ * @example
96
+ * await expect(clipboard).toHaveText('Copied value');
97
+ */
98
+ toHaveTextContent(expected: string, options?: MatcherOptions): Promise<R>;
99
+ /**
100
+ * Asserts that the clipboard content matches the expected JSON value.
101
+ * Uses smart polling to wait for the clipboard to be updated.
102
+ *
103
+ * @param expected The JSON value to compare against the clipboard content.
104
+ * @param options Matcher options.
105
+ * @returns A Promise that resolves when the assertion completes.
106
+ *
107
+ * @example
108
+ * await expect(clipboard).toHaveJSON({ id: 123, status: 'success' });
109
+ */
110
+ toHaveJSONContent(expected: unknown, options?: MatcherOptions): Promise<R>;
71
111
  /**
72
112
  * Asserts that the clipboard content matches the expected value.
73
113
  * Uses smart polling to wait for the clipboard to be updated.
74
114
  * If the `expected` value is an object, it attempts to parse the clipboard
75
115
  * content as JSON before comparing.
76
116
  *
117
+ * @deprecated Use `toHaveText` or `toHaveJSON` instead. This matcher will be removed in future versions.
118
+ *
77
119
  * @param expected The string or object to compare against the clipboard content.
78
120
  * @param options Optional settings for the matcher, such as timeout.
79
121
  * @returns A Promise that resolves when the assertion completes.
@@ -89,6 +131,9 @@ declare global {
89
131
 
90
132
  /**
91
133
  * Asserts that the clipboard content matches the expected value.
134
+ * Uses smart polling to wait for the clipboard to be updated.
135
+ * If the `expected` value is an object, it attempts to parse the clipboard
136
+ * content as JSON before comparing.
92
137
  *
93
138
  * @this ExpectMatcherState
94
139
  * @param clipboard The Clipboard utility instance.
@@ -96,12 +141,44 @@ declare global {
96
141
  * @param options Optional settings for the matcher, such as timeout.
97
142
  * @returns A Promise that resolves to a MatcherReturnType object.
98
143
  */
99
- declare function toHaveData(this: ExpectMatcherState, clipboard: ClipboardHandler, expected: unknown, options?: MatcherOptions): Promise<MatcherReturnType>;
144
+ declare function toHaveData(this: ExpectMatcherState, clipboard: ClipboardHandler, expected: unknown, options?: MatcherOptions): Promise<{
145
+ name: string;
146
+ message: () => string;
147
+ pass: boolean;
148
+ expected?: unknown;
149
+ actual?: any;
150
+ log?: string[];
151
+ timeout?: number;
152
+ }>;
153
+
154
+ /**
155
+ * Asserts that the clipboard content matches the expected JSON value.
156
+ *
157
+ * @this ExpectMatcherState
158
+ * @param clipboard The Clipboard utility instance.
159
+ * @param expected The expected JSON value.
160
+ * @param options Matcher options.
161
+ * @returns A Promise that resolves to a MatcherReturnType object.
162
+ */
163
+ declare function toHaveJSONContent(this: ExpectMatcherState, clipboard: ClipboardHandler, expected: unknown, options?: MatcherOptions): Promise<MatcherReturnType>;
164
+
165
+ /**
166
+ * Asserts that the clipboard content matches the expected text value.
167
+ *
168
+ * @this ExpectMatcherState
169
+ * @param clipboard The Clipboard utility instance.
170
+ * @param expected The expected text value.
171
+ * @param options Matcher options.
172
+ * @returns A Promise that resolves to a MatcherReturnType object.
173
+ */
174
+ declare function toHaveTextContent(this: ExpectMatcherState, clipboard: ClipboardHandler, expected: string, options?: MatcherOptions): Promise<MatcherReturnType>;
100
175
 
101
176
  declare const test: _playwright_test.TestType<_playwright_test.PlaywrightTestArgs & _playwright_test.PlaywrightTestOptions & {
102
177
  clipboard: ClipboardHandler;
103
178
  }, _playwright_test.PlaywrightWorkerArgs & _playwright_test.PlaywrightWorkerOptions>;
104
179
  declare const expect: _playwright_test.Expect<{
180
+ toHaveTextContent: typeof toHaveTextContent;
181
+ toHaveJSONContent: typeof toHaveJSONContent;
105
182
  toHaveData: typeof toHaveData;
106
183
  }>;
107
184
 
@@ -109,7 +186,9 @@ declare const expect: _playwright_test.Expect<{
109
186
  * Export an object containing all the custom clipboard matchers for Playwright.
110
187
  */
111
188
  declare const clipboardMatchers: {
189
+ toHaveTextContent: typeof toHaveTextContent;
190
+ toHaveJSONContent: typeof toHaveJSONContent;
112
191
  toHaveData: typeof toHaveData;
113
192
  };
114
193
 
115
- export { ClipboardHandler, clipboardFixture, clipboardMatchers, expect, firefoxClipboardPrefs, test };
194
+ export { ClipboardHandler, clipboardFixture, clipboardFixtures, clipboardMatchers, contextFixture, expect, firefoxClipboardPrefs, test };
package/dist/index.js CHANGED
@@ -9,28 +9,10 @@ var firefoxClipboardPrefs = {
9
9
 
10
10
  // src/utils/clipboardHandler.ts
11
11
  var ClipboardHandler = class {
12
- constructor(page, context, browserName = "chromium") {
12
+ constructor(page) {
13
13
  this.page = page;
14
- this.context = context;
15
- this.browserName = browserName;
16
- this.isPermissionGranted = false;
17
14
  }
18
15
  page;
19
- context;
20
- browserName;
21
- isPermissionGranted;
22
- /**
23
- * Grants clipboard permissions to the Chromium browser context if not already granted.
24
- * @private
25
- */
26
- async grantPermissions() {
27
- if (this.browserName === "chromium") {
28
- if (!this.isPermissionGranted) {
29
- await this.context.grantPermissions(["clipboard-read", "clipboard-write"]);
30
- this.isPermissionGranted = true;
31
- }
32
- }
33
- }
34
16
  /**
35
17
  * Reads the current text content from the browser clipboard.
36
18
  * If the content is a JSON-encoded string (e.g., has extra quotes),
@@ -39,7 +21,6 @@ var ClipboardHandler = class {
39
21
  * @returns A promise that resolves to the clipboard string content.
40
22
  */
41
23
  async read() {
42
- await this.grantPermissions();
43
24
  return await this.page.evaluate(() => navigator.clipboard.readText());
44
25
  }
45
26
  /**
@@ -61,21 +42,35 @@ var ClipboardHandler = class {
61
42
  };
62
43
 
63
44
  // src/fixtures/clipboardFixture.ts
64
- var clipboardFixture = async ({ page, context, browserName }, use) => {
45
+ var clipboardFixture = async ({ page, browserName }, use) => {
65
46
  if (browserName === "webkit") {
66
47
  throw new Error(
67
48
  `[playwright-clipboard] Browser '${browserName}' is not supported. Clipboard API testing is currently supported only in Chromium-based and Firefox browsers.
68
49
  Add test.skip(browserName === 'webkit', 'Clipboard API is only supported in Chromium and Firefox'); to your test body.`
69
50
  );
70
51
  }
71
- const handler = new ClipboardHandler(page, context, browserName);
52
+ const handler = new ClipboardHandler(page);
72
53
  await use(handler);
73
54
  };
74
55
 
56
+ // src/fixtures/contextFixture.ts
57
+ var contextFixture = async ({ context, browserName }, use) => {
58
+ if (browserName === "chromium") {
59
+ await context.grantPermissions(["clipboard-read", "clipboard-write"]);
60
+ }
61
+ await use(context);
62
+ };
63
+
64
+ // src/fixtures/index.ts
65
+ var clipboardFixtures = {
66
+ context: contextFixture,
67
+ clipboard: clipboardFixture
68
+ };
69
+
75
70
  // src/fixtures.ts
76
71
  import { expect as baseExpect, test as baseTest } from "@playwright/test";
77
72
 
78
- // src/matchers/toHaveData.ts
73
+ // src/matchers/toHaveJSONContent.ts
79
74
  import { expect } from "@playwright/test";
80
75
 
81
76
  // src/utils/matcherUtils.ts
@@ -94,23 +89,68 @@ ${error.message}`;
94
89
  Received: ${this.utils.printReceived(actual)}`;
95
90
  }
96
91
 
97
- // src/matchers/toHaveData.ts
98
- async function toHaveData(clipboard, expected, options = {}) {
99
- const name = "toHaveData";
92
+ // src/matchers/toHaveJSONContent.ts
93
+ async function toHaveJSONContent(clipboard, expected, options = {}) {
94
+ const name = "toHaveJSONContent";
100
95
  let pass;
101
96
  let actual;
97
+ let errorReason = null;
102
98
  const { timeout = 1e4 } = options;
103
99
  const poll = expect.poll(
104
100
  async () => {
105
101
  try {
106
102
  actual = await clipboard.readJSON();
107
- } catch {
108
- actual = await clipboard.read();
103
+ errorReason = null;
104
+ return actual;
105
+ } catch (error) {
106
+ errorReason = error instanceof Error ? error : new Error(String(error));
107
+ try {
108
+ actual = await clipboard.read();
109
+ } catch {
110
+ actual = void 0;
111
+ }
112
+ throw errorReason;
109
113
  }
110
- if (typeof expected === "string" && actual !== null && actual !== void 0) {
111
- return String(actual);
114
+ },
115
+ { timeout }
116
+ );
117
+ try {
118
+ const expectation = this.isNot ? poll.not : poll;
119
+ await expectation.toEqual(expected);
120
+ pass = true;
121
+ } catch {
122
+ pass = false;
123
+ }
124
+ if (this.isNot) pass = !pass;
125
+ const matcherReturn = {
126
+ message: getErrorMessage.call(this, name, expected, actual, errorReason),
127
+ pass,
128
+ name,
129
+ expected,
130
+ actual
131
+ };
132
+ return matcherReturn;
133
+ }
134
+
135
+ // src/matchers/toHaveTextContent.ts
136
+ import { expect as expect2 } from "@playwright/test";
137
+ async function toHaveTextContent(clipboard, expected, options = {}) {
138
+ const name = "toHaveTextContent";
139
+ let pass;
140
+ let actual;
141
+ let errorReason = null;
142
+ const { timeout = 1e4 } = options;
143
+ const poll = expect2.poll(
144
+ async () => {
145
+ try {
146
+ actual = await clipboard.read();
147
+ errorReason = null;
148
+ return actual;
149
+ } catch (error) {
150
+ errorReason = error instanceof Error ? error : new Error(String(error));
151
+ actual = void 0;
152
+ throw errorReason;
112
153
  }
113
- return actual;
114
154
  },
115
155
  { timeout }
116
156
  );
@@ -123,7 +163,7 @@ async function toHaveData(clipboard, expected, options = {}) {
123
163
  }
124
164
  if (this.isNot) pass = !pass;
125
165
  const matcherReturn = {
126
- message: getErrorMessage.call(this, name, expected, actual),
166
+ message: getErrorMessage.call(this, name, expected, actual, errorReason),
127
167
  pass,
128
168
  name,
129
169
  expected,
@@ -132,25 +172,42 @@ async function toHaveData(clipboard, expected, options = {}) {
132
172
  return matcherReturn;
133
173
  }
134
174
 
175
+ // src/matchers/toHaveData.ts
176
+ async function toHaveData(clipboard, expected, options = {}) {
177
+ const name = "toHaveData";
178
+ let matcherReturn = null;
179
+ if (typeof expected === "string") {
180
+ matcherReturn = await toHaveTextContent.call(this, clipboard, expected, options);
181
+ } else {
182
+ matcherReturn = await toHaveJSONContent.call(this, clipboard, expected, options);
183
+ }
184
+ return {
185
+ ...matcherReturn,
186
+ name,
187
+ message: () => {
188
+ const originalMessage = matcherReturn.message();
189
+ return originalMessage.replace("toHaveText", name).replace("toHaveJSON", name);
190
+ }
191
+ };
192
+ }
193
+
135
194
  // src/matchers/clipboardMatchers.ts
136
195
  var clipboardMatchers = {
196
+ toHaveTextContent,
197
+ toHaveJSONContent,
137
198
  toHaveData
138
199
  };
139
200
 
140
201
  // src/fixtures.ts
141
- var test = baseTest.extend({
142
- /**
143
- * A fixture that provides an instance of the Clipboard utility for interacting with the system clipboard.
144
- * It allows reading from the clipboard during tests.
145
- */
146
- clipboard: clipboardFixture
147
- });
148
- var expect2 = baseExpect.extend({ ...clipboardMatchers });
202
+ var test = baseTest.extend(clipboardFixtures);
203
+ var expect3 = baseExpect.extend({ ...clipboardMatchers });
149
204
  export {
150
205
  ClipboardHandler,
151
206
  clipboardFixture,
207
+ clipboardFixtures,
152
208
  clipboardMatchers,
153
- expect2 as expect,
209
+ contextFixture,
210
+ expect3 as expect,
154
211
  firefoxClipboardPrefs,
155
212
  test
156
213
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/utils/clipboardHandler.ts","../src/fixtures/clipboardFixture.ts","../src/fixtures.ts","../src/matchers/toHaveData.ts","../src/utils/matcherUtils.ts","../src/matchers/clipboardMatchers.ts"],"sourcesContent":["export const firefoxClipboardPrefs = {\n 'dom.events.testing.asyncClipboard': true,\n 'dom.events.asyncClipboard.readText': true,\n 'dom.events.asyncClipboard.writeText': true,\n 'permissions.default.clipboard-read': 1,\n 'permissions.default.clipboard-write': 1,\n};\n","/**\n * Playwright-compatible Clipboard utilities.\n *\n * Core functions for interacting with the browser clipboard within Playwright tests.\n * Provides wrappers for reading plain text and JSON.\n *\n * @remarks\n * These utilities require 'clipboard-read' and 'clipboard-write' permissions\n * to be granted in the browser context.\n */\n\nimport type { BrowserContext, Page } from '@playwright/test';\nimport type { BrowserName } from '../types.js';\n\nexport class ClipboardHandler {\n private readonly browserName: BrowserName;\n private isPermissionGranted: boolean;\n\n constructor(\n private readonly page: Page,\n private readonly context: BrowserContext,\n browserName: BrowserName = 'chromium',\n ) {\n this.browserName = browserName;\n this.isPermissionGranted = false;\n }\n\n /**\n * Grants clipboard permissions to the Chromium browser context if not already granted.\n * @private\n */\n private async grantPermissions() {\n if (this.browserName === 'chromium') {\n if (!this.isPermissionGranted) {\n await this.context.grantPermissions(['clipboard-read', 'clipboard-write']);\n this.isPermissionGranted = true;\n }\n }\n }\n\n /**\n * Reads the current text content from the browser clipboard.\n * If the content is a JSON-encoded string (e.g., has extra quotes),\n * it will be returned as is. Use readJSON for automatic parsing.\n *\n * @returns A promise that resolves to the clipboard string content.\n */\n async read(): Promise<string> {\n await this.grantPermissions();\n return await this.page.evaluate(() => navigator.clipboard.readText());\n }\n\n /**\n * Reads the clipboard content and parses it as JSON.\n * If the content is a string literal (e.g., '\"value\"'), it returns the unwrapped string ('value').\n *\n * @template T - The expected type of the parsed JSON object.\n * @returns A promise that resolves to the parsed JSON object of type T.\n * @throws {Error} If the clipboard content is not a valid JSON string.\n */\n async readJSON<T = unknown>(): Promise<T> {\n const text = await this.read();\n try {\n return JSON.parse(text);\n } catch {\n throw new Error(`Clipboard content is not a valid JSON: ${JSON.stringify(text)}`);\n }\n }\n}\n","import type { BrowserContext, Page, TestFixture } from '@playwright/test';\nimport type { BrowserName } from '../types.js';\nimport { ClipboardHandler } from '../utils/clipboardHandler.js';\n\n/**\n * A fixture that provides an instance of the Clipboard utility for interacting with the system clipboard.\n * It allows reading from the clipboard during tests.\n */\nexport const clipboardFixture: TestFixture<\n ClipboardHandler,\n { page: Page; context: BrowserContext; browserName: BrowserName }\n> = async ({ page, context, browserName }, use) => {\n if (browserName === 'webkit') {\n throw new Error(\n `[playwright-clipboard] Browser '${browserName}' is not supported. ` +\n 'Clipboard API testing is currently supported only in Chromium-based and Firefox browsers.\\n' +\n `Add test.skip(browserName === 'webkit', 'Clipboard API is only supported in Chromium and Firefox'); to your test body.`,\n );\n }\n\n const handler = new ClipboardHandler(page, context, browserName);\n await use(handler);\n};\n","import { expect as baseExpect, test as baseTest } from '@playwright/test';\nimport { clipboardFixture } from './fixtures/clipboardFixture.js';\nimport { clipboardMatchers } from './matchers/clipboardMatchers.js';\nimport type { ClipboardHandler } from './utils/clipboardHandler.js';\n\nexport const test = baseTest.extend<{\n clipboard: ClipboardHandler;\n}>({\n /**\n * A fixture that provides an instance of the Clipboard utility for interacting with the system clipboard.\n * It allows reading from the clipboard during tests.\n */\n clipboard: clipboardFixture,\n});\n\nexport const expect = baseExpect.extend({ ...clipboardMatchers });\n","import { type ExpectMatcherState, expect, type MatcherReturnType } from '@playwright/test';\nimport type { ClipboardHandler } from '../utils/clipboardHandler.js';\nimport { getErrorMessage } from '../utils/matcherUtils.js';\nimport type { MatcherOptions } from './types.js';\n\n/**\n * Asserts that the clipboard content matches the expected value.\n *\n * @this ExpectMatcherState\n * @param clipboard The Clipboard utility instance.\n * @param expected The string or object to compare against the clipboard content.\n * @param options Optional settings for the matcher, such as timeout.\n * @returns A Promise that resolves to a MatcherReturnType object.\n */\nexport async function toHaveData(\n this: ExpectMatcherState,\n clipboard: ClipboardHandler,\n expected: unknown,\n options: MatcherOptions = {},\n) {\n const name = 'toHaveData';\n let pass: boolean;\n let actual: unknown;\n\n const { timeout = 10_000 } = options;\n\n const poll = expect.poll(\n async () => {\n try {\n actual = await clipboard.readJSON();\n } catch {\n actual = await clipboard.read();\n }\n\n if (typeof expected === 'string' && actual !== null && actual !== undefined) {\n return String(actual);\n }\n\n return actual;\n },\n { timeout },\n );\n\n try {\n const expectation = this.isNot ? poll.not : poll;\n await expectation.toEqual(expected);\n pass = true;\n } catch {\n pass = false;\n }\n\n if (this.isNot) pass = !pass;\n\n const matcherReturn: MatcherReturnType = {\n message: getErrorMessage.call(this, name, expected, actual),\n pass,\n name,\n expected,\n actual,\n };\n\n return matcherReturn;\n}\n","import type { ExpectMatcherState } from '@playwright/test';\n\n/**\n * Generates an error message for a custom matcher.\n *\n * @this ExpectMatcherState\n * @param name The name of the matcher.\n * @param expected The expected value.\n * @param actual The actual value.\n * @param error An optional error object.\n * @param errorMessage An optional error message string.\n * @returns A function that returns the error message string.\n */\nexport function getErrorMessage(\n this: ExpectMatcherState,\n name: string,\n expected: unknown,\n actual: unknown,\n error?: Error | null,\n errorMessage?: string | undefined | null,\n): () => string {\n const message = `${this.utils.matcherHint(name, undefined, undefined, { isNot: this.isNot })}\\n\\n`;\n\n if (error) {\n return () => `${message}An unexpected error occurred:\\n${error.message}`;\n }\n\n if (errorMessage) {\n return () => `${message}${errorMessage}`;\n }\n\n return () =>\n message +\n `Expected: ${this.isNot ? 'not ' : ''}${this.utils.printExpected(expected)}\\n` +\n `Received: ${this.utils.printReceived(actual)}`;\n}\n","import { toHaveData } from './toHaveData.js';\n\n/**\n * Export an object containing all the custom clipboard matchers for Playwright.\n */\nexport const clipboardMatchers = {\n toHaveData,\n};\n"],"mappings":"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","names":["expect"]}
1
+ {"version":3,"sources":["../src/constants.ts","../src/utils/clipboardHandler.ts","../src/fixtures/clipboardFixture.ts","../src/fixtures/contextFixture.ts","../src/fixtures/index.ts","../src/fixtures.ts","../src/matchers/toHaveJSONContent.ts","../src/utils/matcherUtils.ts","../src/matchers/toHaveTextContent.ts","../src/matchers/toHaveData.ts","../src/matchers/clipboardMatchers.ts"],"sourcesContent":["export const firefoxClipboardPrefs = {\n 'dom.events.testing.asyncClipboard': true,\n 'dom.events.asyncClipboard.readText': true,\n 'dom.events.asyncClipboard.writeText': true,\n 'permissions.default.clipboard-read': 1,\n 'permissions.default.clipboard-write': 1,\n};\n","/**\n * Playwright-compatible Clipboard utilities.\n *\n * Core functions for interacting with the browser clipboard within Playwright tests.\n * Provides wrappers for reading plain text and JSON.\n *\n * @remarks\n * These utilities require 'clipboard-read' and 'clipboard-write' permissions\n * to be granted in the browser context.\n */\n\nimport type { Page } from '@playwright/test';\n\nexport class ClipboardHandler {\n constructor(private readonly page: Page) {}\n\n /**\n * Reads the current text content from the browser clipboard.\n * If the content is a JSON-encoded string (e.g., has extra quotes),\n * it will be returned as is. Use readJSON for automatic parsing.\n *\n * @returns A promise that resolves to the clipboard string content.\n */\n async read(): Promise<string> {\n return await this.page.evaluate(() => navigator.clipboard.readText());\n }\n\n /**\n * Reads the clipboard content and parses it as JSON.\n * If the content is a string literal (e.g., '\"value\"'), it returns the unwrapped string ('value').\n *\n * @template T - The expected type of the parsed JSON object.\n * @returns A promise that resolves to the parsed JSON object of type T.\n * @throws {Error} If the clipboard content is not a valid JSON string.\n */\n async readJSON<T = unknown>(): Promise<T> {\n const text = await this.read();\n try {\n return JSON.parse(text);\n } catch {\n throw new Error(`Clipboard content is not a valid JSON: ${JSON.stringify(text)}`);\n }\n }\n}\n","import type { Page, TestFixture } from '@playwright/test';\nimport type { BrowserName } from '../types.js';\nimport { ClipboardHandler } from '../utils/index.js';\n\n/**\n * A fixture that provides an instance of the Clipboard utility for interacting with the system clipboard.\n * It allows reading from the clipboard during tests.\n */\nexport const clipboardFixture: TestFixture<\n ClipboardHandler,\n { page: Page; browserName: BrowserName }\n> = async ({ page, browserName }, use) => {\n if (browserName === 'webkit') {\n throw new Error(\n `[playwright-clipboard] Browser '${browserName}' is not supported. ` +\n 'Clipboard API testing is currently supported only in Chromium-based and Firefox browsers.\\n' +\n `Add test.skip(browserName === 'webkit', 'Clipboard API is only supported in Chromium and Firefox'); to your test body.`,\n );\n }\n\n const handler = new ClipboardHandler(page);\n await use(handler);\n};\n","import type { BrowserContext, TestFixture } from '@playwright/test';\nimport type { BrowserName } from '../types.js';\n\n/**\n * A fixture that provides a BrowserContext with clipboard permissions granted for Chromium browsers.\n */\nexport const contextFixture: TestFixture<\n BrowserContext,\n { context: BrowserContext; browserName: BrowserName }\n> = async ({ context, browserName }, use) => {\n if (browserName === 'chromium') {\n await context.grantPermissions(['clipboard-read', 'clipboard-write']);\n }\n\n await use(context);\n};\n","import { clipboardFixture } from './clipboardFixture.js';\nimport { contextFixture } from './contextFixture.js';\n\n/**\n * A collection of fixtures related to clipboard testing, including the clipboard fixture and context fixture.\n * These fixtures can be used in Playwright tests to facilitate clipboard interactions and context management.\n */\nexport const clipboardFixtures = {\n context: contextFixture,\n clipboard: clipboardFixture,\n};\n\nexport { clipboardFixture, contextFixture };\n","import { expect as baseExpect, test as baseTest } from '@playwright/test';\nimport { clipboardFixtures } from './fixtures/index.js';\nimport { clipboardMatchers } from './matchers/index.js';\nimport type { ClipboardHandler } from './utils/index.js';\n\nexport const test = baseTest.extend<{\n clipboard: ClipboardHandler;\n}>(clipboardFixtures);\n\nexport const expect = baseExpect.extend({ ...clipboardMatchers });\n","import type { ExpectMatcherState, MatcherReturnType } from '@playwright/test';\nimport { expect } from '@playwright/test';\nimport type { ClipboardHandler } from '../utils/clipboardHandler.js';\nimport { getErrorMessage } from '../utils/matcherUtils.js';\nimport type { MatcherOptions } from './types.js';\n\n/**\n * Asserts that the clipboard content matches the expected JSON value.\n *\n * @this ExpectMatcherState\n * @param clipboard The Clipboard utility instance.\n * @param expected The expected JSON value.\n * @param options Matcher options.\n * @returns A Promise that resolves to a MatcherReturnType object.\n */\nexport async function toHaveJSONContent(\n this: ExpectMatcherState,\n clipboard: ClipboardHandler,\n expected: unknown,\n options: MatcherOptions = {},\n) {\n const name = 'toHaveJSONContent';\n let pass: boolean;\n let actual: unknown;\n let errorReason: Error | null = null;\n\n const { timeout = 10_000 } = options;\n\n const poll = expect.poll(\n async () => {\n try {\n actual = await clipboard.readJSON();\n errorReason = null;\n return actual;\n } catch (error) {\n errorReason = error instanceof Error ? error : new Error(String(error));\n\n try {\n actual = await clipboard.read();\n } catch {\n actual = undefined;\n }\n\n throw errorReason;\n }\n },\n { timeout },\n );\n\n try {\n const expectation = this.isNot ? poll.not : poll;\n await expectation.toEqual(expected);\n pass = true;\n } catch {\n pass = false;\n }\n\n if (this.isNot) pass = !pass;\n\n const matcherReturn: MatcherReturnType = {\n message: getErrorMessage.call(this, name, expected, actual, errorReason),\n pass,\n name,\n expected,\n actual,\n };\n\n return matcherReturn;\n}\n","import type { ExpectMatcherState } from '@playwright/test';\n\n/**\n * Generates an error message for a custom matcher.\n *\n * @this ExpectMatcherState\n * @param name The name of the matcher.\n * @param expected The expected value.\n * @param actual The actual value.\n * @param error An optional error object.\n * @param errorMessage An optional error message string.\n * @returns A function that returns the error message string.\n */\nexport function getErrorMessage(\n this: ExpectMatcherState,\n name: string,\n expected: unknown,\n actual: unknown,\n error?: Error | null,\n errorMessage?: string | undefined | null,\n): () => string {\n const message = `${this.utils.matcherHint(name, undefined, undefined, { isNot: this.isNot })}\\n\\n`;\n\n if (error) {\n return () => `${message}An unexpected error occurred:\\n${error.message}`;\n }\n\n if (errorMessage) {\n return () => `${message}${errorMessage}`;\n }\n\n return () =>\n message +\n `Expected: ${this.isNot ? 'not ' : ''}${this.utils.printExpected(expected)}\\n` +\n `Received: ${this.utils.printReceived(actual)}`;\n}\n","import { type ExpectMatcherState, expect, type MatcherReturnType } from '@playwright/test';\nimport type { ClipboardHandler } from '../utils/clipboardHandler.js';\nimport { getErrorMessage } from '../utils/matcherUtils.js';\nimport type { MatcherOptions } from './types.js';\n\n/**\n * Asserts that the clipboard content matches the expected text value.\n *\n * @this ExpectMatcherState\n * @param clipboard The Clipboard utility instance.\n * @param expected The expected text value.\n * @param options Matcher options.\n * @returns A Promise that resolves to a MatcherReturnType object.\n */\nexport async function toHaveTextContent(\n this: ExpectMatcherState,\n clipboard: ClipboardHandler,\n expected: string,\n options: MatcherOptions = {},\n) {\n const name = 'toHaveTextContent';\n let pass: boolean;\n let actual: unknown;\n let errorReason: Error | null = null;\n\n const { timeout = 10_000 } = options;\n\n const poll = expect.poll(\n async () => {\n try {\n actual = await clipboard.read();\n errorReason = null;\n return actual;\n } catch (error) {\n errorReason = error instanceof Error ? error : new Error(String(error));\n actual = undefined;\n\n throw errorReason;\n }\n },\n { timeout },\n );\n\n try {\n const expectation = this.isNot ? poll.not : poll;\n await expectation.toEqual(expected);\n pass = true;\n } catch {\n pass = false;\n }\n\n if (this.isNot) pass = !pass;\n\n const matcherReturn: MatcherReturnType = {\n message: getErrorMessage.call(this, name, expected, actual, errorReason),\n pass,\n name,\n expected,\n actual,\n };\n\n return matcherReturn;\n}\n","import type { ExpectMatcherState, MatcherReturnType } from '@playwright/test';\nimport type { ClipboardHandler } from '../utils/clipboardHandler.js';\nimport { toHaveJSONContent } from './toHaveJSONContent.js';\nimport { toHaveTextContent } from './toHaveTextContent.js';\nimport type { MatcherOptions } from './types.js';\n\n/**\n * Asserts that the clipboard content matches the expected value.\n * Uses smart polling to wait for the clipboard to be updated.\n * If the `expected` value is an object, it attempts to parse the clipboard\n * content as JSON before comparing.\n *\n * @this ExpectMatcherState\n * @param clipboard The Clipboard utility instance.\n * @param expected The string or object to compare against the clipboard content.\n * @param options Optional settings for the matcher, such as timeout.\n * @returns A Promise that resolves to a MatcherReturnType object.\n */\nexport async function toHaveData(\n this: ExpectMatcherState,\n clipboard: ClipboardHandler,\n expected: unknown,\n options: MatcherOptions = {},\n) {\n const name = 'toHaveData';\n let matcherReturn: MatcherReturnType | null = null;\n\n if (typeof expected === 'string') {\n matcherReturn = await toHaveTextContent.call(this, clipboard, expected, options);\n } else {\n matcherReturn = await toHaveJSONContent.call(this, clipboard, expected, options);\n }\n\n return {\n ...matcherReturn,\n name,\n message: () => {\n const originalMessage = matcherReturn.message();\n return originalMessage.replace('toHaveText', name).replace('toHaveJSON', name);\n },\n };\n}\n","import { toHaveData } from './toHaveData.js';\nimport { toHaveJSONContent } from './toHaveJSONContent.js';\nimport { toHaveTextContent } from './toHaveTextContent.js';\n\n/**\n * Export an object containing all the custom clipboard matchers for Playwright.\n */\nexport const clipboardMatchers = {\n toHaveTextContent,\n toHaveJSONContent,\n toHaveData,\n};\n"],"mappings":"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","names":["expect","expect","expect"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "playwright-clipboard-testing",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Playwright fixture and custom matchers for clipboard testing and assertions.",
5
5
  "author": "Sergii Oleksenko <serg.oleksenko@gmail.com>",
6
6
  "license": "MIT",
@@ -40,7 +40,7 @@
40
40
  "dist"
41
41
  ],
42
42
  "engines": {
43
- "node": ">=18.0.0"
43
+ "node": ">=20.0.0"
44
44
  },
45
45
  "sideEffects": false,
46
46
  "scripts": {
@@ -50,13 +50,19 @@
50
50
  "lint:fix": "biome check --write .",
51
51
  "typecheck": "tsc --noEmit",
52
52
  "format": "biome format --write .",
53
- "test": "echo \"Error: no test specified\" && exit 1"
53
+ "test:unit": "vitest run",
54
+ "test:e2e": "playwright test",
55
+ "test:e2e:ui": "playwright test --ui",
56
+ "test": "npm run test:unit && npm run test:e2e",
57
+ "test:watch": "vitest"
54
58
  },
55
59
  "devDependencies": {
56
60
  "@biomejs/biome": "2.5.10",
57
- "@playwright/test": "1.62.1",
61
+ "@playwright/test": "^1.63.0",
62
+ "@types/node": "^26.4.1",
58
63
  "tsup": "^8.5.1",
59
- "typescript": "5.8.3"
64
+ "typescript": "5.8.3",
65
+ "vitest": "^4.1.11"
60
66
  },
61
67
  "peerDependencies": {
62
68
  "@playwright/test": ">=1.40.0"