@alwaysmeticulous/cli 2.40.0 → 2.41.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 (121) hide show
  1. package/dist/api/test-run.api.d.ts +3 -31
  2. package/dist/api/test-run.api.js +3 -96
  3. package/dist/commands/download-replay/download-replay.command.js +4 -4
  4. package/dist/commands/download-session/download-session.command.js +4 -4
  5. package/dist/commands/record/record.command.js +8 -11
  6. package/dist/commands/replay/replay.command.d.ts +11 -20
  7. package/dist/commands/replay/replay.command.js +20 -235
  8. package/dist/commands/run-all-tests/run-all-tests.command.js +5 -5
  9. package/dist/commands/show-project/show-project.command.js +2 -3
  10. package/dist/index.d.ts +0 -7
  11. package/dist/index.js +1 -13
  12. package/dist/main.js +5 -11
  13. package/dist/utils/sentry.utils.d.ts +0 -4
  14. package/dist/utils/sentry.utils.js +3 -23
  15. package/package.json +14 -32
  16. package/dist/api/client.d.ts +0 -5
  17. package/dist/api/client.js +0 -32
  18. package/dist/api/download.d.ts +0 -1
  19. package/dist/api/download.js +0 -21
  20. package/dist/api/project.api.d.ts +0 -3
  21. package/dist/api/project.api.js +0 -22
  22. package/dist/api/replay-diff.api.d.ts +0 -13
  23. package/dist/api/replay-diff.api.js +0 -32
  24. package/dist/api/replay.api.d.ts +0 -36
  25. package/dist/api/replay.api.js +0 -89
  26. package/dist/api/session.api.d.ts +0 -6
  27. package/dist/api/session.api.js +0 -45
  28. package/dist/api/types.d.ts +0 -39
  29. package/dist/api/types.js +0 -2
  30. package/dist/api/upload.d.ts +0 -1
  31. package/dist/api/upload.js +0 -18
  32. package/dist/archive/archive.d.ts +0 -4
  33. package/dist/archive/archive.js +0 -64
  34. package/dist/command-utils/common-types.d.ts +0 -20
  35. package/dist/command-utils/common-types.js +0 -2
  36. package/dist/commands/bootstrap/bootstrap.command.d.ts +0 -2
  37. package/dist/commands/bootstrap/bootstrap.command.js +0 -33
  38. package/dist/commands/create-test/create-test.command.d.ts +0 -90
  39. package/dist/commands/create-test/create-test.command.js +0 -165
  40. package/dist/commands/replay/utils/compute-diff.d.ts +0 -13
  41. package/dist/commands/replay/utils/compute-diff.js +0 -95
  42. package/dist/commands/replay/utils/exit-early-if-skip-upload-env-var-set.d.ts +0 -1
  43. package/dist/commands/replay/utils/exit-early-if-skip-upload-env-var-set.js +0 -27
  44. package/dist/commands/screenshot-diff/screenshot-diff.command.d.ts +0 -53
  45. package/dist/commands/screenshot-diff/screenshot-diff.command.js +0 -182
  46. package/dist/commands/screenshot-diff/utils/__tests__/get-screenshot-identifier.spec.d.ts +0 -1
  47. package/dist/commands/screenshot-diff/utils/__tests__/get-screenshot-identifier.spec.js +0 -25
  48. package/dist/commands/screenshot-diff/utils/get-screenshot-filename.d.ts +0 -2
  49. package/dist/commands/screenshot-diff/utils/get-screenshot-filename.js +0 -22
  50. package/dist/commands/screenshot-diff/utils/get-screenshot-identifier.d.ts +0 -2
  51. package/dist/commands/screenshot-diff/utils/get-screenshot-identifier.js +0 -39
  52. package/dist/commands/screenshot-diff/utils/has-notable-differences.d.ts +0 -2
  53. package/dist/commands/screenshot-diff/utils/has-notable-differences.js +0 -10
  54. package/dist/commands/serve/serve.command.d.ts +0 -10
  55. package/dist/commands/serve/serve.command.js +0 -31
  56. package/dist/commands/update-tests/update-tests.command.d.ts +0 -21
  57. package/dist/commands/update-tests/update-tests.command.js +0 -96
  58. package/dist/config/config.d.ts +0 -3
  59. package/dist/config/config.js +0 -69
  60. package/dist/config/config.types.d.ts +0 -16
  61. package/dist/config/config.types.js +0 -2
  62. package/dist/config/snippets.d.ts +0 -1
  63. package/dist/config/snippets.js +0 -18
  64. package/dist/errors/config.d.ts +0 -3
  65. package/dist/errors/config.js +0 -10
  66. package/dist/image/diff.utils.d.ts +0 -19
  67. package/dist/image/diff.utils.js +0 -25
  68. package/dist/image/io.utils.d.ts +0 -3
  69. package/dist/image/io.utils.js +0 -25
  70. package/dist/local-data/local-data.utils.d.ts +0 -20
  71. package/dist/local-data/local-data.utils.js +0 -92
  72. package/dist/local-data/replay-assets.d.ts +0 -3
  73. package/dist/local-data/replay-assets.js +0 -94
  74. package/dist/local-data/replays.d.ts +0 -18
  75. package/dist/local-data/replays.js +0 -87
  76. package/dist/local-data/screenshot-diffs.d.ts +0 -7
  77. package/dist/local-data/screenshot-diffs.js +0 -20
  78. package/dist/local-data/serve-assets-from-simulation.d.ts +0 -5
  79. package/dist/local-data/serve-assets-from-simulation.js +0 -52
  80. package/dist/local-data/sessions.d.ts +0 -10
  81. package/dist/local-data/sessions.js +0 -41
  82. package/dist/parallel-tests/__tests__/merge-test-results.spec.d.ts +0 -1
  83. package/dist/parallel-tests/__tests__/merge-test-results.spec.js +0 -104
  84. package/dist/parallel-tests/__tests__/mock-test-results.d.ts +0 -17
  85. package/dist/parallel-tests/__tests__/mock-test-results.js +0 -106
  86. package/dist/parallel-tests/__tests__/parrallel-tests.handler.spec.d.ts +0 -1
  87. package/dist/parallel-tests/__tests__/parrallel-tests.handler.spec.js +0 -205
  88. package/dist/parallel-tests/execute-test-in-child-process.d.ts +0 -3
  89. package/dist/parallel-tests/execute-test-in-child-process.js +0 -44
  90. package/dist/parallel-tests/merge-test-results.d.ts +0 -12
  91. package/dist/parallel-tests/merge-test-results.js +0 -106
  92. package/dist/parallel-tests/messages.types.d.ts +0 -17
  93. package/dist/parallel-tests/messages.types.js +0 -2
  94. package/dist/parallel-tests/parallel-replay.handler.d.ts +0 -3
  95. package/dist/parallel-tests/parallel-replay.handler.js +0 -56
  96. package/dist/parallel-tests/parallel-replay.types.d.ts +0 -16
  97. package/dist/parallel-tests/parallel-replay.types.js +0 -2
  98. package/dist/parallel-tests/parallel-tests.handler.d.ts +0 -14
  99. package/dist/parallel-tests/parallel-tests.handler.js +0 -194
  100. package/dist/parallel-tests/run-all-tests.d.ts +0 -73
  101. package/dist/parallel-tests/run-all-tests.js +0 -237
  102. package/dist/parallel-tests/run-all-tests.types.d.ts +0 -6
  103. package/dist/parallel-tests/run-all-tests.types.js +0 -2
  104. package/dist/parallel-tests/screenshot-diff-results.utils.d.ts +0 -7
  105. package/dist/parallel-tests/screenshot-diff-results.utils.js +0 -20
  106. package/dist/parallel-tests/task.handler.d.ts +0 -1
  107. package/dist/parallel-tests/task.handler.js +0 -86
  108. package/dist/utils/api-token.utils.d.ts +0 -1
  109. package/dist/utils/api-token.utils.js +0 -31
  110. package/dist/utils/commit-sha.utils.d.ts +0 -1
  111. package/dist/utils/commit-sha.utils.js +0 -42
  112. package/dist/utils/config.utils.d.ts +0 -7
  113. package/dist/utils/config.utils.js +0 -33
  114. package/dist/utils/github-summary.utils.d.ts +0 -5
  115. package/dist/utils/github-summary.utils.js +0 -38
  116. package/dist/utils/run-all-tests.utils.d.ts +0 -16
  117. package/dist/utils/run-all-tests.utils.js +0 -32
  118. package/dist/utils/test-run-environment.utils.d.ts +0 -2
  119. package/dist/utils/test-run-environment.utils.js +0 -25
  120. package/dist/utils/version.utils.d.ts +0 -1
  121. package/dist/utils/version.utils.js +0 -17
@@ -1,182 +0,0 @@
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.screenshotDiffCommand = exports.logDifferences = exports.diffScreenshots = void 0;
7
- const path_1 = require("path");
8
- const common_1 = require("@alwaysmeticulous/common");
9
- const fast_json_stable_stringify_1 = __importDefault(require("fast-json-stable-stringify"));
10
- const loglevel_1 = __importDefault(require("loglevel"));
11
- const client_1 = require("../../api/client");
12
- const command_builder_1 = require("../../command-utils/command-builder");
13
- const common_options_1 = require("../../command-utils/common-options");
14
- const diff_utils_1 = require("../../image/diff.utils");
15
- const io_utils_1 = require("../../image/io.utils");
16
- const replays_1 = require("../../local-data/replays");
17
- const screenshot_diffs_1 = require("../../local-data/screenshot-diffs");
18
- const has_notable_differences_1 = require("./utils/has-notable-differences");
19
- const diffScreenshots = async ({ headReplayId, baseReplayId, baseScreenshotsDir, headScreenshotsDir, baseReplayScreenshots, headReplayScreenshots, diffOptions, }) => {
20
- const { diffThreshold, diffPixelThreshold } = diffOptions;
21
- const headReplayScreenshotsByIdentifier = new Map(headReplayScreenshots.map((screenshot) => [
22
- (0, fast_json_stable_stringify_1.default)(screenshot.identifier),
23
- screenshot,
24
- ]));
25
- const baseReplayScreenshotsByIdentifier = new Map(baseReplayScreenshots.map((screenshot) => [
26
- (0, fast_json_stable_stringify_1.default)(screenshot.identifier),
27
- screenshot,
28
- ]));
29
- const missingHeadImages = new Set(baseReplayScreenshots.filter((file) => !headReplayScreenshotsByIdentifier.has((0, fast_json_stable_stringify_1.default)(file.identifier))));
30
- const missingHeadImagesResults = Array.from(missingHeadImages).flatMap(({ identifier, fileName }) => {
31
- return [
32
- {
33
- identifier,
34
- outcome: "missing-head",
35
- baseScreenshotFile: `screenshots/${fileName}`,
36
- },
37
- ];
38
- });
39
- const diffAgainstBase = async (headScreenshot) => {
40
- const baseScreenshot = baseReplayScreenshotsByIdentifier.get((0, fast_json_stable_stringify_1.default)(headScreenshot.identifier));
41
- if (baseScreenshot == null) {
42
- return [
43
- {
44
- identifier: headScreenshot.identifier,
45
- outcome: "missing-base",
46
- headScreenshotFile: `screenshots/${headScreenshot.fileName}`,
47
- },
48
- ];
49
- }
50
- const baseScreenshotFile = (0, path_1.join)(baseScreenshotsDir, baseScreenshot.fileName);
51
- const headScreenshotFile = (0, path_1.join)(headScreenshotsDir, headScreenshot.fileName);
52
- const baseScreenshotContents = await (0, io_utils_1.readPng)(baseScreenshotFile);
53
- const headScreenshotContents = await (0, io_utils_1.readPng)(headScreenshotFile);
54
- if (baseScreenshotContents.width !== headScreenshotContents.width ||
55
- baseScreenshotContents.height !== headScreenshotContents.height) {
56
- return [
57
- {
58
- identifier: headScreenshot.identifier,
59
- outcome: "different-size",
60
- baseScreenshotFile: `screenshots/${baseScreenshot.fileName}`,
61
- headScreenshotFile: `screenshots/${headScreenshot.fileName}`,
62
- baseWidth: baseScreenshotContents.width,
63
- baseHeight: baseScreenshotContents.height,
64
- headWidth: headScreenshotContents.width,
65
- headHeight: headScreenshotContents.height,
66
- },
67
- ];
68
- }
69
- const comparisonResult = (0, diff_utils_1.compareImages)({
70
- base: baseScreenshotContents,
71
- head: headScreenshotContents,
72
- pixelThreshold: diffPixelThreshold,
73
- });
74
- await (0, screenshot_diffs_1.writeScreenshotDiff)({
75
- baseReplayId,
76
- headReplayId,
77
- screenshotFileName: headScreenshot.fileName,
78
- diff: comparisonResult.diff,
79
- });
80
- return [
81
- {
82
- identifier: headScreenshot.identifier,
83
- outcome: comparisonResult.mismatchFraction > diffThreshold
84
- ? "diff"
85
- : "no-diff",
86
- baseScreenshotFile: `screenshots/${baseScreenshot.fileName}`,
87
- headScreenshotFile: `screenshots/${headScreenshot.fileName}`,
88
- width: baseScreenshotContents.width,
89
- height: baseScreenshotContents.height,
90
- mismatchPixels: comparisonResult.mismatchPixels,
91
- mismatchFraction: comparisonResult.mismatchFraction,
92
- },
93
- ];
94
- };
95
- const headDiffResults = (await Promise.all(headReplayScreenshots.map(diffAgainstBase))).flat();
96
- return [...missingHeadImagesResults, ...headDiffResults];
97
- };
98
- exports.diffScreenshots = diffScreenshots;
99
- const logDifferences = ({ results, diffOptions, logger, }) => {
100
- const missingHeadImagesResults = results.flatMap((result) => result.outcome === "missing-head" ? [result] : []);
101
- if (missingHeadImagesResults.length) {
102
- const message = `Head replay is missing screenshots: ${missingHeadImagesResults
103
- .map(({ baseScreenshotFile }) => (0, path_1.basename)(baseScreenshotFile))
104
- .sort()} => FAIL!`;
105
- logger.info(message);
106
- }
107
- const missingBaseImagesResults = results.flatMap((result) => result.outcome === "missing-base" ? [result] : []);
108
- if (missingHeadImagesResults.length) {
109
- const message = `Notice: Base replay is missing screenshots: ${missingBaseImagesResults
110
- .map(({ headScreenshotFile }) => (0, path_1.basename)(headScreenshotFile))
111
- .sort()}`;
112
- logger.info(message);
113
- }
114
- results.forEach((result) => {
115
- const { outcome } = result;
116
- if (outcome === "different-size") {
117
- const message = `Screenshots ${(0, path_1.basename)(result.headScreenshotFile)} have different sizes => FAIL!`;
118
- logger.info(message);
119
- }
120
- if (outcome === "diff" || outcome === "no-diff") {
121
- const mismatch = (result.mismatchFraction * 100).toFixed(3);
122
- const threshold = (diffOptions.diffThreshold * 100).toFixed(3);
123
- const message = `${mismatch}% pixel mismatch for screenshot ${(0, path_1.basename)(result.headScreenshotFile)} (threshold is ${threshold}%) => ${outcome === "no-diff" ? "PASS" : "FAIL!"}`;
124
- logger.info(message);
125
- }
126
- });
127
- };
128
- exports.logDifferences = logDifferences;
129
- const handler = async ({ apiToken, baseSimulationId: baseReplayId, headSimulationId: headReplayId, threshold, pixelThreshold, }) => {
130
- const logger = loglevel_1.default.getLogger(common_1.METICULOUS_LOGGER_NAME);
131
- const client = (0, client_1.createClient)({ apiToken });
132
- await (0, replays_1.getOrFetchReplay)(client, baseReplayId);
133
- await (0, replays_1.getOrFetchReplayArchive)(client, baseReplayId);
134
- await (0, replays_1.getOrFetchReplay)(client, headReplayId);
135
- await (0, replays_1.getOrFetchReplayArchive)(client, headReplayId);
136
- const baseScreenshotsDir = (0, replays_1.getScreenshotsDir)((0, replays_1.getReplayDir)(baseReplayId));
137
- const headScreenshotsDir = (0, replays_1.getScreenshotsDir)((0, replays_1.getReplayDir)(headReplayId));
138
- const diffOptions = {
139
- diffThreshold: threshold,
140
- diffPixelThreshold: pixelThreshold,
141
- };
142
- const baseReplayScreenshots = await (0, replays_1.getScreenshotFiles)(baseScreenshotsDir);
143
- const headReplayScreenshots = await (0, replays_1.getScreenshotFiles)(headScreenshotsDir);
144
- const results = await (0, exports.diffScreenshots)({
145
- baseReplayId,
146
- headReplayId,
147
- baseScreenshotsDir,
148
- headScreenshotsDir,
149
- baseReplayScreenshots,
150
- headReplayScreenshots,
151
- diffOptions,
152
- });
153
- logger.debug(results);
154
- (0, exports.logDifferences)({
155
- results,
156
- diffOptions,
157
- logger,
158
- });
159
- if ((0, has_notable_differences_1.hasNotableDifferences)(results)) {
160
- process.exit(1);
161
- }
162
- };
163
- exports.screenshotDiffCommand = (0, command_builder_1.buildCommand)("screenshot-diff")
164
- .details({ describe: "Diff two replay screenshots" })
165
- .options({
166
- apiToken: {
167
- string: true,
168
- },
169
- baseSimulationId: {
170
- string: true,
171
- demandOption: true,
172
- alias: "baseReplayId",
173
- },
174
- headSimulationId: {
175
- string: true,
176
- demandOption: true,
177
- alias: "headReplayId",
178
- },
179
- threshold: common_options_1.SCREENSHOT_DIFF_OPTIONS.diffThreshold,
180
- pixelThreshold: common_options_1.SCREENSHOT_DIFF_OPTIONS.diffPixelThreshold,
181
- })
182
- .handler(handler);
@@ -1,25 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const get_screenshot_identifier_1 = require("../get-screenshot-identifier");
4
- describe("get-screenshot-identifier", () => {
5
- it("can parse identifiers without version numbers", () => {
6
- expect((0, get_screenshot_identifier_1.getScreenshotIdentifier)("final-state.png")).toEqual({
7
- type: "end-state",
8
- });
9
- expect((0, get_screenshot_identifier_1.getScreenshotIdentifier)("screenshot-after-event-7.png")).toEqual({
10
- type: "after-event",
11
- eventNumber: 7,
12
- });
13
- });
14
- it("can parse identifiers with version numbers", () => {
15
- expect((0, get_screenshot_identifier_1.getScreenshotIdentifier)("final-state-v2.png")).toEqual({
16
- type: "end-state",
17
- logicVersion: 2,
18
- });
19
- expect((0, get_screenshot_identifier_1.getScreenshotIdentifier)("screenshot-after-event-7-v2.png")).toEqual({
20
- type: "after-event",
21
- eventNumber: 7,
22
- logicVersion: 2,
23
- });
24
- });
25
- });
@@ -1,2 +0,0 @@
1
- import { ScreenshotIdentifier } from "@alwaysmeticulous/api";
2
- export declare const getScreenshotFilename: (identifier: ScreenshotIdentifier) => string;
@@ -1,22 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getScreenshotFilename = void 0;
4
- // Note: ideally this should match the filenames produced by the screenshotting code
5
- // in replay-node, and in https://github.com/alwaysmeticulous/meticulous-sdk/blob/395af4394dc51d9b51ba1136fc26b23fcbba5604/packages/replayer/src/screenshot.utils.ts#L42
6
- const getScreenshotFilename = (identifier) => {
7
- if (identifier.type === "end-state") {
8
- return identifier.logicVersion == null
9
- ? "final-state.png"
10
- : `final-state-v${identifier.logicVersion}.png`;
11
- }
12
- else if (identifier.type === "after-event") {
13
- const eventIndexStr = identifier.eventNumber.toString().padStart(5, "0");
14
- return identifier.logicVersion == null
15
- ? `screenshot-after-event-${eventIndexStr}.png`
16
- : `screenshot-after-event-${eventIndexStr}-v${identifier.logicVersion}.png`;
17
- }
18
- else {
19
- throw new Error("Unexpected screenshot identifier: " + JSON.stringify(identifier));
20
- }
21
- };
22
- exports.getScreenshotFilename = getScreenshotFilename;
@@ -1,2 +0,0 @@
1
- import { ScreenshotIdentifier } from "@alwaysmeticulous/api";
2
- export declare const getScreenshotIdentifier: (filename: string) => ScreenshotIdentifier | undefined;
@@ -1,39 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getScreenshotIdentifier = void 0;
4
- const path_1 = require("path");
5
- const getScreenshotIdentifier = (filename) => {
6
- var _a;
7
- const name = (0, path_1.basename)(filename);
8
- if (name === "final-state.png") {
9
- return {
10
- type: "end-state",
11
- };
12
- }
13
- if (name.startsWith("final-state-v")) {
14
- const match = name.match(/^final-state-v(\d+)[.]png$/);
15
- const logicVersionNumber = match ? parseInt(match[1], 10) : undefined;
16
- if (match && logicVersionNumber != null && !isNaN(logicVersionNumber)) {
17
- return {
18
- type: "end-state",
19
- logicVersion: logicVersionNumber,
20
- };
21
- }
22
- }
23
- if (name.startsWith("screenshot-after-event")) {
24
- const match = (_a = name.match(/^(?:.*)-(\d+)-v(\d+)?[.]png$/)) !== null && _a !== void 0 ? _a : name.match(/^(?:.*)-(\d+)[.]png$/);
25
- const eventNumber = match ? parseInt(match[1], 10) : undefined;
26
- const logicVersionNumber = match ? parseInt(match[2], 10) : undefined;
27
- if (match && eventNumber != null && !isNaN(eventNumber)) {
28
- return {
29
- type: "after-event",
30
- eventNumber,
31
- ...(logicVersionNumber != null && !isNaN(logicVersionNumber)
32
- ? { logicVersion: logicVersionNumber }
33
- : {}),
34
- };
35
- }
36
- }
37
- return undefined;
38
- };
39
- exports.getScreenshotIdentifier = getScreenshotIdentifier;
@@ -1,2 +0,0 @@
1
- import { ScreenshotDiffResult } from "@alwaysmeticulous/api";
2
- export declare const hasNotableDifferences: (screenshotDiffResults: ScreenshotDiffResult[]) => boolean;
@@ -1,10 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.hasNotableDifferences = void 0;
4
- const hasNotableDifferences = (screenshotDiffResults) => {
5
- // Note: we ignore flakes & missing-bases here
6
- return screenshotDiffResults.some((diff) => diff.outcome === "diff" ||
7
- diff.outcome === "missing-head" ||
8
- diff.outcome === "different-size");
9
- };
10
- exports.hasNotableDifferences = hasNotableDifferences;
@@ -1,10 +0,0 @@
1
- /// <reference types="yargs" />
2
- export declare const serveCommand: import("yargs").CommandModule<unknown, import("yargs").InferredOptionTypes<{
3
- apiToken: {
4
- string: true;
5
- };
6
- replayId: {
7
- string: true;
8
- demandOption: true;
9
- };
10
- }>>;
@@ -1,31 +0,0 @@
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.serveCommand = void 0;
7
- const common_1 = require("@alwaysmeticulous/common");
8
- const loglevel_1 = __importDefault(require("loglevel"));
9
- const client_1 = require("../../api/client");
10
- const command_builder_1 = require("../../command-utils/command-builder");
11
- const serve_assets_from_simulation_1 = require("../../local-data/serve-assets-from-simulation");
12
- const handler = async ({ apiToken, replayId, }) => {
13
- const logger = loglevel_1.default.getLogger(common_1.METICULOUS_LOGGER_NAME);
14
- const client = (0, client_1.createClient)({ apiToken });
15
- const { url } = await (0, serve_assets_from_simulation_1.serveAssetsFromSimulation)(client, replayId);
16
- logger.info(`Serving assets at url ${url}`);
17
- };
18
- exports.serveCommand = (0, command_builder_1.buildCommand)("serve")
19
- .details({
20
- describe: "Spin up a localhost server to serve the assets that were snapshotted when running a particular replay",
21
- })
22
- .options({
23
- apiToken: {
24
- string: true,
25
- },
26
- replayId: {
27
- string: true,
28
- demandOption: true,
29
- },
30
- })
31
- .handler(handler);
@@ -1,21 +0,0 @@
1
- /// <reference types="yargs" />
2
- export declare const updateTestsCommand: import("yargs").CommandModule<unknown, import("yargs").InferredOptionTypes<{
3
- apiToken: {
4
- string: true;
5
- };
6
- testRunId: {
7
- string: true;
8
- demandOption: true;
9
- description: string;
10
- };
11
- accept: {
12
- string: true;
13
- array: true;
14
- description: string;
15
- };
16
- acceptAll: {
17
- boolean: true;
18
- description: string;
19
- conflicts: string;
20
- };
21
- }>>;
@@ -1,96 +0,0 @@
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.updateTestsCommand = void 0;
7
- const common_1 = require("@alwaysmeticulous/common");
8
- const loglevel_1 = __importDefault(require("loglevel"));
9
- const client_1 = require("../../api/client");
10
- const test_run_api_1 = require("../../api/test-run.api");
11
- const command_builder_1 = require("../../command-utils/command-builder");
12
- const config_1 = require("../../config/config");
13
- const handler = async ({ apiToken, testRunId, accept: accept_, acceptAll: acceptAll_, }) => {
14
- var _a;
15
- const logger = loglevel_1.default.getLogger(common_1.METICULOUS_LOGGER_NAME);
16
- const client = (0, client_1.createClient)({ apiToken });
17
- const config = await (0, config_1.readConfig)();
18
- const testCases = config.testCases || [];
19
- if (!testCases.length) {
20
- logger.error("Error! No test case defined");
21
- process.exit(1);
22
- }
23
- const testRun = await (0, test_run_api_1.getTestRun)({ client, testRunId });
24
- if (!testRun) {
25
- logger.error("Error: Could not retrieve test run. Is the API token correct?");
26
- process.exit(1);
27
- }
28
- if (testRun.status === "Success") {
29
- logger.info("Test run successful, no tests to updates");
30
- return;
31
- }
32
- if (testRun.status === "Running") {
33
- logger.error("Error: Tests are still running");
34
- process.exit(1);
35
- }
36
- const testRunResults = ((_a = testRun.resultData) === null || _a === void 0 ? void 0 : _a.results) || [];
37
- const accept = accept_ || [];
38
- const acceptAll = acceptAll_ || false;
39
- if (!acceptAll && !accept.length) {
40
- throw new Error("One of --accept or --acceptAll needs to be specified.");
41
- }
42
- const testRunResultsBySessionId = new Map();
43
- testRunResults.forEach((result) => {
44
- testRunResultsBySessionId.set(result.sessionId, result);
45
- });
46
- const newTestCases = testCases.map((testCase) => {
47
- const { sessionId } = testCase;
48
- const matched = testRunResultsBySessionId.get(sessionId);
49
- if (!matched) {
50
- logger.warn(`WARNING: ${sessionId} not found in test run`);
51
- return testCase;
52
- }
53
- if (matched.result === "pass" ||
54
- (!acceptAll &&
55
- !accept.find((replayId) => replayId === matched.headReplayId))) {
56
- return testCase;
57
- }
58
- const headReplayId = matched.headReplayId || "";
59
- if (!headReplayId) {
60
- logger.warn(`WARNING: ${sessionId} has no new replay id`);
61
- return testCase;
62
- }
63
- const newTestCase = { ...testCase, baseReplayId: headReplayId };
64
- return newTestCase;
65
- });
66
- const newConfig = {
67
- ...config,
68
- testCases: newTestCases,
69
- };
70
- await (0, config_1.saveConfig)(newConfig);
71
- };
72
- exports.updateTestsCommand = (0, command_builder_1.buildCommand)("update-tests")
73
- .details({
74
- describe: "Updates test cases",
75
- })
76
- .options({
77
- apiToken: {
78
- string: true,
79
- },
80
- testRunId: {
81
- string: true,
82
- demandOption: true,
83
- description: "Test run id to fix",
84
- },
85
- accept: {
86
- string: true,
87
- array: true,
88
- description: "Replay ids to accept as valid",
89
- },
90
- acceptAll: {
91
- boolean: true,
92
- description: "Accept all failing tests as valid",
93
- conflicts: "accept",
94
- },
95
- })
96
- .handler(handler);
@@ -1,3 +0,0 @@
1
- import { MeticulousCliConfig } from "./config.types";
2
- export declare const readConfig: (configFilePath?: string) => Promise<MeticulousCliConfig>;
3
- export declare const saveConfig: (config: MeticulousCliConfig) => Promise<void>;
@@ -1,69 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.saveConfig = exports.readConfig = void 0;
4
- const promises_1 = require("fs/promises");
5
- const path_1 = require("path");
6
- const process_1 = require("process");
7
- const cosmiconfig_1 = require("cosmiconfig");
8
- const METICULOUS_CONFIG_FILE = "meticulous.json";
9
- const findConfig = async () => {
10
- const explorer = (0, cosmiconfig_1.cosmiconfig)("meticulous", {
11
- searchPlaces: [METICULOUS_CONFIG_FILE],
12
- });
13
- const loaded = await explorer.search((0, process_1.cwd)());
14
- return (loaded === null || loaded === void 0 ? void 0 : loaded.filepath) || "";
15
- };
16
- let configFilePath = "";
17
- const getConfigFilePath = async () => {
18
- if (configFilePath) {
19
- return configFilePath;
20
- }
21
- configFilePath = (await findConfig()) || (0, path_1.join)((0, process_1.cwd)(), METICULOUS_CONFIG_FILE);
22
- return configFilePath;
23
- };
24
- const validateReplayOptions = (prevOptions) => {
25
- const { appUrl, diffThreshold, diffPixelThreshold, moveBeforeClick, simulationIdForAssets, } = prevOptions;
26
- return {
27
- ...(appUrl != null ? { appUrl } : {}),
28
- ...(diffThreshold != null ? { diffThreshold } : {}),
29
- ...(diffPixelThreshold != null ? { diffPixelThreshold } : {}),
30
- ...(moveBeforeClick != null ? { moveBeforeClick } : {}),
31
- ...(simulationIdForAssets != null ? { simulationIdForAssets } : {}),
32
- };
33
- };
34
- const validateConfig = (prevConfig) => {
35
- const { testCases, ...rest } = prevConfig;
36
- const nextTestCases = (testCases || [])
37
- .map(({ title, sessionId, options }) => ({
38
- title: typeof title === "string" ? title : "",
39
- sessionId: typeof sessionId === "string" ? sessionId : "",
40
- ...(options ? { options: validateReplayOptions(options) } : {}),
41
- }))
42
- .map(({ title, ...rest }) => ({
43
- title: title || `${rest.sessionId}`,
44
- ...rest,
45
- }))
46
- .filter(({ sessionId }) => sessionId);
47
- return { ...rest, testCases: nextTestCases };
48
- };
49
- const readConfig = async (configFilePath) => {
50
- const filePath = configFilePath !== null && configFilePath !== void 0 ? configFilePath : (await getConfigFilePath());
51
- const configStr = await (0, promises_1.readFile)(filePath, "utf-8").catch((error) => {
52
- // Use an empty config object if there is no config file
53
- if (configFilePath == null &&
54
- error instanceof Error &&
55
- error.code === "ENOENT") {
56
- return "{}";
57
- }
58
- throw error;
59
- });
60
- const config = JSON.parse(configStr);
61
- return validateConfig(config);
62
- };
63
- exports.readConfig = readConfig;
64
- const saveConfig = async (config) => {
65
- const filePath = await getConfigFilePath();
66
- const configStr = JSON.stringify(config, null, 2);
67
- await (0, promises_1.writeFile)(filePath, configStr);
68
- };
69
- exports.saveConfig = saveConfig;
@@ -1,16 +0,0 @@
1
- import { ScreenshotDiffResult, TestCase } from "@alwaysmeticulous/api";
2
- export interface MeticulousCliConfig {
3
- testCases?: TestCase[];
4
- }
5
- export interface TestCaseResult extends TestCase {
6
- headReplayId: string;
7
- /**
8
- * A test case is marked as a flake if there were screenshot comparison failures,
9
- * but for every one of those failures regenerating the screenshot on head sometimes gave
10
- * a different screenshot to the original screenshot taken on head.
11
- */
12
- result: "pass" | "fail" | "flake";
13
- }
14
- export interface DetailedTestCaseResult extends TestCaseResult {
15
- screenshotDiffResultsByBaseReplayId: Record<string, ScreenshotDiffResult[]>;
16
- }
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1 +0,0 @@
1
- export declare const getSnippetsBaseUrl: () => string;
@@ -1,18 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getSnippetsBaseUrl = void 0;
4
- const common_1 = require("@alwaysmeticulous/common");
5
- const config_1 = require("../errors/config");
6
- const getSnippetsBaseUrl = () => {
7
- const baseUrl = process.env["METICULOUS_SNIPPETS_BASE_URL"] || common_1.BASE_SNIPPETS_URL;
8
- try {
9
- return new URL(baseUrl).href;
10
- }
11
- catch (e) {
12
- if (e instanceof TypeError) {
13
- throw new config_1.ConfigurationError(`Invalid base snippets URL: ${baseUrl}`);
14
- }
15
- throw e;
16
- }
17
- };
18
- exports.getSnippetsBaseUrl = getSnippetsBaseUrl;
@@ -1,3 +0,0 @@
1
- export declare class ConfigurationError extends Error {
2
- constructor(message: string);
3
- }
@@ -1,10 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ConfigurationError = void 0;
4
- class ConfigurationError extends Error {
5
- constructor(message) {
6
- super(message);
7
- this.name = "ConfigurationError";
8
- }
9
- }
10
- exports.ConfigurationError = ConfigurationError;
@@ -1,19 +0,0 @@
1
- import { PNG } from "pngjs";
2
- export interface CompareImageOptions {
3
- base: PNG;
4
- head: PNG;
5
- /**
6
- * Maximum colour distance a given pixel is allowed to differ before counting two
7
- * pixels as different.
8
- *
9
- * Measure is based on "Measuring perceived color difference using YIQ NTSC transmission color space
10
- * in mobile applications" by Y. Kotsarenko and F. Ramos
11
- */
12
- pixelThreshold: number;
13
- }
14
- export interface CompareImageResult {
15
- mismatchPixels: number;
16
- mismatchFraction: number;
17
- diff: PNG;
18
- }
19
- export declare const compareImages: (options: CompareImageOptions) => CompareImageResult;
@@ -1,25 +0,0 @@
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.compareImages = void 0;
7
- const pixelmatch_1 = __importDefault(require("pixelmatch"));
8
- const pngjs_1 = require("pngjs");
9
- const compareImages = ({ base, head, pixelThreshold }) => {
10
- if (base.width !== head.width || base.height !== head.height) {
11
- throw new Error("Cannot handle different size yet");
12
- }
13
- const { width, height } = base;
14
- const diff = new pngjs_1.PNG({ width, height });
15
- const mismatchPixels = (0, pixelmatch_1.default)(base.data, head.data, diff.data, width, height, {
16
- threshold: pixelThreshold,
17
- });
18
- const mismatchFraction = mismatchPixels / (width * height);
19
- return {
20
- mismatchPixels,
21
- mismatchFraction,
22
- diff,
23
- };
24
- };
25
- exports.compareImages = compareImages;
@@ -1,3 +0,0 @@
1
- import { PNG } from "pngjs";
2
- export declare const readPng: (path: string) => Promise<PNG>;
3
- export declare const writePng: (png: PNG, path: string) => Promise<void>;