@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.
- package/dist/api/test-run.api.d.ts +2 -1
- package/dist/commands/bootstrap/bootstrap.command.d.ts +1 -1
- package/dist/commands/bootstrap/bootstrap.command.js +2 -2
- package/dist/commands/create-test/create-test.command.d.ts +1 -1
- package/dist/commands/create-test/create-test.command.js +2 -2
- package/dist/commands/debug-replay/debug-replay.command.d.ts +1 -1
- package/dist/commands/debug-replay/debug-replay.command.js +2 -2
- package/dist/commands/download-replay/download-replay.command.d.ts +1 -1
- package/dist/commands/download-replay/download-replay.command.js +2 -2
- package/dist/commands/download-session/download-session.command.d.ts +1 -1
- package/dist/commands/download-session/download-session.command.js +2 -2
- package/dist/commands/record/record.command.d.ts +1 -1
- package/dist/commands/record/record.command.js +2 -2
- package/dist/commands/replay/replay.command.d.ts +9 -3
- package/dist/commands/replay/replay.command.js +62 -85
- package/dist/commands/replay/utils/compute-and-save-diff.d.ts +15 -0
- package/dist/commands/replay/utils/compute-and-save-diff.js +46 -0
- package/dist/commands/run-all-tests/run-all-tests.command.d.ts +4 -2
- package/dist/commands/run-all-tests/run-all-tests.command.js +22 -112
- package/dist/commands/screenshot-diff/screenshot-diff.command.d.ts +12 -12
- package/dist/commands/screenshot-diff/screenshot-diff.command.js +21 -18
- package/dist/commands/serve/serve.command.d.ts +1 -1
- package/dist/commands/serve/serve.command.js +2 -2
- package/dist/commands/show-project/show-project.command.d.ts +1 -1
- package/dist/commands/show-project/show-project.command.js +2 -2
- package/dist/commands/update-tests/update-tests.command.d.ts +1 -1
- package/dist/commands/update-tests/update-tests.command.js +2 -2
- package/dist/config/config.types.d.ts +4 -0
- package/dist/deflake-tests/deflake-tests.handler.d.ts +2 -2
- package/dist/deflake-tests/deflake-tests.handler.js +8 -20
- package/dist/index.d.ts +12 -11
- package/dist/index.js +14 -12
- package/dist/main.js +12 -12
- package/dist/parallel-tests/messages.types.d.ts +2 -2
- package/dist/parallel-tests/parallel-tests.handler.d.ts +5 -9
- package/dist/parallel-tests/parallel-tests.handler.js +14 -19
- package/dist/parallel-tests/run-all-tests.d.ts +55 -0
- package/dist/parallel-tests/run-all-tests.js +180 -0
- package/dist/parallel-tests/run-all-tests.types.d.ts +5 -0
- package/dist/parallel-tests/run-all-tests.types.js +2 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/github-summary.utils.d.ts +1 -2
- package/dist/utils/github-summary.utils.js +1 -3
- package/dist/utils/run-all-tests.utils.d.ts +4 -5
- package/dist/utils/run-all-tests.utils.js +4 -7
- 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:
|
|
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
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
28
|
-
const replayCommandHandler = async ({ replayTarget, executionOptions, screenshottingOptions, apiToken, sessionId, commitSha: commitSha_, save,
|
|
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
|
-
|
|
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
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
154
|
-
|
|
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
|
-
|
|
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
|
-
|
|
160
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
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: {
|