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