@elastic/synthetics 1.0.0-beta.4 → 1.0.0-beta.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (220) hide show
  1. package/README.md +4 -3
  2. package/dist/cli.js +137 -160
  3. package/dist/cli.js.map +1 -1
  4. package/dist/common_types.d.ts +159 -31
  5. package/dist/common_types.d.ts.map +1 -1
  6. package/dist/config.d.ts +3 -5
  7. package/dist/config.d.ts.map +1 -1
  8. package/dist/config.js +7 -6
  9. package/dist/config.js.map +1 -1
  10. package/dist/core/browser-service.d.ts +1 -1
  11. package/dist/core/browser-service.d.ts.map +1 -1
  12. package/dist/core/browser-service.js +7 -6
  13. package/dist/core/browser-service.js.map +1 -1
  14. package/dist/core/expect.d.ts +25 -25
  15. package/dist/core/expect.d.ts.map +1 -1
  16. package/dist/core/expect.js.map +1 -1
  17. package/dist/core/gatherer.d.ts +4 -8
  18. package/dist/core/gatherer.d.ts.map +1 -1
  19. package/dist/core/gatherer.js +50 -15
  20. package/dist/core/gatherer.js.map +1 -1
  21. package/dist/core/index.d.ts +5 -1
  22. package/dist/core/index.d.ts.map +1 -1
  23. package/dist/core/index.js +23 -11
  24. package/dist/core/index.js.map +1 -1
  25. package/dist/core/logger.d.ts +0 -1
  26. package/dist/core/logger.d.ts.map +1 -1
  27. package/dist/core/logger.js +3 -16
  28. package/dist/core/logger.js.map +1 -1
  29. package/dist/core/runner.d.ts +12 -63
  30. package/dist/core/runner.d.ts.map +1 -1
  31. package/dist/core/runner.js +156 -90
  32. package/dist/core/runner.js.map +1 -1
  33. package/dist/core/transform.d.ts +37 -0
  34. package/dist/core/transform.d.ts.map +1 -0
  35. package/dist/core/transform.js +148 -0
  36. package/dist/core/transform.js.map +1 -0
  37. package/dist/dsl/index.js +5 -1
  38. package/dist/dsl/index.js.map +1 -1
  39. package/dist/dsl/journey.d.ts +9 -4
  40. package/dist/dsl/journey.d.ts.map +1 -1
  41. package/dist/dsl/journey.js +37 -9
  42. package/dist/dsl/journey.js.map +1 -1
  43. package/dist/dsl/monitor.d.ts +83 -0
  44. package/dist/dsl/monitor.d.ts.map +1 -0
  45. package/dist/dsl/monitor.js +108 -0
  46. package/dist/dsl/monitor.js.map +1 -0
  47. package/dist/dsl/step.d.ts +3 -2
  48. package/dist/dsl/step.d.ts.map +1 -1
  49. package/dist/dsl/step.js +6 -1
  50. package/dist/dsl/step.js.map +1 -1
  51. package/dist/formatter/javascript.d.ts +98 -0
  52. package/dist/formatter/javascript.d.ts.map +1 -0
  53. package/dist/formatter/javascript.js +298 -0
  54. package/dist/formatter/javascript.js.map +1 -0
  55. package/dist/generator/index.d.ts +24 -0
  56. package/dist/generator/index.d.ts.map +1 -0
  57. package/dist/generator/index.js +241 -0
  58. package/dist/generator/index.js.map +1 -0
  59. package/dist/{reporters/reporter.js → generator/utils.d.ts} +5 -3
  60. package/dist/generator/utils.d.ts.map +1 -0
  61. package/dist/generator/utils.js +84 -0
  62. package/dist/generator/utils.js.map +1 -0
  63. package/dist/helpers.d.ts +28 -3
  64. package/dist/helpers.d.ts.map +1 -1
  65. package/dist/helpers.js +152 -20
  66. package/dist/helpers.js.map +1 -1
  67. package/dist/index.d.ts +6 -7
  68. package/dist/index.d.ts.map +1 -1
  69. package/dist/index.js +5 -26
  70. package/dist/index.js.map +1 -1
  71. package/dist/loader.d.ts +34 -0
  72. package/dist/loader.d.ts.map +1 -0
  73. package/dist/loader.js +149 -0
  74. package/dist/loader.js.map +1 -0
  75. package/dist/locations/index.d.ts +45 -0
  76. package/dist/locations/index.d.ts.map +1 -0
  77. package/dist/locations/index.js +83 -0
  78. package/dist/locations/index.js.map +1 -0
  79. package/dist/{reporters/reporter.d.ts → locations/public-locations.d.ts} +12 -8
  80. package/dist/locations/public-locations.d.ts.map +1 -0
  81. package/dist/locations/public-locations.js +41 -0
  82. package/dist/locations/public-locations.js.map +1 -0
  83. package/dist/options.d.ts +41 -0
  84. package/dist/options.d.ts.map +1 -0
  85. package/dist/options.js +198 -0
  86. package/dist/options.js.map +1 -0
  87. package/dist/plugins/browser-console.d.ts +5 -4
  88. package/dist/plugins/browser-console.d.ts.map +1 -1
  89. package/dist/plugins/browser-console.js +44 -24
  90. package/dist/plugins/browser-console.js.map +1 -1
  91. package/dist/plugins/index.js +5 -1
  92. package/dist/plugins/index.js.map +1 -1
  93. package/dist/plugins/network.d.ts +20 -33
  94. package/dist/plugins/network.d.ts.map +1 -1
  95. package/dist/plugins/network.js +177 -216
  96. package/dist/plugins/network.js.map +1 -1
  97. package/dist/plugins/performance.d.ts +4 -19
  98. package/dist/plugins/performance.d.ts.map +1 -1
  99. package/dist/plugins/performance.js +6 -5
  100. package/dist/plugins/performance.js.map +1 -1
  101. package/dist/plugins/plugin-manager.d.ts +9 -5
  102. package/dist/plugins/plugin-manager.d.ts.map +1 -1
  103. package/dist/plugins/plugin-manager.js +46 -30
  104. package/dist/plugins/plugin-manager.js.map +1 -1
  105. package/dist/plugins/tracing.d.ts +6 -6
  106. package/dist/plugins/tracing.d.ts.map +1 -1
  107. package/dist/plugins/tracing.js +10 -7
  108. package/dist/plugins/tracing.js.map +1 -1
  109. package/dist/push/bundler.d.ts +35 -0
  110. package/dist/push/bundler.d.ts.map +1 -0
  111. package/dist/push/bundler.js +131 -0
  112. package/dist/push/bundler.js.map +1 -0
  113. package/dist/push/index.d.ts +9 -0
  114. package/dist/push/index.d.ts.map +1 -0
  115. package/dist/push/index.js +227 -0
  116. package/dist/push/index.js.map +1 -0
  117. package/dist/push/kibana_api.d.ts +56 -0
  118. package/dist/push/kibana_api.d.ts.map +1 -0
  119. package/dist/push/kibana_api.js +135 -0
  120. package/dist/push/kibana_api.js.map +1 -0
  121. package/dist/push/monitor.d.ts +51 -0
  122. package/dist/push/monitor.d.ts.map +1 -0
  123. package/dist/push/monitor.js +244 -0
  124. package/dist/push/monitor.js.map +1 -0
  125. package/dist/{parse_args.d.ts → push/plugin.d.ts} +9 -6
  126. package/dist/push/plugin.d.ts.map +1 -0
  127. package/dist/push/plugin.js +66 -0
  128. package/dist/push/plugin.js.map +1 -0
  129. package/dist/push/request.d.ts +45 -0
  130. package/dist/push/request.d.ts.map +1 -0
  131. package/dist/push/request.js +109 -0
  132. package/dist/push/request.js.map +1 -0
  133. package/dist/push/utils.d.ts +31 -0
  134. package/dist/push/utils.d.ts.map +1 -0
  135. package/dist/push/utils.js +64 -0
  136. package/dist/push/utils.js.map +1 -0
  137. package/dist/reporters/base.d.ts +14 -6
  138. package/dist/reporters/base.d.ts.map +1 -1
  139. package/dist/reporters/base.js +58 -50
  140. package/dist/reporters/base.js.map +1 -1
  141. package/dist/reporters/index.d.ts +18 -8
  142. package/dist/reporters/index.d.ts.map +1 -1
  143. package/dist/reporters/index.js.map +1 -1
  144. package/dist/reporters/json.d.ts +18 -62
  145. package/dist/reporters/json.d.ts.map +1 -1
  146. package/dist/reporters/json.js +149 -179
  147. package/dist/reporters/json.js.map +1 -1
  148. package/dist/reporters/junit.d.ts +7 -1
  149. package/dist/reporters/junit.d.ts.map +1 -1
  150. package/dist/reporters/junit.js +90 -95
  151. package/dist/reporters/junit.js.map +1 -1
  152. package/dist/sdk/lh-trace-processor.d.ts +35 -9
  153. package/dist/sdk/lh-trace-processor.d.ts.map +1 -1
  154. package/dist/sdk/lh-trace-processor.js +114 -53
  155. package/dist/sdk/lh-trace-processor.js.map +1 -1
  156. package/dist/sdk/trace-metrics.d.ts +4 -4
  157. package/dist/sdk/trace-metrics.d.ts.map +1 -1
  158. package/dist/sdk/trace-metrics.js +3 -4
  159. package/dist/sdk/trace-metrics.js.map +1 -1
  160. package/dist/sdk/trace-processor.d.ts +11 -3
  161. package/dist/sdk/trace-processor.d.ts.map +1 -1
  162. package/dist/sdk/trace-processor.js +17 -9
  163. package/dist/sdk/trace-processor.js.map +1 -1
  164. package/package.json +39 -24
  165. package/src/cli.ts +219 -151
  166. package/src/common_types.ts +192 -31
  167. package/src/config.ts +3 -6
  168. package/src/core/expect.ts +58 -24
  169. package/src/core/gatherer.ts +59 -24
  170. package/src/core/index.ts +36 -15
  171. package/src/core/logger.ts +1 -12
  172. package/src/core/runner.ts +151 -136
  173. package/src/core/transform.ts +160 -0
  174. package/src/dsl/journey.ts +39 -6
  175. package/src/dsl/monitor.ts +140 -0
  176. package/src/dsl/step.ts +9 -2
  177. package/src/formatter/javascript.ts +367 -0
  178. package/src/generator/index.ts +308 -0
  179. package/src/generator/utils.ts +84 -0
  180. package/src/helpers.ts +159 -13
  181. package/src/index.ts +22 -22
  182. package/src/loader.ts +167 -0
  183. package/src/locations/index.ts +95 -0
  184. package/src/{reporters/reporter.ts → locations/public-locations.ts} +12 -9
  185. package/src/options.ts +227 -0
  186. package/src/plugins/browser-console.ts +30 -8
  187. package/src/plugins/network.ts +208 -267
  188. package/src/plugins/performance.ts +6 -22
  189. package/src/plugins/plugin-manager.ts +49 -31
  190. package/src/plugins/tracing.ts +8 -9
  191. package/src/push/bundler.ts +112 -0
  192. package/src/push/index.ts +282 -0
  193. package/src/push/kibana_api.ts +191 -0
  194. package/src/push/monitor.ts +276 -0
  195. package/src/push/plugin.ts +66 -0
  196. package/src/push/request.ts +141 -0
  197. package/src/push/utils.ts +77 -0
  198. package/src/reporters/base.ts +63 -52
  199. package/src/reporters/index.ts +26 -3
  200. package/src/reporters/json.ts +188 -202
  201. package/src/reporters/junit.ts +98 -93
  202. package/src/sdk/lh-trace-processor.ts +132 -68
  203. package/src/sdk/trace-metrics.ts +8 -4
  204. package/src/sdk/trace-processor.ts +28 -13
  205. package/templates/.github/workflows/run-synthetics.yml +27 -0
  206. package/templates/README.md +21 -0
  207. package/templates/journeys/advanced-example-helpers.ts +54 -0
  208. package/templates/journeys/advanced-example.journey.ts +43 -0
  209. package/templates/journeys/example.journey.ts +18 -0
  210. package/templates/lightweight/heartbeat.yml +7 -0
  211. package/templates/synthetics.config.ts +35 -0
  212. package/CHANGELOG.md +0 -131
  213. package/NOTICE.txt +0 -221
  214. package/dist/parse_args.d.ts.map +0 -1
  215. package/dist/parse_args.js +0 -95
  216. package/dist/parse_args.js.map +0 -1
  217. package/dist/reporters/reporter.d.ts.map +0 -1
  218. package/dist/reporters/reporter.js.map +0 -1
  219. package/dist/tsconfig.tsbuildinfo +0 -1888
  220. package/src/parse_args.ts +0 -135
@@ -40,12 +40,19 @@ import { Journey, Step } from '../dsl';
40
40
  import snakeCaseKeys from 'snakecase-keys';
41
41
  import {
42
42
  NetworkInfo,
43
+ SecurityDetails,
44
+ NetworkConditions,
43
45
  TraceOutput,
44
46
  StatusValue,
45
47
  PerfMetrics,
48
+ Params,
49
+ Screenshot,
50
+ StartEvent,
51
+ JourneyStartResult,
52
+ StepEndResult,
53
+ JourneyEndResult,
54
+ PageMetrics,
46
55
  } from '../common_types';
47
- import { Protocol } from 'playwright-chromium/types/protocol';
48
- import { Metrics } from '../plugins';
49
56
 
50
57
  /* eslint-disable @typescript-eslint/no-var-requires */
51
58
  const { version, name } = require('../../package.json');
@@ -57,11 +64,11 @@ type OutputType =
57
64
  | 'screenshot/block'
58
65
  | 'step/screenshot_ref'
59
66
  | 'step/screenshot'
67
+ | 'step/metrics'
68
+ | 'step/filmstrips'
60
69
  | 'step/end'
61
70
  | 'journey/network_info'
62
- | 'journey/filmstrips'
63
71
  | 'journey/browserconsole'
64
- | 'journey/metrics'
65
72
  | 'journey/end';
66
73
 
67
74
  type Payload = {
@@ -69,12 +76,13 @@ type Payload = {
69
76
  start?: number;
70
77
  end?: number;
71
78
  url?: string;
72
- status?: StatusValue | number;
73
- metrics?: Metrics;
74
- params?: Record<string, unknown>;
79
+ status?: StatusValue;
80
+ pagemetrics?: PageMetrics;
81
+ params?: Params;
75
82
  type?: OutputType;
76
83
  text?: string;
77
84
  index?: number;
85
+ network_conditions?: NetworkConditions;
78
86
  };
79
87
 
80
88
  type OutputFields = {
@@ -90,7 +98,7 @@ type OutputFields = {
90
98
  };
91
99
  error?: Error;
92
100
  root_fields?: Record<string, unknown>;
93
- payload?: Payload | NetworkInfo;
101
+ payload?: Payload;
94
102
  blob?: string;
95
103
  blob_mime?: string;
96
104
  };
@@ -112,13 +120,6 @@ type ScreenshotReference = {
112
120
  }>;
113
121
  };
114
122
 
115
- type ScreenshotOutput = {
116
- step: Step;
117
- blob_mime: string;
118
- blocks: Array<ScreenshotBlob>;
119
- reference: ScreenshotReference;
120
- };
121
-
122
123
  function getMetadata() {
123
124
  return {
124
125
  os: {
@@ -131,56 +132,12 @@ function getMetadata() {
131
132
  };
132
133
  }
133
134
 
134
- function formatVersion(protocol: string | undefined) {
135
- if (!protocol) {
136
- return;
137
- }
138
- if (protocol === 'h2') {
139
- return 2;
140
- } else if (protocol === 'http/1.1') {
141
- return 1.1;
142
- } else if (protocol === 'http/1.0') {
143
- return 1.0;
144
- } else if (protocol.startsWith('h3')) {
145
- return 3;
146
- }
147
- }
148
-
149
- function formatRequest(request: Protocol.Network.Request) {
150
- const postData = request.postData ? request.postData : '';
151
- return {
152
- ...request,
153
- body: {
154
- bytes: postData.length,
155
- content: postData,
156
- },
157
- referrer: request.headers?.Referer,
158
- };
159
- }
160
-
161
- function formatResponse(response: Protocol.Network.Response) {
162
- if (!response) {
135
+ function formatTLS(tls: SecurityDetails) {
136
+ if (!tls || !tls.protocol) {
163
137
  return;
164
138
  }
165
- return {
166
- ...response,
167
- body: {
168
- bytes: response.encodedDataLength,
169
- },
170
- status_code: response.status,
171
- };
172
- }
173
-
174
- function formatTLS(tls: Protocol.Network.SecurityDetails) {
175
- if (!tls) {
176
- return;
177
- }
178
- const cipher = `${tls.keyExchange ? tls.keyExchange + '_' : ''}${
179
- tls.cipher
180
- }_${tls.keyExchangeGroup}`;
181
139
  const [name, version] = tls.protocol.toLowerCase().split(' ');
182
140
  return {
183
- cipher,
184
141
  server: {
185
142
  x509: {
186
143
  issuer: {
@@ -194,7 +151,7 @@ function formatTLS(tls: Protocol.Network.SecurityDetails) {
194
151
  },
195
152
  },
196
153
  version_protocol: name,
197
- version: version,
154
+ version,
198
155
  };
199
156
  }
200
157
 
@@ -209,17 +166,14 @@ export function formatNetworkFields(network: NetworkInfo) {
209
166
  original: request.headers?.['User-Agent'],
210
167
  },
211
168
  http: {
212
- version: formatVersion(response?.protocol),
213
- request: formatRequest(request),
214
- response: formatResponse(response),
169
+ request,
170
+ response,
215
171
  },
216
172
  tls: formatTLS(response?.securityDetails),
217
173
  };
218
174
 
219
175
  const pickItems: Array<keyof NetworkInfo> = [
220
176
  'browser',
221
- 'status',
222
- 'method',
223
177
  'type',
224
178
  'isNavigationRequest',
225
179
  'requestSentTime',
@@ -270,8 +224,7 @@ function stepInfo(
270
224
  }
271
225
 
272
226
  export async function getScreenshotBlocks(screenshot: Buffer) {
273
- const img = sharp(screenshot, { sequentialRead: true });
274
- const { width, height } = await img.metadata();
227
+ const { width, height } = await sharp(screenshot).metadata();
275
228
  /**
276
229
  * Chop the screenshot image (1280*720) which is the default
277
230
  * viewport size in to 64 equal blocks for a given image
@@ -281,8 +234,8 @@ export async function getScreenshotBlocks(screenshot: Buffer) {
281
234
  * optimal for caching in the ES and proved out to be bad, so we stick to 8
282
235
  */
283
236
  const divisions = 8;
284
- const blockWidth = width / divisions;
285
- const blockHeight = height / divisions;
237
+ const blockWidth = Math.floor(width / divisions);
238
+ const blockHeight = Math.floor(height / divisions);
286
239
  const reference: ScreenshotReference = {
287
240
  width,
288
241
  height,
@@ -294,7 +247,9 @@ export async function getScreenshotBlocks(screenshot: Buffer) {
294
247
  const top = row * blockHeight;
295
248
  for (let col = 0; col < divisions; col++) {
296
249
  const left = col * blockWidth;
297
- const buf = await img
250
+ // We create a new sharp instance for each block to avoid
251
+ // running in to extraction/orientation issues
252
+ const buf = await sharp(screenshot, { sequentialRead: true })
298
253
  .extract({ top, left, width: blockWidth, height: blockHeight })
299
254
  .jpeg()
300
255
  .toBuffer();
@@ -330,14 +285,14 @@ export async function getScreenshotBlocks(screenshot: Buffer) {
330
285
  */
331
286
  export async function gatherScreenshots(
332
287
  screenshotsPath: string,
333
- callback: (step: Step, data: string) => Promise<void>
288
+ callback: (data: Screenshot) => Promise<void>
334
289
  ) {
335
290
  if (isDirectory(screenshotsPath)) {
336
291
  await totalist(screenshotsPath, async (_, absPath) => {
337
292
  try {
338
293
  const content = readFileSync(absPath, 'utf8');
339
- const { step, data } = JSON.parse(content);
340
- await callback(step, data);
294
+ const screenshot: Screenshot = JSON.parse(content);
295
+ await callback(screenshot);
341
296
  } catch (_) {
342
297
  // TODO: capture progarammatic synthetic errors under different type
343
298
  }
@@ -346,166 +301,194 @@ export async function gatherScreenshots(
346
301
  }
347
302
 
348
303
  export default class JSONReporter extends BaseReporter {
349
- _registerListeners() {
304
+ onStart(params: StartEvent) {
350
305
  /**
351
306
  * report the number of journeys that exists on a suite which
352
307
  * could be used for better sharding
353
308
  */
354
- this.runner.on('start', ({ numJourneys }) => {
355
- this.writeJSON({
356
- type: 'synthetics/metadata',
357
- root_fields: {
358
- num_journeys: numJourneys,
359
- },
360
- });
309
+ this.writeJSON({
310
+ type: 'synthetics/metadata',
311
+ root_fields: {
312
+ num_journeys: params.numJourneys,
313
+ },
314
+ payload: params.networkConditions
315
+ ? {
316
+ network_conditions: params.networkConditions,
317
+ }
318
+ : undefined,
361
319
  });
320
+ }
362
321
 
363
- this.runner.on('journey:register', ({ journey }) => {
364
- this.writeJSON({
365
- type: 'journey/register',
366
- journey,
367
- });
322
+ onJourneyRegister(journey: Journey): void {
323
+ this.writeJSON({
324
+ type: 'journey/register',
325
+ journey,
368
326
  });
327
+ }
369
328
 
370
- this.runner.on('journey:start', ({ journey, timestamp, params }) => {
371
- this.writeJSON({
372
- type: 'journey/start',
373
- journey,
374
- timestamp,
375
- payload: { params, source: journey.callback.toString() },
376
- });
329
+ override onJourneyStart(
330
+ journey: Journey,
331
+ { timestamp, params }: JourneyStartResult
332
+ ) {
333
+ this.writeJSON({
334
+ type: 'journey/start',
335
+ journey,
336
+ timestamp,
337
+ payload: { params, source: journey.callback.toString() },
377
338
  });
339
+ }
378
340
 
379
- this.runner.on(
380
- 'step:end',
381
- ({ journey, step, start, end, error, url, status, metrics }) => {
341
+ override onStepEnd(
342
+ journey: Journey,
343
+ step: Step,
344
+ {
345
+ start,
346
+ end,
347
+ error,
348
+ url,
349
+ status,
350
+ pagemetrics,
351
+ traces,
352
+ metrics,
353
+ filmstrips,
354
+ }: StepEndResult
355
+ ) {
356
+ this.writeMetrics(journey, step, 'relative_trace', traces);
357
+ this.writeMetrics(journey, step, 'experience', metrics);
358
+ if (filmstrips) {
359
+ // Write each filmstrip separately so that we don't get documents that are too large
360
+ filmstrips.forEach((strip, index) => {
382
361
  this.writeJSON({
383
- type: 'step/end',
362
+ type: 'step/filmstrips',
384
363
  journey,
385
- step: {
386
- ...step,
387
- duration: {
388
- us: getDurationInUs(end - start),
389
- },
390
- },
391
- url,
392
- error,
393
- payload: {
394
- source: step.callback.toString(),
395
- url,
396
- status,
397
- metrics,
364
+ step,
365
+ payload: { index },
366
+ root_fields: {
367
+ browser: { relative_trace: { start: strip.start } },
398
368
  },
369
+ blob: strip.blob,
370
+ blob_mime: strip.mime,
399
371
  });
400
- }
401
- );
372
+ });
373
+ }
402
374
 
403
- this.runner.on(
404
- 'journey:end',
405
- async ({
406
- journey,
407
- start,
408
- end,
409
- filmstrips,
410
- networkinfo,
411
- browserconsole,
412
- traces,
413
- metrics,
375
+ this.writeJSON({
376
+ type: 'step/end',
377
+ journey,
378
+ step: {
379
+ ...step,
380
+ duration: {
381
+ us: getDurationInUs(end - start),
382
+ },
383
+ },
384
+ url,
385
+ error,
386
+ payload: {
387
+ source: step.callback.toString(),
388
+ url,
414
389
  status,
415
- error,
416
- options,
417
- }) => {
418
- const { ssblocks, screenshots } = options;
419
- const writeScreenshots =
420
- screenshots === 'on' ||
421
- (screenshots === 'only-on-failure' && status === 'failed');
422
- if (writeScreenshots) {
423
- await gatherScreenshots(
424
- join(CACHE_PATH, 'screenshots'),
425
- async (step, data) => {
426
- if (!data) {
427
- return;
428
- }
429
- if (ssblocks) {
430
- await this.writeScreenshotBlocks(journey, step, data);
431
- } else {
432
- this.writeJSON({
433
- type: 'step/screenshot',
434
- journey,
435
- step,
436
- blob: data,
437
- blob_mime: 'image/jpeg',
438
- });
439
- }
440
- }
441
- );
442
- }
390
+ pagemetrics,
391
+ },
392
+ });
393
+ }
443
394
 
444
- if (networkinfo) {
445
- networkinfo.forEach(ni => {
446
- const { ecs, payload } = formatNetworkFields(ni);
447
- this.writeJSON({
448
- type: 'journey/network_info',
449
- journey,
450
- timestamp: ni.timestamp,
451
- root_fields: snakeCaseKeys(ecs),
452
- step: ni.step,
453
- payload: snakeCaseKeys(payload),
454
- });
455
- });
456
- }
457
- if (filmstrips) {
458
- // Write each filmstrip separately so that we don't get documents that are too large
459
- filmstrips.forEach((strip, index) => {
460
- this.writeJSON({
461
- type: 'journey/filmstrips',
462
- journey,
463
- payload: { index },
464
- root_fields: {
465
- browser: { relative_trace: { start: strip.start } },
466
- },
467
- blob: strip.blob,
468
- blob_mime: strip.mime,
469
- });
470
- });
471
- }
472
- if (browserconsole) {
473
- browserconsole.forEach(({ timestamp, text, type, step }) => {
395
+ override async onJourneyEnd(
396
+ journey: Journey,
397
+ {
398
+ timestamp,
399
+ start,
400
+ end,
401
+ networkinfo,
402
+ browserconsole,
403
+ status,
404
+ error,
405
+ options,
406
+ }: JourneyEndResult
407
+ ) {
408
+ const { ssblocks, screenshots } = options;
409
+ const writeScreenshots =
410
+ screenshots === 'on' ||
411
+ (screenshots === 'only-on-failure' && status === 'failed');
412
+ if (writeScreenshots) {
413
+ await gatherScreenshots(
414
+ join(CACHE_PATH, 'screenshots'),
415
+ async screenshot => {
416
+ const { data, timestamp, step } = screenshot;
417
+ if (!data) {
418
+ return;
419
+ }
420
+ if (ssblocks) {
421
+ await this.writeScreenshotBlocks(journey, screenshot);
422
+ } else {
474
423
  this.writeJSON({
475
- type: 'journey/browserconsole',
476
- journey,
424
+ type: 'step/screenshot',
477
425
  timestamp,
426
+ journey,
478
427
  step,
479
- payload: { text, type } as Payload,
428
+ blob: data,
429
+ blob_mime: 'image/jpeg',
480
430
  });
481
- });
431
+ }
482
432
  }
483
- this.writeMetrics(journey, 'relative_trace', traces);
484
- this.writeMetrics(journey, 'experience', metrics);
433
+ );
434
+ }
435
+
436
+ if (networkinfo) {
437
+ networkinfo.forEach(ni => {
438
+ const { ecs, payload } = formatNetworkFields(ni);
439
+ this.writeJSON({
440
+ type: 'journey/network_info',
441
+ journey,
442
+ timestamp: ni.timestamp,
443
+ root_fields: snakeCaseKeys(ecs),
444
+ step: ni.step,
445
+ payload: snakeCaseKeys(payload),
446
+ });
447
+ });
448
+ }
485
449
 
450
+ if (browserconsole) {
451
+ browserconsole.forEach(({ timestamp, text, type, step, error }) => {
486
452
  this.writeJSON({
487
- type: 'journey/end',
453
+ type: 'journey/browserconsole',
488
454
  journey,
455
+ timestamp,
456
+ step,
489
457
  error,
490
458
  payload: {
491
- start,
492
- end,
493
- status,
494
- },
459
+ text,
460
+ type,
461
+ } as Payload,
495
462
  });
496
- process.nextTick(() => this.runner.emit('journey:end:reported', {}));
497
- }
498
- );
463
+ });
464
+ }
465
+
466
+ this.writeJSON({
467
+ type: 'journey/end',
468
+ journey,
469
+ timestamp,
470
+ error,
471
+ payload: {
472
+ start,
473
+ end,
474
+ status,
475
+ },
476
+ });
477
+ }
478
+
479
+ override onEnd() {
480
+ this.stream.flushSync();
499
481
  }
500
482
 
501
- async writeScreenshotBlocks(journey: Journey, step: Step, data: string) {
483
+ async writeScreenshotBlocks(journey: Journey, screenshot: Screenshot) {
502
484
  const { blob_mime, blocks, reference } = await getScreenshotBlocks(
503
- Buffer.from(data, 'base64')
485
+ Buffer.from(screenshot.data, 'base64')
504
486
  );
505
487
  for (let i = 0; i < blocks.length; i++) {
506
488
  const block = blocks[i];
507
489
  this.writeJSON({
508
490
  type: 'screenshot/block',
491
+ timestamp: screenshot.timestamp,
509
492
  _id: block.id,
510
493
  blob: block.blob,
511
494
  blob_mime,
@@ -513,8 +496,9 @@ export default class JSONReporter extends BaseReporter {
513
496
  }
514
497
  this.writeJSON({
515
498
  type: 'step/screenshot_ref',
499
+ timestamp: screenshot.timestamp,
516
500
  journey,
517
- step,
501
+ step: screenshot.step,
518
502
  root_fields: {
519
503
  screenshot_ref: reference,
520
504
  },
@@ -523,6 +507,7 @@ export default class JSONReporter extends BaseReporter {
523
507
 
524
508
  writeMetrics(
525
509
  journey: Journey,
510
+ step: Step,
526
511
  type: string,
527
512
  events: Array<TraceOutput> | PerfMetrics
528
513
  ) {
@@ -530,8 +515,9 @@ export default class JSONReporter extends BaseReporter {
530
515
  metrics.forEach(event => {
531
516
  event &&
532
517
  this.writeJSON({
533
- type: 'journey/metrics',
518
+ type: 'step/metrics',
534
519
  journey,
520
+ step,
535
521
  root_fields: {
536
522
  browser: {
537
523
  [type]: event,
@@ -541,7 +527,7 @@ export default class JSONReporter extends BaseReporter {
541
527
  });
542
528
  }
543
529
 
544
- // Writes a structered synthetics event
530
+ // Writes a structured synthetics event
545
531
  // Note that blob is ultimately stored in ES as a base64 encoded string. You must base 64 encode
546
532
  // it before passing it into this function!
547
533
  // The payload field is an un-indexed field with no ES mapping, so users can put arbitary structured