@argos-ci/playwright 6.5.0 → 6.6.1

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 DELETED
@@ -1,604 +0,0 @@
1
- // src/aria-snapshot.ts
2
- import { writeFile } from "fs/promises";
3
- import { getMetadataPath, writeMetadata } from "@argos-ci/util";
4
-
5
- // src/util.ts
6
- import { createRequire as createRequire2 } from "module";
7
-
8
- // src/metadata.ts
9
- import {
10
- getGitRepositoryPath,
11
- readVersionFromPackage
12
- } from "@argos-ci/util";
13
- import { relative } from "path";
14
- import { createRequire } from "module";
15
- import { AsyncLocalStorage } from "async_hooks";
16
- var require2 = createRequire(import.meta.url);
17
- function tryResolve(pkg) {
18
- try {
19
- return require2.resolve(pkg);
20
- } catch {
21
- return null;
22
- }
23
- }
24
- var metadataConfigStorage = new AsyncLocalStorage();
25
- function setMetadataConfig(metadata) {
26
- metadataConfigStorage.enterWith(metadata);
27
- }
28
- var DEFAULT_PLAYWRIGHT_LIBRARIES = [
29
- "@playwright/test",
30
- "playwright",
31
- "playwright-core"
32
- ];
33
- function getMetadataOverrides() {
34
- return metadataConfigStorage.getStore();
35
- }
36
- async function getAutomationLibraryMetadata() {
37
- const metadataConfig = metadataConfigStorage.getStore();
38
- const libraries = metadataConfig?.playwrightLibraries ?? DEFAULT_PLAYWRIGHT_LIBRARIES;
39
- for (const name of libraries) {
40
- const pkgPath = tryResolve(`${name}/package.json`);
41
- if (pkgPath) {
42
- const version = await readVersionFromPackage(pkgPath);
43
- return { version, name };
44
- }
45
- }
46
- throw new Error(
47
- `Unable to find any of the following packages: ${libraries.join(", ")}`
48
- );
49
- }
50
- async function getArgosPlaywrightVersion() {
51
- const pkgPath = require2.resolve("@argos-ci/playwright/package.json");
52
- return readVersionFromPackage(pkgPath);
53
- }
54
- async function getSdkMetadata() {
55
- const metadataConfig = metadataConfigStorage.getStore();
56
- if (metadataConfig) {
57
- return metadataConfig.sdk;
58
- }
59
- const argosPlaywrightVersion = await getArgosPlaywrightVersion();
60
- return {
61
- name: "@argos-ci/playwright",
62
- version: argosPlaywrightVersion
63
- };
64
- }
65
- async function getLibraryMetadata() {
66
- const [automationLibrary, sdk] = await Promise.all([
67
- getAutomationLibraryMetadata(),
68
- getSdkMetadata()
69
- ]);
70
- return {
71
- automationLibrary,
72
- sdk
73
- };
74
- }
75
- function resolveTestFilePath(filepath, repositoryPath) {
76
- if (!repositoryPath) {
77
- return filepath;
78
- }
79
- return relative(repositoryPath, filepath);
80
- }
81
- async function getTestMetadata(testInfo) {
82
- const repositoryPath = await getGitRepositoryPath();
83
- const metadataConfig = metadataConfigStorage.getStore();
84
- if (metadataConfig?.test) {
85
- return {
86
- ...metadataConfig.test,
87
- location: metadataConfig.test?.location ? {
88
- file: resolveTestFilePath(
89
- metadataConfig.test.location.file,
90
- repositoryPath
91
- ),
92
- line: metadataConfig.test.location.line,
93
- column: metadataConfig.test.location.column
94
- } : void 0
95
- };
96
- }
97
- if (!testInfo) {
98
- return null;
99
- }
100
- const testMetadata = {
101
- id: testInfo.testId,
102
- title: testInfo.title,
103
- titlePath: testInfo.titlePath,
104
- tags: testInfo.tags.length > 0 ? testInfo.tags : void 0,
105
- retry: testInfo.retry,
106
- retries: testInfo.project.retries,
107
- repeat: testInfo.repeatEachIndex,
108
- location: {
109
- file: resolveTestFilePath(testInfo.file, repositoryPath),
110
- line: testInfo.line,
111
- column: testInfo.column
112
- },
113
- annotations: testInfo.annotations
114
- };
115
- return testMetadata;
116
- }
117
-
118
- // src/util.ts
119
- import {
120
- getGlobalScript
121
- } from "@argos-ci/browser";
122
- import { dirname, resolve } from "path";
123
- import { mkdir } from "fs/promises";
124
- var require3 = createRequire2(import.meta.url);
125
- function checkIsUsingArgosReporter(testInfo) {
126
- if (!testInfo) {
127
- return false;
128
- }
129
- const reporterPath = require3.resolve("@argos-ci/playwright/reporter");
130
- return testInfo.config.reporter.some(
131
- (reporter) => reporter[0].includes("@argos-ci/playwright/reporter") || reporter[0] === reporterPath
132
- );
133
- }
134
- var PNG_EXTENSION = `.png`;
135
- var ARIA_EXTENSION = `.aria.yml`;
136
- var METADATA_EXTENSION = `.argos.json`;
137
- var MAX_NAME_LENGTH = 255 - PNG_EXTENSION.length - METADATA_EXTENSION.length;
138
- async function getTestInfo() {
139
- try {
140
- const { test } = await import("@playwright/test");
141
- return test.info();
142
- } catch {
143
- return null;
144
- }
145
- }
146
- function checkIsPage(value) {
147
- return Boolean(
148
- value && typeof value === "object" && "bringToFront" in value && typeof value.bringToFront === "function"
149
- );
150
- }
151
- function checkIsElementHandle(value) {
152
- return Boolean(
153
- value && typeof value === "object" && "asElement" in value && typeof value.asElement === "function"
154
- );
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
- }
165
- function getViewportSize(page) {
166
- const viewportSize = page.viewportSize();
167
- if (!viewportSize) {
168
- throw new Error("Snapshots can't be taken without a viewport.");
169
- }
170
- return viewportSize;
171
- }
172
- async function setViewportSize(page, viewportSize) {
173
- await page.setViewportSize(viewportSize);
174
- await page.waitForFunction(
175
- ({ width, height }) => window.innerWidth === width && window.innerHeight === height,
176
- { width: viewportSize.width, height: viewportSize.height }
177
- );
178
- }
179
- function getSnapshotNames(name, testInfo) {
180
- if (testInfo) {
181
- const projectName = `${testInfo.project.name}/${name}`;
182
- if (testInfo.repeatEachIndex > 0) {
183
- return {
184
- name: `${projectName} repeat-${testInfo.repeatEachIndex}`,
185
- baseName: projectName
186
- };
187
- }
188
- return { name: projectName, baseName: null };
189
- }
190
- return { name, baseName: null };
191
- }
192
- async function injectArgos(handler) {
193
- const injected = await handler.evaluate(
194
- () => typeof window.__ARGOS__ !== "undefined"
195
- );
196
- if (!injected) {
197
- await handler.addScriptTag({ content: getGlobalScript() });
198
- }
199
- }
200
- async function prepare(args) {
201
- const { handler, useArgosReporter, root } = args;
202
- await Promise.all([
203
- // Create the screenshot folder if it doesn't exist
204
- useArgosReporter ? null : mkdir(root, { recursive: true }),
205
- // Inject Argos script into the page
206
- injectArgos(handler)
207
- ]);
208
- }
209
- async function getPathAndMetadata(args) {
210
- const { handler, testInfo, names, extension, root, useArgosReporter } = args;
211
- const overrides = getMetadataOverrides();
212
- const path = useArgosReporter && testInfo ? testInfo.outputPath("argos", `${names.name}${extension}`) : resolve(root, `${names.name}${extension}`);
213
- const dir = dirname(path);
214
- const [colorScheme, mediaType, libMetadata, testMetadata] = await Promise.all(
215
- [
216
- handler.evaluate(
217
- () => window.__ARGOS__.getColorScheme()
218
- ),
219
- handler.evaluate(
220
- () => window.__ARGOS__.getMediaType()
221
- ),
222
- getLibraryMetadata(),
223
- getTestMetadata(testInfo),
224
- dir !== root ? mkdir(dir, { recursive: true }) : null
225
- ]
226
- );
227
- const viewportSize = checkIsFrame(handler) ? null : getViewportSize(handler);
228
- const browser = getPage(handler).context().browser();
229
- if (!browser) {
230
- throw new Error("Can't take screenshots without a browser.");
231
- }
232
- const browserName = browser.browserType().name();
233
- const browserVersion = browser.version();
234
- const url = overrides?.url ?? handler.url();
235
- const metadata = {
236
- url,
237
- colorScheme,
238
- mediaType,
239
- test: testMetadata,
240
- browser: {
241
- name: browserName,
242
- version: browserVersion
243
- },
244
- ...libMetadata
245
- };
246
- const viewport = viewportSize ?? getMetadataOverrides()?.viewport;
247
- if (viewport) {
248
- metadata.viewport = viewport;
249
- }
250
- metadata.transient = {};
251
- if (names.baseName) {
252
- metadata.transient.baseName = `${names.baseName}${extension}`;
253
- }
254
- return {
255
- metadata,
256
- path
257
- };
258
- }
259
- function screenshotToSnapshotPath(value) {
260
- return value.replace(/\.png$/, ARIA_EXTENSION);
261
- }
262
- async function beforeAll(handler, context, options) {
263
- await handler.evaluate(
264
- (context2) => window.__ARGOS__.beforeAll(context2),
265
- context
266
- );
267
- if (options?.disableHover) {
268
- await getPage(handler).mouse.move(0, 0);
269
- }
270
- return async () => {
271
- await handler.evaluate(
272
- () => window.__ARGOS__.afterAll()
273
- );
274
- };
275
- }
276
- async function beforeEach(handler, context) {
277
- await handler.evaluate(
278
- (context2) => window.__ARGOS__.beforeEach(context2),
279
- context
280
- );
281
- return async () => {
282
- await handler.evaluate(
283
- () => window.__ARGOS__.afterEach()
284
- );
285
- };
286
- }
287
- async function increaseTimeout() {
288
- const testInfo = await getTestInfo();
289
- if (testInfo) {
290
- const { timeout } = testInfo;
291
- testInfo.setTimeout(timeout * 3);
292
- return {
293
- value: timeout,
294
- reset: () => {
295
- testInfo.setTimeout(timeout);
296
- }
297
- };
298
- }
299
- return null;
300
- }
301
- async function waitForReadiness(handler, context) {
302
- const timeout = await increaseTimeout();
303
- try {
304
- await handler.waitForFunction(
305
- (context2) => {
306
- const argos = window.__ARGOS__;
307
- return argos.waitFor(context2);
308
- },
309
- context,
310
- timeout ? { timeout: timeout.value } : void 0
311
- );
312
- timeout?.reset();
313
- } catch (error) {
314
- const reasons = await handler.evaluate(
315
- (context2) => window.__ARGOS__.getWaitFailureExplanations(
316
- context2
317
- ),
318
- context
319
- );
320
- throw new Error(
321
- `
322
- Failed to stabilize screenshot, found the following issues:
323
- ${reasons.map((reason) => `- ${reason}`).join("\n")}
324
- `.trim(),
325
- { cause: error }
326
- );
327
- }
328
- }
329
- async function attachAttachments(args) {
330
- const { attachments, useArgosReporter, testInfo } = args;
331
- if (useArgosReporter && testInfo) {
332
- await Promise.all(
333
- attachments.map(
334
- (attachment) => testInfo.attach(attachment.name, {
335
- path: attachment.path,
336
- contentType: attachment.contentType
337
- })
338
- )
339
- );
340
- }
341
- }
342
-
343
- // src/attachment.ts
344
- function getAttachmentName(name, type) {
345
- return `argos/${type}___${name}`;
346
- }
347
-
348
- // src/aria-snapshot.ts
349
- var DEFAULT_SNAPSHOTS_ROOT = "./screenshots";
350
- async function argosAriaSnapshot(handler, name, options = {}) {
351
- const {
352
- element,
353
- has,
354
- hasText,
355
- hasNot,
356
- hasNotText,
357
- timeout,
358
- root = DEFAULT_SNAPSHOTS_ROOT
359
- } = options;
360
- if (!handler) {
361
- throw new Error("A Playwright `handler` object is required.");
362
- }
363
- if (!name) {
364
- throw new Error("The `name` argument is required.");
365
- }
366
- const snapshotTarget = typeof element === "string" ? handler.locator(element, { has, hasText, hasNot, hasNotText }) : element ?? handler.locator("body");
367
- const testInfo = await getTestInfo();
368
- const useArgosReporter = checkIsUsingArgosReporter(testInfo);
369
- await prepare({ handler, useArgosReporter, root });
370
- const context = getStabilizationContext(options);
371
- const afterAll = await beforeAll(handler, context);
372
- const names = getSnapshotNames(name, testInfo);
373
- const { path: snapshotPath, metadata } = await getPathAndMetadata({
374
- handler,
375
- extension: ARIA_EXTENSION,
376
- names,
377
- root,
378
- testInfo,
379
- useArgosReporter
380
- });
381
- await waitForReadiness(handler, context);
382
- const afterEach = await beforeEach(handler, context);
383
- await waitForReadiness(handler, context);
384
- await Promise.all([
385
- snapshotTarget.ariaSnapshot({ timeout }).then((snapshot) => {
386
- return writeFile(snapshotPath, snapshot, "utf-8");
387
- }),
388
- writeMetadata(snapshotPath, metadata)
389
- ]);
390
- const attachments = [
391
- {
392
- name: getAttachmentName(names.name, "aria"),
393
- contentType: "application/yaml",
394
- path: snapshotPath
395
- },
396
- {
397
- name: getAttachmentName(names.name, "aria/metadata"),
398
- contentType: "application/json",
399
- path: getMetadataPath(snapshotPath)
400
- }
401
- ];
402
- await attachAttachments({ attachments, testInfo, useArgosReporter });
403
- await afterEach();
404
- await afterAll();
405
- return attachments;
406
- }
407
- function getStabilizationContext(options) {
408
- const { stabilize } = options;
409
- return {
410
- fullPage: false,
411
- argosCSS: void 0,
412
- viewports: void 0,
413
- options: stabilize
414
- };
415
- }
416
-
417
- // src/screenshot.ts
418
- import {
419
- resolveViewport
420
- } from "@argos-ci/browser";
421
- import {
422
- getMetadataPath as getMetadataPath2,
423
- getScreenshotName,
424
- validateThreshold,
425
- writeMetadata as writeMetadata2
426
- } from "@argos-ci/util";
427
- import { writeFile as writeFile2 } from "fs/promises";
428
- var DEFAULT_SCREENSHOT_ROOT = "./screenshots";
429
- async function argosScreenshot(handler, name, options = {}) {
430
- const {
431
- element,
432
- has,
433
- hasText,
434
- hasNot,
435
- hasNotText,
436
- viewports,
437
- argosCSS: _argosCSS,
438
- root = DEFAULT_SCREENSHOT_ROOT,
439
- ariaSnapshot,
440
- disableHover = true,
441
- ...playwrightOptions
442
- } = options;
443
- if (!handler) {
444
- throw new Error("A Playwright `handler` object is required.");
445
- }
446
- if (!name) {
447
- throw new Error("The `name` argument is required.");
448
- }
449
- const screenshotTarget = typeof element === "string" ? handler.locator(element, { has, hasText, hasNot, hasNotText }) : element ?? (checkIsFrame(handler) ? handler.locator("body") : handler);
450
- const testInfo = await getTestInfo();
451
- const useArgosReporter = checkIsUsingArgosReporter(testInfo);
452
- await prepare({ handler, useArgosReporter, root });
453
- const originalViewportSize = checkIsFrame(handler) ? null : getViewportSize(handler);
454
- const fullPage = options.fullPage !== void 0 ? options.fullPage : screenshotTarget === handler;
455
- const context = getStabilizationContext2(options);
456
- const afterAll = await beforeAll(handler, context, { disableHover });
457
- const stabilizeAndScreenshot = async (name2) => {
458
- const names = getSnapshotNames(name2, testInfo);
459
- const { path: screenshotPath, metadata } = await getPathAndMetadata({
460
- handler,
461
- extension: PNG_EXTENSION,
462
- root,
463
- names,
464
- testInfo,
465
- useArgosReporter
466
- });
467
- if (options.tag) {
468
- metadata.tags = Array.isArray(options.tag) ? options.tag : [options.tag];
469
- }
470
- if (options.threshold !== void 0) {
471
- validateThreshold(options.threshold);
472
- metadata.transient.threshold = options.threshold;
473
- }
474
- await options.beforeScreenshot?.({
475
- runStabilization: (stabilizationOptions) => waitForReadiness(
476
- handler,
477
- getStabilizationContext2({
478
- ...options,
479
- stabilize: stabilizationOptions ?? options.stabilize
480
- })
481
- )
482
- });
483
- await waitForReadiness(handler, context);
484
- const afterEach = await beforeEach(handler, context);
485
- await waitForReadiness(handler, context);
486
- const [snapshotPath] = await Promise.all([
487
- (async () => {
488
- if (!ariaSnapshot) {
489
- return null;
490
- }
491
- const snapshotTarget = checkIsPage(screenshotTarget) ? screenshotTarget.locator("body") : screenshotTarget;
492
- if (checkIsElementHandle(snapshotTarget)) {
493
- throw new Error(
494
- `Element handle is not supported with "ariaSnapshot" option. Use a Locator instead.`
495
- );
496
- }
497
- const snapshotPath2 = screenshotToSnapshotPath(screenshotPath);
498
- const snapshotMetadata = {
499
- ...metadata,
500
- transient: {
501
- parentName: `${names.name}${PNG_EXTENSION}`,
502
- ...metadata.transient.baseName ? {
503
- baseName: screenshotToSnapshotPath(
504
- metadata.transient.baseName
505
- )
506
- } : {}
507
- }
508
- };
509
- await Promise.all([
510
- snapshotTarget.ariaSnapshot().then((snapshot) => {
511
- return writeFile2(snapshotPath2, snapshot, "utf-8");
512
- }),
513
- writeMetadata2(snapshotPath2, snapshotMetadata)
514
- ]);
515
- return snapshotPath2;
516
- })(),
517
- screenshotTarget.screenshot({
518
- path: screenshotPath,
519
- type: "png",
520
- fullPage,
521
- mask: [handler.locator('[data-visual-test="blackout"]')],
522
- animations: "disabled",
523
- ...playwrightOptions
524
- }),
525
- writeMetadata2(screenshotPath, metadata)
526
- ]);
527
- const attachments = [
528
- {
529
- name: getAttachmentName(names.name, "screenshot"),
530
- contentType: "image/png",
531
- path: screenshotPath
532
- },
533
- {
534
- name: getAttachmentName(names.name, "screenshot/metadata"),
535
- contentType: "application/json",
536
- path: getMetadataPath2(screenshotPath)
537
- }
538
- ];
539
- if (snapshotPath) {
540
- attachments.push(
541
- {
542
- name: getAttachmentName(names.name, "aria"),
543
- contentType: "application/yaml",
544
- path: snapshotPath
545
- },
546
- {
547
- name: getAttachmentName(names.name, "aria/metadata"),
548
- contentType: "application/json",
549
- path: getMetadataPath2(snapshotPath)
550
- }
551
- );
552
- }
553
- await attachAttachments({ attachments, testInfo, useArgosReporter });
554
- await afterEach();
555
- await options.afterScreenshot?.();
556
- return attachments;
557
- };
558
- const allAttachments = [];
559
- if (viewports) {
560
- if (checkIsFrame(handler)) {
561
- throw new Error(`viewports option is not supported with an iframe`);
562
- }
563
- for (const viewport of viewports) {
564
- const viewportSize = resolveViewport(viewport);
565
- await setViewportSize(handler, viewportSize);
566
- const attachments = await stabilizeAndScreenshot(
567
- getScreenshotName(name, { viewportWidth: viewportSize.width })
568
- );
569
- allAttachments.push(...attachments);
570
- }
571
- if (!originalViewportSize) {
572
- throw new Error(`Invariant: viewport size must be saved`);
573
- }
574
- await setViewportSize(handler, originalViewportSize);
575
- } else {
576
- const attachments = await stabilizeAndScreenshot(name);
577
- allAttachments.push(...attachments);
578
- }
579
- await afterAll();
580
- return allAttachments;
581
- }
582
- function getStabilizationContext2(options) {
583
- const { fullPage, argosCSS, stabilize, viewports } = options;
584
- return {
585
- fullPage,
586
- argosCSS,
587
- viewports,
588
- options: stabilize
589
- };
590
- }
591
-
592
- // src/csp.ts
593
- import { getGlobalScript as getGlobalScript2 } from "@argos-ci/browser";
594
- import { createHash } from "crypto";
595
- function getCSPScriptHash() {
596
- const hash = createHash("sha256").update(getGlobalScript2()).digest("base64");
597
- return `'sha256-${hash}'`;
598
- }
599
- export {
600
- setMetadataConfig as DO_NOT_USE_setMetadataConfig,
601
- argosAriaSnapshot,
602
- argosScreenshot,
603
- getCSPScriptHash
604
- };
@@ -1,70 +0,0 @@
1
- import { TestCase, Reporter, FullConfig, TestResult, FullResult } from '@playwright/test/reporter';
2
- import { UploadParameters } from '@argos-ci/core';
3
-
4
- /**
5
- * Dynamic build name.
6
- * We require all values in order to ensure it works correctly in parallel mode.
7
- */
8
- type DynamicBuildName<T extends readonly string[]> = {
9
- /**
10
- * The values that the build name can take.
11
- * It is required to ensure Argos will always upload
12
- * for each build name in order to work in sharding mode.
13
- */
14
- values: readonly [...T];
15
- /**
16
- * Get the build name for a test case.
17
- * Returns any of the values in `values`.
18
- */
19
- get: (test: TestCase) => T[number];
20
- };
21
- type ArgosReporterOptions<T extends string[] = string[]> = Omit<UploadParameters, "files" | "root" | "buildName" | "metadata"> & {
22
- /**
23
- * Upload the report to Argos.
24
- * @default true
25
- */
26
- uploadToArgos?: boolean;
27
- /**
28
- * If true, the reporter will not fail the test suite when the upload fails.
29
- * @default false
30
- */
31
- ignoreUploadFailures?: boolean;
32
- /**
33
- * The name of the build in Argos.
34
- * Can be a string or a function that receives the test case and returns the build name.
35
- */
36
- buildName?: string | DynamicBuildName<T> | null;
37
- };
38
- declare function createArgosReporterOptions<T extends string[]>(options: ArgosReporterOptions<T>): ArgosReporterOptions<T>;
39
- declare class ArgosReporter implements Reporter {
40
- rootUploadDirectoryPromise: null | Promise<string>;
41
- uploadDirectoryPromises: Map<string, Promise<string>>;
42
- config: ArgosReporterOptions;
43
- playwrightConfig: FullConfig;
44
- uploadToArgos: boolean;
45
- constructor(config: ArgosReporterOptions);
46
- /**
47
- * Write a file to the temporary directory.
48
- */
49
- writeFile(path: string, body: Buffer | string): Promise<void>;
50
- /**
51
- * Copy a file to the temporary directory.
52
- */
53
- copyFile(from: string, to: string): Promise<void>;
54
- /**
55
- * Copy the trace file if found in the result.
56
- */
57
- copyTraceIfFound(result: TestResult, path: string): Promise<void>;
58
- /**
59
- * Get the root upload directory (cached).
60
- */
61
- getRootUploadDirectory(): Promise<string>;
62
- onBegin(config: FullConfig): void;
63
- onTestEnd(test: TestCase, result: TestResult): Promise<void>;
64
- onEnd(result: FullResult): Promise<{
65
- status: "failed";
66
- } | undefined>;
67
- printsToStdio(): boolean;
68
- }
69
-
70
- export { type ArgosReporterOptions, createArgosReporterOptions, ArgosReporter as default };