@crvy/rprtr 0.0.5 → 0.0.8

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/server.cjs CHANGED
@@ -35,7 +35,7 @@ __export(server_exports, {
35
35
  module.exports = __toCommonJS(server_exports);
36
36
 
37
37
  // src/server/app.ts
38
- var import_path5 = require("path");
38
+ var import_path6 = require("path");
39
39
  var import_url = require("url");
40
40
  var import_p_limit = __toESM(require("p-limit"), 1);
41
41
 
@@ -62,6 +62,12 @@ function withImageSource(image) {
62
62
  source: classifyImage(image)
63
63
  };
64
64
  }
65
+ function getDeclaredVisualNames(visualNames, visualDeclarations) {
66
+ return visualDeclarations?.map(({ visualName }) => visualName) ?? visualNames;
67
+ }
68
+ function copyVisualDeclarations(visualDeclarations) {
69
+ return visualDeclarations?.map((visualDeclaration) => ({ ...visualDeclaration }));
70
+ }
65
71
  function mergeDeclaredImages(images, visualNames) {
66
72
  const names = /* @__PURE__ */ new Set([...Object.keys(images), ...visualNames]);
67
73
  return Object.fromEntries(
@@ -181,10 +187,14 @@ function applyTestEndEvent(state, data, options = {}) {
181
187
  }
182
188
  test.status = mapStatus(data.status);
183
189
  const resultStatus = data.status === "passed" ? "success" : data.status === "failed" ? "failed" : "pending";
190
+ const visualDeclarations = copyVisualDeclarations(data.visualDeclarations);
184
191
  const images = preservePreviousPassingImages(
185
192
  test,
186
193
  data.status,
187
- mergeDeclaredImages(attachmentsToImages(data.attachments, options.screenshotsBaseUrl), data.visualNames)
194
+ mergeDeclaredImages(
195
+ attachmentsToImages(data.attachments, options.screenshotsBaseUrl),
196
+ getDeclaredVisualNames(data.visualNames, visualDeclarations)
197
+ )
188
198
  );
189
199
  const diffCount = countDiffImages(images);
190
200
  const hasDiffs = diffCount > 0;
@@ -196,6 +206,7 @@ function applyTestEndEvent(state, data, options = {}) {
196
206
  status: resultStatus,
197
207
  retries: 0,
198
208
  images,
209
+ visualDeclarations,
199
210
  error: data.error,
200
211
  duration: data.duration
201
212
  }
@@ -233,6 +244,20 @@ var ImagesSchema = import_zod.z.object({
233
244
  error: import_zod.z.string().optional(),
234
245
  source: VisualSourceSchema.optional()
235
246
  });
247
+ var ScreenshotDeclarationSchema = import_zod.z.discriminatedUnion("kind", [
248
+ import_zod.z.object({
249
+ visualName: import_zod.z.string(),
250
+ kind: import_zod.z.literal("named"),
251
+ declaredName: import_zod.z.string(),
252
+ snapshotBaseName: import_zod.z.string(),
253
+ occurrenceIndex: import_zod.z.number()
254
+ }),
255
+ import_zod.z.object({
256
+ visualName: import_zod.z.string(),
257
+ kind: import_zod.z.literal("unnamed"),
258
+ occurrenceIndex: import_zod.z.number()
259
+ })
260
+ ]);
236
261
  var AttachmentSchema = import_zod.z.object({
237
262
  name: import_zod.z.string(),
238
263
  path: import_zod.z.string(),
@@ -244,6 +269,7 @@ var TestResultSchema = import_zod.z.object({
244
269
  status: TestResultStatusSchema,
245
270
  retries: import_zod.z.number(),
246
271
  images: import_zod.z.record(import_zod.z.string(), ImagesSchema).optional(),
272
+ visualDeclarations: import_zod.z.array(ScreenshotDeclarationSchema).optional(),
247
273
  error: import_zod.z.string().optional(),
248
274
  duration: import_zod.z.number().optional()
249
275
  });
@@ -290,6 +316,10 @@ var TestEndDataSchema = import_zod.z.object({
290
316
  status: import_zod.z.enum(["passed", "failed", "skipped"]),
291
317
  attachments: import_zod.z.array(AttachmentSchema),
292
318
  visualNames: import_zod.z.array(import_zod.z.string()).default([]),
319
+ visualDeclarations: import_zod.z.preprocess(
320
+ (value) => value === null ? void 0 : value,
321
+ import_zod.z.array(ScreenshotDeclarationSchema).optional()
322
+ ),
293
323
  error: import_zod.z.string().optional(),
294
324
  duration: import_zod.z.number().optional()
295
325
  });
@@ -500,7 +530,9 @@ function broadcastToBrowsers(wsClients, msg) {
500
530
  // src/server/handlers.ts
501
531
  function handleTestBegin(ctx, data) {
502
532
  const test = applyTestBeginEvent(ctx, data);
533
+ ctx.reportData.isRunning = true;
503
534
  console.log(` \u25B6 [${test.browser ?? "?"}] ${test.title}`);
535
+ broadcastToBrowsers(ctx.wsClients, { type: "test-begin", data });
504
536
  }
505
537
  function handleTestEnd(ctx, data) {
506
538
  const result = applyTestEndEvent(ctx, data);
@@ -639,13 +671,172 @@ async function watchReportArtifacts(options) {
639
671
  }
640
672
 
641
673
  // src/server/routes.ts
674
+ var import_fs = require("fs");
675
+ var import_path5 = require("path");
676
+
677
+ // src/snapshot-path-resolver.ts
678
+ var import_crypto = require("crypto");
642
679
  var import_path4 = require("path");
680
+ var DEFAULT_SCREENSHOT_TEMPLATE = "{snapshotDir}/{testFileDir}/{testFileName}-snapshots/{arg}{-projectName}{-snapshotSuffix}{ext}";
681
+ var WINDOWS_FILESYSTEM_FRIENDLY_LENGTH = 60;
682
+ function isUnsafeFilePathCharacter(character) {
683
+ const codePoint = character.codePointAt(0);
684
+ return codePoint !== void 0 && (codePoint <= 44 || codePoint >= 46 && codePoint <= 47 || codePoint >= 58 && codePoint <= 64 || codePoint >= 91 && codePoint <= 96 || codePoint >= 123 && codePoint <= 127);
685
+ }
686
+ function sanitizeForFilePath(value) {
687
+ return Array.from(value).reduce(
688
+ (state, character) => {
689
+ const unsafeCharacter = isUnsafeFilePathCharacter(character);
690
+ return unsafeCharacter ? state.previousCharacterWasUnsafe ? state : {
691
+ value: `${state.value}-`,
692
+ previousCharacterWasUnsafe: true
693
+ } : {
694
+ value: `${state.value}${character}`,
695
+ previousCharacterWasUnsafe: false
696
+ };
697
+ },
698
+ {
699
+ value: "",
700
+ previousCharacterWasUnsafe: false
701
+ }
702
+ ).value;
703
+ }
704
+ function trimLongString(value, length = WINDOWS_FILESYSTEM_FRIENDLY_LENGTH) {
705
+ if (value.length <= length) {
706
+ return value;
707
+ }
708
+ const hash = (0, import_crypto.createHash)("sha1").update(value).digest("hex");
709
+ const middle = `-${hash.slice(0, 5)}-`;
710
+ const start = Math.floor((length - middle.length) / 2);
711
+ const end = length - middle.length - start;
712
+ return value.slice(0, start) + middle + value.slice(-end);
713
+ }
714
+ function sanitizeFilePathBeforeExtension(filePath, extension = (0, import_path4.extname)(filePath)) {
715
+ const base = filePath.slice(0, filePath.length - extension.length);
716
+ return sanitizeForFilePath(base) + extension;
717
+ }
718
+ function addSuffixToFilePath(filePath, suffix) {
719
+ const extension = (0, import_path4.extname)(filePath);
720
+ return filePath.slice(0, filePath.length - extension.length) + suffix + extension;
721
+ }
722
+ function normalizedSnapshotDir(config) {
723
+ return (0, import_path4.resolve)(config.configDir, config.snapshotDir);
724
+ }
725
+ function templateValue(template, token, value) {
726
+ return template.replace(
727
+ new RegExp(`\\{(.)?${token}\\}`, "g"),
728
+ (_, prefix) => value === "" ? "" : `${prefix ?? ""}${value}`
729
+ );
730
+ }
731
+ function applyTemplate(input, nameArgument, extension) {
732
+ const template = input.config.toHaveScreenshotPathTemplate ?? input.config.snapshotPathTemplate ?? DEFAULT_SCREENSHOT_TEMPLATE;
733
+ const relativeTestFilePath = (0, import_path4.relative)(input.config.testDir, input.testFile);
734
+ const parsed = (0, import_path4.parse)(relativeTestFilePath);
735
+ const tokens = [
736
+ ["testDir", input.config.testDir],
737
+ ["snapshotDir", normalizedSnapshotDir(input.config)],
738
+ ["snapshotSuffix", input.config.snapshotSuffix],
739
+ ["testFileDir", parsed.dir],
740
+ ["platform", process.platform],
741
+ ["projectName", sanitizeForFilePath(input.config.projectName)],
742
+ ["testName", ""],
743
+ ["testFileName", parsed.base],
744
+ ["testFilePath", relativeTestFilePath],
745
+ ["arg", nameArgument],
746
+ ["ext", extension]
747
+ ];
748
+ const snapshotPath = tokens.reduce(
749
+ (currentTemplate, [token, value]) => templateValue(currentTemplate, token, value),
750
+ template
751
+ );
752
+ return (0, import_path4.resolve)(input.config.configDir, snapshotPath);
753
+ }
754
+ function removeExtension(filePath, extension = (0, import_path4.extname)(filePath)) {
755
+ return filePath.slice(0, filePath.length - extension.length);
756
+ }
757
+ function snapshotNameParts(declaredName) {
758
+ const extension = (0, import_path4.extname)(declaredName) || ".png";
759
+ return {
760
+ extension,
761
+ filePath: (0, import_path4.extname)(declaredName) === "" ? `${declaredName}${extension}` : declaredName
762
+ };
763
+ }
764
+ function filePathForOccurrence(filePath, occurrenceIndex) {
765
+ return occurrenceIndex === 1 ? filePath : addSuffixToFilePath(filePath, `-${occurrenceIndex - 1}`);
766
+ }
767
+ function createResolvedBaselineTarget(input, declaration, nameArgument, extension) {
768
+ return {
769
+ visualName: declaration.visualName,
770
+ attachmentBaseName: declaration.visualName,
771
+ artifactBaseName: sanitizeForFilePath(declaration.visualName),
772
+ snapshotPath: applyTemplate(input, nameArgument, extension)
773
+ };
774
+ }
775
+ function resolveStringCallTarget(input, declaration) {
776
+ const { extension, filePath } = snapshotNameParts(declaration.declaredName);
777
+ const occurrenceFilePath = filePathForOccurrence(filePath, declaration.occurrenceIndex);
778
+ const sanitizedNameWithExtension = sanitizeFilePathBeforeExtension(occurrenceFilePath, extension);
779
+ const nameArgument = removeExtension(sanitizedNameWithExtension, extension);
780
+ return createResolvedBaselineTarget(input, declaration, nameArgument, extension);
781
+ }
782
+ function resolveArrayCallTarget(input, declaration) {
783
+ const { extension, filePath } = snapshotNameParts(declaration.declaredName);
784
+ const occurrenceFilePath = filePathForOccurrence(filePath, declaration.occurrenceIndex);
785
+ const nameArgument = (0, import_path4.join)((0, import_path4.dirname)(occurrenceFilePath), (0, import_path4.basename)(occurrenceFilePath, extension));
786
+ return createResolvedBaselineTarget(input, declaration, nameArgument, extension);
787
+ }
788
+ function resolveNamedTarget(input, declaration) {
789
+ if (!declaration.declaredName.includes("/")) {
790
+ return resolveStringCallTarget(input, declaration);
791
+ }
792
+ const stringCallTarget = resolveStringCallTarget(input, declaration);
793
+ const arrayCallTarget = resolveArrayCallTarget(input, declaration);
794
+ if (stringCallTarget.snapshotPath === arrayCallTarget.snapshotPath) {
795
+ return stringCallTarget;
796
+ }
797
+ if (input.snapshotPathExists === void 0) {
798
+ return void 0;
799
+ }
800
+ const stringCallTargetExists = input.snapshotPathExists(stringCallTarget.snapshotPath);
801
+ const arrayCallTargetExists = input.snapshotPathExists(arrayCallTarget.snapshotPath);
802
+ if (stringCallTargetExists === arrayCallTargetExists) {
803
+ return void 0;
804
+ }
805
+ return stringCallTargetExists ? stringCallTarget : arrayCallTarget;
806
+ }
807
+ function reporterTitlesWithoutProjectAndFile(reporterTitlePath2) {
808
+ return reporterTitlePath2.slice(3).filter((part) => part !== "");
809
+ }
810
+ function anonymousName(reporterTitlePath2, occurrenceIndex) {
811
+ const rawAnonymousName = `${reporterTitlesWithoutProjectAndFile(reporterTitlePath2).join(" ")} ${occurrenceIndex}.png`;
812
+ return sanitizeFilePathBeforeExtension(trimLongString(rawAnonymousName), ".png");
813
+ }
814
+ function resolveTarget(input, declaration) {
815
+ switch (declaration.kind) {
816
+ case "named":
817
+ return typeof declaration.declaredName === "string" && declaration.declaredName !== "" ? resolveNamedTarget(input, declaration) : void 0;
818
+ case "unnamed": {
819
+ const anonymousFileName = anonymousName(input.reporterTitlePath, declaration.occurrenceIndex);
820
+ const extension = ".png";
821
+ const nameArgument = (0, import_path4.join)((0, import_path4.dirname)(anonymousFileName), (0, import_path4.basename)(anonymousFileName, extension));
822
+ return createResolvedBaselineTarget(input, declaration, nameArgument, extension);
823
+ }
824
+ }
825
+ }
826
+ function resolveBaselineTargets(input) {
827
+ return input.declarations.flatMap((declaration) => {
828
+ const resolvedTarget = resolveTarget(input, declaration);
829
+ return resolvedTarget === void 0 ? [] : [resolvedTarget];
830
+ });
831
+ }
832
+
833
+ // src/server/routes.ts
643
834
  var LIVE_UPDATES_WEBSOCKET_PATH = "/";
644
835
  function isWebSocketUpgradeRequest(req) {
645
836
  return new URL(req.url).pathname === LIVE_UPDATES_WEBSOCKET_PATH && req.headers.get("upgrade")?.toLowerCase() === "websocket";
646
837
  }
647
838
  async function handleRoot(ctx) {
648
- const html = await respondWithFile((0, import_path4.join)(ctx.staticDir, "index.html"), "text/html");
839
+ const html = await respondWithFile((0, import_path5.join)(ctx.staticDir, "index.html"), "text/html");
649
840
  return html ?? new Response("Not Found", { status: 404 });
650
841
  }
651
842
  async function handleAppCss() {
@@ -662,6 +853,37 @@ async function handleSrcFiles(req) {
662
853
  function handleApiReport(ctx) {
663
854
  return Response.json(ctx.reportData);
664
855
  }
856
+ var APPROVAL_TARGET_ERROR = "Could not resolve approval target";
857
+ function actualPathFromUrl(ctx, actualUrl) {
858
+ return actualUrl.startsWith("/screenshots/") ? (0, import_path5.join)(ctx.reportData.screenshotDir, actualUrl.slice("/screenshots/".length)) : actualUrl;
859
+ }
860
+ function reporterTitlePath(test) {
861
+ const testFile = test.location?.file;
862
+ return ["", test.browser, testFile ?? "", ...test.titlePath, test.title];
863
+ }
864
+ function resolveApprovalTarget(ctx, test, retry, imageName) {
865
+ const testFile = test.location?.file;
866
+ const declaration = test.results?.[retry]?.visualDeclarations?.find((candidate) => candidate.visualName === imageName);
867
+ if (ctx.approvalRouting === void 0 || testFile === void 0 || declaration === void 0) {
868
+ return null;
869
+ }
870
+ const targets = resolveBaselineTargets({
871
+ testFile,
872
+ reporterTitlePath: reporterTitlePath(test),
873
+ declarations: [declaration],
874
+ config: {
875
+ configDir: ctx.approvalRouting.configDir,
876
+ testDir: ctx.approvalRouting.playwrightTestDir ?? (0, import_path5.dirname)(testFile),
877
+ snapshotDir: ctx.approvalRouting.playwrightSnapshotDir ?? (0, import_path5.dirname)(testFile),
878
+ projectName: test.browser,
879
+ snapshotSuffix: process.platform,
880
+ snapshotPathTemplate: ctx.approvalRouting.playwrightSnapshotPathTemplate,
881
+ toHaveScreenshotPathTemplate: ctx.approvalRouting.playwrightToHaveScreenshotPathTemplate
882
+ },
883
+ snapshotPathExists: import_fs.existsSync
884
+ });
885
+ return targets.length === 1 ? targets[0]?.snapshotPath ?? null : null;
886
+ }
665
887
  async function handleApiApprove(ctx, req) {
666
888
  try {
667
889
  const rawBody = await req.json();
@@ -672,61 +894,96 @@ async function handleApiApprove(ctx, req) {
672
894
  }
673
895
  const { id, retry, image } = parsed;
674
896
  const test = ctx.reportData.tests[id];
675
- if (test !== null && test !== void 0) {
676
- test.approved ??= {};
677
- test.approved[image] = retry;
897
+ if (test === void 0) {
898
+ return Response.json({ success: false, error: "Test not found" }, { status: 404 });
899
+ }
900
+ const actualUrl = test.results?.[retry]?.images?.[image]?.actual;
901
+ if (actualUrl === void 0) {
902
+ return Response.json({ success: false, error: "Actual image not found" }, { status: 409 });
903
+ }
904
+ const snapshotPath = resolveApprovalTarget(ctx, test, retry, image);
905
+ if (snapshotPath === null) {
906
+ return Response.json({ success: false, error: APPROVAL_TARGET_ERROR }, { status: 409 });
907
+ }
908
+ try {
909
+ await copyFilePortable(actualPathFromUrl(ctx, actualUrl), snapshotPath);
910
+ test.approved = { ...test.approved ?? {}, [image]: retry };
678
911
  await ctx.saveReport();
679
- const actualUrl = test.results?.[retry]?.images?.[image]?.actual;
680
- if (actualUrl !== null && actualUrl !== void 0 && test.location?.file !== null && test.location?.file !== void 0) {
681
- const actualPath = actualUrl.replace("/screenshots/", `${ctx.reportData.screenshotDir}/`);
682
- const snapshotPath = `${test.location.file}-snapshots/${image}-${test.browser}-${process.platform}.png`;
683
- try {
684
- await copyFilePortable(actualPath, snapshotPath);
685
- console.log(` \u2714 Updated baseline: ${snapshotPath}`);
686
- } catch (err) {
687
- const errorMsg = err instanceof Error ? err.message : String(err);
688
- console.error(` \u2717 Failed to update baseline: ${errorMsg}`);
689
- }
690
- }
912
+ console.log(` \u2714 Updated baseline: ${snapshotPath}`);
691
913
  console.log(` \u2714 Approved [${test.browser}] ${test.title} \u2014 ${image}`);
914
+ return Response.json({ success: true });
915
+ } catch (err) {
916
+ const errorMsg = err instanceof Error ? err.message : String(err);
917
+ console.error(` \u2717 Failed to update baseline: ${errorMsg}`);
918
+ return Response.json({ success: false, error: "Failed to update baseline" }, { status: 500 });
692
919
  }
693
- return Response.json({ success: true });
694
920
  } catch {
695
921
  return Response.json({ success: false, error: "Invalid request" }, { status: 400 });
696
922
  }
697
923
  }
698
- async function handleApiApproveAll(ctx) {
699
- let approvedCount = 0;
700
- const baselineUpdates = [];
701
- Object.values(ctx.reportData.tests).forEach((test) => {
702
- if (!test?.results) return;
703
- const approved = {};
924
+ function createBulkApprovalUpdates(ctx) {
925
+ return Object.values(ctx.reportData.tests).flatMap((test) => {
926
+ if (!test.results || test.results.length === 0) {
927
+ return [];
928
+ }
704
929
  const lastRetry = test.results.length - 1;
705
930
  const lastResult = test.results[lastRetry];
706
- if (!lastResult?.images) return;
707
- Object.keys(lastResult.images).forEach((imageName) => {
708
- approved[imageName] = lastRetry;
709
- approvedCount++;
931
+ if (!lastResult?.images) {
932
+ return [];
933
+ }
934
+ return Object.keys(lastResult.images).flatMap((imageName) => {
710
935
  const actualUrl = lastResult.images?.[imageName]?.actual;
711
- if (actualUrl !== null && actualUrl !== void 0 && test.location?.file !== null && test.location?.file !== void 0) {
712
- const actualPath = actualUrl.replace("/screenshots/", `${ctx.reportData.screenshotDir}/`);
713
- const snapshotPath = `${test.location.file}-snapshots/${imageName}-${test.browser}-${process.platform}.png`;
714
- baselineUpdates.push(
715
- copyFilePortable(actualPath, snapshotPath).then(() => {
716
- console.log(` \u2714 Updated baseline: ${snapshotPath}`);
717
- }).catch((err) => {
718
- const errorMsg = err instanceof Error ? err.message : String(err);
719
- console.error(` \u2717 Failed to update baseline: ${errorMsg}`);
720
- })
721
- );
936
+ if (actualUrl === void 0) {
937
+ return [Promise.resolve({ kind: "unresolved" })];
938
+ }
939
+ const snapshotPath = resolveApprovalTarget(ctx, test, lastRetry, imageName);
940
+ if (snapshotPath === null) {
941
+ return [Promise.resolve({ kind: "unresolved" })];
722
942
  }
943
+ return [
944
+ copyFilePortable(actualPathFromUrl(ctx, actualUrl), snapshotPath).then(
945
+ () => ({
946
+ kind: "approved",
947
+ imageName,
948
+ retry: lastRetry,
949
+ snapshotPath,
950
+ test
951
+ })
952
+ ).catch((err) => {
953
+ const errorMsg = err instanceof Error ? err.message : String(err);
954
+ console.error(` \u2717 Failed to update baseline: ${errorMsg}`);
955
+ return { kind: "failed" };
956
+ })
957
+ ];
723
958
  });
724
- test.approved = approved;
725
959
  });
960
+ }
961
+ function summarizeBulkApprovalOutcomes(outcomes) {
962
+ return outcomes.reduce(
963
+ (summary, outcome) => {
964
+ switch (outcome.kind) {
965
+ case "approved": {
966
+ outcome.test.approved = { ...outcome.test.approved ?? {}, [outcome.imageName]: outcome.retry };
967
+ console.log(` \u2714 Updated baseline: ${outcome.snapshotPath}`);
968
+ return { ...summary, approved: summary.approved + 1 };
969
+ }
970
+ case "unresolved":
971
+ return { ...summary, unresolved: summary.unresolved + 1 };
972
+ case "failed":
973
+ return { ...summary, failed: summary.failed + 1 };
974
+ }
975
+ },
976
+ { approved: 0, unresolved: 0, failed: 0 }
977
+ );
978
+ }
979
+ async function handleApiApproveAll(ctx) {
980
+ const outcomes = await Promise.all(createBulkApprovalUpdates(ctx));
981
+ const counts = summarizeBulkApprovalOutcomes(outcomes);
726
982
  await ctx.saveReport();
727
- await Promise.all(baselineUpdates);
728
- console.log(` \u2714 Approved all \u2014 ${approvedCount} image(s)`);
729
- return Response.json({ success: true });
983
+ console.log(
984
+ ` \u2714 Approved all \u2014 approved: ${counts.approved}, unresolved: ${counts.unresolved}, failed: ${counts.failed}`
985
+ );
986
+ return Response.json({ success: counts.failed === 0, ...counts });
730
987
  }
731
988
  async function handleApiImages(req) {
732
989
  const path = new URL(req.url).pathname.slice("/api/images/".length);
@@ -742,7 +999,7 @@ async function handleScreenshots(ctx, req) {
742
999
  }
743
1000
  async function handleDist(ctx, req) {
744
1001
  const path = new URL(req.url).pathname.slice("/dist/".length);
745
- const filePath = (0, import_path4.join)(ctx.staticDir, path);
1002
+ const filePath = (0, import_path5.join)(ctx.staticDir, path);
746
1003
  const contentType = filePath.endsWith(".css") ? "text/css" : filePath.endsWith(".js") ? "application/javascript" : filePath.endsWith(".svelte") ? "text/plain" : "application/octet-stream";
747
1004
  const file = await respondWithFile(filePath, contentType);
748
1005
  return file ?? new Response("Not Found", { status: 404 });
@@ -761,10 +1018,10 @@ function handleHttpRequest(ctx, req) {
761
1018
  if (pathname === "/api/report") {
762
1019
  return Promise.resolve(handleApiReport(ctx));
763
1020
  }
764
- if (pathname === "/api/approve") {
1021
+ if (pathname === "/api/approve" && req.method === "POST") {
765
1022
  return handleApiApprove(ctx, req);
766
1023
  }
767
- if (pathname === "/api/approve-all") {
1024
+ if (pathname === "/api/approve-all" && req.method === "POST") {
768
1025
  return handleApiApproveAll(ctx);
769
1026
  }
770
1027
  if (pathname.startsWith("/api/images/")) {
@@ -898,19 +1155,19 @@ function createWebSocketMessageHandler(getHandlerContext) {
898
1155
  };
899
1156
  }
900
1157
  async function resolveStaticDir(staticDir) {
901
- const currentDir = (0, import_path5.dirname)((0, import_url.fileURLToPath)(import_meta.url));
1158
+ const currentDir = (0, import_path6.dirname)((0, import_url.fileURLToPath)(import_meta.url));
902
1159
  const candidates = staticDir === void 0 ? [
903
1160
  currentDir,
904
- (0, import_path5.join)(currentDir, "dist"),
905
- (0, import_path5.join)(currentDir, "..", "dist"),
906
- (0, import_path5.join)(currentDir, "..", "..", "dist"),
907
- (0, import_path5.join)(currentDir, ".."),
908
- (0, import_path5.join)(currentDir, "..", "..")
909
- ] : [staticDir, (0, import_path5.join)(staticDir, "dist")];
1161
+ (0, import_path6.join)(currentDir, "dist"),
1162
+ (0, import_path6.join)(currentDir, "..", "dist"),
1163
+ (0, import_path6.join)(currentDir, "..", "..", "dist"),
1164
+ (0, import_path6.join)(currentDir, ".."),
1165
+ (0, import_path6.join)(currentDir, "..", "..")
1166
+ ] : [staticDir, (0, import_path6.join)(staticDir, "dist")];
910
1167
  const resolvedCandidates = await Promise.all(
911
1168
  candidates.map(async (candidate) => ({
912
1169
  candidate,
913
- exists: await fileExists((0, import_path5.join)(candidate, "index.html"))
1170
+ exists: await fileExists((0, import_path6.join)(candidate, "index.html"))
914
1171
  }))
915
1172
  );
916
1173
  const resolved = resolvedCandidates.find(({ exists }) => exists);
@@ -921,9 +1178,23 @@ async function resolveStaticDir(staticDir) {
921
1178
  }
922
1179
  async function resolveReportPath(reportPath) {
923
1180
  if (await isDirectory(reportPath)) {
924
- return { reportFile: (0, import_path5.join)(reportPath, "report.json"), offlineReportDir: reportPath };
1181
+ return { reportFile: (0, import_path6.join)(reportPath, "report.json"), offlineReportDir: reportPath };
925
1182
  }
926
- return { reportFile: reportPath, offlineReportDir: (0, import_path5.dirname)(reportPath) };
1183
+ return { reportFile: reportPath, offlineReportDir: (0, import_path6.dirname)(reportPath) };
1184
+ }
1185
+ function createRoutesContext(reportData, staticDir, saveReport, options) {
1186
+ return {
1187
+ reportData,
1188
+ staticDir,
1189
+ saveReport,
1190
+ approvalRouting: {
1191
+ configDir: options.configDir ?? process.cwd(),
1192
+ playwrightTestDir: options.playwrightTestDir,
1193
+ playwrightSnapshotDir: options.playwrightSnapshotDir,
1194
+ playwrightSnapshotPathTemplate: options.playwrightSnapshotPathTemplate,
1195
+ playwrightToHaveScreenshotPathTemplate: options.playwrightToHaveScreenshotPathTemplate
1196
+ }
1197
+ };
927
1198
  }
928
1199
  async function createServerApp(options = {}) {
929
1200
  const port = options.port ?? 3e3;
@@ -936,11 +1207,7 @@ async function createServerApp(options = {}) {
936
1207
  async function saveReport() {
937
1208
  await writeJsonFile(reportFile, reportData);
938
1209
  }
939
- const routesContext = {
940
- reportData,
941
- staticDir,
942
- saveReport
943
- };
1210
+ const routesContext = createRoutesContext(reportData, staticDir, saveReport, options);
944
1211
  const getHandlerContext = () => createHandlerContext(reportData, wsClients, currentRunIds, saveReport);
945
1212
  const handleRequest = (req) => handleHttpRequest(routesContext, req);
946
1213
  const handleWebSocketMessage = createWebSocketMessageHandler(getHandlerContext);
@@ -1140,7 +1407,7 @@ function attachWebSocketServer(server, app) {
1140
1407
  });
1141
1408
  }
1142
1409
  async function listen(server, port) {
1143
- await new Promise((resolve, reject) => {
1410
+ await new Promise((resolve2, reject) => {
1144
1411
  const onError = (error) => {
1145
1412
  server.off("error", onError);
1146
1413
  reject(error);
@@ -1148,7 +1415,7 @@ async function listen(server, port) {
1148
1415
  server.on("error", onError);
1149
1416
  server.listen(port, () => {
1150
1417
  server.off("error", onError);
1151
- resolve();
1418
+ resolve2();
1152
1419
  });
1153
1420
  });
1154
1421
  }
package/dist/server.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  startServer
3
- } from "./chunk-IH44LYNM.js";
4
- import "./chunk-MWLM3HWS.js";
3
+ } from "./chunk-XU5VQ3FZ.js";
4
+ import "./chunk-EJRLZZ22.js";
5
5
  export {
6
6
  startServer
7
7
  };
@@ -0,0 +1,30 @@
1
+ import type { ScreenshotDeclaration } from './reporter-utils.ts';
2
+ export interface SnapshotResolverConfig {
3
+ readonly configDir: string;
4
+ readonly testDir: string;
5
+ readonly snapshotDir: string;
6
+ readonly projectName: string;
7
+ readonly snapshotSuffix: string;
8
+ readonly snapshotPathTemplate?: string;
9
+ readonly toHaveScreenshotPathTemplate?: string;
10
+ }
11
+ export interface SnapshotResolverInput {
12
+ readonly testFile: string;
13
+ readonly reporterTitlePath: readonly string[];
14
+ readonly declarations: readonly ScreenshotDeclaration[];
15
+ readonly config: SnapshotResolverConfig;
16
+ readonly snapshotPathExists?: (snapshotPath: string) => boolean;
17
+ }
18
+ export interface ResolvedBaselineTarget {
19
+ readonly visualName: string;
20
+ readonly attachmentBaseName: string;
21
+ readonly artifactBaseName: string;
22
+ readonly snapshotPath: string;
23
+ }
24
+ declare function sanitizeForFilePath(value: string): string;
25
+ declare function trimLongString(value: string, length?: number): string;
26
+ declare function sanitizeFilePathBeforeExtension(filePath: string, extension?: string): string;
27
+ declare function addSuffixToFilePath(filePath: string, suffix: string): string;
28
+ export declare function resolveBaselineTargets(input: SnapshotResolverInput): ResolvedBaselineTarget[];
29
+ export { sanitizeForFilePath, trimLongString, sanitizeFilePathBeforeExtension, addSuffixToFilePath };
30
+ //# sourceMappingURL=snapshot-path-resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot-path-resolver.d.ts","sourceRoot":"","sources":["../src/snapshot-path-resolver.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAA8B,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAM5F,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAA;IACtC,QAAQ,CAAC,4BAA4B,CAAC,EAAE,MAAM,CAAA;CAC/C;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAA;IAC7C,QAAQ,CAAC,YAAY,EAAE,SAAS,qBAAqB,EAAE,CAAA;IACvD,QAAQ,CAAC,MAAM,EAAE,sBAAsB,CAAA;IACvC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAA;CAChE;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAA;IACnC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;CAC9B;AAeD,iBAAS,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAsBlD;AAED,iBAAS,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,SAAqC,GAAG,MAAM,CAW1F;AAED,iBAAS,+BAA+B,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,SAAoB,GAAG,MAAM,CAGhG;AAED,iBAAS,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAGrE;AAsJD,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,qBAAqB,GAAG,sBAAsB,EAAE,CAK7F;AAED,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,+BAA+B,EAAE,mBAAmB,EAAE,CAAA"}
package/dist/types.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { ScreenshotDeclaration } from './reporter-utils.ts';
1
2
  export type VisualSource = 'comparison' | 'baseline-only' | 'declared-only';
2
3
  export interface Images {
3
4
  actual?: string;
@@ -21,6 +22,7 @@ export interface TestResult {
21
22
  status: TestResultStatus;
22
23
  retries: number;
23
24
  images?: Partial<Record<string, Images>>;
25
+ visualDeclarations?: readonly ScreenshotDeclaration[];
24
26
  error?: string;
25
27
  duration?: number;
26
28
  }
@@ -71,6 +73,7 @@ export interface TestEndMessage {
71
73
  status: 'passed' | 'failed' | 'skipped';
72
74
  attachments: Attachment[];
73
75
  visualNames: string[];
76
+ visualDeclarations?: readonly ScreenshotDeclaration[];
74
77
  error?: string;
75
78
  duration?: number;
76
79
  };
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crvy/rprtr",
3
- "version": "0.0.5",
3
+ "version": "0.0.8",
4
4
  "description": "Playwright reporter with visual regression UI for comparing and approving screenshot tests",
5
5
  "keywords": [
6
6
  "crvy",