@argos-ci/playwright 5.0.8 → 5.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ElementHandle, Locator, Page, PageScreenshotOptions, LocatorScreenshotOptions } from '@playwright/test';
1
+ import { ElementHandle, Locator, Page, PageScreenshotOptions, LocatorScreenshotOptions, Frame } from '@playwright/test';
2
2
  import { ViewportOption, StabilizationPluginOptions } from '@argos-ci/browser';
3
3
  import { ScreenshotMetadata } from '@argos-ci/util';
4
4
 
@@ -19,7 +19,7 @@ type ArgosScreenshotOptions = {
19
19
  */
20
20
  argosCSS?: string;
21
21
  /**
22
- * Disable hover effects by moving the mouse to the top-left corner of the page.
22
+ * Disable hover effects by moving the mouse to the top-left corner of the document.
23
23
  * @default true
24
24
  */
25
25
  disableHover?: boolean;
@@ -59,6 +59,12 @@ type ArgosScreenshotOptions = {
59
59
  */
60
60
  afterScreenshot?: () => Promise<void> | void;
61
61
  } & LocatorOptions & ScreenshotOptions<LocatorScreenshotOptions> & ScreenshotOptions<PageScreenshotOptions>;
62
+ type Attachment = {
63
+ name: string;
64
+ contentType: string;
65
+ path: string;
66
+ };
67
+ type Handler = Page | Frame;
62
68
  /**
63
69
  * Stabilize the UI and takes a screenshot of the application under test.
64
70
  *
@@ -68,9 +74,9 @@ type ArgosScreenshotOptions = {
68
74
  */
69
75
  declare function argosScreenshot(
70
76
  /**
71
- * Playwright `page` object.
77
+ * Playwright `page` or `frame` object.
72
78
  */
73
- page: Page,
79
+ handler: Handler,
74
80
  /**
75
81
  * Name of the screenshot. Must be unique.
76
82
  */
@@ -78,7 +84,7 @@ name: string,
78
84
  /**
79
85
  * Options for the screenshot.
80
86
  */
81
- options?: ArgosScreenshotOptions): Promise<void>;
87
+ options?: ArgosScreenshotOptions): Promise<Attachment[]>;
82
88
 
83
89
  /**
84
90
  * Get the CSP script hash.
@@ -88,10 +94,13 @@ declare function getCSPScriptHash(): string;
88
94
  type MetadataConfig = {
89
95
  sdk: ScreenshotMetadata["sdk"];
90
96
  playwrightLibraries: string[];
97
+ url?: string;
98
+ test?: ScreenshotMetadata["test"];
99
+ viewport?: ScreenshotMetadata["viewport"];
91
100
  };
92
101
  /**
93
102
  * Set the metadata config.
94
103
  */
95
104
  declare function setMetadataConfig(metadata: MetadataConfig): void;
96
105
 
97
- export { type ArgosScreenshotOptions, setMetadataConfig as DO_NOT_USE_setMetadataConfig, argosScreenshot, getCSPScriptHash };
106
+ export { type ArgosScreenshotOptions, type Attachment, setMetadataConfig as DO_NOT_USE_setMetadataConfig, type MetadataConfig, argosScreenshot, getCSPScriptHash };
package/dist/index.js CHANGED
@@ -42,6 +42,9 @@ var DEFAULT_PLAYWRIGHT_LIBRARIES = [
42
42
  "playwright",
43
43
  "playwright-core"
44
44
  ];
45
+ function getMetadataOverrides() {
46
+ return metadataConfigStorage.getStore();
47
+ }
45
48
  async function getAutomationLibraryMetadata() {
46
49
  const metadataConfig = metadataConfigStorage.getStore();
47
50
  const libraries = metadataConfig?.playwrightLibraries ?? DEFAULT_PLAYWRIGHT_LIBRARIES;
@@ -81,8 +84,31 @@ async function getLibraryMetadata() {
81
84
  sdk
82
85
  };
83
86
  }
84
- async function getTestMetadataFromTestInfo(testInfo) {
87
+ function resolveTestFilePath(filepath, repositoryPath) {
88
+ if (!repositoryPath) {
89
+ return filepath;
90
+ }
91
+ return relative(repositoryPath, filepath);
92
+ }
93
+ async function getTestMetadata(testInfo) {
85
94
  const repositoryPath = await getGitRepositoryPath();
95
+ const metadataConfig = metadataConfigStorage.getStore();
96
+ if (metadataConfig?.test) {
97
+ return {
98
+ ...metadataConfig.test,
99
+ location: metadataConfig.test?.location ? {
100
+ file: resolveTestFilePath(
101
+ metadataConfig.test.location.file,
102
+ repositoryPath
103
+ ),
104
+ line: metadataConfig.test.location.line,
105
+ column: metadataConfig.test.location.column
106
+ } : void 0
107
+ };
108
+ }
109
+ if (!testInfo) {
110
+ return null;
111
+ }
86
112
  const testMetadata = {
87
113
  id: testInfo.testId,
88
114
  title: testInfo.title,
@@ -91,7 +117,7 @@ async function getTestMetadataFromTestInfo(testInfo) {
91
117
  retries: testInfo.project.retries,
92
118
  repeat: testInfo.repeatEachIndex,
93
119
  location: {
94
- file: repositoryPath ? relative(repositoryPath, testInfo.file) : testInfo.file,
120
+ file: resolveTestFilePath(testInfo.file, repositoryPath),
95
121
  line: testInfo.line,
96
122
  column: testInfo.column
97
123
  }
@@ -111,12 +137,12 @@ function checkIsUsingArgosReporter(testInfo) {
111
137
 
112
138
  // src/screenshot.ts
113
139
  var DEFAULT_SCREENSHOT_ROOT = "./screenshots";
114
- async function injectArgos(page) {
115
- const injected = await page.evaluate(
140
+ async function injectArgos(handler) {
141
+ const injected = await handler.evaluate(
116
142
  () => typeof window.__ARGOS__ !== "undefined"
117
143
  );
118
144
  if (!injected) {
119
- await page.addScriptTag({ content: getGlobalScript() });
145
+ await handler.addScriptTag({ content: getGlobalScript() });
120
146
  }
121
147
  }
122
148
  async function getTestInfo() {
@@ -127,6 +153,15 @@ async function getTestInfo() {
127
153
  return null;
128
154
  }
129
155
  }
156
+ function checkIsFrame(handler) {
157
+ return "page" in handler && typeof handler.page === "function";
158
+ }
159
+ function getPage(handler) {
160
+ if (checkIsFrame(handler)) {
161
+ return handler.page();
162
+ }
163
+ return handler;
164
+ }
130
165
  function getViewportSize(page) {
131
166
  const viewportSize = page.viewportSize();
132
167
  if (!viewportSize) {
@@ -142,37 +177,38 @@ async function setViewportSize(page, viewportSize) {
142
177
  );
143
178
  }
144
179
  function getStabilizationContext(options) {
145
- const { fullPage, argosCSS, stabilize } = options;
180
+ const { fullPage, argosCSS, stabilize, viewports } = options;
146
181
  return {
147
182
  fullPage,
148
183
  argosCSS,
184
+ viewports,
149
185
  options: stabilize
150
186
  };
151
187
  }
152
- async function beforeAll(page, options) {
188
+ async function beforeAll(handler, options) {
153
189
  const { disableHover = true } = options;
154
190
  const context = getStabilizationContext(options);
155
- await page.evaluate(
191
+ await handler.evaluate(
156
192
  (context2) => window.__ARGOS__.beforeAll(context2),
157
193
  context
158
194
  );
159
195
  if (disableHover) {
160
- await page.mouse.move(0, 0);
196
+ await getPage(handler).mouse.move(0, 0);
161
197
  }
162
198
  return async () => {
163
- await page.evaluate(
199
+ await handler.evaluate(
164
200
  () => window.__ARGOS__.afterAll()
165
201
  );
166
202
  };
167
203
  }
168
- async function beforeEach(page, options) {
204
+ async function beforeEach(handler, options) {
169
205
  const context = getStabilizationContext(options);
170
- await page.evaluate(
206
+ await handler.evaluate(
171
207
  (context2) => window.__ARGOS__.beforeEach(context2),
172
208
  context
173
209
  );
174
210
  return async () => {
175
- await page.evaluate(
211
+ await handler.evaluate(
176
212
  () => window.__ARGOS__.afterEach()
177
213
  );
178
214
  };
@@ -191,11 +227,11 @@ async function increaseTimeout() {
191
227
  }
192
228
  return null;
193
229
  }
194
- async function waitForReadiness(page, options) {
230
+ async function waitForReadiness(handler, options) {
195
231
  const context = getStabilizationContext(options);
196
232
  const timeout = await increaseTimeout();
197
233
  try {
198
- await page.waitForFunction(
234
+ await handler.waitForFunction(
199
235
  (context2) => {
200
236
  const argos = window.__ARGOS__;
201
237
  return argos.waitFor(context2);
@@ -205,7 +241,7 @@ async function waitForReadiness(page, options) {
205
241
  );
206
242
  timeout?.reset();
207
243
  } catch (error) {
208
- const reasons = await page.evaluate(
244
+ const reasons = await handler.evaluate(
209
245
  (context2) => window.__ARGOS__.getWaitFailureExplanations(
210
246
  context2
211
247
  ),
@@ -233,7 +269,7 @@ function getScreenshotNames(name, testInfo) {
233
269
  }
234
270
  return { name, baseName: null };
235
271
  }
236
- async function argosScreenshot(page, name, options = {}) {
272
+ async function argosScreenshot(handler, name, options = {}) {
237
273
  const {
238
274
  element,
239
275
  has,
@@ -243,13 +279,13 @@ async function argosScreenshot(page, name, options = {}) {
243
279
  root = DEFAULT_SCREENSHOT_ROOT,
244
280
  ...playwrightOptions
245
281
  } = options;
246
- if (!page) {
247
- throw new Error("A Playwright `page` object is required.");
282
+ if (!handler) {
283
+ throw new Error("A Playwright `handler` object is required.");
248
284
  }
249
285
  if (!name) {
250
286
  throw new Error("The `name` argument is required.");
251
287
  }
252
- const handle = typeof element === "string" ? page.locator(element, { has, hasText }) : element ?? page;
288
+ const screenshotTarget = typeof element === "string" ? handler.locator(element, { has, hasText }) : element ?? (checkIsFrame(handler) ? handler.locator("body") : handler);
253
289
  const testInfo = await getTestInfo();
254
290
  const useArgosReporter = Boolean(
255
291
  testInfo && checkIsUsingArgosReporter(testInfo)
@@ -258,33 +294,33 @@ async function argosScreenshot(page, name, options = {}) {
258
294
  // Create the screenshot folder if it doesn't exist
259
295
  useArgosReporter ? null : mkdir(root, { recursive: true }),
260
296
  // Inject Argos script into the page
261
- injectArgos(page)
297
+ injectArgos(handler)
262
298
  ]);
263
- const originalViewportSize = getViewportSize(page);
264
- const fullPage = options.fullPage !== void 0 ? options.fullPage : handle === page;
265
- const afterAll = await beforeAll(page, options);
299
+ const originalViewportSize = checkIsFrame(handler) ? null : getViewportSize(handler);
300
+ const fullPage = options.fullPage !== void 0 ? options.fullPage : screenshotTarget === handler;
301
+ const afterAll = await beforeAll(handler, options);
266
302
  const collectMetadata = async (testInfo2) => {
303
+ const overrides = getMetadataOverrides();
267
304
  const [colorScheme, mediaType, libMetadata, testMetadata] = await Promise.all([
268
- page.evaluate(
305
+ handler.evaluate(
269
306
  () => window.__ARGOS__.getColorScheme()
270
307
  ),
271
- page.evaluate(
308
+ handler.evaluate(
272
309
  () => window.__ARGOS__.getMediaType()
273
310
  ),
274
311
  getLibraryMetadata(),
275
- testInfo2 ? getTestMetadataFromTestInfo(testInfo2) : null
312
+ getTestMetadata(testInfo2)
276
313
  ]);
277
- const viewportSize = getViewportSize(page);
278
- const browser = page.context().browser();
314
+ const viewportSize = checkIsFrame(handler) ? null : getViewportSize(handler);
315
+ const browser = getPage(handler).context().browser();
279
316
  if (!browser) {
280
317
  throw new Error("Can't take screenshots without a browser.");
281
318
  }
282
319
  const browserName = browser.browserType().name();
283
320
  const browserVersion = browser.version();
284
- const url = page.url();
321
+ const url = overrides?.url ?? handler.url();
285
322
  const metadata = {
286
323
  url,
287
- viewport: viewportSize,
288
324
  colorScheme,
289
325
  mediaType,
290
326
  test: testMetadata,
@@ -294,6 +330,10 @@ async function argosScreenshot(page, name, options = {}) {
294
330
  },
295
331
  ...libMetadata
296
332
  };
333
+ const viewport = viewportSize ?? getMetadataOverrides()?.viewport;
334
+ if (viewport) {
335
+ metadata.viewport = viewport;
336
+ }
297
337
  return metadata;
298
338
  };
299
339
  const stabilizeAndScreenshot = async (name2) => {
@@ -313,52 +353,74 @@ async function argosScreenshot(page, name, options = {}) {
313
353
  await mkdir(dirname(screenshotPath), { recursive: true });
314
354
  }
315
355
  await options.beforeScreenshot?.({
316
- runStabilization: (stabilizationOptions) => waitForReadiness(page, {
356
+ runStabilization: (stabilizationOptions) => waitForReadiness(handler, {
317
357
  ...options,
318
358
  stabilize: stabilizationOptions ?? options.stabilize
319
359
  })
320
360
  });
321
- await waitForReadiness(page, options);
322
- const afterEach = await beforeEach(page, options);
361
+ await waitForReadiness(handler, options);
362
+ const afterEach = await beforeEach(handler, options);
363
+ await waitForReadiness(handler, options);
323
364
  await Promise.all([
324
- handle.screenshot({
365
+ screenshotTarget.screenshot({
325
366
  path: screenshotPath,
326
367
  type: "png",
327
368
  fullPage,
328
- mask: [page.locator('[data-visual-test="blackout"]')],
369
+ mask: [handler.locator('[data-visual-test="blackout"]')],
329
370
  animations: "disabled",
330
371
  ...playwrightOptions
331
372
  }),
332
373
  writeMetadata(screenshotPath, metadata)
333
374
  ]);
375
+ const attachments = [
376
+ {
377
+ name: getAttachmentName(names.name, "screenshot"),
378
+ contentType: "image/png",
379
+ path: screenshotPath
380
+ },
381
+ {
382
+ name: getAttachmentName(names.name, "metadata"),
383
+ contentType: "application/json",
384
+ path: getMetadataPath(screenshotPath)
385
+ }
386
+ ];
334
387
  if (useArgosReporter && testInfo) {
335
- await Promise.all([
336
- testInfo.attach(getAttachmentName(names.name, "metadata"), {
337
- path: getMetadataPath(screenshotPath),
338
- contentType: "application/json"
339
- }),
340
- testInfo.attach(getAttachmentName(names.name, "screenshot"), {
341
- path: screenshotPath,
342
- contentType: "image/png"
343
- })
344
- ]);
388
+ await Promise.all(
389
+ attachments.map(
390
+ (attachment) => testInfo.attach(attachment.name, {
391
+ path: attachment.path,
392
+ contentType: attachment.contentType
393
+ })
394
+ )
395
+ );
345
396
  }
346
397
  await afterEach();
347
398
  await options.afterScreenshot?.();
399
+ return attachments;
348
400
  };
401
+ const allAttachments = [];
349
402
  if (viewports) {
403
+ if (checkIsFrame(handler)) {
404
+ throw new Error(`viewports option is not supported with an iframe`);
405
+ }
350
406
  for (const viewport of viewports) {
351
407
  const viewportSize = resolveViewport(viewport);
352
- await setViewportSize(page, viewportSize);
353
- await stabilizeAndScreenshot(
408
+ await setViewportSize(handler, viewportSize);
409
+ const attachments = await stabilizeAndScreenshot(
354
410
  getScreenshotName(name, { viewportWidth: viewportSize.width })
355
411
  );
412
+ allAttachments.push(...attachments);
413
+ }
414
+ if (!originalViewportSize) {
415
+ throw new Error(`Invariant: viewport size must be saved`);
356
416
  }
357
- await setViewportSize(page, originalViewportSize);
417
+ await setViewportSize(handler, originalViewportSize);
358
418
  } else {
359
- await stabilizeAndScreenshot(name);
419
+ const attachments = await stabilizeAndScreenshot(name);
420
+ allAttachments.push(...attachments);
360
421
  }
361
422
  await afterAll();
423
+ return allAttachments;
362
424
  }
363
425
 
364
426
  // src/csp.ts
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@argos-ci/playwright",
3
3
  "description": "Playwright SDK for visual testing with Argos.",
4
- "version": "5.0.8",
4
+ "version": "5.0.10",
5
5
  "author": "Smooth Code",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -47,9 +47,9 @@
47
47
  "node": ">=18.16.0"
48
48
  },
49
49
  "dependencies": {
50
- "@argos-ci/browser": "4.1.4",
51
- "@argos-ci/core": "3.2.1",
52
- "@argos-ci/util": "2.3.2",
50
+ "@argos-ci/browser": "4.2.1",
51
+ "@argos-ci/core": "3.2.2",
52
+ "@argos-ci/util": "2.3.3",
53
53
  "chalk": "^5.4.1",
54
54
  "debug": "^4.4.0"
55
55
  },
@@ -67,5 +67,5 @@
67
67
  "check-format": "prettier --check --ignore-unknown --ignore-path=../../.gitignore --ignore-path=../../.prettierignore .",
68
68
  "lint": "eslint ."
69
69
  },
70
- "gitHead": "59ebec1a1883175bec3f77a2b885f7f3ef42d7cd"
70
+ "gitHead": "ecab2281c36828d0c43728e3ed98e1eefe227c99"
71
71
  }