@elastic/synthetics 1.0.0-beta.4 → 1.0.0-beta.41
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 +4 -3
- package/dist/cli.js +137 -160
- package/dist/cli.js.map +1 -1
- package/dist/common_types.d.ts +161 -31
- package/dist/common_types.d.ts.map +1 -1
- package/dist/config.d.ts +3 -5
- 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 +4 -8
- package/dist/core/gatherer.d.ts.map +1 -1
- package/dist/core/gatherer.js +53 -15
- 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 +3 -16
- 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 +156 -90
- 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 -4
- package/dist/dsl/journey.d.ts.map +1 -1
- package/dist/dsl/journey.js +37 -9
- package/dist/dsl/journey.js.map +1 -1
- package/dist/dsl/monitor.d.ts +83 -0
- package/dist/dsl/monitor.d.ts.map +1 -0
- package/dist/dsl/monitor.js +108 -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 +98 -0
- package/dist/formatter/javascript.d.ts.map +1 -0
- package/dist/formatter/javascript.js +298 -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 +28 -3
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +152 -20
- package/dist/helpers.js.map +1 -1
- package/dist/index.d.ts +6 -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 +149 -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 +41 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +198 -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 +44 -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 +20 -33
- package/dist/plugins/network.d.ts.map +1 -1
- package/dist/plugins/network.js +177 -216
- 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 +10 -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 +9 -0
- package/dist/push/index.d.ts.map +1 -0
- package/dist/push/index.js +227 -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 +51 -0
- package/dist/push/monitor.d.ts.map +1 -0
- package/dist/push/monitor.js +244 -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 +149 -179
- 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 +39 -24
- package/src/cli.ts +219 -151
- package/src/common_types.ts +193 -31
- package/src/config.ts +3 -6
- package/src/core/expect.ts +58 -24
- package/src/core/gatherer.ts +64 -24
- package/src/core/index.ts +36 -15
- package/src/core/logger.ts +1 -12
- package/src/core/runner.ts +151 -136
- package/src/core/transform.ts +160 -0
- package/src/dsl/journey.ts +39 -6
- package/src/dsl/monitor.ts +140 -0
- package/src/dsl/step.ts +9 -2
- package/src/formatter/javascript.ts +367 -0
- package/src/generator/index.ts +308 -0
- package/src/generator/utils.ts +84 -0
- package/src/helpers.ts +159 -13
- package/src/index.ts +22 -22
- package/src/loader.ts +167 -0
- package/src/locations/index.ts +95 -0
- package/src/{reporters/reporter.ts → locations/public-locations.ts} +12 -9
- package/src/options.ts +227 -0
- package/src/plugins/browser-console.ts +30 -8
- package/src/plugins/network.ts +208 -267
- package/src/plugins/performance.ts +6 -22
- package/src/plugins/plugin-manager.ts +49 -31
- package/src/plugins/tracing.ts +8 -9
- package/src/push/bundler.ts +112 -0
- package/src/push/index.ts +282 -0
- package/src/push/kibana_api.ts +191 -0
- package/src/push/monitor.ts +276 -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 +183 -202
- 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 +8 -0
- package/templates/synthetics.config.ts +35 -0
- package/CHANGELOG.md +0 -131
- package/NOTICE.txt +0 -221
- package/dist/parse_args.d.ts.map +0 -1
- package/dist/parse_args.js +0 -95
- 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 -1888
- package/src/parse_args.ts +0 -135
package/src/core/logger.ts
CHANGED
|
@@ -23,20 +23,9 @@
|
|
|
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
|
-
const defaultFd = process.stdout.fd;
|
|
31
|
-
let logger = new SonicBoom({ fd: defaultFd, sync: true });
|
|
32
|
-
|
|
33
|
-
export const setLogger = (fd: number) => {
|
|
34
|
-
if (fd && fd !== defaultFd) {
|
|
35
|
-
logger = new SonicBoom({ fd });
|
|
36
|
-
}
|
|
37
|
-
return logger;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
29
|
export function log(msg) {
|
|
41
30
|
if (!process.env.DEBUG || !msg) {
|
|
42
31
|
return;
|
|
@@ -45,5 +34,5 @@ export function log(msg) {
|
|
|
45
34
|
msg = JSON.stringify(msg);
|
|
46
35
|
}
|
|
47
36
|
const time = dim(cyan(`at ${parseInt(String(now()))} ms `));
|
|
48
|
-
|
|
37
|
+
console.log(time + italic(grey(msg)) + '\n');
|
|
49
38
|
}
|
package/src/core/runner.ts
CHANGED
|
@@ -23,7 +23,6 @@
|
|
|
23
23
|
*
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import { once, EventEmitter } from 'events';
|
|
27
26
|
import { join } from 'path';
|
|
28
27
|
import { mkdir, rm, writeFile } from 'fs/promises';
|
|
29
28
|
import { Journey } from '../dsl/journey';
|
|
@@ -37,106 +36,50 @@ import {
|
|
|
37
36
|
generateUniqueId,
|
|
38
37
|
} from '../helpers';
|
|
39
38
|
import {
|
|
40
|
-
StatusValue,
|
|
41
39
|
HooksCallback,
|
|
42
40
|
Params,
|
|
43
|
-
PluginOutput,
|
|
44
|
-
CliArgs,
|
|
45
41
|
HooksArgs,
|
|
42
|
+
Driver,
|
|
43
|
+
Screenshot,
|
|
44
|
+
RunOptions,
|
|
45
|
+
JourneyResult,
|
|
46
|
+
StepResult,
|
|
46
47
|
} from '../common_types';
|
|
47
48
|
import { PluginManager } from '../plugins';
|
|
48
|
-
import { PerformanceManager
|
|
49
|
-
import {
|
|
49
|
+
import { PerformanceManager } from '../plugins';
|
|
50
|
+
import { Gatherer } from './gatherer';
|
|
50
51
|
import { log } from './logger';
|
|
52
|
+
import { Monitor, MonitorConfig } from '../dsl/monitor';
|
|
51
53
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
| 'debug'
|
|
55
|
-
| 'json'
|
|
56
|
-
| 'pattern'
|
|
57
|
-
| 'inline'
|
|
58
|
-
| 'require'
|
|
59
|
-
| 'suiteParams'
|
|
60
|
-
| 'reporter'
|
|
61
|
-
| 'richEvents'
|
|
62
|
-
| 'capability'
|
|
63
|
-
> & {
|
|
64
|
-
environment?: string;
|
|
65
|
-
params?: Params;
|
|
66
|
-
reporter?: CliArgs['reporter'] | Reporter;
|
|
67
|
-
};
|
|
54
|
+
type HookType = 'beforeAll' | 'afterAll';
|
|
55
|
+
export type SuiteHooks = Record<HookType, Array<HooksCallback>>;
|
|
68
56
|
|
|
69
|
-
type
|
|
57
|
+
type JourneyContext = {
|
|
70
58
|
params?: Params;
|
|
71
59
|
start: number;
|
|
72
|
-
end?: number;
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
type JourneyContext = BaseContext & {
|
|
76
60
|
driver: Driver;
|
|
77
61
|
pluginManager: PluginManager;
|
|
78
62
|
};
|
|
79
63
|
|
|
80
|
-
type StepResult = {
|
|
81
|
-
status: StatusValue;
|
|
82
|
-
url?: string;
|
|
83
|
-
metrics?: Metrics;
|
|
84
|
-
error?: Error;
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
type JourneyResult = {
|
|
88
|
-
status: StatusValue;
|
|
89
|
-
error?: Error;
|
|
90
|
-
};
|
|
91
|
-
|
|
92
64
|
type RunResult = Record<string, JourneyResult>;
|
|
93
65
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
start: { numJourneys: number };
|
|
99
|
-
'journey:register': {
|
|
100
|
-
journey: Journey;
|
|
101
|
-
};
|
|
102
|
-
'journey:start': {
|
|
103
|
-
journey: Journey;
|
|
104
|
-
timestamp: number;
|
|
105
|
-
params: Params;
|
|
106
|
-
};
|
|
107
|
-
'journey:end': BaseContext &
|
|
108
|
-
JourneyResult &
|
|
109
|
-
PluginOutput & {
|
|
110
|
-
journey: Journey;
|
|
111
|
-
options: RunOptions;
|
|
112
|
-
};
|
|
113
|
-
'journey:end:reported': unknown;
|
|
114
|
-
'step:start': { journey: Journey; step: Step };
|
|
115
|
-
'step:end': StepResult & {
|
|
116
|
-
start: number;
|
|
117
|
-
end: number;
|
|
118
|
-
journey: Journey;
|
|
119
|
-
step: Step;
|
|
120
|
-
};
|
|
121
|
-
end: unknown;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export default interface Runner {
|
|
125
|
-
on<K extends keyof Events>(name: K, listener: (v: Events[K]) => void): this;
|
|
126
|
-
emit<K extends keyof Events>(event: K, args: Events[K]): boolean;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
export default class Runner extends EventEmitter {
|
|
130
|
-
active = false;
|
|
131
|
-
currentJourney?: Journey = null;
|
|
66
|
+
export default class Runner {
|
|
67
|
+
#active = false;
|
|
68
|
+
#reporter: Reporter;
|
|
69
|
+
#currentJourney?: Journey = null;
|
|
132
70
|
journeys: Journey[] = [];
|
|
133
71
|
hooks: SuiteHooks = { beforeAll: [], afterAll: [] };
|
|
134
72
|
hookError: Error | undefined;
|
|
73
|
+
monitor?: Monitor;
|
|
135
74
|
static screenshotPath = join(CACHE_PATH, 'screenshots');
|
|
136
75
|
|
|
137
76
|
static async createContext(options: RunOptions): Promise<JourneyContext> {
|
|
138
|
-
const start = monotonicTimeInSeconds();
|
|
139
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();
|
|
140
83
|
const pluginManager = await Gatherer.beginRecording(driver, options);
|
|
141
84
|
/**
|
|
142
85
|
* For each journey we create the screenshots folder for
|
|
@@ -152,11 +95,11 @@ export default class Runner extends EventEmitter {
|
|
|
152
95
|
}
|
|
153
96
|
|
|
154
97
|
async captureScreenshot(page: Driver['page'], step: Step) {
|
|
155
|
-
await page.waitForLoadState('load');
|
|
156
98
|
const buffer = await page
|
|
157
99
|
.screenshot({
|
|
158
100
|
type: 'jpeg',
|
|
159
101
|
quality: 80,
|
|
102
|
+
timeout: 5000,
|
|
160
103
|
})
|
|
161
104
|
.catch(() => {});
|
|
162
105
|
/**
|
|
@@ -166,23 +109,50 @@ export default class Runner extends EventEmitter {
|
|
|
166
109
|
*/
|
|
167
110
|
if (buffer) {
|
|
168
111
|
const fileName = `${generateUniqueId()}.json`;
|
|
112
|
+
const screenshot: Screenshot = {
|
|
113
|
+
step,
|
|
114
|
+
timestamp: getTimestamp(),
|
|
115
|
+
data: buffer.toString('base64'),
|
|
116
|
+
};
|
|
169
117
|
await writeFile(
|
|
170
118
|
join(Runner.screenshotPath, fileName),
|
|
171
|
-
JSON.stringify(
|
|
172
|
-
step,
|
|
173
|
-
data: buffer.toString('base64'),
|
|
174
|
-
})
|
|
119
|
+
JSON.stringify(screenshot)
|
|
175
120
|
);
|
|
176
121
|
}
|
|
177
122
|
}
|
|
178
123
|
|
|
124
|
+
get currentJourney() {
|
|
125
|
+
return this.#currentJourney;
|
|
126
|
+
}
|
|
127
|
+
|
|
179
128
|
addHook(type: HookType, callback: HooksCallback) {
|
|
180
129
|
this.hooks[type].push(callback);
|
|
181
130
|
}
|
|
182
131
|
|
|
132
|
+
updateMonitor(config: MonitorConfig) {
|
|
133
|
+
if (!this.monitor) {
|
|
134
|
+
this.monitor = new Monitor(config);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
this.monitor.update(config);
|
|
138
|
+
}
|
|
139
|
+
|
|
183
140
|
addJourney(journey: Journey) {
|
|
184
141
|
this.journeys.push(journey);
|
|
185
|
-
this
|
|
142
|
+
this.#currentJourney = journey;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
setReporter(options: RunOptions) {
|
|
146
|
+
/**
|
|
147
|
+
* Set up the corresponding reporter and fallback
|
|
148
|
+
* to default reporter if not provided
|
|
149
|
+
*/
|
|
150
|
+
const { reporter, outfd } = options;
|
|
151
|
+
const Reporter =
|
|
152
|
+
typeof reporter === 'function'
|
|
153
|
+
? reporter
|
|
154
|
+
: reporters[reporter] || reporters['default'];
|
|
155
|
+
this.#reporter = new Reporter({ fd: outfd });
|
|
186
156
|
}
|
|
187
157
|
|
|
188
158
|
async runBeforeAllHook(args: HooksArgs) {
|
|
@@ -214,7 +184,7 @@ export default class Runner extends EventEmitter {
|
|
|
214
184
|
status: 'succeeded',
|
|
215
185
|
};
|
|
216
186
|
log(`Runner: start step (${step.name})`);
|
|
217
|
-
const { metrics, screenshots } = options;
|
|
187
|
+
const { metrics, screenshots, filmstrips, trace } = options;
|
|
218
188
|
const { driver, pluginManager } = context;
|
|
219
189
|
/**
|
|
220
190
|
* URL needs to be the first navigation request of any step
|
|
@@ -225,22 +195,49 @@ export default class Runner extends EventEmitter {
|
|
|
225
195
|
if (!data.url && req.isNavigationRequest()) {
|
|
226
196
|
data.url = req.url();
|
|
227
197
|
}
|
|
228
|
-
driver.
|
|
198
|
+
driver.context.off('request', captureUrl);
|
|
229
199
|
};
|
|
230
|
-
driver.
|
|
200
|
+
driver.context.on('request', captureUrl);
|
|
201
|
+
|
|
231
202
|
try {
|
|
203
|
+
/**
|
|
204
|
+
* Set up plugin manager context and also register
|
|
205
|
+
* step level plugins
|
|
206
|
+
*/
|
|
207
|
+
const traceEnabled = trace || filmstrips;
|
|
232
208
|
pluginManager.onStep(step);
|
|
209
|
+
traceEnabled && (await pluginManager.start('trace'));
|
|
210
|
+
// call the step definition
|
|
233
211
|
await step.callback();
|
|
212
|
+
/**
|
|
213
|
+
* Collect all step level metrics
|
|
214
|
+
*/
|
|
234
215
|
if (metrics) {
|
|
235
|
-
data.
|
|
216
|
+
data.pagemetrics = await (
|
|
217
|
+
pluginManager.get('performance') as PerformanceManager
|
|
218
|
+
).getMetrics();
|
|
219
|
+
}
|
|
220
|
+
if (traceEnabled) {
|
|
221
|
+
const traceOutput = await pluginManager.stop('trace');
|
|
222
|
+
Object.assign(data, traceOutput);
|
|
236
223
|
}
|
|
237
224
|
} catch (error) {
|
|
238
225
|
data.status = 'failed';
|
|
239
226
|
data.error = error;
|
|
240
227
|
} finally {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
228
|
+
/**
|
|
229
|
+
* Capture screenshot for the newly created pages
|
|
230
|
+
* via popup or new windows/tabs
|
|
231
|
+
*
|
|
232
|
+
* Last open page will get us the correct screenshot
|
|
233
|
+
*/
|
|
234
|
+
const pages = driver.context.pages();
|
|
235
|
+
const page = pages[pages.length - 1];
|
|
236
|
+
if (page) {
|
|
237
|
+
data.url ??= page.url();
|
|
238
|
+
if (screenshots && screenshots !== 'off') {
|
|
239
|
+
await this.captureScreenshot(page, step);
|
|
240
|
+
}
|
|
244
241
|
}
|
|
245
242
|
}
|
|
246
243
|
log(`Runner: end step (${step.name})`);
|
|
@@ -256,7 +253,7 @@ export default class Runner extends EventEmitter {
|
|
|
256
253
|
let skipStep = false;
|
|
257
254
|
for (const step of journey.steps) {
|
|
258
255
|
const start = monotonicTimeInSeconds();
|
|
259
|
-
this
|
|
256
|
+
this.#reporter?.onStepStart?.(journey, step);
|
|
260
257
|
let data: StepResult = { status: 'succeeded' };
|
|
261
258
|
if (skipStep) {
|
|
262
259
|
data.status = 'skipped';
|
|
@@ -267,9 +264,7 @@ export default class Runner extends EventEmitter {
|
|
|
267
264
|
*/
|
|
268
265
|
if (data.error) skipStep = true;
|
|
269
266
|
}
|
|
270
|
-
this
|
|
271
|
-
journey,
|
|
272
|
-
step,
|
|
267
|
+
this.#reporter?.onStepEnd?.(journey, step, {
|
|
273
268
|
start,
|
|
274
269
|
end: monotonicTimeInSeconds(),
|
|
275
270
|
...data,
|
|
@@ -283,12 +278,16 @@ export default class Runner extends EventEmitter {
|
|
|
283
278
|
}
|
|
284
279
|
|
|
285
280
|
registerJourney(journey: Journey, context: JourneyContext) {
|
|
286
|
-
this
|
|
281
|
+
this.#currentJourney = journey;
|
|
287
282
|
const timestamp = getTimestamp();
|
|
288
283
|
const { params } = context;
|
|
289
|
-
this
|
|
284
|
+
this.#reporter?.onJourneyStart?.(journey, {
|
|
285
|
+
timestamp,
|
|
286
|
+
params,
|
|
287
|
+
});
|
|
290
288
|
/**
|
|
291
|
-
*
|
|
289
|
+
* Exeucute the journey callback which would
|
|
290
|
+
* register the steps for the current journey
|
|
292
291
|
*/
|
|
293
292
|
journey.callback({ ...context.driver, params });
|
|
294
293
|
}
|
|
@@ -298,25 +297,19 @@ export default class Runner extends EventEmitter {
|
|
|
298
297
|
result: JourneyContext & JourneyResult,
|
|
299
298
|
options: RunOptions
|
|
300
299
|
) {
|
|
300
|
+
const end = monotonicTimeInSeconds();
|
|
301
301
|
const { pluginManager, start, status, error } = result;
|
|
302
302
|
const pluginOutput = await pluginManager.output();
|
|
303
|
-
this
|
|
304
|
-
journey,
|
|
303
|
+
await this.#reporter?.onJourneyEnd?.(journey, {
|
|
305
304
|
status,
|
|
306
305
|
error,
|
|
307
306
|
start,
|
|
308
|
-
end
|
|
307
|
+
end,
|
|
308
|
+
timestamp: getTimestamp(),
|
|
309
309
|
options,
|
|
310
310
|
...pluginOutput,
|
|
311
311
|
browserconsole: status == 'failed' ? pluginOutput.browserconsole : [],
|
|
312
312
|
});
|
|
313
|
-
/**
|
|
314
|
-
* Wait for the all the reported events to be consumed aschronously
|
|
315
|
-
* by reporter.
|
|
316
|
-
*/
|
|
317
|
-
if (options.reporter === 'json') {
|
|
318
|
-
await once(this, 'journey:end:reported');
|
|
319
|
-
}
|
|
320
313
|
// clear screenshots cache after each journey
|
|
321
314
|
await rm(Runner.screenshotPath, { recursive: true, force: true });
|
|
322
315
|
}
|
|
@@ -326,8 +319,7 @@ export default class Runner extends EventEmitter {
|
|
|
326
319
|
*/
|
|
327
320
|
async runFakeJourney(journey: Journey, options: RunOptions) {
|
|
328
321
|
const start = monotonicTimeInSeconds();
|
|
329
|
-
this.
|
|
330
|
-
journey,
|
|
322
|
+
this.#reporter.onJourneyStart?.(journey, {
|
|
331
323
|
timestamp: getTimestamp(),
|
|
332
324
|
params: options.params,
|
|
333
325
|
});
|
|
@@ -335,25 +327,20 @@ export default class Runner extends EventEmitter {
|
|
|
335
327
|
status: 'failed',
|
|
336
328
|
error: this.hookError,
|
|
337
329
|
};
|
|
338
|
-
this.
|
|
339
|
-
|
|
330
|
+
await this.#reporter.onJourneyEnd?.(journey, {
|
|
331
|
+
timestamp: getTimestamp(),
|
|
340
332
|
start,
|
|
341
333
|
options,
|
|
342
334
|
end: monotonicTimeInSeconds(),
|
|
343
335
|
...result,
|
|
344
336
|
});
|
|
345
|
-
if (options.reporter === 'json') {
|
|
346
|
-
await once(this, 'journey:end:reported');
|
|
347
|
-
}
|
|
348
337
|
return result;
|
|
349
338
|
}
|
|
350
339
|
|
|
351
340
|
async runJourney(journey: Journey, options: RunOptions) {
|
|
352
|
-
const result: JourneyResult = {
|
|
353
|
-
status: 'succeeded',
|
|
354
|
-
};
|
|
355
|
-
log(`Runner: start journey (${journey.name})`);
|
|
341
|
+
const result: JourneyResult = { status: 'succeeded' };
|
|
356
342
|
const context = await Runner.createContext(options);
|
|
343
|
+
log(`Runner: start journey (${journey.name})`);
|
|
357
344
|
try {
|
|
358
345
|
this.registerJourney(journey, context);
|
|
359
346
|
const hookArgs = {
|
|
@@ -384,28 +371,56 @@ export default class Runner extends EventEmitter {
|
|
|
384
371
|
}
|
|
385
372
|
|
|
386
373
|
async init(options: RunOptions) {
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
typeof reporter === 'function'
|
|
393
|
-
? reporter
|
|
394
|
-
: reporters[reporter] || reporters['default'];
|
|
395
|
-
new Reporter(this, { fd: outfd });
|
|
396
|
-
this.emit('start', { numJourneys: this.journeys.length });
|
|
374
|
+
this.setReporter(options);
|
|
375
|
+
this.#reporter.onStart?.({
|
|
376
|
+
numJourneys: this.journeys.length,
|
|
377
|
+
networkConditions: options.networkConditions,
|
|
378
|
+
});
|
|
397
379
|
/**
|
|
398
380
|
* Set up the directory for caching screenshots
|
|
399
381
|
*/
|
|
400
382
|
await mkdir(CACHE_PATH, { recursive: true });
|
|
401
383
|
}
|
|
402
384
|
|
|
385
|
+
buildMonitors(options: RunOptions) {
|
|
386
|
+
/**
|
|
387
|
+
* Update the global monitor configuration required for
|
|
388
|
+
* setting defaults
|
|
389
|
+
*/
|
|
390
|
+
this.updateMonitor({
|
|
391
|
+
throttling: options.throttling,
|
|
392
|
+
schedule: options.schedule,
|
|
393
|
+
locations: options.locations,
|
|
394
|
+
privateLocations: options.privateLocations,
|
|
395
|
+
params: options.params,
|
|
396
|
+
playwrightOptions: options.playwrightOptions,
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
const { match, tags } = options;
|
|
400
|
+
const monitors: Monitor[] = [];
|
|
401
|
+
for (const journey of this.journeys) {
|
|
402
|
+
if (!journey.isMatch(match, 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;
|
|
416
|
+
}
|
|
417
|
+
|
|
403
418
|
async run(options: RunOptions) {
|
|
404
419
|
const result: RunResult = {};
|
|
405
|
-
if (this
|
|
420
|
+
if (this.#active) {
|
|
406
421
|
return result;
|
|
407
422
|
}
|
|
408
|
-
this
|
|
423
|
+
this.#active = true;
|
|
409
424
|
log(`Runner: run ${this.journeys.length} journeys`);
|
|
410
425
|
this.init(options);
|
|
411
426
|
await this.runBeforeAllHook({
|
|
@@ -419,7 +434,7 @@ export default class Runner extends EventEmitter {
|
|
|
419
434
|
* Used by heartbeat to gather all registered journeys
|
|
420
435
|
*/
|
|
421
436
|
if (dryRun) {
|
|
422
|
-
this.
|
|
437
|
+
this.#reporter.onJourneyRegister?.(journey);
|
|
423
438
|
continue;
|
|
424
439
|
}
|
|
425
440
|
if (!journey.isMatch(match, tags)) {
|
|
@@ -440,14 +455,14 @@ export default class Runner extends EventEmitter {
|
|
|
440
455
|
}
|
|
441
456
|
|
|
442
457
|
async reset() {
|
|
458
|
+
this.#currentJourney = null;
|
|
459
|
+
this.journeys = [];
|
|
460
|
+
this.#active = false;
|
|
443
461
|
/**
|
|
444
462
|
* Clear all cache data stored for post processing by
|
|
445
463
|
* the current synthetic agent run
|
|
446
464
|
*/
|
|
447
465
|
await rm(CACHE_PATH, { recursive: true, force: true });
|
|
448
|
-
this
|
|
449
|
-
this.journeys = [];
|
|
450
|
-
this.active = false;
|
|
451
|
-
this.emit('end', {});
|
|
466
|
+
await this.#reporter?.onEnd?.();
|
|
452
467
|
}
|
|
453
468
|
}
|
|
@@ -0,0 +1,160 @@
|
|
|
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 { addHook } from 'pirates';
|
|
27
|
+
import {
|
|
28
|
+
transformSync,
|
|
29
|
+
Loader,
|
|
30
|
+
CommonOptions,
|
|
31
|
+
TransformOptions,
|
|
32
|
+
} from 'esbuild';
|
|
33
|
+
import path from 'path';
|
|
34
|
+
import sourceMapSupport from 'source-map-support';
|
|
35
|
+
|
|
36
|
+
// Cache that holds the sourcemap content for each file
|
|
37
|
+
const sourceMaps: Map<string, string> = new Map();
|
|
38
|
+
|
|
39
|
+
// Register the source-map-support library to resolve the sourcemaps
|
|
40
|
+
// for the files that are transpiled by esbuild
|
|
41
|
+
/**
|
|
42
|
+
* Register the source-map-support library to resolve the sourcemaps
|
|
43
|
+
* for the files that are transpiled by esbuild and cache the sourcemaps
|
|
44
|
+
* for each file.
|
|
45
|
+
*
|
|
46
|
+
* Caching the sourcemap file is important, as it is used by the Synthetics agent
|
|
47
|
+
* to resolve the stack traces of journey, monitor and step functions.
|
|
48
|
+
*/
|
|
49
|
+
sourceMapSupport.install({
|
|
50
|
+
environment: 'node',
|
|
51
|
+
handleUncaughtExceptions: false,
|
|
52
|
+
retrieveSourceMap(source) {
|
|
53
|
+
if (!sourceMaps.has(source)) return null;
|
|
54
|
+
return {
|
|
55
|
+
map: JSON.parse(sourceMaps.get(source)),
|
|
56
|
+
url: source,
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Default list of files and corresponding loaders we support
|
|
63
|
+
* while pushing project based monitors
|
|
64
|
+
*/
|
|
65
|
+
const LOADERS: Record<string, Loader> = {
|
|
66
|
+
'.ts': 'ts',
|
|
67
|
+
'.js': 'js',
|
|
68
|
+
'.mjs': 'js',
|
|
69
|
+
'.cjs': 'js',
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const getLoader = (filename: string) => {
|
|
73
|
+
const ext = path.extname(filename);
|
|
74
|
+
return LOADERS[ext] || 'default';
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
export function commonOptions(): CommonOptions {
|
|
78
|
+
/**
|
|
79
|
+
* We are not minifying the code as we want it to be in sync with previous
|
|
80
|
+
* transformation phase and introduce it later.
|
|
81
|
+
*/
|
|
82
|
+
return {
|
|
83
|
+
minify: false,
|
|
84
|
+
minifyIdentifiers: false,
|
|
85
|
+
minifySyntax: false,
|
|
86
|
+
minifyWhitespace: false,
|
|
87
|
+
sourcemap: 'both',
|
|
88
|
+
sourcesContent: false,
|
|
89
|
+
platform: 'node',
|
|
90
|
+
logLevel: 'silent',
|
|
91
|
+
format: 'cjs',
|
|
92
|
+
target: `node${process.version.slice(1)}`,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Transform the given code using esbuild and save the corresponding
|
|
98
|
+
* map file in memory to be retrived later.
|
|
99
|
+
*/
|
|
100
|
+
export function transform(
|
|
101
|
+
code: string,
|
|
102
|
+
filename: string,
|
|
103
|
+
options: TransformOptions = {}
|
|
104
|
+
) {
|
|
105
|
+
const result = transformSync(code, {
|
|
106
|
+
...commonOptions(),
|
|
107
|
+
sourcefile: filename,
|
|
108
|
+
loader: getLoader(filename),
|
|
109
|
+
/**
|
|
110
|
+
* Add this only for the transformation phase, using it on
|
|
111
|
+
* bundling phase would disable tree shaking and uncessary bloat
|
|
112
|
+
*
|
|
113
|
+
* Ensures backwards compatability with tsc's implicit strict behaviour
|
|
114
|
+
*/
|
|
115
|
+
tsconfigRaw: {
|
|
116
|
+
compilerOptions: {
|
|
117
|
+
alwaysStrict: true,
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
...options,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const warnings = result.warnings;
|
|
124
|
+
if (warnings && warnings.length > 0) {
|
|
125
|
+
for (const warning of warnings) {
|
|
126
|
+
console.log(warning.location);
|
|
127
|
+
console.log(warning.text);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Cache the sourcemap contents in memory, so we can look it up
|
|
133
|
+
* later when we try to resolve the sourcemap for a given file.
|
|
134
|
+
*
|
|
135
|
+
* Every time the synthetics agent is started, we register the source-map-support
|
|
136
|
+
* library to resolve the sourcemaps for the files that are transpiled by esbuild.
|
|
137
|
+
*/
|
|
138
|
+
if (result.map) {
|
|
139
|
+
sourceMaps.set(filename, result.map);
|
|
140
|
+
}
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Install the pirates hook to transform the code on the fly
|
|
146
|
+
* for all of the imported files.
|
|
147
|
+
*/
|
|
148
|
+
export function installTransform() {
|
|
149
|
+
const revertPirates = addHook(
|
|
150
|
+
(source: string, filename: string) => {
|
|
151
|
+
const { code } = transform(source, filename);
|
|
152
|
+
return code;
|
|
153
|
+
},
|
|
154
|
+
{ exts: ['.ts', '.js', '.mjs', '.cjs'] }
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
return () => {
|
|
158
|
+
revertPirates();
|
|
159
|
+
};
|
|
160
|
+
}
|