@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,28 +1,13 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.runAllTests = void 0;
7
- const common_1 = require("@alwaysmeticulous/common");
8
- const loglevel_1 = __importDefault(require("loglevel"));
3
+ exports.runAllTestsCommand = void 0;
9
4
  const client_1 = require("../../api/client");
10
5
  const test_run_api_1 = require("../../api/test-run.api");
11
6
  const command_builder_1 = require("../../command-utils/command-builder");
12
7
  const common_options_1 = require("../../command-utils/common-options");
13
- const config_1 = require("../../config/config");
14
- const deflake_tests_handler_1 = require("../../deflake-tests/deflake-tests.handler");
15
- const replay_assets_1 = require("../../local-data/replay-assets");
16
- const parallel_tests_handler_1 = require("../../parallel-tests/parallel-tests.handler");
8
+ const run_all_tests_1 = require("../../parallel-tests/run-all-tests");
17
9
  const commit_sha_utils_1 = require("../../utils/commit-sha.utils");
18
- const config_utils_1 = require("../../utils/config.utils");
19
- const github_summary_utils_1 = require("../../utils/github-summary.utils");
20
- const run_all_tests_utils_1 = require("../../utils/run-all-tests.utils");
21
- const version_utils_1 = require("../../utils/version.utils");
22
- const handler = async ({ apiToken, commitSha: commitSha_, baseCommitSha, appUrl, useAssetsSnapshottedInBaseSimulation, headless, devTools, bypassCSP, diffThreshold, diffPixelThreshold, padTime, shiftTime, networkStubbing, githubSummary, parallelize, parallelTasks, deflake, useCache, testsFile, disableRemoteFonts, noSandbox, skipPauses, moveBeforeClick, maxDurationMs, maxEventCount, storyboard, }) => {
23
- if (appUrl != null && useAssetsSnapshottedInBaseSimulation) {
24
- throw new Error("Arguments useAssetsSnapshottedInBaseSimulation and appUrl are mutually exclusive");
25
- }
10
+ const handler = async ({ apiToken, commitSha: commitSha_, baseCommitSha, appUrl, useAssetsSnapshottedInBaseSimulation, headless, devTools, bypassCSP, diffThreshold, diffPixelThreshold, padTime, shiftTime, networkStubbing, githubSummary, parallelize, parallelTasks: parrelelTasks_, deflake, useCache, testsFile, disableRemoteFonts, noSandbox, skipPauses, moveBeforeClick, maxDurationMs, maxEventCount, storyboard, }) => {
26
11
  const executionOptions = {
27
12
  headless,
28
13
  devTools,
@@ -46,108 +31,31 @@ const handler = async ({ apiToken, commitSha: commitSha_, baseCommitSha, appUrl,
46
31
  diffOptions: { diffPixelThreshold, diffThreshold },
47
32
  storyboardOptions,
48
33
  };
49
- const logger = loglevel_1.default.getLogger(common_1.METICULOUS_LOGGER_NAME);
50
- const client = (0, client_1.createClient)({ apiToken });
51
- const config = await (0, config_1.readConfig)(testsFile || undefined);
52
- const testCases = config.testCases || [];
53
- if (!testCases.length) {
54
- logger.error("Error! No test case defined");
55
- process.exit(1);
56
- }
34
+ const parrelelTasks = parallelize ? parrelelTasks_ : 1;
57
35
  const commitSha = (await (0, commit_sha_utils_1.getCommitSha)(commitSha_)) || "unknown";
58
- const meticulousSha = await (0, version_utils_1.getMeticulousVersion)();
36
+ const client = (0, client_1.createClient)({ apiToken });
59
37
  const cachedTestRunResults = useCache
60
38
  ? await (0, test_run_api_1.getCachedTestRunResults)({ client, commitSha })
61
39
  : [];
62
- const replayEventsDependencies = await (0, replay_assets_1.loadReplayEventsDependencies)();
63
- const testRun = await (0, test_run_api_1.createTestRun)({
64
- client,
40
+ const { testRun } = await (0, run_all_tests_1.runAllTests)({
41
+ testsFile: testsFile !== null && testsFile !== void 0 ? testsFile : null,
42
+ executionOptions,
43
+ screenshottingOptions,
44
+ apiToken: apiToken !== null && apiToken !== void 0 ? apiToken : null,
65
45
  commitSha,
66
- meticulousSha,
67
- configData: config,
46
+ baseCommitSha: baseCommitSha !== null && baseCommitSha !== void 0 ? baseCommitSha : null,
47
+ appUrl: appUrl !== null && appUrl !== void 0 ? appUrl : null,
48
+ useAssetsSnapshottedInBaseSimulation,
49
+ parallelTasks: parrelelTasks !== null && parrelelTasks !== void 0 ? parrelelTasks : null,
50
+ deflake,
51
+ cachedTestRunResults,
52
+ githubSummary,
68
53
  });
69
- const testRunUrl = (0, test_run_api_1.getTestRunUrl)(testRun);
70
- logger.info("");
71
- logger.info(`Test run URL: ${testRunUrl}`);
72
- logger.info("");
73
- const getResults = async () => {
74
- if (parallelize) {
75
- const results = await (0, parallel_tests_handler_1.runAllTestsInParallel)({
76
- config,
77
- client,
78
- testRun,
79
- executionOptions,
80
- screenshottingOptions,
81
- apiToken: apiToken !== null && apiToken !== void 0 ? apiToken : null,
82
- commitSha,
83
- appUrl: appUrl !== null && appUrl !== void 0 ? appUrl : null,
84
- useAssetsSnapshottedInBaseSimulation,
85
- parallelTasks: parallelTasks !== null && parallelTasks !== void 0 ? parallelTasks : null,
86
- deflake,
87
- cachedTestRunResults,
88
- replayEventsDependencies,
89
- baseCommitSha: baseCommitSha !== null && baseCommitSha !== void 0 ? baseCommitSha : null,
90
- });
91
- return results;
92
- }
93
- const results = [...cachedTestRunResults];
94
- const testsToRun = await (0, run_all_tests_utils_1.getTestsToRun)({
95
- testCases,
96
- cachedTestRunResults,
97
- client,
98
- baseCommitSha: baseCommitSha !== null && baseCommitSha !== void 0 ? baseCommitSha : null,
99
- });
100
- for (const testCase of testsToRun) {
101
- const result = await (0, deflake_tests_handler_1.deflakeReplayCommandHandler)({
102
- replayTarget: (0, config_utils_1.getReplayTargetForTestCase)({
103
- useAssetsSnapshottedInBaseSimulation,
104
- appUrl: appUrl !== null && appUrl !== void 0 ? appUrl : null,
105
- testCase,
106
- }),
107
- executionOptions,
108
- screenshottingOptions,
109
- testCase,
110
- apiToken: apiToken !== null && apiToken !== void 0 ? apiToken : null,
111
- commitSha,
112
- deflake: deflake !== null && deflake !== void 0 ? deflake : false,
113
- generatedBy: { type: "testRun", runId: testRun.id },
114
- testRunId: testRun.id,
115
- replayEventsDependencies,
116
- });
117
- results.push(result);
118
- await (0, test_run_api_1.putTestRunResults)({
119
- client,
120
- testRunId: testRun.id,
121
- status: "Running",
122
- resultData: { results },
123
- });
124
- }
125
- return (0, run_all_tests_utils_1.sortResults)({ results, testCases });
126
- };
127
- const results = await getResults();
128
- const runAllFailure = results.find(({ result }) => result === "fail");
129
- await (0, test_run_api_1.putTestRunResults)({
130
- client,
131
- testRunId: testRun.id,
132
- status: runAllFailure ? "Failure" : "Success",
133
- resultData: { results },
134
- });
135
- logger.info("");
136
- logger.info("Results");
137
- logger.info("=======");
138
- logger.info(`URL: ${testRunUrl}`);
139
- logger.info("=======");
140
- results.forEach(({ title, result }) => {
141
- logger.info(`${title} => ${result}`);
142
- });
143
- if (githubSummary) {
144
- await (0, github_summary_utils_1.writeGitHubSummary)({ testRun, results });
145
- }
146
- if (runAllFailure) {
54
+ if (testRun.status === "Failure") {
147
55
  process.exit(1);
148
56
  }
149
57
  };
150
- exports.runAllTests = (0, command_builder_1.buildCommand)("run-all-tests")
58
+ exports.runAllTestsCommand = (0, command_builder_1.buildCommand)("run-all-tests")
151
59
  .details({ describe: "Run all replay test cases" })
152
60
  .options({
153
61
  apiToken: common_options_1.OPTIONS.apiToken,
@@ -170,14 +78,16 @@ exports.runAllTests = (0, command_builder_1.buildCommand)("run-all-tests")
170
78
  githubSummary: {
171
79
  boolean: true,
172
80
  description: "Outputs a summary page for GitHub actions",
81
+ default: false,
173
82
  },
174
83
  parallelize: {
175
84
  boolean: true,
176
85
  description: "Run tests in parallel",
86
+ default: false,
177
87
  },
178
88
  parallelTasks: {
179
89
  number: true,
180
- description: "Number of tasks to run in parallel",
90
+ description: "Number of tasks to run in parallel (if not set a default value is used based on the number of CPUs)",
181
91
  coerce: (value) => {
182
92
  if (typeof value === "number" && value <= 0) {
183
93
  return null;
@@ -9,23 +9,23 @@ export declare const diffScreenshots: ({ client, headReplayId, baseReplayId, hea
9
9
  headScreenshotsDir: string;
10
10
  diffOptions: ScreenshotDiffOptions;
11
11
  }) => Promise<ScreenshotDiffResult[]>;
12
- export declare const checkScreenshotDiffResult: ({ baseReplayId, headReplayId, results, diffOptions, }: {
12
+ export declare const summarizeDifferences: ({ baseReplayId, headReplayId, results, diffOptions, }: {
13
13
  baseReplayId: string;
14
14
  headReplayId: string;
15
15
  results: ScreenshotDiffResult[];
16
16
  diffOptions: ScreenshotDiffOptions;
17
- }) => void;
18
- export declare class ScreenshotDiffError extends Error {
19
- readonly extras?: {
20
- baseReplayId: string;
21
- headReplayId: string;
22
- } | undefined;
23
- constructor(message: string, extras?: {
24
- baseReplayId: string;
25
- headReplayId: string;
26
- } | undefined);
17
+ }) => ScreenshotDiffsSummary;
18
+ export declare type ScreenshotDiffsSummary = HasDiffsScreenshotDiffsResult | NoDiffsScreenshotDiffsResult;
19
+ export interface HasDiffsScreenshotDiffsResult {
20
+ hasDiffs: true;
21
+ summaryMessage: string;
22
+ baseReplayId: string;
23
+ headReplayId: string;
24
+ }
25
+ export interface NoDiffsScreenshotDiffsResult {
26
+ hasDiffs: false;
27
27
  }
28
- export declare const screenshotDiff: import("yargs").CommandModule<unknown, import("yargs").InferredOptionTypes<{
28
+ export declare const screenshotDiffCommand: import("yargs").CommandModule<unknown, import("yargs").InferredOptionTypes<{
29
29
  apiToken: {
30
30
  string: true;
31
31
  };
@@ -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.screenshotDiff = exports.ScreenshotDiffError = exports.checkScreenshotDiffResult = exports.diffScreenshots = void 0;
6
+ exports.screenshotDiffCommand = exports.summarizeDifferences = exports.diffScreenshots = 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 diffScreenshots = async ({ client, headReplayId, baseReplayId, headScreens
99
99
  return [...missingHeadImagesResults, ...headDiffResults];
100
100
  };
101
101
  exports.diffScreenshots = diffScreenshots;
102
- const checkScreenshotDiffResult = ({ baseReplayId, headReplayId, results, diffOptions, }) => {
102
+ const summarizeDifferences = ({ baseReplayId, headReplayId, results, diffOptions, }) => {
103
103
  const logger = loglevel_1.default.getLogger(common_1.METICULOUS_LOGGER_NAME);
104
104
  const missingHeadImagesResults = results.flatMap((result) => result.outcome === "missing-head" ? [result] : []);
105
105
  if (missingHeadImagesResults.length) {
@@ -107,10 +107,12 @@ const checkScreenshotDiffResult = ({ baseReplayId, headReplayId, results, diffOp
107
107
  .map(({ baseScreenshotFile }) => (0, path_1.basename)(baseScreenshotFile))
108
108
  .sort()} => FAIL!`;
109
109
  logger.info(message);
110
- throw new ScreenshotDiffError(message, {
110
+ return {
111
+ hasDiffs: true,
112
+ summaryMessage: message,
111
113
  baseReplayId,
112
114
  headReplayId,
113
- });
115
+ };
114
116
  }
115
117
  const missingBaseImagesResults = results.flatMap((result) => result.outcome === "missing-base" ? [result] : []);
116
118
  if (missingHeadImagesResults.length) {
@@ -124,10 +126,12 @@ const checkScreenshotDiffResult = ({ baseReplayId, headReplayId, results, diffOp
124
126
  if (outcome === "different-size") {
125
127
  const message = `Screenshots ${(0, path_1.basename)(result.headScreenshotFile)} have different sizes => FAIL!`;
126
128
  logger.info(message);
127
- throw new ScreenshotDiffError(message, {
129
+ return {
130
+ hasDiffs: true,
131
+ summaryMessage: message,
128
132
  baseReplayId,
129
133
  headReplayId,
130
- });
134
+ };
131
135
  }
132
136
  if (outcome === "diff" || outcome === "no-diff") {
133
137
  const mismatch = (result.mismatchFraction * 100).toFixed(3);
@@ -135,22 +139,18 @@ const checkScreenshotDiffResult = ({ baseReplayId, headReplayId, results, diffOp
135
139
  const message = `${mismatch}% pixel mismatch for screenshot ${(0, path_1.basename)(result.headScreenshotFile)} (threshold is ${threshold}%) => ${outcome === "no-diff" ? "PASS" : "FAIL!"}`;
136
140
  logger.info(message);
137
141
  if (outcome === "diff") {
138
- throw new ScreenshotDiffError(message, {
142
+ return {
143
+ hasDiffs: true,
144
+ summaryMessage: message,
139
145
  baseReplayId,
140
146
  headReplayId,
141
- });
147
+ };
142
148
  }
143
149
  }
144
150
  });
151
+ return { hasDiffs: false };
145
152
  };
146
- exports.checkScreenshotDiffResult = checkScreenshotDiffResult;
147
- class ScreenshotDiffError extends Error {
148
- constructor(message, extras) {
149
- super(message);
150
- this.extras = extras;
151
- }
152
- }
153
- exports.ScreenshotDiffError = ScreenshotDiffError;
153
+ exports.summarizeDifferences = summarizeDifferences;
154
154
  const getScreenshotIdentifier = (filename) => {
155
155
  const name = (0, path_1.basename)(filename);
156
156
  if (name === "final-state.png") {
@@ -192,14 +192,17 @@ const handler = async ({ apiToken, baseSimulationId: baseReplayId, headSimulatio
192
192
  diffOptions,
193
193
  });
194
194
  logger.debug(results);
195
- (0, exports.checkScreenshotDiffResult)({
195
+ const diffSummary = (0, exports.summarizeDifferences)({
196
196
  baseReplayId,
197
197
  headReplayId,
198
198
  results,
199
199
  diffOptions,
200
200
  });
201
+ if (diffSummary.hasDiffs) {
202
+ process.exit(1);
203
+ }
201
204
  };
202
- exports.screenshotDiff = (0, command_builder_1.buildCommand)("screenshot-diff")
205
+ exports.screenshotDiffCommand = (0, command_builder_1.buildCommand)("screenshot-diff")
203
206
  .details({ describe: "Diff two replay screenshots" })
204
207
  .options({
205
208
  apiToken: {
@@ -1,5 +1,5 @@
1
1
  /// <reference types="yargs" />
2
- export declare const serve: import("yargs").CommandModule<unknown, import("yargs").InferredOptionTypes<{
2
+ export declare const serveCommand: 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.serve = void 0;
6
+ exports.serveCommand = 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");
@@ -15,7 +15,7 @@ const handler = async ({ apiToken, replayId, }) => {
15
15
  const { url } = await (0, serve_assets_from_simulation_1.serveAssetsFromSimulation)(client, replayId);
16
16
  logger.info(`Serving assets at url ${url}`);
17
17
  };
18
- exports.serve = (0, command_builder_1.buildCommand)("serve")
18
+ exports.serveCommand = (0, command_builder_1.buildCommand)("serve")
19
19
  .details({
20
20
  describe: "Spin up a localhost server to serve the assets that were snapshotted when running a particular replay",
21
21
  })
@@ -1,5 +1,5 @@
1
1
  /// <reference types="yargs" />
2
- export declare const showProject: import("yargs").CommandModule<unknown, import("yargs").InferredOptionTypes<{
2
+ export declare const showProjectCommand: 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.showProject = void 0;
6
+ exports.showProjectCommand = 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");
@@ -19,7 +19,7 @@ const handler = async ({ apiToken }) => {
19
19
  }
20
20
  logger.info(project);
21
21
  };
22
- exports.showProject = (0, command_builder_1.buildCommand)("show-project")
22
+ exports.showProjectCommand = (0, command_builder_1.buildCommand)("show-project")
23
23
  .details({
24
24
  describe: "Shows project linked with current API token",
25
25
  })
@@ -1,5 +1,5 @@
1
1
  /// <reference types="yargs" />
2
- export declare const updateTests: import("yargs").CommandModule<unknown, import("yargs").InferredOptionTypes<{
2
+ export declare const updateTestsCommand: 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.updateTests = void 0;
6
+ exports.updateTestsCommand = 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");
@@ -69,7 +69,7 @@ const handler = async ({ apiToken, testRunId, accept: accept_, acceptAll: accept
69
69
  };
70
70
  await (0, config_1.saveConfig)(newConfig);
71
71
  };
72
- exports.updateTests = (0, command_builder_1.buildCommand)("update-tests")
72
+ exports.updateTestsCommand = (0, command_builder_1.buildCommand)("update-tests")
73
73
  .details({
74
74
  describe: "Updates test cases",
75
75
  })
@@ -1,3 +1,4 @@
1
+ import { ScreenshotDiffResult } from "@alwaysmeticulous/api";
1
2
  import { ScreenshotDiffOptions } from "../command-utils/common-types";
2
3
  export interface TestCaseReplayOptions extends Partial<ScreenshotDiffOptions> {
3
4
  appUrl?: string | null | undefined;
@@ -21,3 +22,6 @@ export interface TestCaseResult extends TestCase {
21
22
  headReplayId: string;
22
23
  result: "pass" | "fail";
23
24
  }
25
+ export interface DetailedTestCaseResult extends TestCaseResult {
26
+ screenshotDiffResults: ScreenshotDiffResult[];
27
+ }
@@ -1,6 +1,6 @@
1
1
  import { GeneratedBy, ReplayEventsDependencies, ReplayExecutionOptions, ReplayTarget } from "@alwaysmeticulous/common";
2
2
  import { ScreenshotAssertionsEnabledOptions } from "../command-utils/common-types";
3
- import { TestCase, TestCaseResult } from "../config/config.types";
3
+ import { DetailedTestCaseResult, TestCase } from "../config/config.types";
4
4
  export interface DeflakeReplayCommandHandlerOptions extends HandleReplayOptions {
5
5
  deflake: boolean;
6
6
  }
@@ -15,5 +15,5 @@ interface HandleReplayOptions {
15
15
  testRunId: string | null;
16
16
  replayEventsDependencies: ReplayEventsDependencies;
17
17
  }
18
- export declare const deflakeReplayCommandHandler: (options: DeflakeReplayCommandHandlerOptions) => Promise<TestCaseResult>;
18
+ export declare const deflakeReplayCommandHandler: ({ deflake, ...otherOptions }: DeflakeReplayCommandHandlerOptions) => Promise<DetailedTestCaseResult>;
19
19
  export {};
@@ -7,11 +7,9 @@ exports.deflakeReplayCommandHandler = void 0;
7
7
  const common_1 = require("@alwaysmeticulous/common");
8
8
  const loglevel_1 = __importDefault(require("loglevel"));
9
9
  const replay_command_1 = require("../commands/replay/replay.command");
10
- const screenshot_diff_command_1 = require("../commands/screenshot-diff/screenshot-diff.command");
11
10
  const handleReplay = async ({ testCase, replayTarget, executionOptions, screenshottingOptions, apiToken, commitSha, generatedBy, testRunId, replayEventsDependencies, }) => {
12
11
  var _a, _b;
13
- const logger = loglevel_1.default.getLogger(common_1.METICULOUS_LOGGER_NAME);
14
- const replayPromise = (0, replay_command_1.replayCommandHandler)({
12
+ const { replay, screenshotDiffResults, screenshotDiffsSummary } = await (0, replay_command_1.replayCommandHandler)({
15
13
  replayTarget,
16
14
  executionOptions: applyTestCaseExecutionOptionOverrides(executionOptions, (_a = testCase.options) !== null && _a !== void 0 ? _a : {}),
17
15
  screenshottingOptions: applyTestCaseScreenshottingOptionsOverrides(screenshottingOptions, (_b = testCase.options) !== null && _b !== void 0 ? _b : {}),
@@ -20,30 +18,20 @@ const handleReplay = async ({ testCase, replayTarget, executionOptions, screensh
20
18
  sessionId: testCase.sessionId,
21
19
  baseSimulationId: testCase.baseReplayId,
22
20
  save: false,
23
- exitOnMismatch: false,
24
21
  cookiesFile: null,
25
22
  generatedBy,
26
23
  testRunId,
27
24
  replayEventsDependencies,
28
25
  });
29
- const result = await replayPromise
30
- .then((replay) => ({
26
+ if (screenshotDiffResults == null) {
27
+ throw new Error(`replayCommandHandler returned a null screenshotDiffResults, but was called with screenshottingOptions.enabled = true`);
28
+ }
29
+ return {
31
30
  ...testCase,
32
31
  headReplayId: replay.id,
33
- result: "pass",
34
- }))
35
- .catch((error) => {
36
- if (error instanceof screenshot_diff_command_1.ScreenshotDiffError && error.extras) {
37
- return {
38
- ...testCase,
39
- headReplayId: error.extras.headReplayId,
40
- result: "fail",
41
- };
42
- }
43
- logger.error(error);
44
- return { ...testCase, headReplayId: "", result: "fail" };
45
- });
46
- return result;
32
+ result: screenshotDiffsSummary.hasDiffs ? "pass" : "fail",
33
+ screenshotDiffResults,
34
+ };
47
35
  };
48
36
  const deflakeReplayCommandHandler = async ({ deflake, ...otherOptions }) => {
49
37
  const logger = loglevel_1.default.getLogger(common_1.METICULOUS_LOGGER_NAME);
package/dist/index.d.ts CHANGED
@@ -1,11 +1,12 @@
1
- export { bootstrap } from "./commands/bootstrap/bootstrap.command";
2
- export { createTest } from "./commands/create-test/create-test.command";
3
- export { debugReplay } from "./commands/debug-replay/debug-replay.command";
4
- export { downloadReplay } from "./commands/download-replay/download-replay.command";
5
- export { downloadSession } from "./commands/download-session/download-session.command";
6
- export { record } from "./commands/record/record.command";
7
- export { replay } from "./commands/replay/replay.command";
8
- export { runAllTests } from "./commands/run-all-tests/run-all-tests.command";
9
- export { screenshotDiff } from "./commands/screenshot-diff/screenshot-diff.command";
10
- export { showProject } from "./commands/show-project/show-project.command";
11
- export { updateTests } from "./commands/update-tests/update-tests.command";
1
+ export { bootstrapCommand } from "./commands/bootstrap/bootstrap.command";
2
+ export { createTestCommand } from "./commands/create-test/create-test.command";
3
+ export { debugReplayCommand } from "./commands/debug-replay/debug-replay.command";
4
+ export { downloadReplayCommand } from "./commands/download-replay/download-replay.command";
5
+ export { downloadSessionCommand } from "./commands/download-session/download-session.command";
6
+ export { recordCommand } from "./commands/record/record.command";
7
+ export { replayCommand } from "./commands/replay/replay.command";
8
+ export { runAllTestsCommand } from "./commands/run-all-tests/run-all-tests.command";
9
+ export { screenshotDiffCommand } from "./commands/screenshot-diff/screenshot-diff.command";
10
+ export { showProjectCommand } from "./commands/show-project/show-project.command";
11
+ export { updateTestsCommand } from "./commands/update-tests/update-tests.command";
12
+ export { runAllTests, TestRun, RunAllTestsResult, } from "./parallel-tests/run-all-tests";
package/dist/index.js CHANGED
@@ -1,25 +1,27 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.updateTests = exports.showProject = exports.screenshotDiff = exports.runAllTests = exports.replay = exports.record = exports.downloadSession = exports.downloadReplay = exports.debugReplay = exports.createTest = exports.bootstrap = void 0;
3
+ exports.runAllTests = exports.updateTestsCommand = exports.showProjectCommand = exports.screenshotDiffCommand = exports.runAllTestsCommand = exports.replayCommand = exports.recordCommand = exports.downloadSessionCommand = exports.downloadReplayCommand = exports.debugReplayCommand = exports.createTestCommand = exports.bootstrapCommand = void 0;
4
4
  var bootstrap_command_1 = require("./commands/bootstrap/bootstrap.command");
5
- Object.defineProperty(exports, "bootstrap", { enumerable: true, get: function () { return bootstrap_command_1.bootstrap; } });
5
+ Object.defineProperty(exports, "bootstrapCommand", { enumerable: true, get: function () { return bootstrap_command_1.bootstrapCommand; } });
6
6
  var create_test_command_1 = require("./commands/create-test/create-test.command");
7
- Object.defineProperty(exports, "createTest", { enumerable: true, get: function () { return create_test_command_1.createTest; } });
7
+ Object.defineProperty(exports, "createTestCommand", { enumerable: true, get: function () { return create_test_command_1.createTestCommand; } });
8
8
  var debug_replay_command_1 = require("./commands/debug-replay/debug-replay.command");
9
- Object.defineProperty(exports, "debugReplay", { enumerable: true, get: function () { return debug_replay_command_1.debugReplay; } });
9
+ Object.defineProperty(exports, "debugReplayCommand", { enumerable: true, get: function () { return debug_replay_command_1.debugReplayCommand; } });
10
10
  var download_replay_command_1 = require("./commands/download-replay/download-replay.command");
11
- Object.defineProperty(exports, "downloadReplay", { enumerable: true, get: function () { return download_replay_command_1.downloadReplay; } });
11
+ Object.defineProperty(exports, "downloadReplayCommand", { enumerable: true, get: function () { return download_replay_command_1.downloadReplayCommand; } });
12
12
  var download_session_command_1 = require("./commands/download-session/download-session.command");
13
- Object.defineProperty(exports, "downloadSession", { enumerable: true, get: function () { return download_session_command_1.downloadSession; } });
13
+ Object.defineProperty(exports, "downloadSessionCommand", { enumerable: true, get: function () { return download_session_command_1.downloadSessionCommand; } });
14
14
  var record_command_1 = require("./commands/record/record.command");
15
- Object.defineProperty(exports, "record", { enumerable: true, get: function () { return record_command_1.record; } });
15
+ Object.defineProperty(exports, "recordCommand", { enumerable: true, get: function () { return record_command_1.recordCommand; } });
16
16
  var replay_command_1 = require("./commands/replay/replay.command");
17
- Object.defineProperty(exports, "replay", { enumerable: true, get: function () { return replay_command_1.replay; } });
17
+ Object.defineProperty(exports, "replayCommand", { enumerable: true, get: function () { return replay_command_1.replayCommand; } });
18
18
  var run_all_tests_command_1 = require("./commands/run-all-tests/run-all-tests.command");
19
- Object.defineProperty(exports, "runAllTests", { enumerable: true, get: function () { return run_all_tests_command_1.runAllTests; } });
19
+ Object.defineProperty(exports, "runAllTestsCommand", { enumerable: true, get: function () { return run_all_tests_command_1.runAllTestsCommand; } });
20
20
  var screenshot_diff_command_1 = require("./commands/screenshot-diff/screenshot-diff.command");
21
- Object.defineProperty(exports, "screenshotDiff", { enumerable: true, get: function () { return screenshot_diff_command_1.screenshotDiff; } });
21
+ Object.defineProperty(exports, "screenshotDiffCommand", { enumerable: true, get: function () { return screenshot_diff_command_1.screenshotDiffCommand; } });
22
22
  var show_project_command_1 = require("./commands/show-project/show-project.command");
23
- Object.defineProperty(exports, "showProject", { enumerable: true, get: function () { return show_project_command_1.showProject; } });
23
+ Object.defineProperty(exports, "showProjectCommand", { enumerable: true, get: function () { return show_project_command_1.showProjectCommand; } });
24
24
  var update_tests_command_1 = require("./commands/update-tests/update-tests.command");
25
- Object.defineProperty(exports, "updateTests", { enumerable: true, get: function () { return update_tests_command_1.updateTests; } });
25
+ Object.defineProperty(exports, "updateTestsCommand", { enumerable: true, get: function () { return update_tests_command_1.updateTestsCommand; } });
26
+ var run_all_tests_1 = require("./parallel-tests/run-all-tests");
27
+ Object.defineProperty(exports, "runAllTests", { enumerable: true, get: function () { return run_all_tests_1.runAllTests; } });
package/dist/main.js CHANGED
@@ -31,18 +31,18 @@ const main = () => {
31
31
  .usage(`$0 <command>
32
32
 
33
33
  Meticulous CLI`)
34
- .command(bootstrap_command_1.bootstrap)
35
- .command(create_test_command_1.createTest)
36
- .command(debug_replay_command_1.debugReplay)
37
- .command(download_replay_command_1.downloadReplay)
38
- .command(download_session_command_1.downloadSession)
39
- .command(record_command_1.record)
40
- .command(replay_command_1.replay)
41
- .command(run_all_tests_command_1.runAllTests)
42
- .command(screenshot_diff_command_1.screenshotDiff)
43
- .command(show_project_command_1.showProject)
44
- .command(update_tests_command_1.updateTests)
45
- .command("serve", false, serve_command_1.serve) // This is a debugging command, so we hide it to not pollute the main menu
34
+ .command(bootstrap_command_1.bootstrapCommand)
35
+ .command(create_test_command_1.createTestCommand)
36
+ .command(debug_replay_command_1.debugReplayCommand)
37
+ .command(download_replay_command_1.downloadReplayCommand)
38
+ .command(download_session_command_1.downloadSessionCommand)
39
+ .command(record_command_1.recordCommand)
40
+ .command(replay_command_1.replayCommand)
41
+ .command(run_all_tests_command_1.runAllTestsCommand)
42
+ .command(screenshot_diff_command_1.screenshotDiffCommand)
43
+ .command(show_project_command_1.showProjectCommand)
44
+ .command(update_tests_command_1.updateTestsCommand)
45
+ .command("serve", false, serve_command_1.serveCommand) // This is a debugging command, so we hide it to not pollute the main menu
46
46
  .help()
47
47
  .strict()
48
48
  .demandCommand()
@@ -1,5 +1,5 @@
1
1
  import log from "loglevel";
2
- import { TestCaseResult } from "../config/config.types";
2
+ import { DetailedTestCaseResult } from "../config/config.types";
3
3
  import { DeflakeReplayCommandHandlerOptions } from "../deflake-tests/deflake-tests.handler";
4
4
  export interface InitMessage {
5
5
  kind: "init";
@@ -12,6 +12,6 @@ export interface InitMessage {
12
12
  export interface ResultMessage {
13
13
  kind: "result";
14
14
  data: {
15
- result: TestCaseResult;
15
+ result: DetailedTestCaseResult;
16
16
  };
17
17
  }
@@ -1,26 +1,22 @@
1
1
  import { ReplayEventsDependencies, ReplayExecutionOptions } from "@alwaysmeticulous/common";
2
- import { AxiosInstance } from "axios";
3
2
  import { TestRun } from "../api/test-run.api";
4
3
  import { ScreenshotAssertionsEnabledOptions } from "../command-utils/common-types";
5
- import { MeticulousCliConfig, TestCaseResult } from "../config/config.types";
4
+ import { DetailedTestCaseResult, MeticulousCliConfig, TestCase } from "../config/config.types";
5
+ import { TestRunProgress } from "./run-all-tests.types";
6
6
  export interface RunAllTestsInParallelOptions {
7
7
  config: MeticulousCliConfig;
8
- client: AxiosInstance;
9
8
  testRun: TestRun;
9
+ testsToRun: TestCase[];
10
10
  executionOptions: ReplayExecutionOptions;
11
11
  screenshottingOptions: ScreenshotAssertionsEnabledOptions;
12
12
  apiToken: string | null;
13
13
  commitSha: string;
14
- /**
15
- * The base commit to compare test results against for test cases that don't have a baseReplayId specified.
16
- */
17
- baseCommitSha: string | null;
18
14
  appUrl: string | null;
19
15
  useAssetsSnapshottedInBaseSimulation: boolean;
20
16
  parallelTasks: number | null;
21
17
  deflake: boolean;
22
- cachedTestRunResults: TestCaseResult[];
23
18
  replayEventsDependencies: ReplayEventsDependencies;
19
+ onTestFinished?: (progress: TestRunProgress, resultsSoFar: DetailedTestCaseResult[]) => Promise<void>;
24
20
  }
25
21
  /** Handler for running Meticulous tests in parallel using child processes */
26
- export declare const runAllTestsInParallel: (options: RunAllTestsInParallelOptions) => Promise<TestCaseResult[]>;
22
+ export declare const runAllTestsInParallel: (options: RunAllTestsInParallelOptions) => Promise<DetailedTestCaseResult[]>;