@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.
Files changed (220) hide show
  1. package/README.md +5 -4
  2. package/dist/cli.js +139 -165
  3. package/dist/cli.js.map +1 -1
  4. package/dist/common_types.d.ts +158 -34
  5. package/dist/common_types.d.ts.map +1 -1
  6. package/dist/config.d.ts +1 -0
  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 +5 -8
  18. package/dist/core/gatherer.d.ts.map +1 -1
  19. package/dist/core/gatherer.js +75 -17
  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 +10 -17
  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 +159 -92
  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 -7
  40. package/dist/dsl/journey.d.ts.map +1 -1
  41. package/dist/dsl/journey.js +32 -39
  42. package/dist/dsl/journey.js.map +1 -1
  43. package/dist/dsl/monitor.d.ts +93 -0
  44. package/dist/dsl/monitor.d.ts.map +1 -0
  45. package/dist/dsl/monitor.js +110 -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 +115 -0
  52. package/dist/formatter/javascript.d.ts.map +1 -0
  53. package/dist/formatter/javascript.js +331 -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 +36 -9
  64. package/dist/helpers.d.ts.map +1 -1
  65. package/dist/helpers.js +170 -24
  66. package/dist/helpers.js.map +1 -1
  67. package/dist/index.d.ts +5 -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 +153 -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 +42 -0
  84. package/dist/options.d.ts.map +1 -0
  85. package/dist/options.js +146 -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 +47 -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 +24 -31
  94. package/dist/plugins/network.d.ts.map +1 -1
  95. package/dist/plugins/network.js +226 -229
  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 +13 -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 +10 -0
  114. package/dist/push/index.d.ts.map +1 -0
  115. package/dist/push/index.js +235 -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 +55 -0
  122. package/dist/push/monitor.d.ts.map +1 -0
  123. package/dist/push/monitor.js +268 -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 +17 -62
  145. package/dist/reporters/json.d.ts.map +1 -1
  146. package/dist/reporters/json.js +147 -177
  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 +38 -30
  165. package/src/cli.ts +223 -158
  166. package/src/common_types.ts +191 -34
  167. package/src/config.ts +1 -1
  168. package/src/core/expect.ts +58 -24
  169. package/src/core/gatherer.ts +92 -25
  170. package/src/core/index.ts +36 -15
  171. package/src/core/logger.ts +8 -12
  172. package/src/core/runner.ts +158 -148
  173. package/src/core/transform.ts +160 -0
  174. package/src/dsl/journey.ts +41 -21
  175. package/src/dsl/monitor.ts +152 -0
  176. package/src/dsl/step.ts +9 -2
  177. package/src/formatter/javascript.ts +414 -0
  178. package/src/generator/index.ts +308 -0
  179. package/src/generator/utils.ts +84 -0
  180. package/src/helpers.ts +182 -16
  181. package/src/index.ts +21 -22
  182. package/src/loader.ts +171 -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 +175 -0
  186. package/src/plugins/browser-console.ts +33 -8
  187. package/src/plugins/network.ts +266 -284
  188. package/src/plugins/performance.ts +6 -22
  189. package/src/plugins/plugin-manager.ts +49 -31
  190. package/src/plugins/tracing.ts +11 -9
  191. package/src/push/bundler.ts +112 -0
  192. package/src/push/index.ts +291 -0
  193. package/src/push/kibana_api.ts +191 -0
  194. package/src/push/monitor.ts +307 -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 +181 -201
  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 +9 -0
  211. package/templates/synthetics.config.ts +35 -0
  212. package/CHANGELOG.md +0 -181
  213. package/NOTICE.txt +0 -221
  214. package/dist/parse_args.d.ts.map +0 -1
  215. package/dist/parse_args.js +0 -98
  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 -1895
  220. package/src/parse_args.ts +0 -146
@@ -23,12 +23,26 @@
23
23
  *
24
24
  */
25
25
 
26
- import { BrowserContextOptions, LaunchOptions } from 'playwright-chromium';
27
- import { Protocol } from 'playwright-chromium/types/protocol';
26
+ import {
27
+ BrowserContextOptions,
28
+ LaunchOptions,
29
+ CDPSession,
30
+ ChromiumBrowser,
31
+ ChromiumBrowserContext,
32
+ Page,
33
+ APIRequestContext,
34
+ } from 'playwright-chromium';
28
35
  import { Step } from './dsl';
29
- import { reporters } from './reporters';
36
+ import { BuiltInReporterName, ReporterInstance } from './reporters';
37
+ import { MonitorConfig } from './dsl/monitor';
30
38
 
31
39
  export type VoidCallback = () => void;
40
+ export type Location = {
41
+ file: string;
42
+ line: number;
43
+ column: number;
44
+ };
45
+
32
46
  export type Params = Record<string, any>;
33
47
  export type HooksArgs = {
34
48
  env: string;
@@ -36,7 +50,21 @@ export type HooksArgs = {
36
50
  };
37
51
  export type HooksCallback = (args: HooksArgs) => void;
38
52
  export type StatusValue = 'succeeded' | 'failed' | 'skipped';
39
- export type Reporters = keyof typeof reporters;
53
+
54
+ export type NetworkConditions = {
55
+ offline: boolean;
56
+ downloadThroughput: number;
57
+ uploadThroughput: number;
58
+ latency: number;
59
+ };
60
+
61
+ export type Driver = {
62
+ browser: ChromiumBrowser;
63
+ context: ChromiumBrowserContext;
64
+ page: Page;
65
+ client: CDPSession;
66
+ request: APIRequestContext;
67
+ };
40
68
 
41
69
  export type TraceOutput = {
42
70
  name: string;
@@ -74,26 +102,69 @@ export type BrowserInfo = {
74
102
  version: string;
75
103
  };
76
104
 
105
+ export type Screenshot = {
106
+ timestamp: number;
107
+ step: Step;
108
+ data: string;
109
+ };
110
+
111
+ export type SecurityDetails = {
112
+ issuer?: string;
113
+ protocol?: string;
114
+ subjectName?: string;
115
+ validFrom?: number;
116
+ validTo?: number;
117
+ };
118
+
119
+ export type Request = {
120
+ method: string;
121
+ url: string;
122
+ headers: Record<string, string>;
123
+ // Total size in bytes of the request (body and headers)
124
+ bytes?: number;
125
+ body?: {
126
+ // Size in bytes of the request body
127
+ bytes: number;
128
+ };
129
+ referrer?: string;
130
+ };
131
+
132
+ export type Response = {
133
+ url?: string;
134
+ status: number;
135
+ statusText?: string;
136
+ mimeType?: string;
137
+ headers: Record<string, string>;
138
+ // Total size in bytes of the response (body and headers)
139
+ bytes?: number;
140
+ body?: {
141
+ // Size in bytes of the response body
142
+ bytes: number;
143
+ };
144
+ transferSize?: number;
145
+ redirectURL?: string;
146
+ securityDetails?: SecurityDetails;
147
+ remoteIPAddress?: string;
148
+ remotePort?: number;
149
+ fromServiceWorker?: boolean;
150
+ };
151
+
77
152
  export type NetworkInfo = {
78
153
  url: string;
79
154
  browser: BrowserInfo;
80
- method: string;
81
155
  type: string;
82
- request: Protocol.Network.Request;
83
- response?: Protocol.Network.Response;
156
+ request: Request;
157
+ response: Response;
84
158
  isNavigationRequest: boolean;
85
159
  requestSentTime: number;
86
160
  loadEndTime: number;
87
161
  responseReceivedTime: number;
88
- status: number;
89
162
  resourceSize: number;
90
163
  transferSize: number;
91
- timings?: {
164
+ timings: {
92
165
  blocked: number;
93
- queueing: number;
94
166
  dns: number;
95
167
  ssl: number;
96
- proxy: number;
97
168
  connect: number;
98
169
  send: number;
99
170
  wait: number;
@@ -102,9 +173,12 @@ export type NetworkInfo = {
102
173
  };
103
174
  } & DefaultPluginOutput;
104
175
 
176
+ export type PageMetrics = Record<string, number>;
177
+
105
178
  export type BrowserMessage = {
106
179
  text: string;
107
180
  type: string;
181
+ error?: Error;
108
182
  } & DefaultPluginOutput;
109
183
 
110
184
  export type PluginOutput = {
@@ -117,39 +191,122 @@ export type PluginOutput = {
117
191
 
118
192
  export type ScreenshotOptions = 'on' | 'off' | 'only-on-failure';
119
193
 
120
- export type CliArgs = {
121
- capability?: Array<string>;
122
- config?: string;
123
- outfd?: number;
124
- headless?: boolean;
194
+ export type ThrottlingOptions = {
195
+ download?: number;
196
+ upload?: number;
197
+ latency?: number;
198
+ };
199
+
200
+ type BaseArgs = {
201
+ params?: Params;
125
202
  screenshots?: ScreenshotOptions;
126
- ssblocks?: boolean;
127
- metrics?: boolean;
128
- filmstrips?: boolean;
129
- trace?: boolean;
130
203
  dryRun?: boolean;
131
- network?: boolean;
132
- pauseOnError?: boolean;
133
- reporter?: Reporters;
204
+ match?: string;
205
+ tags?: Array<string>;
206
+ outfd?: number;
134
207
  wsEndpoint?: string;
208
+ pauseOnError?: boolean;
209
+ ignoreHttpsErrors?: boolean;
210
+ playwrightOptions?: PlaywrightOptions;
211
+ quietExitCode?: boolean;
212
+ throttling?: MonitorConfig['throttling'];
213
+ schedule?: MonitorConfig['schedule'];
214
+ locations?: MonitorConfig['locations'];
215
+ privateLocations?: MonitorConfig['privateLocations'];
216
+ };
217
+
218
+ export type CliArgs = BaseArgs & {
219
+ config?: string;
220
+ reporter?: BuiltInReporterName;
221
+ pattern?: string;
222
+ inline?: boolean;
223
+ require?: Array<string>;
135
224
  sandbox?: boolean;
136
- json?: boolean;
225
+ richEvents?: boolean;
226
+ capability?: Array<string>;
227
+ ignoreHttpsErrors?: boolean;
228
+ };
229
+
230
+ export type RunOptions = BaseArgs & {
231
+ metrics?: boolean;
232
+ ssblocks?: boolean;
233
+ network?: boolean;
234
+ trace?: boolean;
235
+ filmstrips?: boolean;
236
+ environment?: string;
237
+ playwrightOptions?: PlaywrightOptions;
238
+ networkConditions?: NetworkConditions;
239
+ reporter?: BuiltInReporterName | ReporterInstance;
240
+ };
241
+
242
+ export type PushOptions = Partial<ProjectSettings> & {
243
+ auth: string;
244
+ schedule?: MonitorConfig['schedule'];
245
+ locations?: MonitorConfig['locations'];
246
+ privateLocations?: MonitorConfig['privateLocations'];
247
+ yes?: boolean;
137
248
  pattern?: string;
138
- inline: boolean;
139
249
  match?: string;
140
250
  tags?: Array<string>;
141
- require: Array<string>;
142
- debug?: boolean;
143
- /**
144
- * @deprecated use `params` instead
145
- */
146
- suiteParams?: Params;
147
- params?: Params;
148
- richEvents?: boolean;
149
251
  };
150
252
 
151
- export type PlaywrightOptions = LaunchOptions & BrowserContextOptions;
253
+ export type ProjectSettings = {
254
+ id: string;
255
+ url: string;
256
+ space: string;
257
+ };
258
+
259
+ export type PlaywrightOptions = LaunchOptions &
260
+ BrowserContextOptions & {
261
+ testIdAttribute?: string;
262
+ actionTimeout?: number;
263
+ navigationTimeout?: number;
264
+ };
152
265
  export type SyntheticsConfig = {
153
266
  params?: Params;
154
267
  playwrightOptions?: PlaywrightOptions;
268
+ monitor?: MonitorConfig;
269
+ project?: ProjectSettings;
270
+ };
271
+
272
+ /** Runner Payload types */
273
+ export type JourneyResult = {
274
+ status: StatusValue;
275
+ error?: Error;
276
+ networkinfo?: PluginOutput['networkinfo'];
277
+ browserconsole?: PluginOutput['browserconsole'];
278
+ };
279
+
280
+ export type StepResult = {
281
+ status: StatusValue;
282
+ url?: string;
283
+ error?: Error;
284
+ pagemetrics?: PageMetrics;
285
+ filmstrips?: PluginOutput['filmstrips'];
286
+ metrics?: PluginOutput['metrics'];
287
+ traces?: PluginOutput['traces'];
288
+ };
289
+
290
+ /** Reporter and Runner contract */
291
+ export type StartEvent = {
292
+ numJourneys: number;
293
+ networkConditions?: NetworkConditions;
294
+ };
295
+
296
+ export type JourneyStartResult = {
297
+ timestamp: number;
298
+ params?: Params;
299
+ };
300
+
301
+ export type JourneyEndResult = JourneyStartResult &
302
+ JourneyResult & {
303
+ start: number;
304
+ end: number;
305
+ options: RunOptions;
306
+ timestamp: number;
307
+ };
308
+
309
+ export type StepEndResult = StepResult & {
310
+ start: number;
311
+ end: number;
155
312
  };
package/src/config.ts CHANGED
@@ -80,7 +80,7 @@ function getConfigFile(ext: string) {
80
80
  return 'synthetics.config' + ext;
81
81
  }
82
82
 
83
- function findSyntheticsConfig(resolvePath, cwd) {
83
+ export function findSyntheticsConfig(resolvePath, cwd) {
84
84
  const configPath = ['.js', '.ts']
85
85
  .map(ext => resolve(resolvePath, getConfigFile(ext)))
86
86
  .find(isFile);
@@ -28,6 +28,8 @@ import type {
28
28
  AsymmetricMatcher,
29
29
  MatcherState,
30
30
  ExpectedAssertionsErrors,
31
+ Inverse,
32
+ PromiseMatchers,
31
33
  } from 'expect/build/types';
32
34
 
33
35
  // Copied source code from expect/build/types.d.ts
@@ -61,99 +63,122 @@ declare global {
61
63
  /**
62
64
  * If you know how to test something, `.not` lets you test its opposite.
63
65
  */
64
- not: Matchers<R>;
66
+ not: Matchers<R> & Inverse<Matchers<R>> & PromiseMatchers;
65
67
  /**
66
68
  * Use resolves to unwrap the value of a fulfilled promise so any other
67
69
  * matcher can be chained. If the promise is rejected the assertion fails.
68
70
  */
69
- resolves: Matchers<Promise<R>>;
71
+ resolves: Matchers<R> & Inverse<Matchers<R>> & PromiseMatchers;
70
72
  /**
71
73
  * Unwraps the reason of a rejected promise so any other matcher can be chained.
72
74
  * If the promise is fulfilled the assertion fails.
73
75
  */
74
- rejects: Matchers<Promise<R>>;
76
+ rejects: Matchers<R> & Inverse<Matchers<R>> & PromiseMatchers;
75
77
  /**
76
78
  * Checks that a value is what you expect. It uses `===` to check strict equality.
77
79
  * Don't use `toBe` with floating-point numbers.
78
80
  */
79
- toBe(expected: unknown): R;
81
+ toBe(
82
+ expected: unknown
83
+ ): Matchers<R> & Inverse<Matchers<R>> & PromiseMatchers;
80
84
  /**
81
85
  * Using exact equality with floating point numbers is a bad idea.
82
86
  * Rounding means that intuitive things fail.
83
87
  * The default for numDigits is 2.
84
88
  */
85
- toBeCloseTo(expected: number, numDigits?: number): R;
89
+ toBeCloseTo(
90
+ expected: number,
91
+ numDigits?: number
92
+ ): Matchers<R> & Inverse<Matchers<R>> & PromiseMatchers;
86
93
  /**
87
94
  * Ensure that a variable is not undefined.
88
95
  */
89
- toBeDefined(): R;
96
+ toBeDefined(): Matchers<R> & Inverse<Matchers<R>> & PromiseMatchers;
90
97
  /**
91
98
  * When you don't care what a value is, you just want to
92
99
  * ensure a value is false in a boolean context.
93
100
  */
94
- toBeFalsy(): R;
101
+ toBeFalsy(): Matchers<R> & Inverse<Matchers<R>> & PromiseMatchers;
95
102
  /**
96
103
  * For comparing floating point numbers.
97
104
  */
98
- toBeGreaterThan(expected: number | bigint): R;
105
+ toBeGreaterThan(
106
+ expected: number | bigint
107
+ ): Matchers<R> & Inverse<Matchers<R>> & PromiseMatchers;
99
108
  /**
100
109
  * For comparing floating point numbers.
101
110
  */
102
- toBeGreaterThanOrEqual(expected: number | bigint): R;
111
+ toBeGreaterThanOrEqual(
112
+ expected: number | bigint
113
+ ): Matchers<R> & Inverse<Matchers<R>> & PromiseMatchers;
103
114
  /**
104
115
  * Ensure that an object is an instance of a class.
105
116
  * This matcher uses `instanceof` underneath.
106
117
  */
107
118
  /* eslint-disable-next-line */
108
- toBeInstanceOf(expected: Function): R;
119
+ toBeInstanceOf(
120
+ expected: unknown
121
+ ): Matchers<R> & Inverse<Matchers<R>> & PromiseMatchers;
109
122
  /**
110
123
  * For comparing floating point numbers.
111
124
  */
112
- toBeLessThan(expected: number | bigint): R;
125
+ toBeLessThan(
126
+ expected: number | bigint
127
+ ): Matchers<R> & Inverse<Matchers<R>> & PromiseMatchers;
113
128
  /**
114
129
  * For comparing floating point numbers.
115
130
  */
116
- toBeLessThanOrEqual(expected: number | bigint): R;
131
+ toBeLessThanOrEqual(
132
+ expected: number | bigint
133
+ ): Matchers<R> & Inverse<Matchers<R>> & PromiseMatchers;
117
134
  /**
118
135
  * This is the same as `.toBe(null)` but the error messages are a bit nicer.
119
136
  * So use `.toBeNull()` when you want to check that something is null.
120
137
  */
121
- toBeNull(): R;
138
+ toBeNull(): Matchers<R> & Inverse<Matchers<R>> & PromiseMatchers;
122
139
  /**
123
140
  * Use when you don't care what a value is, you just want to ensure a value
124
141
  * is true in a boolean context. In JavaScript, there are six falsy values:
125
142
  * `false`, `0`, `''`, `null`, `undefined`, and `NaN`. Everything else is truthy.
126
143
  */
127
- toBeTruthy(): R;
144
+ toBeTruthy(): Matchers<R> & Inverse<Matchers<R>> & PromiseMatchers;
128
145
  /**
129
146
  * Used to check that a variable is undefined.
130
147
  */
131
- toBeUndefined(): R;
148
+ toBeUndefined(): Matchers<R> & Inverse<Matchers<R>> & PromiseMatchers;
132
149
  /**
133
150
  * Used to check that a variable is NaN.
134
151
  */
135
- toBeNaN(): R;
152
+ toBeNaN(): Matchers<R> & Inverse<Matchers<R>> & PromiseMatchers;
136
153
  /**
137
154
  * Used when you want to check that an item is in a list.
138
155
  * For testing the items in the list, this uses `===`, a strict equality check.
139
156
  */
140
- toContain(expected: unknown): R;
157
+ toContain(
158
+ expected: unknown
159
+ ): Matchers<R> & Inverse<Matchers<R>> & PromiseMatchers;
141
160
  /**
142
161
  * Used when you want to check that an item is in a list.
143
162
  * For testing the items in the list, this matcher recursively checks the
144
163
  * equality of all fields, rather than checking for object identity.
145
164
  */
146
- toContainEqual(expected: unknown): R;
165
+ toContainEqual(
166
+ expected: unknown
167
+ ): Matchers<R> & Inverse<Matchers<R>> & PromiseMatchers;
147
168
  /**
148
169
  * Used when you want to check that two objects have the same value.
149
170
  * This matcher recursively checks the equality of all fields, rather than checking for object identity.
150
171
  */
151
- toEqual(expected: unknown): R;
172
+ toEqual(
173
+ expected: unknown
174
+ ): Matchers<R> & Inverse<Matchers<R>> & PromiseMatchers;
152
175
  /**
153
176
  * Used to check that an object has a `.length` property
154
177
  * and it is set to a certain numeric value.
155
178
  */
156
- toHaveLength(expected: number): R;
179
+ toHaveLength(
180
+ expected: number
181
+ ): Matchers<R> & Inverse<Matchers<R>> & PromiseMatchers;
157
182
  /**
158
183
  * Use to check if property at provided reference keyPath exists for an object.
159
184
  * For checking deeply nested properties in an object you may use dot notation or an array containing
@@ -167,19 +192,28 @@ declare global {
167
192
  *
168
193
  * expect(houseForSale).toHaveProperty('kitchen.area', 20);
169
194
  */
170
- toHaveProperty(keyPath: string | Array<string>, value?: unknown): R;
195
+ toHaveProperty(
196
+ keyPath: string | Array<string>,
197
+ value?: unknown
198
+ ): Matchers<R> & Inverse<Matchers<R>> & PromiseMatchers;
171
199
  /**
172
200
  * Check that a string matches a regular expression.
173
201
  */
174
- toMatch(expected: string | RegExp): R;
202
+ toMatch(
203
+ expected: string | RegExp
204
+ ): Matchers<R> & Inverse<Matchers<R>> & PromiseMatchers;
175
205
  /**
176
206
  * Used to check that a JavaScript object matches a subset of the properties of an object
177
207
  */
178
- toMatchObject(expected: Record<string, unknown> | Array<unknown>): R;
208
+ toMatchObject(
209
+ expected: Record<string, unknown> | Array<unknown>
210
+ ): Matchers<R> & Inverse<Matchers<R>> & PromiseMatchers;
179
211
  /**
180
212
  * Use to test that objects have the same types as well as structure.
181
213
  */
182
- toStrictEqual(expected: unknown): R;
214
+ toStrictEqual(
215
+ expected: unknown
216
+ ): Matchers<R> & Inverse<Matchers<R>> & PromiseMatchers;
183
217
  }
184
218
  }
185
219
  }
@@ -24,22 +24,18 @@
24
24
  */
25
25
 
26
26
  import {
27
- CDPSession,
28
27
  chromium,
29
28
  ChromiumBrowser,
30
- ChromiumBrowserContext,
31
- Page,
29
+ BrowserContext,
30
+ request as apiRequest,
31
+ selectors,
32
32
  } from 'playwright-chromium';
33
33
  import { PluginManager } from '../plugins';
34
- import { RunOptions } from './runner';
35
34
  import { log } from './logger';
35
+ import { Driver, NetworkConditions, RunOptions } from '../common_types';
36
36
 
37
- export type Driver = {
38
- browser: ChromiumBrowser;
39
- context: ChromiumBrowserContext;
40
- page: Page;
41
- client: CDPSession;
42
- };
37
+ // Default timeout for Playwright actions and Navigations
38
+ const DEFAULT_TIMEOUT = 50000;
43
39
 
44
40
  /**
45
41
  * Purpose of the Gatherer is to set up the necessary browser driver
@@ -49,19 +45,93 @@ export class Gatherer {
49
45
  static browser: ChromiumBrowser;
50
46
 
51
47
  static async setupDriver(options: RunOptions): Promise<Driver> {
48
+ log('Gatherer: setup driver');
52
49
  const { wsEndpoint, playwrightOptions } = options;
50
+
53
51
  if (Gatherer.browser == null) {
54
52
  if (wsEndpoint) {
55
53
  log(`Gatherer: connecting to WS endpoint: ${wsEndpoint}`);
56
- Gatherer.browser = await chromium.connect({ wsEndpoint });
54
+ Gatherer.browser = await chromium.connect(wsEndpoint);
57
55
  } else {
58
- Gatherer.browser = await chromium.launch(playwrightOptions);
56
+ Gatherer.browser = await chromium.launch({
57
+ ...playwrightOptions,
58
+ args: [
59
+ ...(playwrightOptions?.headless ? ['--disable-gpu'] : []),
60
+ ...(playwrightOptions?.args ?? []),
61
+ ],
62
+ });
59
63
  }
60
64
  }
61
- const context = await Gatherer.browser.newContext(playwrightOptions);
65
+ const context = await Gatherer.browser.newContext({
66
+ ...playwrightOptions,
67
+ userAgent: await Gatherer.getUserAgent(playwrightOptions?.userAgent),
68
+ });
69
+ // Set timeouts for actions and navigations
70
+ context.setDefaultTimeout(
71
+ playwrightOptions?.actionTimeout ?? DEFAULT_TIMEOUT
72
+ );
73
+ context.setDefaultNavigationTimeout(
74
+ playwrightOptions?.navigationTimeout ?? DEFAULT_TIMEOUT
75
+ );
76
+
77
+ // TODO: Network throttling via chrome devtools emulation is disabled for now.
78
+ // See docs/throttling.md for more details.
79
+ // Gatherer.setNetworkConditions(context, networkConditions);
80
+ if (playwrightOptions?.testIdAttribute) {
81
+ selectors.setTestIdAttribute(playwrightOptions.testIdAttribute);
82
+ }
83
+
62
84
  const page = await context.newPage();
63
85
  const client = await context.newCDPSession(page);
64
- return { browser: Gatherer.browser, context, page, client };
86
+ const request = await apiRequest.newContext({ ...playwrightOptions });
87
+
88
+ // Register sig int handler to close the browser
89
+ process.on('SIGINT', async () => {
90
+ await Gatherer.closeBrowser();
91
+ process.exit(130);
92
+ });
93
+ return { browser: Gatherer.browser, context, page, client, request };
94
+ }
95
+
96
+ static async getUserAgent(userAgent?: string) {
97
+ if (!userAgent) {
98
+ const session = await Gatherer.browser.newBrowserCDPSession();
99
+ ({ userAgent } = await session.send('Browser.getVersion'));
100
+ return userAgent + ' Elastic/Synthetics';
101
+ }
102
+ return userAgent;
103
+ }
104
+
105
+ static setNetworkConditions(
106
+ context: BrowserContext,
107
+ networkConditions: NetworkConditions
108
+ ) {
109
+ if (networkConditions) {
110
+ context.on('page', page => {
111
+ const context = page.context();
112
+ const emulatePromise = context
113
+ .newCDPSession(page)
114
+ .then(client =>
115
+ client.send('Network.emulateNetworkConditions', networkConditions)
116
+ );
117
+ /**
118
+ * Guard against pages that gets closed before the emulation kicks to capture
119
+ * unhandled rejections from accessing the CDP session of closed page
120
+ */
121
+ Promise.race([
122
+ new Promise<void>(resolve => page.on('close', () => resolve())),
123
+ emulatePromise,
124
+ ]);
125
+ });
126
+ }
127
+ }
128
+
129
+ static async closeBrowser() {
130
+ log(`Gatherer: closing browser`);
131
+ if (Gatherer.browser) {
132
+ await Gatherer.browser.close();
133
+ Gatherer.browser = null;
134
+ }
65
135
  }
66
136
 
67
137
  /**
@@ -70,26 +140,23 @@ export class Gatherer {
70
140
  */
71
141
  static async beginRecording(driver: Driver, options: RunOptions) {
72
142
  log('Gatherer: started recording');
73
- const { filmstrips, trace, network, metrics } = options;
143
+ const { network, metrics } = options;
74
144
  const pluginManager = new PluginManager(driver);
75
- const plugins = [pluginManager.start('browserconsole')];
76
- network && plugins.push(pluginManager.start('network'));
77
- metrics && plugins.push(pluginManager.start('performance'));
78
- if (filmstrips || trace) {
79
- plugins.push(pluginManager.start('trace', { filmstrips, trace }));
80
- }
145
+ pluginManager.registerAll(options);
146
+ const plugins = [await pluginManager.start('browserconsole')];
147
+ network && plugins.push(await pluginManager.start('network'));
148
+ metrics && plugins.push(await pluginManager.start('performance'));
81
149
  await Promise.all(plugins);
82
150
  return pluginManager;
83
151
  }
84
152
 
85
153
  static async dispose(driver: Driver) {
154
+ log(`Gatherer: closing all contexts`);
155
+ await driver.request.dispose();
86
156
  await driver.context.close();
87
157
  }
88
158
 
89
159
  static async stop() {
90
- if (Gatherer.browser) {
91
- await Gatherer.browser.close();
92
- Gatherer.browser = null;
93
- }
160
+ await Gatherer.closeBrowser();
94
161
  }
95
162
  }