@alwaysmeticulous/cli 2.3.4 → 2.4.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 (30) hide show
  1. package/dist/command-utils/command-utils.d.ts +9 -0
  2. package/dist/command-utils/command-utils.js +18 -0
  3. package/dist/command-utils/common-options.d.ts +110 -0
  4. package/dist/command-utils/common-options.js +87 -0
  5. package/dist/command-utils/common-types.d.ts +20 -0
  6. package/dist/command-utils/common-types.js +2 -0
  7. package/dist/commands/create-test/create-test.command.d.ts +2 -2
  8. package/dist/commands/create-test/create-test.command.js +23 -40
  9. package/dist/commands/record/record.command.d.ts +9 -9
  10. package/dist/commands/record/record.command.js +2 -1
  11. package/dist/commands/replay/replay.command.d.ts +24 -26
  12. package/dist/commands/replay/replay.command.js +84 -76
  13. package/dist/commands/run-all-tests/run-all-tests.command.d.ts +11 -18
  14. package/dist/commands/run-all-tests/run-all-tests.command.js +38 -77
  15. package/dist/commands/screenshot-diff/screenshot-diff.command.d.ts +4 -4
  16. package/dist/commands/screenshot-diff/screenshot-diff.command.js +15 -19
  17. package/dist/config/config.js +2 -3
  18. package/dist/config/config.types.d.ts +7 -8
  19. package/dist/deflake-tests/deflake-tests.handler.d.ts +12 -3
  20. package/dist/deflake-tests/deflake-tests.handler.js +41 -6
  21. package/dist/image/diff.utils.d.ts +8 -1
  22. package/dist/image/diff.utils.js +1 -5
  23. package/dist/parallel-tests/messages.types.d.ts +3 -18
  24. package/dist/parallel-tests/parallel-tests.handler.d.ts +9 -14
  25. package/dist/parallel-tests/parallel-tests.handler.js +11 -15
  26. package/dist/parallel-tests/task.handler.js +2 -26
  27. package/dist/tsconfig.tsbuildinfo +1 -1
  28. package/dist/utils/config.utils.d.ts +6 -1
  29. package/dist/utils/config.utils.js +17 -8
  30. package/package.json +6 -6
@@ -0,0 +1,9 @@
1
+ declare type UndefinedToNullOrUndefined<T extends object> = {
2
+ [K in keyof T]: undefined extends T[K] ? T[K] | null : T[K];
3
+ };
4
+ /**
5
+ * yargs normally passes through undefineds, but passes through nulls for
6
+ * numbers which fail to parse. We convert everything to undefined to standardize.
7
+ */
8
+ export declare const handleNulls: <T extends object>(handler: (args: T) => Promise<void>) => (args: UndefinedToNullOrUndefined<T>) => Promise<void>;
9
+ export {};
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleNulls = void 0;
4
+ /**
5
+ * yargs normally passes through undefineds, but passes through nulls for
6
+ * numbers which fail to parse. We convert everything to undefined to standardize.
7
+ */
8
+ const handleNulls = (handler) => {
9
+ return (args) => {
10
+ const keys = Object.keys(args);
11
+ const newArgs = keys.reduce((partialArgs, key) => ({
12
+ ...partialArgs,
13
+ [key]: args[key] === null ? undefined : args[key],
14
+ }), {});
15
+ return handler(newArgs);
16
+ };
17
+ };
18
+ exports.handleNulls = handleNulls;
@@ -0,0 +1,110 @@
1
+ export declare const OPTIONS: {
2
+ apiToken: {
3
+ string: boolean;
4
+ };
5
+ commitSha: {
6
+ string: boolean;
7
+ };
8
+ headless: {
9
+ boolean: boolean;
10
+ description: string;
11
+ default: boolean;
12
+ };
13
+ devTools: {
14
+ boolean: boolean;
15
+ description: string;
16
+ default: boolean;
17
+ };
18
+ bypassCSP: {
19
+ boolean: boolean;
20
+ description: string;
21
+ default: boolean;
22
+ };
23
+ padTime: {
24
+ boolean: boolean;
25
+ description: string;
26
+ default: boolean;
27
+ };
28
+ shiftTime: {
29
+ boolean: boolean;
30
+ description: string;
31
+ default: boolean;
32
+ };
33
+ networkStubbing: {
34
+ boolean: boolean;
35
+ description: string;
36
+ default: boolean;
37
+ };
38
+ accelerate: {
39
+ boolean: boolean;
40
+ description: string;
41
+ default: boolean;
42
+ };
43
+ moveBeforeClick: {
44
+ boolean: boolean;
45
+ description: string;
46
+ default: boolean;
47
+ };
48
+ diffThreshold: {
49
+ number: boolean;
50
+ description: string;
51
+ default: number;
52
+ };
53
+ diffPixelThreshold: {
54
+ number: boolean;
55
+ description: string;
56
+ default: number;
57
+ };
58
+ };
59
+ export declare const SCREENSHOT_DIFF_OPTIONS: {
60
+ diffThreshold: {
61
+ number: boolean;
62
+ description: string;
63
+ default: number;
64
+ };
65
+ diffPixelThreshold: {
66
+ number: boolean;
67
+ description: string;
68
+ default: number;
69
+ };
70
+ };
71
+ /**
72
+ * Options that are passed onto replayEvents, that are shared by the replay, run-all-tests, and create-test commands
73
+ */
74
+ export declare const COMMON_REPLAY_OPTIONS: {
75
+ headless: {
76
+ boolean: boolean;
77
+ description: string;
78
+ default: boolean;
79
+ };
80
+ devTools: {
81
+ boolean: boolean;
82
+ description: string;
83
+ default: boolean;
84
+ };
85
+ bypassCSP: {
86
+ boolean: boolean;
87
+ description: string;
88
+ default: boolean;
89
+ };
90
+ padTime: {
91
+ boolean: boolean;
92
+ description: string;
93
+ default: boolean;
94
+ };
95
+ shiftTime: {
96
+ boolean: boolean;
97
+ description: string;
98
+ default: boolean;
99
+ };
100
+ networkStubbing: {
101
+ boolean: boolean;
102
+ description: string;
103
+ default: boolean;
104
+ };
105
+ accelerate: {
106
+ boolean: boolean;
107
+ description: string;
108
+ default: boolean;
109
+ };
110
+ };
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ // We keep all options that are used by multiple commands in one file.
3
+ // This ensures the defaults and descriptions stay in sync. Where we do want
4
+ // a different default or description we override it, like:
5
+ //
6
+ // headless: {
7
+ // ...COMMON_REPLAY_OPTIONS.headless,
8
+ // default: true,
9
+ // },
10
+ //
11
+ // This then makes the difference in behaviour explicit
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.COMMON_REPLAY_OPTIONS = exports.SCREENSHOT_DIFF_OPTIONS = exports.OPTIONS = void 0;
14
+ exports.OPTIONS = {
15
+ apiToken: {
16
+ string: true,
17
+ },
18
+ commitSha: {
19
+ string: true,
20
+ },
21
+ headless: {
22
+ boolean: true,
23
+ description: "Start browser in headless mode",
24
+ default: false,
25
+ },
26
+ devTools: {
27
+ boolean: true,
28
+ description: "Open Chrome Dev Tools",
29
+ default: false,
30
+ },
31
+ bypassCSP: {
32
+ boolean: true,
33
+ description: "Enables bypass CSP in the browser (danger: this could mean you tests hit your production backend)",
34
+ default: false,
35
+ },
36
+ padTime: {
37
+ boolean: true,
38
+ description: "Pad replay time according to recording duration. Please note this option will be ignored if running with the '--accelerate' option.",
39
+ default: true,
40
+ },
41
+ shiftTime: {
42
+ boolean: true,
43
+ description: "Shift time during simulation to be set as the recording time",
44
+ default: true,
45
+ },
46
+ networkStubbing: {
47
+ boolean: true,
48
+ description: "Stub network requests during replay",
49
+ default: true,
50
+ },
51
+ accelerate: {
52
+ boolean: true,
53
+ description: "Fast forward through any pauses to replay as fast as possible. Warning: this option is experimental and may be deprecated",
54
+ default: false,
55
+ },
56
+ moveBeforeClick: {
57
+ boolean: true,
58
+ description: "Simulate mouse movement before clicking",
59
+ default: false,
60
+ },
61
+ diffThreshold: {
62
+ number: true,
63
+ description: "Acceptable maximum proportion of changed pixels, between 0 and 1. If this proportion is exceeded then the test will fail.",
64
+ default: 0.01,
65
+ },
66
+ diffPixelThreshold: {
67
+ number: true,
68
+ description: "A number between 0 and 1. Color/brightness differences in individual pixels will be ignored if the difference is less than this threshold. A value of 1.0 would accept any difference in color, while a value of 0.0 would accept no difference in color.",
69
+ default: 0.01,
70
+ },
71
+ };
72
+ exports.SCREENSHOT_DIFF_OPTIONS = {
73
+ diffThreshold: exports.OPTIONS.diffThreshold,
74
+ diffPixelThreshold: exports.OPTIONS.diffPixelThreshold,
75
+ };
76
+ /**
77
+ * Options that are passed onto replayEvents, that are shared by the replay, run-all-tests, and create-test commands
78
+ */
79
+ exports.COMMON_REPLAY_OPTIONS = {
80
+ headless: exports.OPTIONS.headless,
81
+ devTools: exports.OPTIONS.devTools,
82
+ bypassCSP: exports.OPTIONS.bypassCSP,
83
+ padTime: exports.OPTIONS.padTime,
84
+ shiftTime: exports.OPTIONS.shiftTime,
85
+ networkStubbing: exports.OPTIONS.networkStubbing,
86
+ accelerate: exports.OPTIONS.accelerate,
87
+ };
@@ -0,0 +1,20 @@
1
+ import { ScreenshottingEnabledOptions } from "@alwaysmeticulous/common";
2
+ /**
3
+ * Options for taking a screenshot and comparing it against a previous screenshot
4
+ */
5
+ export declare type ScreenshotAssertionsOptions = {
6
+ enabled: false;
7
+ } | ScreenshotAssertionsEnabledOptions;
8
+ export interface ScreenshotAssertionsEnabledOptions extends ScreenshottingEnabledOptions {
9
+ diffOptions: ScreenshotDiffOptions;
10
+ }
11
+ export interface ScreenshotDiffOptions {
12
+ /**
13
+ * Acceptable maximum proportion of changed pixels, between 0 and 1.
14
+ */
15
+ diffThreshold: number;
16
+ /**
17
+ * A number between 0 and 1. Color/brightness differences in individual pixels will be ignored if the difference is less than this threshold. A value of 1.0 would accept any difference in color, while a value of 0.0 would accept no difference in color.
18
+ */
19
+ diffPixelThreshold: number;
20
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,7 +1,7 @@
1
1
  import { CommandModule } from "yargs";
2
2
  import { RecordCommandHandlerOptions } from "../record/record.command";
3
- import { ReplayCommandHandlerOptions } from "../replay/replay.command";
4
- interface Options extends RecordCommandHandlerOptions, ReplayCommandHandlerOptions {
3
+ import { RawReplayCommandHandlerOptions } from "../replay/replay.command";
4
+ interface Options extends Omit<RecordCommandHandlerOptions, "devTools" | "bypassCSP">, RawReplayCommandHandlerOptions {
5
5
  }
6
6
  export declare const createTest: CommandModule<unknown, Options>;
7
7
  export {};
@@ -5,13 +5,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.createTest = void 0;
7
7
  const common_1 = require("@alwaysmeticulous/common");
8
- const loglevel_1 = __importDefault(require("loglevel"));
9
8
  const chalk_1 = __importDefault(require("chalk"));
10
9
  const inquirer_1 = __importDefault(require("inquirer"));
10
+ const loglevel_1 = __importDefault(require("loglevel"));
11
+ const common_options_1 = require("../../command-utils/common-options");
12
+ const config_utils_1 = require("../../utils/config.utils");
11
13
  const sentry_utils_1 = require("../../utils/sentry.utils");
12
14
  const record_command_1 = require("../record/record.command");
13
15
  const replay_command_1 = require("../replay/replay.command");
14
- const config_utils_1 = require("../../utils/config.utils");
15
16
  const handleTestCreation = async (replay, sessionId) => {
16
17
  const logger = loglevel_1.default.getLogger(common_1.METICULOUS_LOGGER_NAME);
17
18
  const validationResponse = await inquirer_1.default.prompt([
@@ -102,8 +103,19 @@ headless, screenshotSelector, padTime, shiftTime, networkStubbing, moveBeforeCli
102
103
  moveBeforeClick,
103
104
  cookiesFile,
104
105
  accelerate,
106
+ save: false,
107
+ // We replay against the original recorded URL
108
+ appUrl: undefined,
109
+ simulationIdForAssets: undefined,
110
+ // We don't try comparing to the original screenshot, so just set these to their defaults
111
+ baseSimulationId: undefined,
112
+ diffThreshold: common_options_1.OPTIONS.diffThreshold.default,
113
+ diffPixelThreshold: common_options_1.OPTIONS.diffPixelThreshold.default,
114
+ // We don't expose these options
115
+ maxDurationMs: undefined,
116
+ maxEventCount: undefined,
105
117
  };
106
- const replay = await (0, replay_command_1.replayCommandHandler)(replayOptions);
118
+ const replay = await (0, replay_command_1.rawReplayCommandHandler)(replayOptions);
107
119
  await handleTestCreation(replay, lastSessionId);
108
120
  };
109
121
  exports.createTest = {
@@ -111,21 +123,8 @@ exports.createTest = {
111
123
  describe: "Create a new test",
112
124
  builder: {
113
125
  // Common options
114
- apiToken: {
115
- string: true,
116
- demandOption: true,
117
- },
118
- commitSha: {
119
- string: true,
120
- },
121
- devTools: {
122
- boolean: true,
123
- description: "Open Chrome Dev Tools",
124
- },
125
- bypassCSP: {
126
- boolean: true,
127
- description: "Enables bypass CSP in the browser",
128
- },
126
+ apiToken: common_options_1.OPTIONS.apiToken,
127
+ commitSha: common_options_1.OPTIONS.commitSha,
129
128
  // Record options
130
129
  width: {
131
130
  number: true,
@@ -147,30 +146,10 @@ exports.createTest = {
147
146
  description: "Enable verbose logging",
148
147
  },
149
148
  // Replay options
150
- headless: {
151
- boolean: true,
152
- description: "Start browser in headless mode",
153
- default: true,
154
- },
155
149
  screenshotSelector: {
156
150
  string: true,
157
151
  description: "Query selector to screenshot a specific DOM element instead of the whole page",
158
152
  },
159
- padTime: {
160
- boolean: true,
161
- description: "Pad simulation time according to recording duration",
162
- default: true,
163
- },
164
- shiftTime: {
165
- boolean: true,
166
- description: "Shift time during simulation to be set as the recording time",
167
- default: true,
168
- },
169
- networkStubbing: {
170
- boolean: true,
171
- description: "Stub network requests during simulation",
172
- default: true,
173
- },
174
153
  moveBeforeClick: {
175
154
  boolean: true,
176
155
  description: "Simulate mouse movement before clicking",
@@ -179,10 +158,14 @@ exports.createTest = {
179
158
  string: true,
180
159
  description: "Path to cookies to inject before simulation",
181
160
  },
161
+ ...common_options_1.COMMON_REPLAY_OPTIONS,
162
+ headless: {
163
+ ...common_options_1.COMMON_REPLAY_OPTIONS.headless,
164
+ default: true,
165
+ },
182
166
  accelerate: {
183
- boolean: true,
167
+ ...common_options_1.COMMON_REPLAY_OPTIONS.accelerate,
184
168
  description: "Fast forward through any pauses to replay as fast as possible when replaying for the first time to create the test. Warning: this option is experimental and may be deprecated",
185
- default: false,
186
169
  },
187
170
  },
188
171
  handler: (0, sentry_utils_1.wrapHandler)(handler),
@@ -1,14 +1,14 @@
1
1
  import { CommandModule } from "yargs";
2
2
  export interface RecordCommandHandlerOptions {
3
- apiToken?: string | null | undefined;
4
- commitSha?: string | null | undefined;
5
- devTools?: boolean | null | undefined;
6
- bypassCSP?: boolean | null | undefined;
7
- width?: number | null | undefined;
8
- height?: number | null | undefined;
9
- uploadIntervalMs?: number | null | undefined;
10
- incognito?: boolean | null | undefined;
11
- trace?: boolean | null | undefined;
3
+ apiToken: string | undefined;
4
+ commitSha: string | undefined;
5
+ devTools: boolean | undefined;
6
+ bypassCSP: boolean | undefined;
7
+ width: number | undefined;
8
+ height: number | undefined;
9
+ uploadIntervalMs: number | undefined;
10
+ incognito: boolean | undefined;
11
+ trace: boolean | undefined;
12
12
  onDetectedSession?: (sessionId: string) => void;
13
13
  }
14
14
  export declare const recordCommandHandler: (options: RecordCommandHandlerOptions) => Promise<void>;
@@ -10,6 +10,7 @@ const path_1 = require("path");
10
10
  const client_1 = require("../../api/client");
11
11
  const project_api_1 = require("../../api/project.api");
12
12
  const session_api_1 = require("../../api/session.api");
13
+ const command_utils_1 = require("../../command-utils/command-utils");
13
14
  const replay_assets_1 = require("../../local-data/replay-assets");
14
15
  const commit_sha_utils_1 = require("../../utils/commit-sha.utils");
15
16
  const sentry_utils_1 = require("../../utils/sentry.utils");
@@ -138,5 +139,5 @@ exports.record = {
138
139
  description: "Enable verbose logging",
139
140
  },
140
141
  },
141
- handler: (0, sentry_utils_1.wrapHandler)(exports.recordCommandHandler),
142
+ handler: (0, sentry_utils_1.wrapHandler)((0, command_utils_1.handleNulls)(exports.recordCommandHandler)),
142
143
  };
@@ -1,30 +1,28 @@
1
1
  import { Replay } from "@alwaysmeticulous/common";
2
+ import { ReplayExecutionOptions, ReplayTarget } from "@alwaysmeticulous/common/dist/types/replay.types";
2
3
  import { CommandModule } from "yargs";
3
- export interface ReplayCommandHandlerOptions {
4
- apiToken?: string | null | undefined;
5
- commitSha?: string | null | undefined;
6
- sessionId: string;
7
- appUrl?: string | null | undefined;
8
- simulationIdForAssets?: string | null | undefined;
9
- headless?: boolean | null | undefined;
10
- devTools?: boolean | null | undefined;
11
- bypassCSP?: boolean | null | undefined;
4
+ import { ScreenshotDiffOptions, ScreenshotAssertionsOptions } from "../../command-utils/common-types";
5
+ export interface ReplayOptions extends AdditionalReplayOptions {
6
+ replayTarget: ReplayTarget;
7
+ executionOptions: ReplayExecutionOptions;
8
+ screenshottingOptions: ScreenshotAssertionsOptions;
9
+ exitOnMismatch: boolean;
10
+ }
11
+ export declare const replayCommandHandler: ({ replayTarget, executionOptions, screenshottingOptions, apiToken, sessionId, commitSha: commitSha_, save, exitOnMismatch, baseSimulationId: baseReplayId_, cookiesFile, }: ReplayOptions) => Promise<Replay>;
12
+ export interface RawReplayCommandHandlerOptions extends ScreenshotDiffOptions, ReplayExecutionOptions, AdditionalReplayOptions {
12
13
  screenshot: boolean;
13
- screenshotSelector?: string | null | undefined;
14
- baseSimulationId?: string | null | undefined;
15
- diffThreshold?: number | null | undefined;
16
- diffPixelThreshold?: number | null | undefined;
17
- save?: boolean | null | undefined;
18
- exitOnMismatch?: boolean | null | undefined;
19
- padTime: boolean;
20
- shiftTime: boolean;
21
- networkStubbing: boolean;
22
- moveBeforeClick?: boolean | null | undefined;
23
- cookies?: Record<string, any>[];
24
- cookiesFile?: string | null | undefined;
25
- accelerate: boolean;
26
- maxDurationMs?: number | null | undefined;
27
- maxEventCount?: number | null | undefined;
14
+ appUrl: string | undefined;
15
+ simulationIdForAssets: string | undefined;
16
+ screenshotSelector: string | undefined;
17
+ }
18
+ interface AdditionalReplayOptions {
19
+ apiToken: string | undefined;
20
+ commitSha: string | undefined;
21
+ sessionId: string;
22
+ save: boolean | undefined;
23
+ baseSimulationId: string | undefined;
24
+ cookiesFile: string | undefined;
28
25
  }
29
- export declare const replayCommandHandler: (options: ReplayCommandHandlerOptions) => Promise<Replay>;
30
- export declare const replay: CommandModule<unknown, ReplayCommandHandlerOptions>;
26
+ export declare const rawReplayCommandHandler: ({ apiToken, commitSha, sessionId, appUrl, simulationIdForAssets, headless, devTools, bypassCSP, screenshot, screenshotSelector, baseSimulationId, diffThreshold, diffPixelThreshold, save, padTime, shiftTime, networkStubbing, moveBeforeClick, cookiesFile, accelerate, maxDurationMs, maxEventCount, }: RawReplayCommandHandlerOptions) => Promise<Replay>;
27
+ export declare const replay: CommandModule<unknown, RawReplayCommandHandlerOptions>;
28
+ export {};