@argos-ci/playwright 6.2.0 → 6.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,34 +1,9 @@
1
- // src/screenshot.ts
2
- import { mkdir } from "fs/promises";
3
- import { resolve, dirname } from "path";
4
- import {
5
- resolveViewport,
6
- getGlobalScript
7
- } from "@argos-ci/browser";
8
- import {
9
- getMetadataPath,
10
- getScreenshotName,
11
- validateThreshold,
12
- writeMetadata
13
- } from "@argos-ci/util";
1
+ // src/aria-snapshot.ts
2
+ import { writeFile } from "fs/promises";
3
+ import { getMetadataPath, writeMetadata } from "@argos-ci/util";
14
4
 
15
5
  // src/util.ts
16
- import { createRequire } from "module";
17
- var require2 = createRequire(import.meta.url);
18
- function checkIsUsingArgosReporter(testInfo) {
19
- const reporterPath = require2.resolve("@argos-ci/playwright/reporter");
20
- return testInfo.config.reporter.some(
21
- (reporter) => reporter[0].includes("@argos-ci/playwright/reporter") || reporter[0] === reporterPath
22
- );
23
- }
24
- var PNG_EXTENSION = `.png`;
25
- var METADATA_EXTENSION = `.argos.json`;
26
- var MAX_NAME_LENGTH = 255 - PNG_EXTENSION.length - METADATA_EXTENSION.length;
27
-
28
- // src/attachment.ts
29
- function getAttachmentName(name, type) {
30
- return `argos/${type}___${name}`;
31
- }
6
+ import { createRequire as createRequire2 } from "module";
32
7
 
33
8
  // src/metadata.ts
34
9
  import {
@@ -36,12 +11,12 @@ import {
36
11
  readVersionFromPackage
37
12
  } from "@argos-ci/util";
38
13
  import { relative } from "path";
39
- import { createRequire as createRequire2 } from "module";
14
+ import { createRequire } from "module";
40
15
  import { AsyncLocalStorage } from "async_hooks";
41
- var require3 = createRequire2(import.meta.url);
16
+ var require2 = createRequire(import.meta.url);
42
17
  function tryResolve(pkg) {
43
18
  try {
44
- return require3.resolve(pkg);
19
+ return require2.resolve(pkg);
45
20
  } catch {
46
21
  return null;
47
22
  }
@@ -73,7 +48,7 @@ async function getAutomationLibraryMetadata() {
73
48
  );
74
49
  }
75
50
  async function getArgosPlaywrightVersion() {
76
- const pkgPath = require3.resolve("@argos-ci/playwright/package.json");
51
+ const pkgPath = require2.resolve("@argos-ci/playwright/package.json");
77
52
  return readVersionFromPackage(pkgPath);
78
53
  }
79
54
  async function getSdkMetadata() {
@@ -139,16 +114,26 @@ async function getTestMetadata(testInfo) {
139
114
  return testMetadata;
140
115
  }
141
116
 
142
- // src/screenshot.ts
143
- var DEFAULT_SCREENSHOT_ROOT = "./screenshots";
144
- async function injectArgos(handler) {
145
- const injected = await handler.evaluate(
146
- () => typeof window.__ARGOS__ !== "undefined"
147
- );
148
- if (!injected) {
149
- await handler.addScriptTag({ content: getGlobalScript() });
117
+ // src/util.ts
118
+ import {
119
+ getGlobalScript
120
+ } from "@argos-ci/browser";
121
+ import { dirname, resolve } from "path";
122
+ import { mkdir } from "fs/promises";
123
+ var require3 = createRequire2(import.meta.url);
124
+ function checkIsUsingArgosReporter(testInfo) {
125
+ if (!testInfo) {
126
+ return false;
150
127
  }
128
+ const reporterPath = require3.resolve("@argos-ci/playwright/reporter");
129
+ return testInfo.config.reporter.some(
130
+ (reporter) => reporter[0].includes("@argos-ci/playwright/reporter") || reporter[0] === reporterPath
131
+ );
151
132
  }
133
+ var PNG_EXTENSION = `.png`;
134
+ var ARIA_EXTENSION = `.aria.yml`;
135
+ var METADATA_EXTENSION = `.argos.json`;
136
+ var MAX_NAME_LENGTH = 255 - PNG_EXTENSION.length - METADATA_EXTENSION.length;
152
137
  async function getTestInfo() {
153
138
  try {
154
139
  const { test } = await import("@playwright/test");
@@ -157,6 +142,16 @@ async function getTestInfo() {
157
142
  return null;
158
143
  }
159
144
  }
145
+ function checkIsPage(value) {
146
+ return Boolean(
147
+ value && typeof value === "object" && "bringToFront" in value && typeof value.bringToFront === "function"
148
+ );
149
+ }
150
+ function checkIsElementHandle(value) {
151
+ return Boolean(
152
+ value && typeof value === "object" && "asElement" in value && typeof value.asElement === "function"
153
+ );
154
+ }
160
155
  function checkIsFrame(handler) {
161
156
  return "page" in handler && typeof handler.page === "function";
162
157
  }
@@ -169,7 +164,7 @@ function getPage(handler) {
169
164
  function getViewportSize(page) {
170
165
  const viewportSize = page.viewportSize();
171
166
  if (!viewportSize) {
172
- throw new Error("Can't take screenshots without a viewport.");
167
+ throw new Error("Snapshots can't be taken without a viewport.");
173
168
  }
174
169
  return viewportSize;
175
170
  }
@@ -180,23 +175,95 @@ async function setViewportSize(page, viewportSize) {
180
175
  { width: viewportSize.width, height: viewportSize.height }
181
176
  );
182
177
  }
183
- function getStabilizationContext(options) {
184
- const { fullPage, argosCSS, stabilize, viewports } = options;
178
+ function getSnapshotNames(name, testInfo) {
179
+ if (testInfo) {
180
+ const projectName = `${testInfo.project.name}/${name}`;
181
+ if (testInfo.repeatEachIndex > 0) {
182
+ return {
183
+ name: `${projectName} repeat-${testInfo.repeatEachIndex}`,
184
+ baseName: projectName
185
+ };
186
+ }
187
+ return { name: projectName, baseName: null };
188
+ }
189
+ return { name, baseName: null };
190
+ }
191
+ async function injectArgos(handler) {
192
+ const injected = await handler.evaluate(
193
+ () => typeof window.__ARGOS__ !== "undefined"
194
+ );
195
+ if (!injected) {
196
+ await handler.addScriptTag({ content: getGlobalScript() });
197
+ }
198
+ }
199
+ async function prepare(args) {
200
+ const { handler, useArgosReporter, root } = args;
201
+ await Promise.all([
202
+ // Create the screenshot folder if it doesn't exist
203
+ useArgosReporter ? null : mkdir(root, { recursive: true }),
204
+ // Inject Argos script into the page
205
+ injectArgos(handler)
206
+ ]);
207
+ }
208
+ async function getPathAndMetadata(args) {
209
+ const { handler, testInfo, names, extension, root, useArgosReporter } = args;
210
+ const overrides = getMetadataOverrides();
211
+ const path = useArgosReporter && testInfo ? testInfo.outputPath("argos", `${names.name}${extension}`) : resolve(root, `${names.name}${extension}`);
212
+ const dir = dirname(path);
213
+ const [colorScheme, mediaType, libMetadata, testMetadata] = await Promise.all(
214
+ [
215
+ handler.evaluate(
216
+ () => window.__ARGOS__.getColorScheme()
217
+ ),
218
+ handler.evaluate(
219
+ () => window.__ARGOS__.getMediaType()
220
+ ),
221
+ getLibraryMetadata(),
222
+ getTestMetadata(testInfo),
223
+ dir !== root ? mkdir(dir, { recursive: true }) : null
224
+ ]
225
+ );
226
+ const viewportSize = checkIsFrame(handler) ? null : getViewportSize(handler);
227
+ const browser = getPage(handler).context().browser();
228
+ if (!browser) {
229
+ throw new Error("Can't take screenshots without a browser.");
230
+ }
231
+ const browserName = browser.browserType().name();
232
+ const browserVersion = browser.version();
233
+ const url = overrides?.url ?? handler.url();
234
+ const metadata = {
235
+ url,
236
+ colorScheme,
237
+ mediaType,
238
+ test: testMetadata,
239
+ browser: {
240
+ name: browserName,
241
+ version: browserVersion
242
+ },
243
+ ...libMetadata
244
+ };
245
+ const viewport = viewportSize ?? getMetadataOverrides()?.viewport;
246
+ if (viewport) {
247
+ metadata.viewport = viewport;
248
+ }
249
+ metadata.transient = {};
250
+ if (names.baseName) {
251
+ metadata.transient.baseName = `${names.baseName}${extension}`;
252
+ }
185
253
  return {
186
- fullPage,
187
- argosCSS,
188
- viewports,
189
- options: stabilize
254
+ metadata,
255
+ path
190
256
  };
191
257
  }
192
- async function beforeAll(handler, options) {
193
- const { disableHover = true } = options;
194
- const context = getStabilizationContext(options);
258
+ function screenshotToSnapshotPath(value) {
259
+ return value.replace(/\.png$/, ARIA_EXTENSION);
260
+ }
261
+ async function beforeAll(handler, context, options) {
195
262
  await handler.evaluate(
196
263
  (context2) => window.__ARGOS__.beforeAll(context2),
197
264
  context
198
265
  );
199
- if (disableHover) {
266
+ if (options?.disableHover) {
200
267
  await getPage(handler).mouse.move(0, 0);
201
268
  }
202
269
  return async () => {
@@ -205,8 +272,7 @@ async function beforeAll(handler, options) {
205
272
  );
206
273
  };
207
274
  }
208
- async function beforeEach(handler, options) {
209
- const context = getStabilizationContext(options);
275
+ async function beforeEach(handler, context) {
210
276
  await handler.evaluate(
211
277
  (context2) => window.__ARGOS__.beforeEach(context2),
212
278
  context
@@ -231,8 +297,7 @@ async function increaseTimeout() {
231
297
  }
232
298
  return null;
233
299
  }
234
- async function waitForReadiness(handler, options) {
235
- const context = getStabilizationContext(options);
300
+ async function waitForReadiness(handler, context) {
236
301
  const timeout = await increaseTimeout();
237
302
  try {
238
303
  await handler.waitForFunction(
@@ -260,27 +325,118 @@ ${reasons.map((reason) => `- ${reason}`).join("\n")}
260
325
  );
261
326
  }
262
327
  }
263
- function getScreenshotNames(name, testInfo) {
264
- if (testInfo) {
265
- const projectName = `${testInfo.project.name}/${name}`;
266
- if (testInfo.repeatEachIndex > 0) {
267
- return {
268
- name: `${projectName} repeat-${testInfo.repeatEachIndex}`,
269
- baseName: projectName
270
- };
271
- }
272
- return { name: projectName, baseName: null };
328
+ async function attachAttachments(args) {
329
+ const { attachments, useArgosReporter, testInfo } = args;
330
+ if (useArgosReporter && testInfo) {
331
+ await Promise.all(
332
+ attachments.map(
333
+ (attachment) => testInfo.attach(attachment.name, {
334
+ path: attachment.path,
335
+ contentType: attachment.contentType
336
+ })
337
+ )
338
+ );
273
339
  }
274
- return { name, baseName: null };
275
340
  }
341
+
342
+ // src/attachment.ts
343
+ function getAttachmentName(name, type) {
344
+ return `argos/${type}___${name}`;
345
+ }
346
+
347
+ // src/aria-snapshot.ts
348
+ var DEFAULT_SNAPSHOTS_ROOT = "./screenshots";
349
+ async function argosAriaSnapshot(handler, name, options = {}) {
350
+ const {
351
+ element,
352
+ has,
353
+ hasText,
354
+ hasNot,
355
+ hasNotText,
356
+ timeout,
357
+ root = DEFAULT_SNAPSHOTS_ROOT
358
+ } = options;
359
+ if (!handler) {
360
+ throw new Error("A Playwright `handler` object is required.");
361
+ }
362
+ if (!name) {
363
+ throw new Error("The `name` argument is required.");
364
+ }
365
+ const snapshotTarget = typeof element === "string" ? handler.locator(element, { has, hasText, hasNot, hasNotText }) : element ?? handler.locator("body");
366
+ const testInfo = await getTestInfo();
367
+ const useArgosReporter = checkIsUsingArgosReporter(testInfo);
368
+ await prepare({ handler, useArgosReporter, root });
369
+ const context = getStabilizationContext(options);
370
+ const afterAll = await beforeAll(handler, context);
371
+ const names = getSnapshotNames(name, testInfo);
372
+ const { path: snapshotPath, metadata } = await getPathAndMetadata({
373
+ handler,
374
+ extension: ARIA_EXTENSION,
375
+ names,
376
+ root,
377
+ testInfo,
378
+ useArgosReporter
379
+ });
380
+ await waitForReadiness(handler, context);
381
+ const afterEach = await beforeEach(handler, context);
382
+ await waitForReadiness(handler, context);
383
+ await Promise.all([
384
+ snapshotTarget.ariaSnapshot({ timeout }).then((snapshot) => {
385
+ return writeFile(snapshotPath, snapshot, "utf-8");
386
+ }),
387
+ writeMetadata(snapshotPath, metadata)
388
+ ]);
389
+ const attachments = [
390
+ {
391
+ name: getAttachmentName(names.name, "aria"),
392
+ contentType: "application/yaml",
393
+ path: snapshotPath
394
+ },
395
+ {
396
+ name: getAttachmentName(names.name, "aria/metadata"),
397
+ contentType: "application/json",
398
+ path: getMetadataPath(snapshotPath)
399
+ }
400
+ ];
401
+ await attachAttachments({ attachments, testInfo, useArgosReporter });
402
+ await afterEach();
403
+ await afterAll();
404
+ return attachments;
405
+ }
406
+ function getStabilizationContext(options) {
407
+ const { stabilize } = options;
408
+ return {
409
+ fullPage: false,
410
+ argosCSS: void 0,
411
+ viewports: void 0,
412
+ options: stabilize
413
+ };
414
+ }
415
+
416
+ // src/screenshot.ts
417
+ import {
418
+ resolveViewport
419
+ } from "@argos-ci/browser";
420
+ import {
421
+ getMetadataPath as getMetadataPath2,
422
+ getScreenshotName,
423
+ validateThreshold,
424
+ writeMetadata as writeMetadata2
425
+ } from "@argos-ci/util";
426
+ import { writeFile as writeFile2 } from "fs/promises";
427
+ var DEFAULT_SCREENSHOT_ROOT = "./screenshots";
276
428
  async function argosScreenshot(handler, name, options = {}) {
277
429
  const {
278
430
  element,
279
431
  has,
280
432
  hasText,
433
+ hasNot,
434
+ hasNotText,
281
435
  viewports,
282
436
  argosCSS: _argosCSS,
283
437
  root = DEFAULT_SCREENSHOT_ROOT,
438
+ ariaSnapshot,
439
+ disableHover = true,
284
440
  ...playwrightOptions
285
441
  } = options;
286
442
  if (!handler) {
@@ -289,83 +445,71 @@ async function argosScreenshot(handler, name, options = {}) {
289
445
  if (!name) {
290
446
  throw new Error("The `name` argument is required.");
291
447
  }
292
- const screenshotTarget = typeof element === "string" ? handler.locator(element, { has, hasText }) : element ?? (checkIsFrame(handler) ? handler.locator("body") : handler);
448
+ const screenshotTarget = typeof element === "string" ? handler.locator(element, { has, hasText, hasNot, hasNotText }) : element ?? (checkIsFrame(handler) ? handler.locator("body") : handler);
293
449
  const testInfo = await getTestInfo();
294
- const useArgosReporter = Boolean(
295
- testInfo && checkIsUsingArgosReporter(testInfo)
296
- );
297
- await Promise.all([
298
- // Create the screenshot folder if it doesn't exist
299
- useArgosReporter ? null : mkdir(root, { recursive: true }),
300
- // Inject Argos script into the page
301
- injectArgos(handler)
302
- ]);
450
+ const useArgosReporter = checkIsUsingArgosReporter(testInfo);
451
+ await prepare({ handler, useArgosReporter, root });
303
452
  const originalViewportSize = checkIsFrame(handler) ? null : getViewportSize(handler);
304
453
  const fullPage = options.fullPage !== void 0 ? options.fullPage : screenshotTarget === handler;
305
- const afterAll = await beforeAll(handler, options);
306
- const collectMetadata = async (testInfo2) => {
307
- const overrides = getMetadataOverrides();
308
- const [colorScheme, mediaType, libMetadata, testMetadata] = await Promise.all([
309
- handler.evaluate(
310
- () => window.__ARGOS__.getColorScheme()
311
- ),
312
- handler.evaluate(
313
- () => window.__ARGOS__.getMediaType()
314
- ),
315
- getLibraryMetadata(),
316
- getTestMetadata(testInfo2)
317
- ]);
318
- const viewportSize = checkIsFrame(handler) ? null : getViewportSize(handler);
319
- const browser = getPage(handler).context().browser();
320
- if (!browser) {
321
- throw new Error("Can't take screenshots without a browser.");
322
- }
323
- const browserName = browser.browserType().name();
324
- const browserVersion = browser.version();
325
- const url = overrides?.url ?? handler.url();
326
- const metadata = {
327
- url,
328
- colorScheme,
329
- mediaType,
330
- test: testMetadata,
331
- browser: {
332
- name: browserName,
333
- version: browserVersion
334
- },
335
- ...libMetadata
336
- };
337
- const viewport = viewportSize ?? getMetadataOverrides()?.viewport;
338
- if (viewport) {
339
- metadata.viewport = viewport;
340
- }
341
- return metadata;
342
- };
454
+ const context = getStabilizationContext2(options);
455
+ const afterAll = await beforeAll(handler, context, { disableHover });
343
456
  const stabilizeAndScreenshot = async (name2) => {
344
- const names = getScreenshotNames(name2, testInfo);
345
- const metadata = await collectMetadata(testInfo);
346
- metadata.transient = {};
457
+ const names = getSnapshotNames(name2, testInfo);
458
+ const { path: screenshotPath, metadata } = await getPathAndMetadata({
459
+ handler,
460
+ extension: PNG_EXTENSION,
461
+ root,
462
+ names,
463
+ testInfo,
464
+ useArgosReporter
465
+ });
347
466
  if (options.threshold !== void 0) {
348
467
  validateThreshold(options.threshold);
349
468
  metadata.transient.threshold = options.threshold;
350
469
  }
351
- if (names.baseName) {
352
- metadata.transient.baseName = `${names.baseName}.png`;
353
- }
354
- const screenshotPath = useArgosReporter && testInfo ? testInfo.outputPath("argos", `${names.name}.png`) : resolve(root, `${names.name}.png`);
355
- const dir = dirname(screenshotPath);
356
- if (dir !== root) {
357
- await mkdir(dirname(screenshotPath), { recursive: true });
358
- }
359
470
  await options.beforeScreenshot?.({
360
- runStabilization: (stabilizationOptions) => waitForReadiness(handler, {
361
- ...options,
362
- stabilize: stabilizationOptions ?? options.stabilize
363
- })
471
+ runStabilization: (stabilizationOptions) => waitForReadiness(
472
+ handler,
473
+ getStabilizationContext2({
474
+ ...options,
475
+ stabilize: stabilizationOptions ?? options.stabilize
476
+ })
477
+ )
364
478
  });
365
479
  await waitForReadiness(handler, options);
366
- const afterEach = await beforeEach(handler, options);
480
+ const afterEach = await beforeEach(handler, context);
367
481
  await waitForReadiness(handler, options);
368
- await Promise.all([
482
+ const [snapshotPath] = await Promise.all([
483
+ (async () => {
484
+ if (!ariaSnapshot) {
485
+ return null;
486
+ }
487
+ const snapshotTarget = checkIsPage(screenshotTarget) ? screenshotTarget.locator("body") : screenshotTarget;
488
+ if (checkIsElementHandle(snapshotTarget)) {
489
+ throw new Error(
490
+ `Element handle is not supported with "ariaSnapshot" option. Use a Locator instead.`
491
+ );
492
+ }
493
+ const snapshotPath2 = screenshotToSnapshotPath(screenshotPath);
494
+ const snapshotMetadata = {
495
+ ...metadata,
496
+ transient: {
497
+ parentName: `${names.name}${PNG_EXTENSION}`,
498
+ ...metadata.transient.baseName ? {
499
+ baseName: screenshotToSnapshotPath(
500
+ metadata.transient.baseName
501
+ )
502
+ } : {}
503
+ }
504
+ };
505
+ await Promise.all([
506
+ snapshotTarget.ariaSnapshot().then((snapshot) => {
507
+ return writeFile2(snapshotPath2, snapshot, "utf-8");
508
+ }),
509
+ writeMetadata2(snapshotPath2, snapshotMetadata)
510
+ ]);
511
+ return snapshotPath2;
512
+ })(),
369
513
  screenshotTarget.screenshot({
370
514
  path: screenshotPath,
371
515
  type: "png",
@@ -374,7 +518,7 @@ async function argosScreenshot(handler, name, options = {}) {
374
518
  animations: "disabled",
375
519
  ...playwrightOptions
376
520
  }),
377
- writeMetadata(screenshotPath, metadata)
521
+ writeMetadata2(screenshotPath, metadata)
378
522
  ]);
379
523
  const attachments = [
380
524
  {
@@ -383,21 +527,26 @@ async function argosScreenshot(handler, name, options = {}) {
383
527
  path: screenshotPath
384
528
  },
385
529
  {
386
- name: getAttachmentName(names.name, "metadata"),
530
+ name: getAttachmentName(names.name, "screenshot/metadata"),
387
531
  contentType: "application/json",
388
- path: getMetadataPath(screenshotPath)
532
+ path: getMetadataPath2(screenshotPath)
389
533
  }
390
534
  ];
391
- if (useArgosReporter && testInfo) {
392
- await Promise.all(
393
- attachments.map(
394
- (attachment) => testInfo.attach(attachment.name, {
395
- path: attachment.path,
396
- contentType: attachment.contentType
397
- })
398
- )
535
+ if (snapshotPath) {
536
+ attachments.push(
537
+ {
538
+ name: getAttachmentName(names.name, "aria"),
539
+ contentType: "application/yaml",
540
+ path: snapshotPath
541
+ },
542
+ {
543
+ name: getAttachmentName(names.name, "aria/metadata"),
544
+ contentType: "application/json",
545
+ path: getMetadataPath2(snapshotPath)
546
+ }
399
547
  );
400
548
  }
549
+ await attachAttachments({ attachments, testInfo, useArgosReporter });
401
550
  await afterEach();
402
551
  await options.afterScreenshot?.();
403
552
  return attachments;
@@ -426,6 +575,15 @@ async function argosScreenshot(handler, name, options = {}) {
426
575
  await afterAll();
427
576
  return allAttachments;
428
577
  }
578
+ function getStabilizationContext2(options) {
579
+ const { fullPage, argosCSS, stabilize, viewports } = options;
580
+ return {
581
+ fullPage,
582
+ argosCSS,
583
+ viewports,
584
+ options: stabilize
585
+ };
586
+ }
429
587
 
430
588
  // src/csp.ts
431
589
  import { getGlobalScript as getGlobalScript2 } from "@argos-ci/browser";
@@ -436,6 +594,7 @@ function getCSPScriptHash() {
436
594
  }
437
595
  export {
438
596
  setMetadataConfig as DO_NOT_USE_setMetadataConfig,
597
+ argosAriaSnapshot,
439
598
  argosScreenshot,
440
599
  getCSPScriptHash
441
600
  };