@crvy/rprtr 0.0.4 → 0.0.5

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/reporter.cjs CHANGED
@@ -47,6 +47,30 @@ var import_url = require("url");
47
47
  function normalizeScreenshotsBaseUrl(baseUrl) {
48
48
  return baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
49
49
  }
50
+ function classifyImage(image) {
51
+ if (image.actual !== void 0 || image.diff !== void 0) {
52
+ return "comparison";
53
+ }
54
+ if (image.expect !== void 0) {
55
+ return "baseline-only";
56
+ }
57
+ return "declared-only";
58
+ }
59
+ function withImageSource(image) {
60
+ return {
61
+ ...image,
62
+ source: classifyImage(image)
63
+ };
64
+ }
65
+ function mergeDeclaredImages(images, visualNames) {
66
+ const names = /* @__PURE__ */ new Set([...Object.keys(images), ...visualNames]);
67
+ return Object.fromEntries(
68
+ Array.from(names, (name) => {
69
+ const current = images[name] ?? {};
70
+ return [name, withImageSource(current)];
71
+ })
72
+ );
73
+ }
50
74
  function attachmentsToImages(attachments, screenshotsBaseUrl = "/screenshots/") {
51
75
  const images = {};
52
76
  const baseUrl = normalizeScreenshotsBaseUrl(screenshotsBaseUrl);
@@ -57,7 +81,7 @@ function attachmentsToImages(attachments, screenshotsBaseUrl = "/screenshots/")
57
81
  const baseName = match[1];
58
82
  const role = match[2];
59
83
  if (baseName === null || baseName === void 0 || role === null || role === void 0) continue;
60
- images[baseName] ??= { actual: "" };
84
+ images[baseName] ??= {};
61
85
  const url = `${baseUrl}${attachment.path}`;
62
86
  const img = images[baseName];
63
87
  if (img !== null && img !== void 0) {
@@ -68,10 +92,11 @@ function attachmentsToImages(attachments, screenshotsBaseUrl = "/screenshots/")
68
92
  }
69
93
  for (const key of Object.keys(images)) {
70
94
  const img = images[key];
71
- if (img?.actual !== null && img?.actual !== void 0 && img?.expect !== null && img?.expect !== void 0 && img?.diff === void 0)
95
+ if (img?.actual !== void 0 && img?.expect !== void 0 && img?.diff === void 0) {
72
96
  delete img.expect;
97
+ }
73
98
  }
74
- return images;
99
+ return mergeDeclaredImages(images, []);
75
100
  }
76
101
  function mapStatus(status) {
77
102
  switch (status) {
@@ -87,17 +112,39 @@ function mapStatus(status) {
87
112
  }
88
113
 
89
114
  // src/report-state.ts
90
- function hasReviewablePassingImages(images) {
91
- return Object.values(images).some(
92
- (img) => img !== null && img !== void 0 && img.actual !== null && img.actual !== void 0 && img.diff === void 0
93
- );
115
+ function isCurrentArtifact(image) {
116
+ return image?.actual !== void 0 || image?.expect !== void 0 || image?.diff !== void 0;
117
+ }
118
+ function isReusablePassingImage(image) {
119
+ const source = image.source ?? classifyImage(image);
120
+ if (source === "comparison") {
121
+ return image.actual !== void 0 && image.diff === void 0;
122
+ }
123
+ return source === "baseline-only";
124
+ }
125
+ function hasReusablePassingImages(images) {
126
+ return Object.values(images).some((img) => img !== null && img !== void 0 && isReusablePassingImage(img));
94
127
  }
95
128
  function preservePreviousPassingImages(test, status, images) {
96
- if (status !== "passed" || Object.keys(images).length > 0) {
129
+ if (status !== "passed") {
97
130
  return images;
98
131
  }
99
132
  const previousImages = test.results?.[0]?.images ?? {};
100
- return hasReviewablePassingImages(previousImages) ? previousImages : images;
133
+ if (!hasReusablePassingImages(previousImages)) {
134
+ return images;
135
+ }
136
+ return Object.entries(previousImages).reduce((currentImages, [name, previousImage]) => {
137
+ if (!Object.hasOwn(currentImages, name) || previousImage === void 0 || !isReusablePassingImage(previousImage) || isCurrentArtifact(currentImages[name])) {
138
+ return currentImages;
139
+ }
140
+ return {
141
+ ...currentImages,
142
+ [name]: {
143
+ ...previousImage,
144
+ source: previousImage.source ?? classifyImage(previousImage)
145
+ }
146
+ };
147
+ }, images);
101
148
  }
102
149
  function countDiffImages(images) {
103
150
  return Object.values(images).filter((img) => img?.diff !== null && img?.diff !== void 0).length;
@@ -133,10 +180,11 @@ function applyTestEndEvent(state, data, options = {}) {
133
180
  return null;
134
181
  }
135
182
  test.status = mapStatus(data.status);
183
+ const resultStatus = data.status === "passed" ? "success" : data.status === "failed" ? "failed" : "pending";
136
184
  const images = preservePreviousPassingImages(
137
185
  test,
138
186
  data.status,
139
- attachmentsToImages(data.attachments, options.screenshotsBaseUrl)
187
+ mergeDeclaredImages(attachmentsToImages(data.attachments, options.screenshotsBaseUrl), data.visualNames)
140
188
  );
141
189
  const diffCount = countDiffImages(images);
142
190
  const hasDiffs = diffCount > 0;
@@ -145,7 +193,7 @@ function applyTestEndEvent(state, data, options = {}) {
145
193
  }
146
194
  test.results = [
147
195
  {
148
- status: data.status === "passed" ? "success" : "failed",
196
+ status: resultStatus,
149
197
  retries: 0,
150
198
  images,
151
199
  error: data.error,
@@ -177,11 +225,13 @@ var LocationSchema = import_zod.z.object({
177
225
  file: import_zod.z.string(),
178
226
  line: import_zod.z.number()
179
227
  });
228
+ var VisualSourceSchema = import_zod.z.enum(["comparison", "baseline-only", "declared-only"]);
180
229
  var ImagesSchema = import_zod.z.object({
181
- actual: import_zod.z.string(),
230
+ actual: import_zod.z.string().optional(),
182
231
  expect: import_zod.z.string().optional(),
183
232
  diff: import_zod.z.string().optional(),
184
- error: import_zod.z.string().optional()
233
+ error: import_zod.z.string().optional(),
234
+ source: VisualSourceSchema.optional()
185
235
  });
186
236
  var AttachmentSchema = import_zod.z.object({
187
237
  name: import_zod.z.string(),
@@ -189,10 +239,10 @@ var AttachmentSchema = import_zod.z.object({
189
239
  contentType: import_zod.z.string()
190
240
  });
191
241
  var TestStatusSchema = import_zod.z.enum(["unknown", "pending", "running", "failed", "approved", "success", "retrying"]);
242
+ var TestResultStatusSchema = import_zod.z.enum(["failed", "success", "pending"]);
192
243
  var TestResultSchema = import_zod.z.object({
193
- status: import_zod.z.enum(["failed", "success"]),
244
+ status: TestResultStatusSchema,
194
245
  retries: import_zod.z.number(),
195
- // eslint-disable-next-line typescript/no-unsafe-type-assertion
196
246
  images: import_zod.z.record(import_zod.z.string(), ImagesSchema).optional(),
197
247
  error: import_zod.z.string().optional(),
198
248
  duration: import_zod.z.number().optional()
@@ -221,7 +271,6 @@ var CrvyRprtrSuiteSchema = import_zod.z.lazy(
221
271
  opened: import_zod.z.boolean(),
222
272
  checked: import_zod.z.boolean(),
223
273
  indeterminate: import_zod.z.boolean(),
224
- // eslint-disable-next-line typescript/no-unsafe-type-assertion
225
274
  children: import_zod.z.record(import_zod.z.string(), import_zod.z.union([CrvyRprtrSuiteSchema, CrvyRprtrTestSchema])).optional()
226
275
  })
227
276
  );
@@ -240,6 +289,7 @@ var TestEndDataSchema = import_zod.z.object({
240
289
  id: import_zod.z.string(),
241
290
  status: import_zod.z.enum(["passed", "failed", "skipped"]),
242
291
  attachments: import_zod.z.array(AttachmentSchema),
292
+ visualNames: import_zod.z.array(import_zod.z.string()).default([]),
243
293
  error: import_zod.z.string().optional(),
244
294
  duration: import_zod.z.number().optional()
245
295
  });
@@ -412,14 +462,64 @@ async function writeReportArtifact(options) {
412
462
  }
413
463
 
414
464
  // src/reporter-utils.ts
415
- function extractScreenshotNames(steps) {
416
- const names = [];
465
+ var NAMED_SCREENSHOT_STEP_TITLE = /toHaveScreenshot\((.+?)\)/;
466
+ var UNNAMED_SCREENSHOT_STEP_TITLE = /^Expect "toHaveScreenshot"(?:\s|$)/;
467
+ var SYNTHETIC_SCREENSHOT_PREFIX = "__unnamed-screenshot-";
468
+ function normalizeNamedScreenshot(titleMatch) {
469
+ const unquotedName = titleMatch.trim().replace(/^['"`]|['"`]$/g, "");
470
+ if (unquotedName === "") {
471
+ return null;
472
+ }
473
+ const normalizedPath = unquotedName.replace(/\\/g, "/");
474
+ const normalizedName = normalizedPath.replace(/\.png$/, "");
475
+ if (normalizedName === "") {
476
+ return null;
477
+ }
478
+ return {
479
+ visualName: normalizedName,
480
+ snapshotBaseName: normalizedName
481
+ };
482
+ }
483
+ function appendDeclaration(state, declaration) {
484
+ if (state.seenVisualNames.has(declaration.visualName)) {
485
+ return;
486
+ }
487
+ state.seenVisualNames.add(declaration.visualName);
488
+ state.declarations.push(declaration);
489
+ }
490
+ function visitStep(step, state) {
491
+ const declarationsBeforeChildren = state.declarations.length;
492
+ for (const nestedStep of step.steps) {
493
+ visitStep(nestedStep, state);
494
+ }
495
+ const namedMatch = step.title.match(NAMED_SCREENSHOT_STEP_TITLE);
496
+ if (namedMatch?.[1] !== void 0) {
497
+ const declaration = normalizeNamedScreenshot(namedMatch[1]);
498
+ if (declaration !== null) {
499
+ appendDeclaration(state, declaration);
500
+ return true;
501
+ }
502
+ }
503
+ const hasNestedScreenshotDeclaration = state.declarations.length > declarationsBeforeChildren;
504
+ if (UNNAMED_SCREENSHOT_STEP_TITLE.test(step.title) && !hasNestedScreenshotDeclaration) {
505
+ appendDeclaration(state, {
506
+ visualName: `${SYNTHETIC_SCREENSHOT_PREFIX}${state.nextUnnamedIndex}`
507
+ });
508
+ state.nextUnnamedIndex += 1;
509
+ return true;
510
+ }
511
+ return hasNestedScreenshotDeclaration;
512
+ }
513
+ function extractScreenshotDeclarations(steps) {
514
+ const state = {
515
+ declarations: [],
516
+ seenVisualNames: /* @__PURE__ */ new Set(),
517
+ nextUnnamedIndex: 1
518
+ };
417
519
  for (const step of steps) {
418
- const match = step.title.match(/toHaveScreenshot\((.+?)\)/);
419
- if (match?.[1] !== void 0 && match[1] !== "") names.push(match[1]);
420
- if (step.steps.length) names.push(...extractScreenshotNames(step.steps));
520
+ visitStep(step, state);
421
521
  }
422
- return names;
522
+ return state.declarations;
423
523
  }
424
524
 
425
525
  // src/reporter.ts
@@ -504,8 +604,10 @@ var CrvyRprtr = class {
504
604
  });
505
605
  }
506
606
  async onTestEnd(test, result) {
607
+ const screenshotDeclarations = extractScreenshotDeclarations(result.steps);
608
+ const visualNames = screenshotDeclarations.map(({ visualName }) => visualName);
507
609
  const savedAttachments = await this.saveAttachments(test.id, result);
508
- await this.copySnapshotBaselines(test, result, savedAttachments);
610
+ await this.copySnapshotBaselines(test, result.status, screenshotDeclarations, savedAttachments);
509
611
  this.send({
510
612
  type: "test-end",
511
613
  data: {
@@ -513,27 +615,29 @@ var CrvyRprtr = class {
513
615
  title: test.title,
514
616
  status: result.status,
515
617
  attachments: savedAttachments,
618
+ visualNames,
516
619
  error: result.errors.length > 0 ? result.errors[0]?.message : void 0,
517
620
  duration: result.duration
518
621
  }
519
622
  });
520
623
  }
521
- async copySnapshotBaselines(test, result, savedAttachments) {
522
- if (result.status !== "passed") return;
523
- const snapshotNames = extractScreenshotNames(result.steps);
524
- if (snapshotNames.length === 0) return;
525
- const projectName = test.parent.project()?.name ?? "chromium";
624
+ async copySnapshotBaselines(test, status, screenshotDeclarations, savedAttachments) {
625
+ if (status !== "passed") return;
626
+ const namedDeclarations = screenshotDeclarations.filter(
627
+ (declaration) => declaration.snapshotBaseName !== void 0
628
+ );
629
+ if (namedDeclarations.length === 0) return;
630
+ const projectName = test.parent.project()?.name;
526
631
  const snapshotDir = `${test.location.file}-snapshots`;
527
632
  const testScreenshotDir = (0, import_path2.join)(this.screenshotDir, this.sanitizeId(test.id));
528
633
  const limit = (0, import_p_limit.default)(MAX_CONCURRENT_FILE_OPS);
529
- const copyPromises = snapshotNames.map(
530
- (name) => limit(async () => {
531
- const baseName = name.replace(/\.png$/, "");
532
- const snapshotPath = (0, import_path2.join)(snapshotDir, `${baseName}-${projectName}-${process.platform}.png`);
533
- const destName = `${baseName}-expected`;
634
+ const copyPromises = namedDeclarations.map(
635
+ ({ visualName, snapshotBaseName }) => limit(async () => {
636
+ const destName = `${visualName}-expected.png`;
534
637
  const destPath = (0, import_path2.join)(testScreenshotDir, destName);
638
+ const snapshotPath = projectName === "" ? (0, import_path2.join)(snapshotDir, `${snapshotBaseName}-${process.platform}.png`) : (0, import_path2.join)(snapshotDir, `${snapshotBaseName}-${projectName ?? "chromium"}-${process.platform}.png`);
535
639
  try {
536
- await (0, import_promises2.mkdir)(testScreenshotDir, { recursive: true });
640
+ await (0, import_promises2.mkdir)((0, import_path2.dirname)(destPath), { recursive: true });
537
641
  await (0, import_promises2.copyFile)(snapshotPath, destPath);
538
642
  savedAttachments.push({
539
643
  name: destName,
@@ -1 +1 @@
1
- {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAQ9G,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AAQD,qBAAa,SAAU,YAAW,QAAQ;IACxC,OAAO,CAAC,EAAE,CAAyB;IACnC,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,iBAAiB,CAAQ;IACjC,OAAO,CAAC,cAAc,CAAQ;IAC9B,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,cAAc,CAAQ;IAC9B,OAAO,CAAC,SAAS,CAA4E;gBAEjF,OAAO,GAAE,gBAAqB;IAQpC,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;IAM9D,OAAO,CAAC,OAAO;IA8Bf,OAAO,CAAC,iBAAiB;IAQzB,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI;IAsB3B,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;YAiBpD,qBAAqB;YAsCrB,eAAe;IAyC7B,OAAO,CAAC,UAAU;YAIJ,kBAAkB;YAyBlB,mBAAmB;IAa3B,KAAK,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IA8B9C,OAAO,CAAC,IAAI;CAkBb;AAED,eAAe,SAAS,CAAA"}
1
+ {"version":3,"file":"reporter.d.ts","sourceRoot":"","sources":["../src/reporter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAO9G,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB;AACD,qBAAa,SAAU,YAAW,QAAQ;IACxC,OAAO,CAAC,EAAE,CAAyB;IACnC,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,iBAAiB,CAAQ;IACjC,OAAO,CAAC,cAAc,CAAQ;IAC9B,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,cAAc,CAAQ;IAC9B,OAAO,CAAC,SAAS,CAA4E;gBAEjF,OAAO,GAAE,gBAAqB;IAQpC,OAAO,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;IAM9D,OAAO,CAAC,OAAO;IA8Bf,OAAO,CAAC,iBAAiB;IAQzB,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG,IAAI;IAsB3B,SAAS,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;YAoBpD,qBAAqB;YA8CrB,eAAe;IAwC7B,OAAO,CAAC,UAAU;YAIJ,kBAAkB;YAyBlB,mBAAmB;IAa3B,KAAK,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IA8B9C,OAAO,CAAC,IAAI;CAkBb;AACD,eAAe,SAAS,CAAA"}
package/dist/reporter.js CHANGED
@@ -7,11 +7,11 @@ import {
7
7
  createMutableReportState,
8
8
  finalizeRunEvent,
9
9
  safeParse
10
- } from "./chunk-IEYNAB6M.js";
10
+ } from "./chunk-MWLM3HWS.js";
11
11
 
12
12
  // src/reporter.ts
13
13
  import { mkdir as mkdir2, copyFile, writeFile as writeFile2 } from "fs/promises";
14
- import { join } from "path";
14
+ import { dirname as dirname2, join } from "path";
15
15
  import pLimit from "p-limit";
16
16
 
17
17
  // src/report-artifact.ts
@@ -136,14 +136,64 @@ async function writeReportArtifact(options) {
136
136
  }
137
137
 
138
138
  // src/reporter-utils.ts
139
- function extractScreenshotNames(steps) {
140
- const names = [];
139
+ var NAMED_SCREENSHOT_STEP_TITLE = /toHaveScreenshot\((.+?)\)/;
140
+ var UNNAMED_SCREENSHOT_STEP_TITLE = /^Expect "toHaveScreenshot"(?:\s|$)/;
141
+ var SYNTHETIC_SCREENSHOT_PREFIX = "__unnamed-screenshot-";
142
+ function normalizeNamedScreenshot(titleMatch) {
143
+ const unquotedName = titleMatch.trim().replace(/^['"`]|['"`]$/g, "");
144
+ if (unquotedName === "") {
145
+ return null;
146
+ }
147
+ const normalizedPath = unquotedName.replace(/\\/g, "/");
148
+ const normalizedName = normalizedPath.replace(/\.png$/, "");
149
+ if (normalizedName === "") {
150
+ return null;
151
+ }
152
+ return {
153
+ visualName: normalizedName,
154
+ snapshotBaseName: normalizedName
155
+ };
156
+ }
157
+ function appendDeclaration(state, declaration) {
158
+ if (state.seenVisualNames.has(declaration.visualName)) {
159
+ return;
160
+ }
161
+ state.seenVisualNames.add(declaration.visualName);
162
+ state.declarations.push(declaration);
163
+ }
164
+ function visitStep(step, state) {
165
+ const declarationsBeforeChildren = state.declarations.length;
166
+ for (const nestedStep of step.steps) {
167
+ visitStep(nestedStep, state);
168
+ }
169
+ const namedMatch = step.title.match(NAMED_SCREENSHOT_STEP_TITLE);
170
+ if (namedMatch?.[1] !== void 0) {
171
+ const declaration = normalizeNamedScreenshot(namedMatch[1]);
172
+ if (declaration !== null) {
173
+ appendDeclaration(state, declaration);
174
+ return true;
175
+ }
176
+ }
177
+ const hasNestedScreenshotDeclaration = state.declarations.length > declarationsBeforeChildren;
178
+ if (UNNAMED_SCREENSHOT_STEP_TITLE.test(step.title) && !hasNestedScreenshotDeclaration) {
179
+ appendDeclaration(state, {
180
+ visualName: `${SYNTHETIC_SCREENSHOT_PREFIX}${state.nextUnnamedIndex}`
181
+ });
182
+ state.nextUnnamedIndex += 1;
183
+ return true;
184
+ }
185
+ return hasNestedScreenshotDeclaration;
186
+ }
187
+ function extractScreenshotDeclarations(steps) {
188
+ const state = {
189
+ declarations: [],
190
+ seenVisualNames: /* @__PURE__ */ new Set(),
191
+ nextUnnamedIndex: 1
192
+ };
141
193
  for (const step of steps) {
142
- const match = step.title.match(/toHaveScreenshot\((.+?)\)/);
143
- if (match?.[1] !== void 0 && match[1] !== "") names.push(match[1]);
144
- if (step.steps.length) names.push(...extractScreenshotNames(step.steps));
194
+ visitStep(step, state);
145
195
  }
146
- return names;
196
+ return state.declarations;
147
197
  }
148
198
 
149
199
  // src/reporter.ts
@@ -228,8 +278,10 @@ var CrvyRprtr = class {
228
278
  });
229
279
  }
230
280
  async onTestEnd(test, result) {
281
+ const screenshotDeclarations = extractScreenshotDeclarations(result.steps);
282
+ const visualNames = screenshotDeclarations.map(({ visualName }) => visualName);
231
283
  const savedAttachments = await this.saveAttachments(test.id, result);
232
- await this.copySnapshotBaselines(test, result, savedAttachments);
284
+ await this.copySnapshotBaselines(test, result.status, screenshotDeclarations, savedAttachments);
233
285
  this.send({
234
286
  type: "test-end",
235
287
  data: {
@@ -237,27 +289,29 @@ var CrvyRprtr = class {
237
289
  title: test.title,
238
290
  status: result.status,
239
291
  attachments: savedAttachments,
292
+ visualNames,
240
293
  error: result.errors.length > 0 ? result.errors[0]?.message : void 0,
241
294
  duration: result.duration
242
295
  }
243
296
  });
244
297
  }
245
- async copySnapshotBaselines(test, result, savedAttachments) {
246
- if (result.status !== "passed") return;
247
- const snapshotNames = extractScreenshotNames(result.steps);
248
- if (snapshotNames.length === 0) return;
249
- const projectName = test.parent.project()?.name ?? "chromium";
298
+ async copySnapshotBaselines(test, status, screenshotDeclarations, savedAttachments) {
299
+ if (status !== "passed") return;
300
+ const namedDeclarations = screenshotDeclarations.filter(
301
+ (declaration) => declaration.snapshotBaseName !== void 0
302
+ );
303
+ if (namedDeclarations.length === 0) return;
304
+ const projectName = test.parent.project()?.name;
250
305
  const snapshotDir = `${test.location.file}-snapshots`;
251
306
  const testScreenshotDir = join(this.screenshotDir, this.sanitizeId(test.id));
252
307
  const limit = pLimit(MAX_CONCURRENT_FILE_OPS);
253
- const copyPromises = snapshotNames.map(
254
- (name) => limit(async () => {
255
- const baseName = name.replace(/\.png$/, "");
256
- const snapshotPath = join(snapshotDir, `${baseName}-${projectName}-${process.platform}.png`);
257
- const destName = `${baseName}-expected`;
308
+ const copyPromises = namedDeclarations.map(
309
+ ({ visualName, snapshotBaseName }) => limit(async () => {
310
+ const destName = `${visualName}-expected.png`;
258
311
  const destPath = join(testScreenshotDir, destName);
312
+ const snapshotPath = projectName === "" ? join(snapshotDir, `${snapshotBaseName}-${process.platform}.png`) : join(snapshotDir, `${snapshotBaseName}-${projectName ?? "chromium"}-${process.platform}.png`);
259
313
  try {
260
- await mkdir2(testScreenshotDir, { recursive: true });
314
+ await mkdir2(dirname2(destPath), { recursive: true });
261
315
  await copyFile(snapshotPath, destPath);
262
316
  savedAttachments.push({
263
317
  name: destName,
package/dist/schemas.d.ts CHANGED
@@ -4,11 +4,22 @@ export declare const LocationSchema: z.ZodObject<{
4
4
  line: z.ZodNumber;
5
5
  }, z.core.$strip>;
6
6
  export type Location = z.infer<typeof LocationSchema>;
7
+ export declare const VisualSourceSchema: z.ZodEnum<{
8
+ comparison: "comparison";
9
+ "baseline-only": "baseline-only";
10
+ "declared-only": "declared-only";
11
+ }>;
12
+ export type VisualSource = z.infer<typeof VisualSourceSchema>;
7
13
  export declare const ImagesSchema: z.ZodObject<{
8
- actual: z.ZodString;
14
+ actual: z.ZodOptional<z.ZodString>;
9
15
  expect: z.ZodOptional<z.ZodString>;
10
16
  diff: z.ZodOptional<z.ZodString>;
11
17
  error: z.ZodOptional<z.ZodString>;
18
+ source: z.ZodOptional<z.ZodEnum<{
19
+ comparison: "comparison";
20
+ "baseline-only": "baseline-only";
21
+ "declared-only": "declared-only";
22
+ }>>;
12
23
  }, z.core.$strip>;
13
24
  export type Images = z.infer<typeof ImagesSchema>;
14
25
  export declare const AttachmentSchema: z.ZodObject<{
@@ -27,13 +38,30 @@ export declare const TestStatusSchema: z.ZodEnum<{
27
38
  retrying: "retrying";
28
39
  }>;
29
40
  export type TestStatus = z.infer<typeof TestStatusSchema>;
41
+ export declare const TestResultStatusSchema: z.ZodEnum<{
42
+ pending: "pending";
43
+ failed: "failed";
44
+ success: "success";
45
+ }>;
46
+ export type TestResultStatus = z.infer<typeof TestResultStatusSchema>;
30
47
  export declare const TestResultSchema: z.ZodObject<{
31
48
  status: z.ZodEnum<{
49
+ pending: "pending";
32
50
  failed: "failed";
33
51
  success: "success";
34
52
  }>;
35
53
  retries: z.ZodNumber;
36
- images: z.ZodType<Partial<Record<string, Images>>>;
54
+ images: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
55
+ actual: z.ZodOptional<z.ZodString>;
56
+ expect: z.ZodOptional<z.ZodString>;
57
+ diff: z.ZodOptional<z.ZodString>;
58
+ error: z.ZodOptional<z.ZodString>;
59
+ source: z.ZodOptional<z.ZodEnum<{
60
+ comparison: "comparison";
61
+ "baseline-only": "baseline-only";
62
+ "declared-only": "declared-only";
63
+ }>>;
64
+ }, z.core.$strip>>>;
37
65
  error: z.ZodOptional<z.ZodString>;
38
66
  duration: z.ZodOptional<z.ZodNumber>;
39
67
  }, z.core.$strip>;
@@ -56,11 +84,22 @@ export declare const TestDataSchema: z.ZodObject<{
56
84
  }>>;
57
85
  results: z.ZodOptional<z.ZodArray<z.ZodObject<{
58
86
  status: z.ZodEnum<{
87
+ pending: "pending";
59
88
  failed: "failed";
60
89
  success: "success";
61
90
  }>;
62
91
  retries: z.ZodNumber;
63
- images: z.ZodType<Partial<Record<string, Images>>>;
92
+ images: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
93
+ actual: z.ZodOptional<z.ZodString>;
94
+ expect: z.ZodOptional<z.ZodString>;
95
+ diff: z.ZodOptional<z.ZodString>;
96
+ error: z.ZodOptional<z.ZodString>;
97
+ source: z.ZodOptional<z.ZodEnum<{
98
+ comparison: "comparison";
99
+ "baseline-only": "baseline-only";
100
+ "declared-only": "declared-only";
101
+ }>>;
102
+ }, z.core.$strip>>>;
64
103
  error: z.ZodOptional<z.ZodString>;
65
104
  duration: z.ZodOptional<z.ZodNumber>;
66
105
  }, z.core.$strip>>>;
@@ -94,11 +133,22 @@ export declare const CrvyRprtrTestSchema: z.ZodObject<{
94
133
  }>>;
95
134
  results: z.ZodOptional<z.ZodArray<z.ZodObject<{
96
135
  status: z.ZodEnum<{
136
+ pending: "pending";
97
137
  failed: "failed";
98
138
  success: "success";
99
139
  }>;
100
140
  retries: z.ZodNumber;
101
- images: z.ZodType<Partial<Record<string, Images>>>;
141
+ images: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
142
+ actual: z.ZodOptional<z.ZodString>;
143
+ expect: z.ZodOptional<z.ZodString>;
144
+ diff: z.ZodOptional<z.ZodString>;
145
+ error: z.ZodOptional<z.ZodString>;
146
+ source: z.ZodOptional<z.ZodEnum<{
147
+ comparison: "comparison";
148
+ "baseline-only": "baseline-only";
149
+ "declared-only": "declared-only";
150
+ }>>;
151
+ }, z.core.$strip>>>;
102
152
  error: z.ZodOptional<z.ZodString>;
103
153
  duration: z.ZodOptional<z.ZodNumber>;
104
154
  }, z.core.$strip>>>;
@@ -159,6 +209,7 @@ export declare const TestEndDataSchema: z.ZodObject<{
159
209
  path: z.ZodString;
160
210
  contentType: z.ZodString;
161
211
  }, z.core.$strip>>;
212
+ visualNames: z.ZodDefault<z.ZodArray<z.ZodString>>;
162
213
  error: z.ZodOptional<z.ZodString>;
163
214
  duration: z.ZodOptional<z.ZodNumber>;
164
215
  }, z.core.$strip>;
@@ -183,11 +234,22 @@ export declare const ReportDataSchema: z.ZodObject<{
183
234
  }>>;
184
235
  results: z.ZodOptional<z.ZodArray<z.ZodObject<{
185
236
  status: z.ZodEnum<{
237
+ pending: "pending";
186
238
  failed: "failed";
187
239
  success: "success";
188
240
  }>;
189
241
  retries: z.ZodNumber;
190
- images: z.ZodType<Partial<Record<string, Images>>>;
242
+ images: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
243
+ actual: z.ZodOptional<z.ZodString>;
244
+ expect: z.ZodOptional<z.ZodString>;
245
+ diff: z.ZodOptional<z.ZodString>;
246
+ error: z.ZodOptional<z.ZodString>;
247
+ source: z.ZodOptional<z.ZodEnum<{
248
+ comparison: "comparison";
249
+ "baseline-only": "baseline-only";
250
+ "declared-only": "declared-only";
251
+ }>>;
252
+ }, z.core.$strip>>>;
191
253
  error: z.ZodOptional<z.ZodString>;
192
254
  duration: z.ZodOptional<z.ZodNumber>;
193
255
  }, z.core.$strip>>>;
@@ -226,11 +288,22 @@ export declare const LoadedReportDataSchema: z.ZodObject<{
226
288
  }>>;
227
289
  results: z.ZodOptional<z.ZodArray<z.ZodObject<{
228
290
  status: z.ZodEnum<{
291
+ pending: "pending";
229
292
  failed: "failed";
230
293
  success: "success";
231
294
  }>;
232
295
  retries: z.ZodNumber;
233
- images: z.ZodType<Partial<Record<string, Images>>>;
296
+ images: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
297
+ actual: z.ZodOptional<z.ZodString>;
298
+ expect: z.ZodOptional<z.ZodString>;
299
+ diff: z.ZodOptional<z.ZodString>;
300
+ error: z.ZodOptional<z.ZodString>;
301
+ source: z.ZodOptional<z.ZodEnum<{
302
+ comparison: "comparison";
303
+ "baseline-only": "baseline-only";
304
+ "declared-only": "declared-only";
305
+ }>>;
306
+ }, z.core.$strip>>>;
234
307
  error: z.ZodOptional<z.ZodString>;
235
308
  duration: z.ZodOptional<z.ZodNumber>;
236
309
  }, z.core.$strip>>>;
@@ -300,11 +373,22 @@ export declare const ReportApiResponseSchema: z.ZodObject<{
300
373
  }>>;
301
374
  results: z.ZodOptional<z.ZodArray<z.ZodObject<{
302
375
  status: z.ZodEnum<{
376
+ pending: "pending";
303
377
  failed: "failed";
304
378
  success: "success";
305
379
  }>;
306
380
  retries: z.ZodNumber;
307
- images: z.ZodType<Partial<Record<string, Images>>>;
381
+ images: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
382
+ actual: z.ZodOptional<z.ZodString>;
383
+ expect: z.ZodOptional<z.ZodString>;
384
+ diff: z.ZodOptional<z.ZodString>;
385
+ error: z.ZodOptional<z.ZodString>;
386
+ source: z.ZodOptional<z.ZodEnum<{
387
+ comparison: "comparison";
388
+ "baseline-only": "baseline-only";
389
+ "declared-only": "declared-only";
390
+ }>>;
391
+ }, z.core.$strip>>>;
308
392
  error: z.ZodOptional<z.ZodString>;
309
393
  duration: z.ZodOptional<z.ZodNumber>;
310
394
  }, z.core.$strip>>>;
@@ -342,11 +426,22 @@ export declare const ClientBootstrapDataSchema: z.ZodObject<{
342
426
  }>>;
343
427
  results: z.ZodOptional<z.ZodArray<z.ZodObject<{
344
428
  status: z.ZodEnum<{
429
+ pending: "pending";
345
430
  failed: "failed";
346
431
  success: "success";
347
432
  }>;
348
433
  retries: z.ZodNumber;
349
- images: z.ZodType<Partial<Record<string, Images>>>;
434
+ images: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
435
+ actual: z.ZodOptional<z.ZodString>;
436
+ expect: z.ZodOptional<z.ZodString>;
437
+ diff: z.ZodOptional<z.ZodString>;
438
+ error: z.ZodOptional<z.ZodString>;
439
+ source: z.ZodOptional<z.ZodEnum<{
440
+ comparison: "comparison";
441
+ "baseline-only": "baseline-only";
442
+ "declared-only": "declared-only";
443
+ }>>;
444
+ }, z.core.$strip>>>;
350
445
  error: z.ZodOptional<z.ZodString>;
351
446
  duration: z.ZodOptional<z.ZodNumber>;
352
447
  }, z.core.$strip>>>;
@@ -1 +1 @@
1
- {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"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"}
@@ -9,6 +9,7 @@ export interface ServerOptions {
9
9
  export interface ServerApp {
10
10
  port: number;
11
11
  wsClients: Set<RuntimeWebSocket>;
12
+ close: () => void;
12
13
  handleRequest: (req: Request) => Promise<Response>;
13
14
  handleWebSocketMessage: (message: string) => Promise<void>;
14
15
  }