@alwaysmeticulous/cli 2.16.1 → 2.18.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.
Files changed (46) hide show
  1. package/dist/api/test-run.api.d.ts +2 -1
  2. package/dist/commands/bootstrap/bootstrap.command.d.ts +1 -1
  3. package/dist/commands/bootstrap/bootstrap.command.js +2 -2
  4. package/dist/commands/create-test/create-test.command.d.ts +1 -1
  5. package/dist/commands/create-test/create-test.command.js +2 -2
  6. package/dist/commands/debug-replay/debug-replay.command.d.ts +1 -1
  7. package/dist/commands/debug-replay/debug-replay.command.js +2 -2
  8. package/dist/commands/download-replay/download-replay.command.d.ts +1 -1
  9. package/dist/commands/download-replay/download-replay.command.js +2 -2
  10. package/dist/commands/download-session/download-session.command.d.ts +1 -1
  11. package/dist/commands/download-session/download-session.command.js +2 -2
  12. package/dist/commands/record/record.command.d.ts +1 -1
  13. package/dist/commands/record/record.command.js +2 -2
  14. package/dist/commands/replay/replay.command.d.ts +9 -3
  15. package/dist/commands/replay/replay.command.js +62 -85
  16. package/dist/commands/replay/utils/compute-and-save-diff.d.ts +15 -0
  17. package/dist/commands/replay/utils/compute-and-save-diff.js +46 -0
  18. package/dist/commands/run-all-tests/run-all-tests.command.d.ts +4 -2
  19. package/dist/commands/run-all-tests/run-all-tests.command.js +22 -112
  20. package/dist/commands/screenshot-diff/screenshot-diff.command.d.ts +12 -12
  21. package/dist/commands/screenshot-diff/screenshot-diff.command.js +21 -18
  22. package/dist/commands/serve/serve.command.d.ts +1 -1
  23. package/dist/commands/serve/serve.command.js +2 -2
  24. package/dist/commands/show-project/show-project.command.d.ts +1 -1
  25. package/dist/commands/show-project/show-project.command.js +2 -2
  26. package/dist/commands/update-tests/update-tests.command.d.ts +1 -1
  27. package/dist/commands/update-tests/update-tests.command.js +2 -2
  28. package/dist/config/config.types.d.ts +4 -0
  29. package/dist/deflake-tests/deflake-tests.handler.d.ts +2 -2
  30. package/dist/deflake-tests/deflake-tests.handler.js +8 -20
  31. package/dist/index.d.ts +12 -11
  32. package/dist/index.js +14 -12
  33. package/dist/main.js +12 -12
  34. package/dist/parallel-tests/messages.types.d.ts +2 -2
  35. package/dist/parallel-tests/parallel-tests.handler.d.ts +5 -9
  36. package/dist/parallel-tests/parallel-tests.handler.js +14 -19
  37. package/dist/parallel-tests/run-all-tests.d.ts +55 -0
  38. package/dist/parallel-tests/run-all-tests.js +180 -0
  39. package/dist/parallel-tests/run-all-tests.types.d.ts +5 -0
  40. package/dist/parallel-tests/run-all-tests.types.js +2 -0
  41. package/dist/tsconfig.tsbuildinfo +1 -1
  42. package/dist/utils/github-summary.utils.d.ts +1 -2
  43. package/dist/utils/github-summary.utils.js +1 -3
  44. package/dist/utils/run-all-tests.utils.d.ts +4 -5
  45. package/dist/utils/run-all-tests.utils.js +4 -7
  46. package/package.json +2 -2
@@ -1,8 +1,9 @@
1
1
  import { AxiosInstance } from "axios";
2
2
  import { TestCaseResult } from "../config/config.types";
3
+ export declare type TestRunStatus = "Running" | "Success" | "Failure";
3
4
  export interface TestRun {
4
5
  id: string;
5
- status: "Running" | "Success" | "Failure";
6
+ status: TestRunStatus;
6
7
  resultData?: {
7
8
  results: TestCaseResult[];
8
9
  [key: string]: any;
@@ -1,2 +1,2 @@
1
1
  /// <reference types="yargs" />
2
- export declare const bootstrap: import("yargs").CommandModule<unknown, import("yargs").InferredOptionTypes<{}>>;
2
+ export declare const bootstrapCommand: import("yargs").CommandModule<unknown, import("yargs").InferredOptionTypes<{}>>;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.bootstrap = void 0;
6
+ exports.bootstrapCommand = void 0;
7
7
  const common_1 = require("@alwaysmeticulous/common");
8
8
  const chalk_1 = __importDefault(require("chalk"));
9
9
  const loglevel_1 = __importDefault(require("loglevel"));
@@ -25,7 +25,7 @@ const handler = async () => {
25
25
  command: "meticulous run-all-tests --headless --parallelize --deflake",
26
26
  });
27
27
  };
28
- exports.bootstrap = (0, command_builder_1.buildCommand)("bootstrap")
28
+ exports.bootstrapCommand = (0, command_builder_1.buildCommand)("bootstrap")
29
29
  .details({
30
30
  describe: "Bootstrap your project to use Meticulous",
31
31
  })
@@ -1,5 +1,5 @@
1
1
  /// <reference types="yargs" />
2
- export declare const createTest: import("yargs").CommandModule<unknown, import("yargs").InferredOptionTypes<{
2
+ export declare const createTestCommand: import("yargs").CommandModule<unknown, import("yargs").InferredOptionTypes<{
3
3
  headless: {
4
4
  default: boolean;
5
5
  boolean: true;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.createTest = void 0;
6
+ exports.createTestCommand = void 0;
7
7
  const common_1 = require("@alwaysmeticulous/common");
8
8
  const chalk_1 = __importDefault(require("chalk"));
9
9
  const inquirer_1 = require("inquirer");
@@ -121,7 +121,7 @@ headless, screenshotSelector, padTime, shiftTime, networkStubbing, moveBeforeCli
121
121
  const replay = await (0, replay_command_1.rawReplayCommandHandler)(replayOptions);
122
122
  await handleTestCreation(replay, lastSessionId);
123
123
  };
124
- exports.createTest = (0, command_builder_1.buildCommand)("create-test")
124
+ exports.createTestCommand = (0, command_builder_1.buildCommand)("create-test")
125
125
  .details({
126
126
  describe: "Create a new test",
127
127
  })
@@ -1,5 +1,5 @@
1
1
  /// <reference types="yargs" />
2
- export declare const debugReplay: import("yargs").CommandModule<unknown, import("yargs").InferredOptionTypes<{
2
+ export declare const debugReplayCommand: import("yargs").CommandModule<unknown, import("yargs").InferredOptionTypes<{
3
3
  apiToken: {
4
4
  string: true;
5
5
  };
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.debugReplay = void 0;
6
+ exports.debugReplayCommand = void 0;
7
7
  const common_1 = require("@alwaysmeticulous/common");
8
8
  const loglevel_1 = __importDefault(require("loglevel"));
9
9
  const client_1 = require("../../api/client");
@@ -60,7 +60,7 @@ const handler = async ({ apiToken, sessionId, appUrl, devTools, shiftTime, netwo
60
60
  };
61
61
  await createReplayer(createReplayerParams);
62
62
  };
63
- exports.debugReplay = (0, command_builder_1.buildCommand)("debug-simulation")
63
+ exports.debugReplayCommand = (0, command_builder_1.buildCommand)("debug-simulation")
64
64
  .details({
65
65
  aliases: ["debug-replay"],
66
66
  describe: "Replay and debug a recorded session",
@@ -1,5 +1,5 @@
1
1
  /// <reference types="yargs" />
2
- export declare const downloadReplay: import("yargs").CommandModule<unknown, import("yargs").InferredOptionTypes<{
2
+ export declare const downloadReplayCommand: import("yargs").CommandModule<unknown, import("yargs").InferredOptionTypes<{
3
3
  apiToken: {
4
4
  string: true;
5
5
  };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.downloadReplay = void 0;
3
+ exports.downloadReplayCommand = void 0;
4
4
  const client_1 = require("../../api/client");
5
5
  const command_builder_1 = require("../../command-utils/command-builder");
6
6
  const replays_1 = require("../../local-data/replays");
@@ -9,7 +9,7 @@ const handler = async ({ apiToken, replayId, }) => {
9
9
  await (0, replays_1.getOrFetchReplay)(client, replayId);
10
10
  await (0, replays_1.getOrFetchReplayArchive)(client, replayId);
11
11
  };
12
- exports.downloadReplay = (0, command_builder_1.buildCommand)("download-simulation")
12
+ exports.downloadReplayCommand = (0, command_builder_1.buildCommand)("download-simulation")
13
13
  .details({
14
14
  aliases: ["download-replay"],
15
15
  describe: "Download a simulation from Meticulous",
@@ -1,5 +1,5 @@
1
1
  /// <reference types="yargs" />
2
- export declare const downloadSession: import("yargs").CommandModule<unknown, import("yargs").InferredOptionTypes<{
2
+ export declare const downloadSessionCommand: import("yargs").CommandModule<unknown, import("yargs").InferredOptionTypes<{
3
3
  apiToken: {
4
4
  string: true;
5
5
  };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.downloadSession = void 0;
3
+ exports.downloadSessionCommand = void 0;
4
4
  const client_1 = require("../../api/client");
5
5
  const command_builder_1 = require("../../command-utils/command-builder");
6
6
  const sessions_1 = require("../../local-data/sessions");
@@ -9,7 +9,7 @@ const handler = async ({ apiToken, sessionId, }) => {
9
9
  await (0, sessions_1.getOrFetchRecordedSession)(client, sessionId);
10
10
  await (0, sessions_1.getOrFetchRecordedSessionData)(client, sessionId);
11
11
  };
12
- exports.downloadSession = (0, command_builder_1.buildCommand)("download-session")
12
+ exports.downloadSessionCommand = (0, command_builder_1.buildCommand)("download-session")
13
13
  .details({
14
14
  describe: "Download recorded session from Meticulous",
15
15
  })
@@ -12,7 +12,7 @@ export interface RecordCommandHandlerOptions {
12
12
  onDetectedSession?: (sessionId: string) => void;
13
13
  }
14
14
  export declare const recordCommandHandler: (options: RecordCommandHandlerOptions) => Promise<void>;
15
- export declare const record: import("yargs").CommandModule<unknown, import("yargs").InferredOptionTypes<{
15
+ export declare const recordCommand: import("yargs").CommandModule<unknown, import("yargs").InferredOptionTypes<{
16
16
  apiToken: {
17
17
  string: true;
18
18
  demandOption: true;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.record = exports.recordCommandHandler = void 0;
6
+ exports.recordCommand = exports.recordCommandHandler = void 0;
7
7
  const path_1 = require("path");
8
8
  const common_1 = require("@alwaysmeticulous/common");
9
9
  const loglevel_1 = __importDefault(require("loglevel"));
@@ -99,7 +99,7 @@ const recordCommandHandler = async ({ apiToken, commitSha: commitSha_, devTools,
99
99
  });
100
100
  };
101
101
  exports.recordCommandHandler = recordCommandHandler;
102
- exports.record = (0, command_builder_1.buildCommand)("record")
102
+ exports.recordCommand = (0, command_builder_1.buildCommand)("record")
103
103
  .details({
104
104
  describe: "Record a session",
105
105
  })
@@ -1,16 +1,22 @@
1
1
  /// <reference types="yargs" />
2
+ import { ScreenshotDiffResult } from "@alwaysmeticulous/api";
2
3
  import { GeneratedBy, Replay, ReplayEventsDependencies, ReplayExecutionOptions, ReplayTarget } from "@alwaysmeticulous/common";
3
4
  import { ScreenshotAssertionsOptions, ScreenshotDiffOptions } from "../../command-utils/common-types";
5
+ import { ScreenshotDiffsSummary } from "../screenshot-diff/screenshot-diff.command";
4
6
  export interface ReplayOptions extends AdditionalReplayOptions {
5
7
  replayTarget: ReplayTarget;
6
8
  executionOptions: ReplayExecutionOptions;
7
9
  screenshottingOptions: ScreenshotAssertionsOptions;
8
- exitOnMismatch: boolean;
9
10
  generatedBy: GeneratedBy;
10
11
  testRunId: string | null;
11
12
  replayEventsDependencies: ReplayEventsDependencies;
12
13
  }
13
- export declare const replayCommandHandler: ({ replayTarget, executionOptions, screenshottingOptions, apiToken, sessionId, commitSha: commitSha_, save, exitOnMismatch, baseSimulationId: baseReplayId_, cookiesFile, generatedBy, testRunId, replayEventsDependencies, }: ReplayOptions) => Promise<Replay>;
14
+ export interface ReplayResult {
15
+ replay: Replay;
16
+ screenshotDiffResults: ScreenshotDiffResult[] | null;
17
+ screenshotDiffsSummary: ScreenshotDiffsSummary;
18
+ }
19
+ export declare const replayCommandHandler: ({ replayTarget, executionOptions, screenshottingOptions, apiToken, sessionId, commitSha: commitSha_, save, baseSimulationId: baseReplayId_, cookiesFile, generatedBy, testRunId, replayEventsDependencies, }: ReplayOptions) => Promise<ReplayResult>;
14
20
  export interface RawReplayCommandHandlerOptions extends ScreenshotDiffOptions, Omit<ReplayExecutionOptions, "maxDurationMs" | "maxEventCount">, AdditionalReplayOptions {
15
21
  screenshot: boolean;
16
22
  appUrl: string | null | undefined;
@@ -33,7 +39,7 @@ export declare const getReplayTarget: ({ appUrl, simulationIdForAssets, }: {
33
39
  appUrl: string | null;
34
40
  simulationIdForAssets: string | null;
35
41
  }) => ReplayTarget;
36
- export declare const replay: import("yargs").CommandModule<unknown, import("yargs").InferredOptionTypes<{
42
+ export declare const replayCommand: import("yargs").CommandModule<unknown, import("yargs").InferredOptionTypes<{
37
43
  diffThreshold: {
38
44
  readonly number: true;
39
45
  readonly description: "Acceptable maximum proportion of changed pixels, between 0 and 1. If this proportion is exceeded then the test will fail.";
@@ -3,14 +3,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.replay = exports.getReplayTarget = exports.rawReplayCommandHandler = exports.replayCommandHandler = void 0;
6
+ exports.replayCommand = exports.getReplayTarget = exports.rawReplayCommandHandler = exports.replayCommandHandler = void 0;
7
7
  const promises_1 = require("fs/promises");
8
8
  const path_1 = require("path");
9
9
  const common_1 = require("@alwaysmeticulous/common");
10
10
  const loglevel_1 = __importDefault(require("loglevel"));
11
11
  const luxon_1 = require("luxon");
12
12
  const client_1 = require("../../api/client");
13
- const replay_diff_api_1 = require("../../api/replay-diff.api");
14
13
  const replay_api_1 = require("../../api/replay.api");
15
14
  const upload_1 = require("../../api/upload");
16
15
  const archive_1 = require("../../archive/archive");
@@ -18,14 +17,13 @@ const command_builder_1 = require("../../command-utils/command-builder");
18
17
  const common_options_1 = require("../../command-utils/common-options");
19
18
  const local_data_utils_1 = require("../../local-data/local-data.utils");
20
19
  const replay_assets_1 = require("../../local-data/replay-assets");
21
- const replays_1 = require("../../local-data/replays");
22
20
  const serve_assets_from_simulation_1 = require("../../local-data/serve-assets-from-simulation");
23
21
  const sessions_1 = require("../../local-data/sessions");
24
22
  const commit_sha_utils_1 = require("../../utils/commit-sha.utils");
25
23
  const config_utils_1 = require("../../utils/config.utils");
26
24
  const version_utils_1 = require("../../utils/version.utils");
27
- const screenshot_diff_command_1 = require("../screenshot-diff/screenshot-diff.command");
28
- const replayCommandHandler = async ({ replayTarget, executionOptions, screenshottingOptions, apiToken, sessionId, commitSha: commitSha_, save, exitOnMismatch, baseSimulationId: baseReplayId_, cookiesFile, generatedBy, testRunId, replayEventsDependencies, }) => {
25
+ const compute_and_save_diff_1 = require("./utils/compute-and-save-diff");
26
+ const replayCommandHandler = async ({ replayTarget, executionOptions, screenshottingOptions, apiToken, sessionId, commitSha: commitSha_, save, baseSimulationId: baseReplayId_, cookiesFile, generatedBy, testRunId, replayEventsDependencies, }) => {
29
27
  const logger = loglevel_1.default.getLogger(common_1.METICULOUS_LOGGER_NAME);
30
28
  const client = (0, client_1.createClient)({ apiToken });
31
29
  // 1. Check session files
@@ -82,93 +80,69 @@ const replayCommandHandler = async ({ replayTarget, executionOptions, screenshot
82
80
  logger.info("Sending simulation results to Meticulous");
83
81
  // 8. Create a Zip archive containing the replay files
84
82
  const archivePath = await (0, archive_1.createReplayArchive)(tempDir);
85
- // 9. Get upload URL
86
- const replay = await (0, replay_api_1.createReplay)({
87
- client,
88
- commitSha,
89
- sessionId,
90
- meticulousSha,
91
- version: "v2",
92
- metadata: { generatedBy },
93
- });
94
- const uploadUrlData = await (0, replay_api_1.getReplayPushUrl)(client, replay.id);
95
- if (!uploadUrlData) {
96
- logger.error("Error: Could not get a push URL from the Meticulous API");
97
- process.exit(1);
98
- }
99
- const uploadUrl = uploadUrlData.pushUrl;
100
- // 10. Send archive to S3
101
83
  try {
102
- await (0, upload_1.uploadArchive)(uploadUrl, archivePath);
103
- }
104
- catch (error) {
105
- await (0, replay_api_1.putReplayPushedStatus)(client, replay.id, "failure", replayCommandId).catch(logger.error);
106
- logger.error(error);
107
- process.exit(1);
108
- }
109
- // 11. Report successful upload to Meticulous
110
- const updatedProjectBuild = await (0, replay_api_1.putReplayPushedStatus)(client, replay.id, "success", replayCommandId);
111
- logger.info("Simulation artifacts successfully sent to Meticulous");
112
- logger.debug(updatedProjectBuild);
113
- const replayUrl = (0, replay_api_1.getReplayUrl)(replay);
114
- logger.info("=======");
115
- logger.info(`View simulation at: ${replayUrl}`);
116
- logger.info("=======");
117
- // 12. Diff against base replay screenshot if one is provided
118
- const baseReplayId = baseReplayId_ || "";
119
- if (screenshottingOptions.enabled && baseReplayId) {
120
- logger.info(`Diffing screenshots against replay ${baseReplayId}`);
121
- await (0, replays_1.getOrFetchReplay)(client, baseReplayId);
122
- await (0, replays_1.getOrFetchReplayArchive)(client, baseReplayId);
123
- const baseReplayScreenshotsDir = (0, replays_1.getScreenshotsDir)((0, replays_1.getReplayDir)(baseReplayId));
124
- const headReplayScreenshotsDir = (0, replays_1.getScreenshotsDir)(tempDir);
125
- const screenshotDiffResults = await (0, screenshot_diff_command_1.diffScreenshots)({
84
+ // 9. Get upload URL
85
+ const replay = await (0, replay_api_1.createReplay)({
126
86
  client,
127
- baseReplayId,
128
- headReplayId: replay.id,
129
- baseScreenshotsDir: baseReplayScreenshotsDir,
130
- headScreenshotsDir: headReplayScreenshotsDir,
131
- diffOptions: screenshottingOptions.diffOptions,
132
- });
133
- const replayDiff = await (0, replay_diff_api_1.createReplayDiff)({
134
- client,
135
- headReplayId: replay.id,
136
- baseReplayId,
137
- testRunId,
138
- data: {
139
- screenshotAssertionsOptions: screenshottingOptions,
140
- screenshotDiffResults,
141
- },
87
+ commitSha,
88
+ sessionId,
89
+ meticulousSha,
90
+ version: "v2",
91
+ metadata: { generatedBy },
142
92
  });
143
- logger.debug(replayDiff);
93
+ const uploadUrlData = await (0, replay_api_1.getReplayPushUrl)(client, replay.id);
94
+ if (!uploadUrlData) {
95
+ logger.error("Error: Could not get a push URL from the Meticulous API");
96
+ process.exit(1);
97
+ }
98
+ const uploadUrl = uploadUrlData.pushUrl;
99
+ // 10. Send archive to S3
144
100
  try {
145
- (0, screenshot_diff_command_1.checkScreenshotDiffResult)({
146
- baseReplayId,
147
- headReplayId: replay.id,
148
- results: screenshotDiffResults,
149
- diffOptions: screenshottingOptions.diffOptions,
150
- });
101
+ await (0, upload_1.uploadArchive)(uploadUrl, archivePath);
151
102
  }
152
103
  catch (error) {
153
- if (exitOnMismatch) {
154
- process.exit(1);
104
+ await (0, replay_api_1.putReplayPushedStatus)(client, replay.id, "failure", replayCommandId).catch(logger.error);
105
+ logger.error(error);
106
+ process.exit(1);
107
+ }
108
+ // 11. Report successful upload to Meticulous
109
+ const updatedProjectBuild = await (0, replay_api_1.putReplayPushedStatus)(client, replay.id, "success", replayCommandId);
110
+ logger.info("Simulation artifacts successfully sent to Meticulous");
111
+ logger.debug(updatedProjectBuild);
112
+ const replayUrl = (0, replay_api_1.getReplayUrl)(replay);
113
+ logger.info("=======");
114
+ logger.info(`View simulation at: ${replayUrl}`);
115
+ logger.info("=======");
116
+ // 12. Diff against base replay screenshot if one is provided
117
+ const { screenshotDiffResults, screenshotDiffsSummary } = screenshottingOptions.enabled && baseReplayId_
118
+ ? await (0, compute_and_save_diff_1.computeAndSaveDiff)({
119
+ client,
120
+ baseReplayId: baseReplayId_ !== null && baseReplayId_ !== void 0 ? baseReplayId_ : "",
121
+ headReplayId: replay.id,
122
+ tempDir,
123
+ screenshottingOptions,
124
+ testRunId,
125
+ })
126
+ : {
127
+ screenshotDiffResults: null,
128
+ screenshotDiffsSummary: { hasDiffs: false },
129
+ };
130
+ // 13. Add test case to meticulous.json if --save option is passed
131
+ if (save) {
132
+ if (!screenshottingOptions.enabled) {
133
+ logger.error("Warning: saving a new test case without screenshot enabled.");
155
134
  }
156
- throw error;
135
+ await (0, config_utils_1.addTestCase)({
136
+ title: `${sessionId} | ${replay.id}`,
137
+ sessionId,
138
+ baseReplayId: replay.id,
139
+ });
157
140
  }
141
+ return { replay, screenshotDiffResults, screenshotDiffsSummary };
158
142
  }
159
- // 13. Add test case to meticulous.json if --save option is passed
160
- if (save) {
161
- if (!screenshottingOptions.enabled) {
162
- logger.error("Warning: saving a new test case without screenshot enabled.");
163
- }
164
- await (0, config_utils_1.addTestCase)({
165
- title: `${sessionId} | ${replay.id}`,
166
- sessionId,
167
- baseReplayId: replay.id,
168
- });
143
+ finally {
144
+ await (0, archive_1.deleteArchive)(archivePath);
169
145
  }
170
- await (0, archive_1.deleteArchive)(archivePath);
171
- return replay;
172
146
  };
173
147
  exports.replayCommandHandler = replayCommandHandler;
174
148
  const serveOrGetAppUrl = async (client, replayTarget) => {
@@ -218,7 +192,7 @@ const rawReplayCommandHandler = async ({ apiToken, commitSha, sessionId, appUrl,
218
192
  }
219
193
  : { enabled: false };
220
194
  const replayEventsDependencies = await (0, replay_assets_1.loadReplayEventsDependencies)();
221
- return (0, exports.replayCommandHandler)({
195
+ const { replay, screenshotDiffsSummary } = await (0, exports.replayCommandHandler)({
222
196
  replayTarget: (0, exports.getReplayTarget)({
223
197
  appUrl: appUrl !== null && appUrl !== void 0 ? appUrl : null,
224
198
  simulationIdForAssets: simulationIdForAssets !== null && simulationIdForAssets !== void 0 ? simulationIdForAssets : null,
@@ -231,11 +205,14 @@ const rawReplayCommandHandler = async ({ apiToken, commitSha, sessionId, appUrl,
231
205
  sessionId,
232
206
  baseSimulationId,
233
207
  save,
234
- exitOnMismatch: true,
235
208
  generatedBy: generatedByOption,
236
209
  testRunId: null,
237
210
  replayEventsDependencies,
238
211
  });
212
+ if (screenshotDiffsSummary.hasDiffs) {
213
+ process.exit(1);
214
+ }
215
+ return replay;
239
216
  };
240
217
  exports.rawReplayCommandHandler = rawReplayCommandHandler;
241
218
  const getReplayTarget = ({ appUrl, simulationIdForAssets, }) => {
@@ -248,7 +225,7 @@ const getReplayTarget = ({ appUrl, simulationIdForAssets, }) => {
248
225
  return { type: "original-recorded-url" };
249
226
  };
250
227
  exports.getReplayTarget = getReplayTarget;
251
- exports.replay = (0, command_builder_1.buildCommand)("simulate")
228
+ exports.replayCommand = (0, command_builder_1.buildCommand)("simulate")
252
229
  .details({
253
230
  aliases: ["replay"],
254
231
  describe: "Simulate (replay) a recorded session",
@@ -0,0 +1,15 @@
1
+ import { ScreenshotAssertionsEnabledOptions, ScreenshotDiffResult } from "@alwaysmeticulous/api";
2
+ import { AxiosInstance } from "axios";
3
+ import { ScreenshotDiffsSummary } from "../../screenshot-diff/screenshot-diff.command";
4
+ export interface ComputeAndSaveDiffOptions {
5
+ client: AxiosInstance;
6
+ testRunId: string | null;
7
+ baseReplayId: string;
8
+ headReplayId: string;
9
+ tempDir: string;
10
+ screenshottingOptions: ScreenshotAssertionsEnabledOptions;
11
+ }
12
+ export declare const computeAndSaveDiff: ({ client, baseReplayId, tempDir, headReplayId, screenshottingOptions, testRunId, }: ComputeAndSaveDiffOptions) => Promise<{
13
+ screenshotDiffResults: ScreenshotDiffResult[];
14
+ screenshotDiffsSummary: ScreenshotDiffsSummary;
15
+ }>;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.computeAndSaveDiff = void 0;
7
+ const common_1 = require("@alwaysmeticulous/common");
8
+ const loglevel_1 = __importDefault(require("loglevel"));
9
+ const replay_diff_api_1 = require("../../../api/replay-diff.api");
10
+ const replays_1 = require("../../../local-data/replays");
11
+ const screenshot_diff_command_1 = require("../../screenshot-diff/screenshot-diff.command");
12
+ const computeAndSaveDiff = async ({ client, baseReplayId, tempDir, headReplayId, screenshottingOptions, testRunId, }) => {
13
+ const logger = loglevel_1.default.getLogger(common_1.METICULOUS_LOGGER_NAME);
14
+ logger.info(`Diffing screenshots against replay ${baseReplayId}`);
15
+ await (0, replays_1.getOrFetchReplay)(client, baseReplayId);
16
+ await (0, replays_1.getOrFetchReplayArchive)(client, baseReplayId);
17
+ const baseReplayScreenshotsDir = (0, replays_1.getScreenshotsDir)((0, replays_1.getReplayDir)(baseReplayId));
18
+ const headReplayScreenshotsDir = (0, replays_1.getScreenshotsDir)(tempDir);
19
+ const screenshotDiffResults = await (0, screenshot_diff_command_1.diffScreenshots)({
20
+ client,
21
+ baseReplayId,
22
+ headReplayId,
23
+ baseScreenshotsDir: baseReplayScreenshotsDir,
24
+ headScreenshotsDir: headReplayScreenshotsDir,
25
+ diffOptions: screenshottingOptions.diffOptions,
26
+ });
27
+ const replayDiff = await (0, replay_diff_api_1.createReplayDiff)({
28
+ client,
29
+ headReplayId,
30
+ baseReplayId,
31
+ testRunId,
32
+ data: {
33
+ screenshotAssertionsOptions: screenshottingOptions,
34
+ screenshotDiffResults,
35
+ },
36
+ });
37
+ logger.debug(replayDiff);
38
+ const screenshotDiffsSummary = (0, screenshot_diff_command_1.summarizeDifferences)({
39
+ baseReplayId,
40
+ headReplayId,
41
+ results: screenshotDiffResults,
42
+ diffOptions: screenshottingOptions.diffOptions,
43
+ });
44
+ return { screenshotDiffResults, screenshotDiffsSummary };
45
+ };
46
+ exports.computeAndSaveDiff = computeAndSaveDiff;
@@ -1,5 +1,5 @@
1
1
  /// <reference types="yargs" />
2
- export declare const runAllTests: import("yargs").CommandModule<unknown, import("yargs").InferredOptionTypes<{
2
+ export declare const runAllTestsCommand: import("yargs").CommandModule<unknown, import("yargs").InferredOptionTypes<{
3
3
  readonly diffThreshold: {
4
4
  readonly number: true;
5
5
  readonly description: "Acceptable maximum proportion of changed pixels, between 0 and 1. If this proportion is exceeded then the test will fail.";
@@ -90,14 +90,16 @@ export declare const runAllTests: import("yargs").CommandModule<unknown, import(
90
90
  readonly githubSummary: {
91
91
  readonly boolean: true;
92
92
  readonly description: "Outputs a summary page for GitHub actions";
93
+ readonly default: false;
93
94
  };
94
95
  readonly parallelize: {
95
96
  readonly boolean: true;
96
97
  readonly description: "Run tests in parallel";
98
+ readonly default: false;
97
99
  };
98
100
  readonly parallelTasks: {
99
101
  readonly number: true;
100
- readonly description: "Number of tasks to run in parallel";
102
+ readonly description: "Number of tasks to run in parallel (if not set a default value is used based on the number of CPUs)";
101
103
  readonly coerce: (value: number | null | undefined) => number | null | undefined;
102
104
  };
103
105
  readonly deflake: {