@elastic/synthetics 1.17.1 → 1.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/cli.js.map +1 -1
- package/dist/common_types.d.ts.map +1 -1
- package/dist/core/globals.d.ts +1 -0
- package/dist/core/globals.d.ts.map +1 -1
- package/dist/core/globals.js +12 -1
- package/dist/core/globals.js.map +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +13 -12
- package/dist/core/index.js.map +1 -1
- package/dist/core/logger.d.ts.map +1 -1
- package/dist/core/logger.js +2 -7
- package/dist/core/logger.js.map +1 -1
- package/dist/core/mfa.d.ts.map +1 -1
- package/dist/core/mfa.js +1 -1
- package/dist/core/runner.d.ts +40 -0
- package/dist/core/runner.d.ts.map +1 -1
- package/dist/core/runner.js +71 -6
- package/dist/core/runner.js.map +1 -1
- package/dist/dsl/journey.d.ts +35 -0
- package/dist/dsl/journey.d.ts.map +1 -1
- package/dist/dsl/journey.js +49 -0
- package/dist/dsl/journey.js.map +1 -1
- package/dist/dsl/monitor.d.ts +4 -0
- package/dist/dsl/monitor.d.ts.map +1 -1
- package/dist/dsl/monitor.js +6 -0
- package/dist/dsl/monitor.js.map +1 -1
- package/dist/dsl/step.d.ts +5 -0
- package/dist/dsl/step.d.ts.map +1 -1
- package/dist/dsl/step.js +7 -0
- package/dist/dsl/step.js.map +1 -1
- package/dist/formatter/javascript.d.ts.map +1 -1
- package/dist/formatter/javascript.js.map +1 -1
- package/dist/generator/utils.d.ts +1 -1
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js.map +1 -1
- package/dist/plugins/tracing.js.map +1 -1
- package/dist/push/bundler.d.ts +2 -5
- package/dist/push/bundler.d.ts.map +1 -1
- package/dist/push/bundler.js +15 -30
- package/dist/push/bundler.js.map +1 -1
- package/dist/push/index.d.ts.map +1 -1
- package/dist/push/index.js +21 -6
- package/dist/push/index.js.map +1 -1
- package/dist/push/monitor.d.ts +4 -1
- package/dist/push/monitor.d.ts.map +1 -1
- package/dist/push/monitor.js +13 -1
- package/dist/push/monitor.js.map +1 -1
- package/dist/push/run-local.d.ts +27 -0
- package/dist/push/run-local.d.ts.map +1 -0
- package/dist/push/run-local.js +132 -0
- package/dist/push/run-local.js.map +1 -0
- package/dist/push/utils.d.ts +2 -0
- package/dist/push/utils.d.ts.map +1 -1
- package/dist/push/utils.js +33 -1
- package/dist/push/utils.js.map +1 -1
- package/dist/reporters/base.d.ts.map +1 -1
- package/dist/reporters/base.js.map +1 -1
- package/dist/reporters/build_kite_cli.d.ts.map +1 -1
- package/dist/reporters/build_kite_cli.js.map +1 -1
- package/dist/reporters/json.d.ts +1 -1
- package/dist/reporters/json.d.ts.map +1 -1
- package/dist/reporters/json.js +6 -2
- package/dist/reporters/json.js.map +1 -1
- package/dist/reporters/junit.d.ts.map +1 -1
- package/dist/reporters/junit.js.map +1 -1
- package/package.json +8 -5
- package/src/cli.ts +8 -3
- package/src/common_types.ts +1 -1
- package/src/core/globals.ts +12 -0
- package/src/core/index.ts +3 -1
- package/src/core/logger.ts +2 -8
- package/src/core/mfa.ts +11 -11
- package/src/core/runner.ts +102 -33
- package/src/dsl/journey.ts +63 -1
- package/src/dsl/monitor.ts +7 -0
- package/src/dsl/step.ts +8 -0
- package/src/formatter/javascript.ts +3 -1
- package/src/helpers.ts +3 -3
- package/src/loader.ts +1 -1
- package/src/plugins/tracing.ts +1 -1
- package/src/push/bundler.ts +16 -36
- package/src/push/index.ts +28 -10
- package/src/push/monitor.ts +16 -4
- package/src/push/run-local.ts +155 -0
- package/src/push/utils.ts +51 -5
- package/src/reporters/base.ts +8 -4
- package/src/reporters/build_kite_cli.ts +7 -6
- package/src/reporters/json.ts +10 -14
- package/src/reporters/junit.ts +4 -10
package/src/push/index.ts
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
*/
|
|
25
25
|
import { readFile, writeFile } from 'fs/promises';
|
|
26
26
|
import { prompt } from 'enquirer';
|
|
27
|
-
import { bold,
|
|
27
|
+
import { bold, underline } from 'kleur/colors';
|
|
28
28
|
import {
|
|
29
29
|
getLocalMonitors,
|
|
30
30
|
buildMonitorSchema,
|
|
@@ -57,8 +57,11 @@ import {
|
|
|
57
57
|
isBulkAPISupported,
|
|
58
58
|
isLightweightMonitorSupported,
|
|
59
59
|
logDiff,
|
|
60
|
+
logGroups,
|
|
61
|
+
printBytes,
|
|
60
62
|
} from './utils';
|
|
61
|
-
import {
|
|
63
|
+
import { runLocal } from './run-local';
|
|
64
|
+
import { inDebugMode } from '../core/globals';
|
|
62
65
|
|
|
63
66
|
export async function push(monitors: Monitor[], options: PushOptions) {
|
|
64
67
|
if (parseInt(process.env.CHUNK_SIZE) > 250) {
|
|
@@ -84,7 +87,7 @@ export async function push(monitors: Monitor[], options: PushOptions) {
|
|
|
84
87
|
const { monitors: remote } = await bulkGetMonitors(options);
|
|
85
88
|
|
|
86
89
|
progress(`preparing ${monitors.length} monitors`);
|
|
87
|
-
const schemas = await buildMonitorSchema(monitors, true);
|
|
90
|
+
const { schemas, sizes } = await buildMonitorSchema(monitors, true);
|
|
88
91
|
const local = getLocalMonitors(schemas);
|
|
89
92
|
|
|
90
93
|
const { newIDs, changedIDs, removedIDs, unchangedIDs } = diffMonitorHashIDs(
|
|
@@ -92,6 +95,22 @@ export async function push(monitors: Monitor[], options: PushOptions) {
|
|
|
92
95
|
remote
|
|
93
96
|
);
|
|
94
97
|
logDiff(newIDs, changedIDs, removedIDs, unchangedIDs);
|
|
98
|
+
if (inDebugMode()) {
|
|
99
|
+
logGroups(sizes, newIDs, changedIDs, removedIDs, unchangedIDs);
|
|
100
|
+
// show bundle size for the whole project
|
|
101
|
+
let totalSize = 0;
|
|
102
|
+
for (const value of sizes.values()) {
|
|
103
|
+
totalSize += value;
|
|
104
|
+
}
|
|
105
|
+
progress('total size of the monitors payload is ' + printBytes(totalSize));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
if (options.dryRun) {
|
|
109
|
+
progress('Running browser monitors in dry run mode');
|
|
110
|
+
await runLocal(schemas);
|
|
111
|
+
progress('Dry run completed');
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
95
114
|
|
|
96
115
|
const updatedMonitors = new Set<string>([...changedIDs, ...newIDs]);
|
|
97
116
|
if (updatedMonitors.size > 0) {
|
|
@@ -106,7 +125,6 @@ export async function push(monitors: Monitor[], options: PushOptions) {
|
|
|
106
125
|
}
|
|
107
126
|
|
|
108
127
|
if (removedIDs.size > 0) {
|
|
109
|
-
log(`deleting monitor ids: ${Array.from(removedIDs.keys()).join(', ')}`);
|
|
110
128
|
if (updatedMonitors.size === 0 && unchangedIDs.size === 0) {
|
|
111
129
|
await confirmDelete(
|
|
112
130
|
`Pushing without any monitors will delete all monitors associated with the project.\n Do you want to continue?`,
|
|
@@ -126,8 +144,7 @@ export async function push(monitors: Monitor[], options: PushOptions) {
|
|
|
126
144
|
);
|
|
127
145
|
}
|
|
128
146
|
}
|
|
129
|
-
|
|
130
|
-
done(`Pushed: ${grey(getMonitorManagementURL(options.url))}`);
|
|
147
|
+
done(`Pushed: ${underline(getMonitorManagementURL(options.url))} `);
|
|
131
148
|
}
|
|
132
149
|
|
|
133
150
|
async function confirmDelete(message: string, skip: boolean) {
|
|
@@ -223,8 +240,9 @@ export function validateSettings(opts: PushOptions) {
|
|
|
223
240
|
- CLI '--schedule <mins>'
|
|
224
241
|
- Config file 'monitors.schedule' field`;
|
|
225
242
|
} else if (opts.schedule && !ALLOWED_SCHEDULES.includes(opts.schedule)) {
|
|
226
|
-
reason = `Set default schedule(${
|
|
227
|
-
|
|
243
|
+
reason = `Set default schedule(${
|
|
244
|
+
opts.schedule
|
|
245
|
+
}) to one of the allowed values - ${ALLOWED_SCHEDULES.join(',')}`;
|
|
228
246
|
} else if (
|
|
229
247
|
(opts.locations ?? []).length > 0 &&
|
|
230
248
|
(opts?.playwrightOptions?.clientCertificates ?? []).filter(cert => {
|
|
@@ -301,7 +319,7 @@ export async function pushLegacy(monitors: Monitor[], options: PushOptions) {
|
|
|
301
319
|
let schemas: MonitorSchema[] = [];
|
|
302
320
|
if (monitors.length > 0) {
|
|
303
321
|
progress(`preparing ${monitors.length} monitors`);
|
|
304
|
-
schemas = await buildMonitorSchema(monitors, false);
|
|
322
|
+
({ schemas } = await buildMonitorSchema(monitors, false));
|
|
305
323
|
const chunks = getChunks(schemas, 10);
|
|
306
324
|
for (const chunk of chunks) {
|
|
307
325
|
await liveProgress(
|
|
@@ -320,7 +338,7 @@ export async function pushLegacy(monitors: Monitor[], options: PushOptions) {
|
|
|
320
338
|
`deleting all stale monitors`
|
|
321
339
|
);
|
|
322
340
|
|
|
323
|
-
done(`Pushed: ${
|
|
341
|
+
done(`Pushed: ${underline(getMonitorManagementURL(options.url))}`);
|
|
324
342
|
}
|
|
325
343
|
|
|
326
344
|
// prints warning if any of the monitors has throttling settings enabled during push
|
package/src/push/monitor.ts
CHANGED
|
@@ -42,6 +42,8 @@ import { isParamOptionSupported, normalizeMonitorName } from './utils';
|
|
|
42
42
|
|
|
43
43
|
// Allowed extensions for lightweight monitor files
|
|
44
44
|
const ALLOWED_LW_EXTENSIONS = ['.yml', '.yaml'];
|
|
45
|
+
// 1500kB Max Gzipped limit for bundled monitor code to be pushed as Kibana project monitors.
|
|
46
|
+
const SIZE_LIMIT_KB = 1500;
|
|
45
47
|
|
|
46
48
|
export type MonitorSchema = Omit<MonitorConfig, 'locations'> & {
|
|
47
49
|
locations: string[];
|
|
@@ -131,6 +133,7 @@ export async function buildMonitorSchema(monitors: Monitor[], isV2: boolean) {
|
|
|
131
133
|
await mkdir(bundlePath, { recursive: true });
|
|
132
134
|
const bundler = new Bundler();
|
|
133
135
|
const schemas: MonitorSchema[] = [];
|
|
136
|
+
const sizes: Map<string, number> = new Map();
|
|
134
137
|
|
|
135
138
|
for (const monitor of monitors) {
|
|
136
139
|
const { source, config, filter, type } = monitor;
|
|
@@ -148,6 +151,17 @@ export async function buildMonitorSchema(monitors: Monitor[], isV2: boolean) {
|
|
|
148
151
|
monitor.setContent(content);
|
|
149
152
|
Object.assign(schema, { content, filter });
|
|
150
153
|
}
|
|
154
|
+
const size = monitor.size();
|
|
155
|
+
const sizeKB = Math.round(size / 1000);
|
|
156
|
+
if (sizeKB > SIZE_LIMIT_KB) {
|
|
157
|
+
let outer = bold(
|
|
158
|
+
`Aborted: Bundled code ${sizeKB}kB exceeds the recommended ${SIZE_LIMIT_KB}kB limit. Please check the dependencies imported.\n`
|
|
159
|
+
);
|
|
160
|
+
const inner = `* ${config.id} - ${source.file}:${source.line}:${source.column}\n`;
|
|
161
|
+
outer += indent(inner);
|
|
162
|
+
throw red(outer);
|
|
163
|
+
}
|
|
164
|
+
sizes.set(config.id, size);
|
|
151
165
|
/**
|
|
152
166
|
* Generate hash only after the bundled content is created
|
|
153
167
|
* to capture code changes in imported files
|
|
@@ -159,7 +173,7 @@ export async function buildMonitorSchema(monitors: Monitor[], isV2: boolean) {
|
|
|
159
173
|
}
|
|
160
174
|
|
|
161
175
|
await rm(bundlePath, { recursive: true });
|
|
162
|
-
return schemas;
|
|
176
|
+
return { schemas, sizes };
|
|
163
177
|
}
|
|
164
178
|
|
|
165
179
|
export async function createLightweightMonitors(
|
|
@@ -225,9 +239,7 @@ export async function createLightweightMonitors(
|
|
|
225
239
|
const monitor = mergedConfig[i];
|
|
226
240
|
// Skip browser monitors from the YML files
|
|
227
241
|
if (monitor['type'] === 'browser') {
|
|
228
|
-
warn(
|
|
229
|
-
`Browser monitors from ${file} are skipped.`
|
|
230
|
-
);
|
|
242
|
+
warn(`Browser monitors from ${file} are skipped.`);
|
|
231
243
|
continue;
|
|
232
244
|
}
|
|
233
245
|
const { line, col } = lineCounter.linePos(offsets[i]);
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MIT License
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2020-present, Elastic NV
|
|
5
|
+
*
|
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
* in the Software without restriction, including without limitation the rights
|
|
9
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
* furnished to do so, subject to the following conditions:
|
|
12
|
+
*
|
|
13
|
+
* The above copyright notice and this permission notice shall be included in
|
|
14
|
+
* all copies or substantial portions of the Software.
|
|
15
|
+
*
|
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
* THE SOFTWARE.
|
|
23
|
+
*
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { execFileSync, spawn } from 'child_process';
|
|
27
|
+
import { rm, writeFile } from 'fs/promises';
|
|
28
|
+
import { createReadStream } from 'fs';
|
|
29
|
+
import { tmpdir } from 'os';
|
|
30
|
+
import { Extract } from 'unzip-stream';
|
|
31
|
+
import { red } from 'kleur/colors';
|
|
32
|
+
import { join } from 'path';
|
|
33
|
+
import { pathToFileURL } from 'url';
|
|
34
|
+
import { MonitorSchema } from './monitor';
|
|
35
|
+
|
|
36
|
+
async function unzipFile(zipPath, destination) {
|
|
37
|
+
return new Promise<void>((resolve, reject) => {
|
|
38
|
+
createReadStream(zipPath)
|
|
39
|
+
.pipe(Extract({ path: destination }))
|
|
40
|
+
.on('close', resolve)
|
|
41
|
+
.on('error', err =>
|
|
42
|
+
reject(new Error(`failed to extract zip ${zipPath} : ${err.message}`))
|
|
43
|
+
);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function runNpmInstall(directory) {
|
|
48
|
+
return new Promise<void>((resolve, reject) => {
|
|
49
|
+
const flags = [
|
|
50
|
+
'--no-audit', // Prevent audit checks
|
|
51
|
+
'--no-update-notifier', // Prevent update checks
|
|
52
|
+
'--no-fund', // No need for package funding messages here
|
|
53
|
+
'--package-lock=false', // no need to write package lock here
|
|
54
|
+
'--progress=false', // no need to display progress
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
const npmInstall = spawn('npm', ['install', ...flags], {
|
|
58
|
+
cwd: directory,
|
|
59
|
+
stdio: 'ignore',
|
|
60
|
+
});
|
|
61
|
+
npmInstall.on('close', code => {
|
|
62
|
+
if (code === 0) {
|
|
63
|
+
resolve();
|
|
64
|
+
} else {
|
|
65
|
+
reject(new Error(`npm install failed with exit code ${code}`));
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
npmInstall.on('error', err =>
|
|
69
|
+
reject(new Error(`failed to setup: ${err.message}`))
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function runTest(directory, schema: MonitorSchema) {
|
|
75
|
+
return new Promise<void>((resolve, reject) => {
|
|
76
|
+
const runTest = spawn(
|
|
77
|
+
'npx',
|
|
78
|
+
[
|
|
79
|
+
'@elastic/synthetics',
|
|
80
|
+
'.',
|
|
81
|
+
'--playwright-options',
|
|
82
|
+
JSON.stringify(schema.playwrightOptions),
|
|
83
|
+
'--params',
|
|
84
|
+
JSON.stringify(schema.params),
|
|
85
|
+
],
|
|
86
|
+
{
|
|
87
|
+
cwd: directory,
|
|
88
|
+
stdio: 'inherit',
|
|
89
|
+
}
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
runTest.on('close', resolve);
|
|
93
|
+
runTest.on('error', err => {
|
|
94
|
+
reject(
|
|
95
|
+
new Error(`Failed to execute @elastic/synthetics : ${err.message}`)
|
|
96
|
+
);
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function writePkgJSON(dir: string, synthPath: string) {
|
|
102
|
+
const packageJsonContent = {
|
|
103
|
+
name: 'project-journey',
|
|
104
|
+
private: 'true',
|
|
105
|
+
dependencies: {
|
|
106
|
+
'@elastic/synthetics': pathToFileURL(synthPath),
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
await writeFile(
|
|
110
|
+
join(dir, 'package.json'),
|
|
111
|
+
JSON.stringify(packageJsonContent, null, 2),
|
|
112
|
+
'utf-8'
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function extract(
|
|
117
|
+
schema: MonitorSchema,
|
|
118
|
+
zipPath: string,
|
|
119
|
+
unzipPath: string
|
|
120
|
+
) {
|
|
121
|
+
if (schema.type !== 'browser') {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const content = schema.content;
|
|
125
|
+
await writeFile(zipPath, content, 'base64');
|
|
126
|
+
await unzipFile(zipPath, unzipPath);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export async function runLocal(schemas: MonitorSchema[]) {
|
|
130
|
+
// lookup installed bin path of a node module
|
|
131
|
+
const resolvedPath = execFileSync('which', ['elastic-synthetics'], {
|
|
132
|
+
encoding: 'utf8',
|
|
133
|
+
}).trim();
|
|
134
|
+
const synthPath = resolvedPath.replace(
|
|
135
|
+
join('bin', 'elastic-synthetics'),
|
|
136
|
+
join('lib', 'node_modules', '@elastic/synthetics')
|
|
137
|
+
);
|
|
138
|
+
const rand = Date.now();
|
|
139
|
+
const zipPath = join(tmpdir(), `synthetics-zip-${rand}.zip`);
|
|
140
|
+
const unzipPath = join(tmpdir(), `synthetics-unzip-${rand}`);
|
|
141
|
+
try {
|
|
142
|
+
for (const schema of schemas) {
|
|
143
|
+
await extract(schema, zipPath, unzipPath);
|
|
144
|
+
}
|
|
145
|
+
await writePkgJSON(unzipPath, synthPath);
|
|
146
|
+
await runNpmInstall(unzipPath);
|
|
147
|
+
// TODO: figure out a way to collect all params and Playwright options
|
|
148
|
+
await runTest(unzipPath, schemas[0]);
|
|
149
|
+
} catch (e) {
|
|
150
|
+
throw red(`Aborted: ${e.message}`);
|
|
151
|
+
} finally {
|
|
152
|
+
await rm(zipPath, { recursive: true, force: true });
|
|
153
|
+
await rm(unzipPath, { recursive: true, force: true });
|
|
154
|
+
}
|
|
155
|
+
}
|
package/src/push/utils.ts
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
import semver from 'semver';
|
|
27
27
|
import { progress, removeTrailingSlash } from '../helpers';
|
|
28
|
-
import { green, red, grey, yellow } from 'kleur/colors';
|
|
28
|
+
import { green, red, grey, yellow, Colorize, bold } from 'kleur/colors';
|
|
29
29
|
import { PushOptions } from '../common_types';
|
|
30
30
|
import { Monitor } from '../dsl/monitor';
|
|
31
31
|
|
|
@@ -37,13 +37,59 @@ export function logDiff<T extends Set<string>>(
|
|
|
37
37
|
) {
|
|
38
38
|
progress(
|
|
39
39
|
'Monitor Diff: ' +
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
green(`Added(${newIDs.size}) `) +
|
|
41
|
+
yellow(`Updated(${changedIDs.size}) `) +
|
|
42
|
+
red(`Removed(${removedIDs.size}) `) +
|
|
43
|
+
grey(`Unchanged(${unchangedIDs.size})`)
|
|
44
44
|
);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
export function logGroups<T extends Set<string>>(
|
|
48
|
+
sizes: Map<string, number>,
|
|
49
|
+
newIDs: T,
|
|
50
|
+
changedIDs: T,
|
|
51
|
+
removedIDs: T,
|
|
52
|
+
unchangedIDs: T
|
|
53
|
+
) {
|
|
54
|
+
console.groupCollapsed();
|
|
55
|
+
logGroup(sizes, 'Added', newIDs, green);
|
|
56
|
+
logGroup(sizes, 'Updated', changedIDs, yellow);
|
|
57
|
+
logGroup(sizes, 'Removed', removedIDs, red);
|
|
58
|
+
logGroup(sizes, 'Unchanged', unchangedIDs, grey);
|
|
59
|
+
console.groupEnd();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function logGroup(
|
|
63
|
+
sizes: Map<string, number>,
|
|
64
|
+
name: string,
|
|
65
|
+
ids: Set<string>,
|
|
66
|
+
color: Colorize
|
|
67
|
+
) {
|
|
68
|
+
if (ids.size === 0) return;
|
|
69
|
+
// under collapsed group, so giving 2 space for padding
|
|
70
|
+
printLine(process.stdout.columns - 2);
|
|
71
|
+
console.groupCollapsed(color(bold(name)));
|
|
72
|
+
[...ids].forEach(id => {
|
|
73
|
+
console.log(grey(`- ${id} (${printBytes(sizes.get(id))})`));
|
|
74
|
+
});
|
|
75
|
+
console.groupEnd();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function printLine(length: number = process.stdout.columns) {
|
|
79
|
+
console.log(grey('-').repeat(length));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const BYTE_UNITS = ['B', 'kB', 'MB', 'GB', 'TB', 'PB'];
|
|
83
|
+
export function printBytes(bytes: number) {
|
|
84
|
+
if (bytes <= 0) return '0 B';
|
|
85
|
+
const exponent = Math.min(
|
|
86
|
+
Math.floor(Math.log10(bytes) / 3),
|
|
87
|
+
BYTE_UNITS.length - 1
|
|
88
|
+
);
|
|
89
|
+
bytes /= 1000 ** exponent;
|
|
90
|
+
return `${bytes.toFixed(1)} ${BYTE_UNITS[exponent]}`;
|
|
91
|
+
}
|
|
92
|
+
|
|
47
93
|
export function getChunks<T>(arr: Array<T>, size: number): Array<T[]> {
|
|
48
94
|
const chunks = [];
|
|
49
95
|
for (let i = 0; i < arr.length; i += size) {
|
package/src/reporters/base.ts
CHANGED
|
@@ -29,7 +29,11 @@ import { renderError, serializeError } from './reporter-util';
|
|
|
29
29
|
import { symbols, indent, now } from '../helpers';
|
|
30
30
|
import { Reporter, ReporterOptions } from '.';
|
|
31
31
|
import { Journey, Step } from '../dsl';
|
|
32
|
-
import {
|
|
32
|
+
import {
|
|
33
|
+
JourneyEndResult,
|
|
34
|
+
JourneyStartResult,
|
|
35
|
+
StepResult,
|
|
36
|
+
} from '../common_types';
|
|
33
37
|
|
|
34
38
|
export function renderDuration(durationMs) {
|
|
35
39
|
return parseInt(durationMs);
|
|
@@ -62,11 +66,11 @@ export default class BaseReporter implements Reporter {
|
|
|
62
66
|
this.metrics.registered++;
|
|
63
67
|
}
|
|
64
68
|
|
|
65
|
-
onJourneyStart(journey: Journey, {
|
|
69
|
+
onJourneyStart(journey: Journey, {}: JourneyStartResult) {
|
|
66
70
|
this.write(`\nJourney: ${journey.name}`);
|
|
67
71
|
}
|
|
68
72
|
|
|
69
|
-
onStepEnd(_: Journey, step: Step, {
|
|
73
|
+
onStepEnd(_: Journey, step: Step, {}: StepResult) {
|
|
70
74
|
const { status, error } = step;
|
|
71
75
|
const message = `${symbols[status]} Step: '${step.name}' ${status} ${gray(
|
|
72
76
|
'(' + renderDuration(step.duration * 1000) + ' ms)'
|
|
@@ -80,7 +84,7 @@ export default class BaseReporter implements Reporter {
|
|
|
80
84
|
}
|
|
81
85
|
|
|
82
86
|
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
83
|
-
onJourneyEnd(journey: Journey, {
|
|
87
|
+
onJourneyEnd(journey: Journey, {}: JourneyEndResult) {
|
|
84
88
|
const { failed, succeeded, skipped } = this.metrics;
|
|
85
89
|
const total = failed + succeeded + skipped;
|
|
86
90
|
/**
|
|
@@ -43,7 +43,7 @@ export default class BuildKiteCLIReporter extends BaseReporter {
|
|
|
43
43
|
super(options);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
override onJourneyStart(journey: Journey, {
|
|
46
|
+
override onJourneyStart(journey: Journey, {}: JourneyStartResult) {
|
|
47
47
|
this.write(`\n--- Journey: ${journey.name}`);
|
|
48
48
|
}
|
|
49
49
|
|
|
@@ -57,7 +57,9 @@ export default class BuildKiteCLIReporter extends BaseReporter {
|
|
|
57
57
|
|
|
58
58
|
override async onJourneyEnd(journey: Journey, result: JourneyEndResult) {
|
|
59
59
|
super.onJourneyEnd(journey, result);
|
|
60
|
-
const message = `${symbols[journey.status]} Took (${renderDuration(
|
|
60
|
+
const message = `${symbols[journey.status]} Took (${renderDuration(
|
|
61
|
+
journey.duration
|
|
62
|
+
)} seconds)`;
|
|
61
63
|
this.write(message);
|
|
62
64
|
}
|
|
63
65
|
|
|
@@ -76,10 +78,9 @@ export default class BuildKiteCLIReporter extends BaseReporter {
|
|
|
76
78
|
const name = red(`Journey: ${journeyName} :slightly_frowning_face:`);
|
|
77
79
|
this.write(`\n+++ ${name}`);
|
|
78
80
|
steps.forEach(step => {
|
|
79
|
-
const message = `${symbols[step.status]
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
)} ms)`;
|
|
81
|
+
const message = `${symbols[step.status]} Step: '${step.name}' ${
|
|
82
|
+
step.status
|
|
83
|
+
} (${renderDuration(step.duration * 1000)} ms)`;
|
|
83
84
|
this.write(indent(message));
|
|
84
85
|
if (step.error) {
|
|
85
86
|
this.write(renderError(serializeError(step.error)));
|
package/src/reporters/json.ts
CHANGED
|
@@ -253,14 +253,15 @@ function formatJSONError(error: Error | any) {
|
|
|
253
253
|
};
|
|
254
254
|
}
|
|
255
255
|
|
|
256
|
-
function journeyInfo(
|
|
257
|
-
journey: Partial<Journey>,
|
|
258
|
-
type: OutputFields['type'],
|
|
259
|
-
) {
|
|
256
|
+
function journeyInfo(journey: Partial<Journey>, type: OutputFields['type']) {
|
|
260
257
|
if (!journey) {
|
|
261
258
|
return;
|
|
262
259
|
}
|
|
263
|
-
const info: JourneyInfo = {
|
|
260
|
+
const info: JourneyInfo = {
|
|
261
|
+
name: journey.name,
|
|
262
|
+
id: journey.id,
|
|
263
|
+
tags: journey.tags,
|
|
264
|
+
};
|
|
264
265
|
const isEnd = type === 'journey/end';
|
|
265
266
|
if (isEnd) {
|
|
266
267
|
info.status = journey.status;
|
|
@@ -271,7 +272,7 @@ function journeyInfo(
|
|
|
271
272
|
|
|
272
273
|
function stepInfo(
|
|
273
274
|
step: Partial<Step>,
|
|
274
|
-
type: OutputFields['type']
|
|
275
|
+
type: OutputFields['type']
|
|
275
276
|
): Omit<Partial<Step>, 'duration'> & Duration {
|
|
276
277
|
if (!step) {
|
|
277
278
|
return;
|
|
@@ -375,8 +376,8 @@ export default class JSONReporter extends BaseReporter {
|
|
|
375
376
|
},
|
|
376
377
|
payload: event.networkConditions
|
|
377
378
|
? {
|
|
378
|
-
|
|
379
|
-
|
|
379
|
+
network_conditions: event.networkConditions,
|
|
380
|
+
}
|
|
380
381
|
: undefined,
|
|
381
382
|
});
|
|
382
383
|
}
|
|
@@ -400,12 +401,7 @@ export default class JSONReporter extends BaseReporter {
|
|
|
400
401
|
override onStepEnd(
|
|
401
402
|
journey: Journey,
|
|
402
403
|
step: Step,
|
|
403
|
-
{
|
|
404
|
-
pagemetrics,
|
|
405
|
-
traces,
|
|
406
|
-
metrics,
|
|
407
|
-
filmstrips,
|
|
408
|
-
}: StepEndResult
|
|
404
|
+
{ pagemetrics, traces, metrics, filmstrips }: StepEndResult
|
|
409
405
|
) {
|
|
410
406
|
this.writeMetrics(journey, step, 'relative_trace', traces);
|
|
411
407
|
this.writeMetrics(journey, step, 'experience', metrics);
|
package/src/reporters/junit.ts
CHANGED
|
@@ -25,10 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
import { mkdir, writeFile } from 'fs/promises';
|
|
27
27
|
import { dirname } from 'path';
|
|
28
|
-
import {
|
|
29
|
-
JourneyEndResult,
|
|
30
|
-
JourneyStartResult,
|
|
31
|
-
} from '../common_types';
|
|
28
|
+
import { JourneyEndResult, JourneyStartResult } from '../common_types';
|
|
32
29
|
import { Journey, Step } from '../dsl';
|
|
33
30
|
import { indent, now } from '../helpers';
|
|
34
31
|
import BaseReporter from './base';
|
|
@@ -59,7 +56,7 @@ export default class JUnitReporter extends BaseReporter {
|
|
|
59
56
|
private totalSkipped = 0;
|
|
60
57
|
#journeyMap = new Map<string, XMLEntry>();
|
|
61
58
|
|
|
62
|
-
override onJourneyStart(journey: Journey, {
|
|
59
|
+
override onJourneyStart(journey: Journey, {}: JourneyStartResult) {
|
|
63
60
|
if (!this.#journeyMap.has(journey.name)) {
|
|
64
61
|
const entry = {
|
|
65
62
|
name: 'testsuite',
|
|
@@ -76,10 +73,7 @@ export default class JUnitReporter extends BaseReporter {
|
|
|
76
73
|
}
|
|
77
74
|
}
|
|
78
75
|
|
|
79
|
-
override onStepEnd(
|
|
80
|
-
journey: Journey,
|
|
81
|
-
step: Step,
|
|
82
|
-
) {
|
|
76
|
+
override onStepEnd(journey: Journey, step: Step) {
|
|
83
77
|
if (!this.#journeyMap.has(journey.name)) {
|
|
84
78
|
return;
|
|
85
79
|
}
|
|
@@ -117,7 +111,7 @@ export default class JUnitReporter extends BaseReporter {
|
|
|
117
111
|
entry.children.push(caseEntry);
|
|
118
112
|
}
|
|
119
113
|
|
|
120
|
-
override onJourneyEnd(journey: Journey, {
|
|
114
|
+
override onJourneyEnd(journey: Journey, {}: JourneyEndResult) {
|
|
121
115
|
if (!this.#journeyMap.has(journey.name)) {
|
|
122
116
|
return;
|
|
123
117
|
}
|