@elastic/synthetics 1.0.0-beta.8 → 1.0.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/README.md +5 -4
- package/dist/cli.js +139 -165
- package/dist/cli.js.map +1 -1
- package/dist/common_types.d.ts +158 -34
- package/dist/common_types.d.ts.map +1 -1
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +7 -6
- package/dist/config.js.map +1 -1
- package/dist/core/browser-service.d.ts +1 -1
- package/dist/core/browser-service.d.ts.map +1 -1
- package/dist/core/browser-service.js +7 -6
- package/dist/core/browser-service.js.map +1 -1
- package/dist/core/expect.d.ts +25 -25
- package/dist/core/expect.d.ts.map +1 -1
- package/dist/core/expect.js.map +1 -1
- package/dist/core/gatherer.d.ts +5 -8
- package/dist/core/gatherer.d.ts.map +1 -1
- package/dist/core/gatherer.js +75 -17
- package/dist/core/gatherer.js.map +1 -1
- package/dist/core/index.d.ts +5 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +23 -11
- package/dist/core/index.js.map +1 -1
- package/dist/core/logger.d.ts +0 -1
- package/dist/core/logger.d.ts.map +1 -1
- package/dist/core/logger.js +10 -17
- package/dist/core/logger.js.map +1 -1
- package/dist/core/runner.d.ts +12 -63
- package/dist/core/runner.d.ts.map +1 -1
- package/dist/core/runner.js +159 -92
- package/dist/core/runner.js.map +1 -1
- package/dist/core/transform.d.ts +37 -0
- package/dist/core/transform.d.ts.map +1 -0
- package/dist/core/transform.js +148 -0
- package/dist/core/transform.js.map +1 -0
- package/dist/dsl/index.js +5 -1
- package/dist/dsl/index.js.map +1 -1
- package/dist/dsl/journey.d.ts +9 -7
- package/dist/dsl/journey.d.ts.map +1 -1
- package/dist/dsl/journey.js +32 -39
- package/dist/dsl/journey.js.map +1 -1
- package/dist/dsl/monitor.d.ts +93 -0
- package/dist/dsl/monitor.d.ts.map +1 -0
- package/dist/dsl/monitor.js +110 -0
- package/dist/dsl/monitor.js.map +1 -0
- package/dist/dsl/step.d.ts +3 -2
- package/dist/dsl/step.d.ts.map +1 -1
- package/dist/dsl/step.js +6 -1
- package/dist/dsl/step.js.map +1 -1
- package/dist/formatter/javascript.d.ts +115 -0
- package/dist/formatter/javascript.d.ts.map +1 -0
- package/dist/formatter/javascript.js +331 -0
- package/dist/formatter/javascript.js.map +1 -0
- package/dist/generator/index.d.ts +24 -0
- package/dist/generator/index.d.ts.map +1 -0
- package/dist/generator/index.js +241 -0
- package/dist/generator/index.js.map +1 -0
- package/dist/{reporters/reporter.js → generator/utils.d.ts} +5 -3
- package/dist/generator/utils.d.ts.map +1 -0
- package/dist/generator/utils.js +84 -0
- package/dist/generator/utils.js.map +1 -0
- package/dist/helpers.d.ts +36 -9
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +170 -24
- package/dist/helpers.js.map +1 -1
- package/dist/index.d.ts +5 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -26
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +34 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +153 -0
- package/dist/loader.js.map +1 -0
- package/dist/locations/index.d.ts +45 -0
- package/dist/locations/index.d.ts.map +1 -0
- package/dist/locations/index.js +83 -0
- package/dist/locations/index.js.map +1 -0
- package/dist/{reporters/reporter.d.ts → locations/public-locations.d.ts} +12 -8
- package/dist/locations/public-locations.d.ts.map +1 -0
- package/dist/locations/public-locations.js +41 -0
- package/dist/locations/public-locations.js.map +1 -0
- package/dist/options.d.ts +42 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +146 -0
- package/dist/options.js.map +1 -0
- package/dist/plugins/browser-console.d.ts +5 -4
- package/dist/plugins/browser-console.d.ts.map +1 -1
- package/dist/plugins/browser-console.js +47 -24
- package/dist/plugins/browser-console.js.map +1 -1
- package/dist/plugins/index.js +5 -1
- package/dist/plugins/index.js.map +1 -1
- package/dist/plugins/network.d.ts +24 -31
- package/dist/plugins/network.d.ts.map +1 -1
- package/dist/plugins/network.js +226 -229
- package/dist/plugins/network.js.map +1 -1
- package/dist/plugins/performance.d.ts +4 -19
- package/dist/plugins/performance.d.ts.map +1 -1
- package/dist/plugins/performance.js +6 -5
- package/dist/plugins/performance.js.map +1 -1
- package/dist/plugins/plugin-manager.d.ts +9 -5
- package/dist/plugins/plugin-manager.d.ts.map +1 -1
- package/dist/plugins/plugin-manager.js +46 -30
- package/dist/plugins/plugin-manager.js.map +1 -1
- package/dist/plugins/tracing.d.ts +6 -6
- package/dist/plugins/tracing.d.ts.map +1 -1
- package/dist/plugins/tracing.js +13 -7
- package/dist/plugins/tracing.js.map +1 -1
- package/dist/push/bundler.d.ts +35 -0
- package/dist/push/bundler.d.ts.map +1 -0
- package/dist/push/bundler.js +131 -0
- package/dist/push/bundler.js.map +1 -0
- package/dist/push/index.d.ts +10 -0
- package/dist/push/index.d.ts.map +1 -0
- package/dist/push/index.js +235 -0
- package/dist/push/index.js.map +1 -0
- package/dist/push/kibana_api.d.ts +56 -0
- package/dist/push/kibana_api.d.ts.map +1 -0
- package/dist/push/kibana_api.js +135 -0
- package/dist/push/kibana_api.js.map +1 -0
- package/dist/push/monitor.d.ts +55 -0
- package/dist/push/monitor.d.ts.map +1 -0
- package/dist/push/monitor.js +268 -0
- package/dist/push/monitor.js.map +1 -0
- package/dist/{parse_args.d.ts → push/plugin.d.ts} +9 -6
- package/dist/push/plugin.d.ts.map +1 -0
- package/dist/push/plugin.js +66 -0
- package/dist/push/plugin.js.map +1 -0
- package/dist/push/request.d.ts +45 -0
- package/dist/push/request.d.ts.map +1 -0
- package/dist/push/request.js +109 -0
- package/dist/push/request.js.map +1 -0
- package/dist/push/utils.d.ts +31 -0
- package/dist/push/utils.d.ts.map +1 -0
- package/dist/push/utils.js +64 -0
- package/dist/push/utils.js.map +1 -0
- package/dist/reporters/base.d.ts +14 -6
- package/dist/reporters/base.d.ts.map +1 -1
- package/dist/reporters/base.js +58 -50
- package/dist/reporters/base.js.map +1 -1
- package/dist/reporters/index.d.ts +18 -8
- package/dist/reporters/index.d.ts.map +1 -1
- package/dist/reporters/index.js.map +1 -1
- package/dist/reporters/json.d.ts +17 -62
- package/dist/reporters/json.d.ts.map +1 -1
- package/dist/reporters/json.js +147 -177
- package/dist/reporters/json.js.map +1 -1
- package/dist/reporters/junit.d.ts +7 -1
- package/dist/reporters/junit.d.ts.map +1 -1
- package/dist/reporters/junit.js +90 -95
- package/dist/reporters/junit.js.map +1 -1
- package/dist/sdk/lh-trace-processor.d.ts +35 -9
- package/dist/sdk/lh-trace-processor.d.ts.map +1 -1
- package/dist/sdk/lh-trace-processor.js +114 -53
- package/dist/sdk/lh-trace-processor.js.map +1 -1
- package/dist/sdk/trace-metrics.d.ts +4 -4
- package/dist/sdk/trace-metrics.d.ts.map +1 -1
- package/dist/sdk/trace-metrics.js +3 -4
- package/dist/sdk/trace-metrics.js.map +1 -1
- package/dist/sdk/trace-processor.d.ts +11 -3
- package/dist/sdk/trace-processor.d.ts.map +1 -1
- package/dist/sdk/trace-processor.js +17 -9
- package/dist/sdk/trace-processor.js.map +1 -1
- package/package.json +38 -30
- package/src/cli.ts +223 -158
- package/src/common_types.ts +191 -34
- package/src/config.ts +1 -1
- package/src/core/expect.ts +58 -24
- package/src/core/gatherer.ts +92 -25
- package/src/core/index.ts +36 -15
- package/src/core/logger.ts +8 -12
- package/src/core/runner.ts +158 -148
- package/src/core/transform.ts +160 -0
- package/src/dsl/journey.ts +41 -21
- package/src/dsl/monitor.ts +152 -0
- package/src/dsl/step.ts +9 -2
- package/src/formatter/javascript.ts +414 -0
- package/src/generator/index.ts +308 -0
- package/src/generator/utils.ts +84 -0
- package/src/helpers.ts +182 -16
- package/src/index.ts +21 -22
- package/src/loader.ts +171 -0
- package/src/locations/index.ts +95 -0
- package/src/{reporters/reporter.ts → locations/public-locations.ts} +12 -9
- package/src/options.ts +175 -0
- package/src/plugins/browser-console.ts +33 -8
- package/src/plugins/network.ts +266 -284
- package/src/plugins/performance.ts +6 -22
- package/src/plugins/plugin-manager.ts +49 -31
- package/src/plugins/tracing.ts +11 -9
- package/src/push/bundler.ts +112 -0
- package/src/push/index.ts +291 -0
- package/src/push/kibana_api.ts +191 -0
- package/src/push/monitor.ts +307 -0
- package/src/push/plugin.ts +66 -0
- package/src/push/request.ts +141 -0
- package/src/push/utils.ts +77 -0
- package/src/reporters/base.ts +63 -52
- package/src/reporters/index.ts +26 -3
- package/src/reporters/json.ts +181 -201
- package/src/reporters/junit.ts +98 -93
- package/src/sdk/lh-trace-processor.ts +132 -68
- package/src/sdk/trace-metrics.ts +8 -4
- package/src/sdk/trace-processor.ts +28 -13
- package/templates/.github/workflows/run-synthetics.yml +27 -0
- package/templates/README.md +21 -0
- package/templates/journeys/advanced-example-helpers.ts +54 -0
- package/templates/journeys/advanced-example.journey.ts +43 -0
- package/templates/journeys/example.journey.ts +18 -0
- package/templates/lightweight/heartbeat.yml +9 -0
- package/templates/synthetics.config.ts +35 -0
- package/CHANGELOG.md +0 -181
- package/NOTICE.txt +0 -221
- package/dist/parse_args.d.ts.map +0 -1
- package/dist/parse_args.js +0 -98
- package/dist/parse_args.js.map +0 -1
- package/dist/reporters/reporter.d.ts.map +0 -1
- package/dist/reporters/reporter.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1895
- package/src/parse_args.ts +0 -146
package/src/core/index.ts
CHANGED
|
@@ -25,8 +25,10 @@
|
|
|
25
25
|
|
|
26
26
|
import { Journey, JourneyCallback, JourneyOptions } from '../dsl';
|
|
27
27
|
import Runner from './runner';
|
|
28
|
-
import { VoidCallback, HooksCallback } from '../common_types';
|
|
28
|
+
import { VoidCallback, HooksCallback, Location } from '../common_types';
|
|
29
|
+
import { wrapFnWithLocation } from '../helpers';
|
|
29
30
|
import { log } from './logger';
|
|
31
|
+
import { MonitorConfig } from '../dsl/monitor';
|
|
30
32
|
|
|
31
33
|
/**
|
|
32
34
|
* Use a gloabl Runner which would be accessed by the runtime and
|
|
@@ -39,22 +41,41 @@ if (!global[SYNTHETICS_RUNNER]) {
|
|
|
39
41
|
|
|
40
42
|
export const runner: Runner = global[SYNTHETICS_RUNNER];
|
|
41
43
|
|
|
42
|
-
export const journey = (
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
44
|
+
export const journey = wrapFnWithLocation(
|
|
45
|
+
(
|
|
46
|
+
location: Location,
|
|
47
|
+
options: JourneyOptions | string,
|
|
48
|
+
callback: JourneyCallback
|
|
49
|
+
) => {
|
|
50
|
+
log(`Journey register: ${JSON.stringify(options)}`);
|
|
51
|
+
if (typeof options === 'string') {
|
|
52
|
+
options = { name: options, id: options };
|
|
53
|
+
}
|
|
54
|
+
const j = new Journey(options, callback, location);
|
|
55
|
+
runner.addJourney(j);
|
|
56
|
+
return j;
|
|
49
57
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
export const step = wrapFnWithLocation(
|
|
61
|
+
(location: Location, name: string, callback: VoidCallback) => {
|
|
62
|
+
log(`Step register: ${name}`);
|
|
63
|
+
return runner.currentJourney?.addStep(name, callback, location);
|
|
64
|
+
}
|
|
65
|
+
);
|
|
54
66
|
|
|
55
|
-
export const
|
|
56
|
-
|
|
57
|
-
|
|
67
|
+
export const monitor = {
|
|
68
|
+
use: wrapFnWithLocation((location: Location, config: MonitorConfig) => {
|
|
69
|
+
/**
|
|
70
|
+
* If the context is inside journey, then set it to journey context
|
|
71
|
+
* otherwise set to the global monitor which will be used for all journeys
|
|
72
|
+
*/
|
|
73
|
+
if (runner.currentJourney) {
|
|
74
|
+
runner.currentJourney.updateMonitor(config);
|
|
75
|
+
} else {
|
|
76
|
+
runner.updateMonitor(config);
|
|
77
|
+
}
|
|
78
|
+
}),
|
|
58
79
|
};
|
|
59
80
|
|
|
60
81
|
export const beforeAll = (callback: HooksCallback) => {
|
package/src/core/logger.ts
CHANGED
|
@@ -23,27 +23,23 @@
|
|
|
23
23
|
*
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import SonicBoom from 'sonic-boom';
|
|
27
26
|
import { grey, cyan, dim, italic } from 'kleur/colors';
|
|
28
27
|
import { now } from '../helpers';
|
|
29
28
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
return logger;
|
|
38
|
-
};
|
|
29
|
+
/**
|
|
30
|
+
* Set debug based on DEBUG ENV and namespace - synthetics
|
|
31
|
+
*/
|
|
32
|
+
if (process.env.DEBUG && process.env.DEBUG.includes('synthetics')) {
|
|
33
|
+
process.env['__SYNTHETICS__DEBUG__'] = '1';
|
|
34
|
+
}
|
|
39
35
|
|
|
40
36
|
export function log(msg) {
|
|
41
|
-
if (!process.env
|
|
37
|
+
if (!process.env['__SYNTHETICS__DEBUG__'] || !msg) {
|
|
42
38
|
return;
|
|
43
39
|
}
|
|
44
40
|
if (typeof msg === 'object') {
|
|
45
41
|
msg = JSON.stringify(msg);
|
|
46
42
|
}
|
|
47
43
|
const time = dim(cyan(`at ${parseInt(String(now()))} ms `));
|
|
48
|
-
|
|
44
|
+
process.stderr.write(time + italic(grey(msg)) + '\n');
|
|
49
45
|
}
|
package/src/core/runner.ts
CHANGED
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
*
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import { once, EventEmitter } from 'events';
|
|
27
26
|
import { join } from 'path';
|
|
27
|
+
import { mkdir, rm, writeFile } from 'fs/promises';
|
|
28
28
|
import { Journey } from '../dsl/journey';
|
|
29
29
|
import { Step } from '../dsl/step';
|
|
30
30
|
import { reporters, Reporter } from '../reporters';
|
|
@@ -34,120 +34,58 @@ import {
|
|
|
34
34
|
getTimestamp,
|
|
35
35
|
runParallel,
|
|
36
36
|
generateUniqueId,
|
|
37
|
-
mkdirAsync,
|
|
38
|
-
rmdirAsync,
|
|
39
|
-
writeFileAsync,
|
|
40
37
|
} from '../helpers';
|
|
41
38
|
import {
|
|
42
|
-
StatusValue,
|
|
43
39
|
HooksCallback,
|
|
44
40
|
Params,
|
|
45
|
-
PluginOutput,
|
|
46
|
-
CliArgs,
|
|
47
41
|
HooksArgs,
|
|
48
|
-
|
|
42
|
+
Driver,
|
|
43
|
+
Screenshot,
|
|
44
|
+
RunOptions,
|
|
45
|
+
JourneyResult,
|
|
46
|
+
StepResult,
|
|
49
47
|
} from '../common_types';
|
|
50
48
|
import { PluginManager } from '../plugins';
|
|
51
|
-
import { PerformanceManager
|
|
52
|
-
import {
|
|
49
|
+
import { PerformanceManager } from '../plugins';
|
|
50
|
+
import { Gatherer } from './gatherer';
|
|
53
51
|
import { log } from './logger';
|
|
52
|
+
import { Monitor, MonitorConfig } from '../dsl/monitor';
|
|
54
53
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
| 'debug'
|
|
58
|
-
| 'json'
|
|
59
|
-
| 'pattern'
|
|
60
|
-
| 'inline'
|
|
61
|
-
| 'require'
|
|
62
|
-
| 'suiteParams'
|
|
63
|
-
| 'reporter'
|
|
64
|
-
| 'richEvents'
|
|
65
|
-
| 'capability'
|
|
66
|
-
| 'sandbox'
|
|
67
|
-
| 'headless'
|
|
68
|
-
> & {
|
|
69
|
-
environment?: string;
|
|
70
|
-
playwrightOptions?: PlaywrightOptions;
|
|
71
|
-
reporter?: CliArgs['reporter'] | Reporter;
|
|
72
|
-
};
|
|
54
|
+
type HookType = 'beforeAll' | 'afterAll';
|
|
55
|
+
export type SuiteHooks = Record<HookType, Array<HooksCallback>>;
|
|
73
56
|
|
|
74
|
-
type
|
|
57
|
+
type JourneyContext = {
|
|
75
58
|
params?: Params;
|
|
76
59
|
start: number;
|
|
77
|
-
end?: number;
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
type JourneyContext = BaseContext & {
|
|
81
60
|
driver: Driver;
|
|
82
61
|
pluginManager: PluginManager;
|
|
83
62
|
};
|
|
84
63
|
|
|
85
|
-
type StepResult = {
|
|
86
|
-
status: StatusValue;
|
|
87
|
-
url?: string;
|
|
88
|
-
metrics?: Metrics;
|
|
89
|
-
error?: Error;
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
type JourneyResult = {
|
|
93
|
-
status: StatusValue;
|
|
94
|
-
error?: Error;
|
|
95
|
-
};
|
|
96
|
-
|
|
97
64
|
type RunResult = Record<string, JourneyResult>;
|
|
98
65
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
start: { numJourneys: number };
|
|
104
|
-
'journey:register': {
|
|
105
|
-
journey: Journey;
|
|
106
|
-
};
|
|
107
|
-
'journey:start': {
|
|
108
|
-
journey: Journey;
|
|
109
|
-
timestamp: number;
|
|
110
|
-
params: Params;
|
|
111
|
-
};
|
|
112
|
-
'journey:end': BaseContext &
|
|
113
|
-
JourneyResult &
|
|
114
|
-
PluginOutput & {
|
|
115
|
-
journey: Journey;
|
|
116
|
-
options: RunOptions;
|
|
117
|
-
};
|
|
118
|
-
'journey:end:reported': unknown;
|
|
119
|
-
'step:start': { journey: Journey; step: Step };
|
|
120
|
-
'step:end': StepResult & {
|
|
121
|
-
start: number;
|
|
122
|
-
end: number;
|
|
123
|
-
journey: Journey;
|
|
124
|
-
step: Step;
|
|
125
|
-
};
|
|
126
|
-
end: unknown;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export default interface Runner {
|
|
130
|
-
on<K extends keyof Events>(name: K, listener: (v: Events[K]) => void): this;
|
|
131
|
-
emit<K extends keyof Events>(event: K, args: Events[K]): boolean;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
export default class Runner extends EventEmitter {
|
|
135
|
-
active = false;
|
|
136
|
-
currentJourney?: Journey = null;
|
|
66
|
+
export default class Runner {
|
|
67
|
+
#active = false;
|
|
68
|
+
#reporter: Reporter;
|
|
69
|
+
#currentJourney?: Journey = null;
|
|
137
70
|
journeys: Journey[] = [];
|
|
138
71
|
hooks: SuiteHooks = { beforeAll: [], afterAll: [] };
|
|
139
72
|
hookError: Error | undefined;
|
|
73
|
+
monitor?: Monitor;
|
|
140
74
|
static screenshotPath = join(CACHE_PATH, 'screenshots');
|
|
141
75
|
|
|
142
76
|
static async createContext(options: RunOptions): Promise<JourneyContext> {
|
|
143
|
-
const start = monotonicTimeInSeconds();
|
|
144
77
|
const driver = await Gatherer.setupDriver(options);
|
|
78
|
+
/**
|
|
79
|
+
* Do not include browser launch/context creation duration
|
|
80
|
+
* as part of journey duration
|
|
81
|
+
*/
|
|
82
|
+
const start = monotonicTimeInSeconds();
|
|
145
83
|
const pluginManager = await Gatherer.beginRecording(driver, options);
|
|
146
84
|
/**
|
|
147
85
|
* For each journey we create the screenshots folder for
|
|
148
86
|
* caching all screenshots and clear them at end of each journey
|
|
149
87
|
*/
|
|
150
|
-
await
|
|
88
|
+
await mkdir(this.screenshotPath, { recursive: true });
|
|
151
89
|
return {
|
|
152
90
|
start,
|
|
153
91
|
params: options.params,
|
|
@@ -157,11 +95,11 @@ export default class Runner extends EventEmitter {
|
|
|
157
95
|
}
|
|
158
96
|
|
|
159
97
|
async captureScreenshot(page: Driver['page'], step: Step) {
|
|
160
|
-
await page.waitForLoadState('load');
|
|
161
98
|
const buffer = await page
|
|
162
99
|
.screenshot({
|
|
163
100
|
type: 'jpeg',
|
|
164
101
|
quality: 80,
|
|
102
|
+
timeout: 5000,
|
|
165
103
|
})
|
|
166
104
|
.catch(() => {});
|
|
167
105
|
/**
|
|
@@ -171,23 +109,51 @@ export default class Runner extends EventEmitter {
|
|
|
171
109
|
*/
|
|
172
110
|
if (buffer) {
|
|
173
111
|
const fileName = `${generateUniqueId()}.json`;
|
|
174
|
-
|
|
112
|
+
const screenshot: Screenshot = {
|
|
113
|
+
step,
|
|
114
|
+
timestamp: getTimestamp(),
|
|
115
|
+
data: buffer.toString('base64'),
|
|
116
|
+
};
|
|
117
|
+
await writeFile(
|
|
175
118
|
join(Runner.screenshotPath, fileName),
|
|
176
|
-
JSON.stringify(
|
|
177
|
-
step,
|
|
178
|
-
data: buffer.toString('base64'),
|
|
179
|
-
})
|
|
119
|
+
JSON.stringify(screenshot)
|
|
180
120
|
);
|
|
121
|
+
log(`Runner: captured screenshot for (${step.name})`);
|
|
181
122
|
}
|
|
182
123
|
}
|
|
183
124
|
|
|
125
|
+
get currentJourney() {
|
|
126
|
+
return this.#currentJourney;
|
|
127
|
+
}
|
|
128
|
+
|
|
184
129
|
addHook(type: HookType, callback: HooksCallback) {
|
|
185
130
|
this.hooks[type].push(callback);
|
|
186
131
|
}
|
|
187
132
|
|
|
133
|
+
updateMonitor(config: MonitorConfig) {
|
|
134
|
+
if (!this.monitor) {
|
|
135
|
+
this.monitor = new Monitor(config);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
this.monitor.update(config);
|
|
139
|
+
}
|
|
140
|
+
|
|
188
141
|
addJourney(journey: Journey) {
|
|
189
142
|
this.journeys.push(journey);
|
|
190
|
-
this
|
|
143
|
+
this.#currentJourney = journey;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
setReporter(options: RunOptions) {
|
|
147
|
+
/**
|
|
148
|
+
* Set up the corresponding reporter and fallback
|
|
149
|
+
* to default reporter if not provided
|
|
150
|
+
*/
|
|
151
|
+
const { reporter, outfd } = options;
|
|
152
|
+
const Reporter =
|
|
153
|
+
typeof reporter === 'function'
|
|
154
|
+
? reporter
|
|
155
|
+
: reporters[reporter] || reporters['default'];
|
|
156
|
+
this.#reporter = new Reporter({ fd: outfd });
|
|
191
157
|
}
|
|
192
158
|
|
|
193
159
|
async runBeforeAllHook(args: HooksArgs) {
|
|
@@ -219,7 +185,7 @@ export default class Runner extends EventEmitter {
|
|
|
219
185
|
status: 'succeeded',
|
|
220
186
|
};
|
|
221
187
|
log(`Runner: start step (${step.name})`);
|
|
222
|
-
const { metrics, screenshots } = options;
|
|
188
|
+
const { metrics, screenshots, filmstrips, trace } = options;
|
|
223
189
|
const { driver, pluginManager } = context;
|
|
224
190
|
/**
|
|
225
191
|
* URL needs to be the first navigation request of any step
|
|
@@ -230,22 +196,49 @@ export default class Runner extends EventEmitter {
|
|
|
230
196
|
if (!data.url && req.isNavigationRequest()) {
|
|
231
197
|
data.url = req.url();
|
|
232
198
|
}
|
|
233
|
-
driver.
|
|
199
|
+
driver.context.off('request', captureUrl);
|
|
234
200
|
};
|
|
235
|
-
driver.
|
|
201
|
+
driver.context.on('request', captureUrl);
|
|
202
|
+
|
|
203
|
+
const traceEnabled = trace || filmstrips;
|
|
236
204
|
try {
|
|
205
|
+
/**
|
|
206
|
+
* Set up plugin manager context and also register
|
|
207
|
+
* step level plugins
|
|
208
|
+
*/
|
|
237
209
|
pluginManager.onStep(step);
|
|
210
|
+
traceEnabled && (await pluginManager.start('trace'));
|
|
211
|
+
// call the step definition
|
|
238
212
|
await step.callback();
|
|
239
|
-
if (metrics) {
|
|
240
|
-
data.metrics = await pluginManager.get(PerformanceManager).getMetrics();
|
|
241
|
-
}
|
|
242
213
|
} catch (error) {
|
|
243
214
|
data.status = 'failed';
|
|
244
215
|
data.error = error;
|
|
245
216
|
} finally {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
217
|
+
/**
|
|
218
|
+
* Collect all step level metrics and trace events
|
|
219
|
+
*/
|
|
220
|
+
if (metrics) {
|
|
221
|
+
data.pagemetrics = await (
|
|
222
|
+
pluginManager.get('performance') as PerformanceManager
|
|
223
|
+
).getMetrics();
|
|
224
|
+
}
|
|
225
|
+
if (traceEnabled) {
|
|
226
|
+
const traceOutput = await pluginManager.stop('trace');
|
|
227
|
+
Object.assign(data, traceOutput);
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Capture screenshot for the newly created pages
|
|
231
|
+
* via popup or new windows/tabs
|
|
232
|
+
*
|
|
233
|
+
* Last open page will get us the correct screenshot
|
|
234
|
+
*/
|
|
235
|
+
const pages = driver.context.pages();
|
|
236
|
+
const page = pages[pages.length - 1];
|
|
237
|
+
if (page) {
|
|
238
|
+
data.url ??= page.url();
|
|
239
|
+
if (screenshots && screenshots !== 'off') {
|
|
240
|
+
await this.captureScreenshot(page, step);
|
|
241
|
+
}
|
|
249
242
|
}
|
|
250
243
|
}
|
|
251
244
|
log(`Runner: end step (${step.name})`);
|
|
@@ -261,7 +254,7 @@ export default class Runner extends EventEmitter {
|
|
|
261
254
|
let skipStep = false;
|
|
262
255
|
for (const step of journey.steps) {
|
|
263
256
|
const start = monotonicTimeInSeconds();
|
|
264
|
-
this
|
|
257
|
+
this.#reporter?.onStepStart?.(journey, step);
|
|
265
258
|
let data: StepResult = { status: 'succeeded' };
|
|
266
259
|
if (skipStep) {
|
|
267
260
|
data.status = 'skipped';
|
|
@@ -272,9 +265,7 @@ export default class Runner extends EventEmitter {
|
|
|
272
265
|
*/
|
|
273
266
|
if (data.error) skipStep = true;
|
|
274
267
|
}
|
|
275
|
-
this
|
|
276
|
-
journey,
|
|
277
|
-
step,
|
|
268
|
+
this.#reporter?.onStepEnd?.(journey, step, {
|
|
278
269
|
start,
|
|
279
270
|
end: monotonicTimeInSeconds(),
|
|
280
271
|
...data,
|
|
@@ -288,12 +279,16 @@ export default class Runner extends EventEmitter {
|
|
|
288
279
|
}
|
|
289
280
|
|
|
290
281
|
registerJourney(journey: Journey, context: JourneyContext) {
|
|
291
|
-
this
|
|
282
|
+
this.#currentJourney = journey;
|
|
292
283
|
const timestamp = getTimestamp();
|
|
293
284
|
const { params } = context;
|
|
294
|
-
this
|
|
285
|
+
this.#reporter?.onJourneyStart?.(journey, {
|
|
286
|
+
timestamp,
|
|
287
|
+
params,
|
|
288
|
+
});
|
|
295
289
|
/**
|
|
296
|
-
*
|
|
290
|
+
* Exeucute the journey callback which would
|
|
291
|
+
* register the steps for the current journey
|
|
297
292
|
*/
|
|
298
293
|
journey.callback({ ...context.driver, params });
|
|
299
294
|
}
|
|
@@ -303,27 +298,21 @@ export default class Runner extends EventEmitter {
|
|
|
303
298
|
result: JourneyContext & JourneyResult,
|
|
304
299
|
options: RunOptions
|
|
305
300
|
) {
|
|
301
|
+
const end = monotonicTimeInSeconds();
|
|
306
302
|
const { pluginManager, start, status, error } = result;
|
|
307
303
|
const pluginOutput = await pluginManager.output();
|
|
308
|
-
this
|
|
309
|
-
journey,
|
|
304
|
+
await this.#reporter?.onJourneyEnd?.(journey, {
|
|
310
305
|
status,
|
|
311
306
|
error,
|
|
312
307
|
start,
|
|
313
|
-
end
|
|
308
|
+
end,
|
|
309
|
+
timestamp: getTimestamp(),
|
|
314
310
|
options,
|
|
315
311
|
...pluginOutput,
|
|
316
312
|
browserconsole: status == 'failed' ? pluginOutput.browserconsole : [],
|
|
317
313
|
});
|
|
318
|
-
/**
|
|
319
|
-
* Wait for the all the reported events to be consumed aschronously
|
|
320
|
-
* by reporter.
|
|
321
|
-
*/
|
|
322
|
-
if (options.reporter === 'json') {
|
|
323
|
-
await once(this, 'journey:end:reported');
|
|
324
|
-
}
|
|
325
314
|
// clear screenshots cache after each journey
|
|
326
|
-
await
|
|
315
|
+
await rm(Runner.screenshotPath, { recursive: true, force: true });
|
|
327
316
|
}
|
|
328
317
|
|
|
329
318
|
/**
|
|
@@ -331,8 +320,7 @@ export default class Runner extends EventEmitter {
|
|
|
331
320
|
*/
|
|
332
321
|
async runFakeJourney(journey: Journey, options: RunOptions) {
|
|
333
322
|
const start = monotonicTimeInSeconds();
|
|
334
|
-
this.
|
|
335
|
-
journey,
|
|
323
|
+
this.#reporter.onJourneyStart?.(journey, {
|
|
336
324
|
timestamp: getTimestamp(),
|
|
337
325
|
params: options.params,
|
|
338
326
|
});
|
|
@@ -340,25 +328,20 @@ export default class Runner extends EventEmitter {
|
|
|
340
328
|
status: 'failed',
|
|
341
329
|
error: this.hookError,
|
|
342
330
|
};
|
|
343
|
-
this.
|
|
344
|
-
|
|
331
|
+
await this.#reporter.onJourneyEnd?.(journey, {
|
|
332
|
+
timestamp: getTimestamp(),
|
|
345
333
|
start,
|
|
346
334
|
options,
|
|
347
335
|
end: monotonicTimeInSeconds(),
|
|
348
336
|
...result,
|
|
349
337
|
});
|
|
350
|
-
if (options.reporter === 'json') {
|
|
351
|
-
await once(this, 'journey:end:reported');
|
|
352
|
-
}
|
|
353
338
|
return result;
|
|
354
339
|
}
|
|
355
340
|
|
|
356
341
|
async runJourney(journey: Journey, options: RunOptions) {
|
|
357
|
-
const result: JourneyResult = {
|
|
358
|
-
status: 'succeeded',
|
|
359
|
-
};
|
|
360
|
-
log(`Runner: start journey (${journey.name})`);
|
|
342
|
+
const result: JourneyResult = { status: 'succeeded' };
|
|
361
343
|
const context = await Runner.createContext(options);
|
|
344
|
+
log(`Runner: start journey (${journey.name})`);
|
|
362
345
|
try {
|
|
363
346
|
this.registerJourney(journey, context);
|
|
364
347
|
const hookArgs = {
|
|
@@ -389,28 +372,55 @@ export default class Runner extends EventEmitter {
|
|
|
389
372
|
}
|
|
390
373
|
|
|
391
374
|
async init(options: RunOptions) {
|
|
392
|
-
|
|
375
|
+
this.setReporter(options);
|
|
376
|
+
this.#reporter.onStart?.({
|
|
377
|
+
numJourneys: this.journeys.length,
|
|
378
|
+
networkConditions: options.networkConditions,
|
|
379
|
+
});
|
|
393
380
|
/**
|
|
394
|
-
* Set up the
|
|
381
|
+
* Set up the directory for caching screenshots
|
|
395
382
|
*/
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
new Reporter(this, { fd: outfd });
|
|
401
|
-
this.emit('start', { numJourneys: this.journeys.length });
|
|
383
|
+
await mkdir(CACHE_PATH, { recursive: true });
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
buildMonitors(options: RunOptions) {
|
|
402
387
|
/**
|
|
403
|
-
*
|
|
388
|
+
* Update the global monitor configuration required for
|
|
389
|
+
* setting defaults
|
|
404
390
|
*/
|
|
405
|
-
|
|
391
|
+
this.updateMonitor({
|
|
392
|
+
throttling: options.throttling,
|
|
393
|
+
schedule: options.schedule,
|
|
394
|
+
locations: options.locations,
|
|
395
|
+
privateLocations: options.privateLocations,
|
|
396
|
+
params: options.params,
|
|
397
|
+
playwrightOptions: options.playwrightOptions,
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
const monitors: Monitor[] = [];
|
|
401
|
+
for (const journey of this.journeys) {
|
|
402
|
+
if (!journey.isMatch(options.match, options.tags)) {
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
this.#currentJourney = journey;
|
|
406
|
+
/**
|
|
407
|
+
* Execute dummy callback to get all monitor specific
|
|
408
|
+
* configurations for the current journey
|
|
409
|
+
*/
|
|
410
|
+
journey.callback({ params: options.params } as any);
|
|
411
|
+
journey.monitor.update(this.monitor?.config);
|
|
412
|
+
journey.monitor.validate();
|
|
413
|
+
monitors.push(journey.monitor);
|
|
414
|
+
}
|
|
415
|
+
return monitors;
|
|
406
416
|
}
|
|
407
417
|
|
|
408
418
|
async run(options: RunOptions) {
|
|
409
419
|
const result: RunResult = {};
|
|
410
|
-
if (this
|
|
420
|
+
if (this.#active) {
|
|
411
421
|
return result;
|
|
412
422
|
}
|
|
413
|
-
this
|
|
423
|
+
this.#active = true;
|
|
414
424
|
log(`Runner: run ${this.journeys.length} journeys`);
|
|
415
425
|
this.init(options);
|
|
416
426
|
await this.runBeforeAllHook({
|
|
@@ -424,7 +434,7 @@ export default class Runner extends EventEmitter {
|
|
|
424
434
|
* Used by heartbeat to gather all registered journeys
|
|
425
435
|
*/
|
|
426
436
|
if (dryRun) {
|
|
427
|
-
this.
|
|
437
|
+
this.#reporter.onJourneyRegister?.(journey);
|
|
428
438
|
continue;
|
|
429
439
|
}
|
|
430
440
|
if (!journey.isMatch(match, tags)) {
|
|
@@ -445,14 +455,14 @@ export default class Runner extends EventEmitter {
|
|
|
445
455
|
}
|
|
446
456
|
|
|
447
457
|
async reset() {
|
|
458
|
+
this.#currentJourney = null;
|
|
459
|
+
this.journeys = [];
|
|
460
|
+
this.#active = false;
|
|
448
461
|
/**
|
|
449
462
|
* Clear all cache data stored for post processing by
|
|
450
463
|
* the current synthetic agent run
|
|
451
464
|
*/
|
|
452
|
-
await
|
|
453
|
-
this
|
|
454
|
-
this.journeys = [];
|
|
455
|
-
this.active = false;
|
|
456
|
-
this.emit('end', {});
|
|
465
|
+
await rm(CACHE_PATH, { recursive: true, force: true });
|
|
466
|
+
await this.#reporter?.onEnd?.();
|
|
457
467
|
}
|
|
458
468
|
}
|