cypress 5.6.0 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -12,7 +12,7 @@ After installing you'll be able to:
12
12
 
13
13
  ## Install
14
14
 
15
- Requires Node version >= 4.0.0
15
+ Requires Node version >= 10.0.0
16
16
 
17
17
  ```sh
18
18
  npm install --save-dev cypress
package/lib/cli.js CHANGED
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
 
3
+ // @ts-check
3
4
  const _ = require('lodash');
4
5
 
5
6
  const R = require('ramda');
@@ -156,11 +157,58 @@ function includesVersion(args) {
156
157
  return _.includes(args, 'version') || _.includes(args, '--version') || _.includes(args, '-v');
157
158
  }
158
159
 
159
- function showVersions() {
160
+ function showVersions(args) {
160
161
  debug('printing Cypress version');
161
- return require('./exec/versions').getVersions().then((versions = {}) => {
162
+ debug('additional arguments %o', args);
163
+ const versionParser = commander.option('--component <package|binary|electron|node>', 'component to report version for').allowUnknownOption(true);
164
+ const parsed = versionParser.parse(args);
165
+ const parsedOptions = {
166
+ component: parsed.component
167
+ };
168
+ debug('parsed version arguments %o', parsedOptions);
169
+
170
+ const reportAllVersions = versions => {
162
171
  logger.always('Cypress package version:', versions.package);
163
172
  logger.always('Cypress binary version:', versions.binary);
173
+ logger.always('Electron version:', versions.electronVersion);
174
+ logger.always('Bundled Node version:', versions.electronNodeVersion);
175
+ };
176
+
177
+ const reportComponentVersion = (componentName, versions) => {
178
+ const names = {
179
+ package: 'package',
180
+ binary: 'binary',
181
+ electron: 'electronVersion',
182
+ node: 'electronNodeVersion'
183
+ };
184
+
185
+ if (!names[componentName]) {
186
+ throw new Error(`Unknown component name "${componentName}"`);
187
+ }
188
+
189
+ const name = names[componentName];
190
+
191
+ if (!versions[name]) {
192
+ throw new Error(`Cannot find version for component "${componentName}" under property "${name}"`);
193
+ }
194
+
195
+ const version = versions[name];
196
+ logger.always(version);
197
+ };
198
+
199
+ const defaultVersions = {
200
+ package: undefined,
201
+ binary: undefined,
202
+ electronVersion: undefined,
203
+ electronNodeVersion: undefined
204
+ };
205
+ return require('./exec/versions').getVersions().then((versions = defaultVersions) => {
206
+ if (parsedOptions.component) {
207
+ reportComponentVersion(parsedOptions.component, versions);
208
+ } else {
209
+ reportAllVersions(versions);
210
+ }
211
+
164
212
  process.exit(0);
165
213
  }).catch(util.logErrorExit1);
166
214
  }
@@ -266,7 +314,9 @@ module.exports = {
266
314
  program.command('help').description('Shows CLI help and exits').action(() => {
267
315
  program.help();
268
316
  });
269
- program.option('-v, --version', text('version')).command('version').description(text('version')).action(showVersions);
317
+ program.option('-v, --version', text('version')).command('version').description(text('version')).action(() => {
318
+ showVersions(args);
319
+ });
270
320
  addCypressRunCommand(program).action((...fnArgs) => {
271
321
  debug('running Cypress with args %o', fnArgs);
272
322
 
@@ -346,14 +396,14 @@ module.exports = {
346
396
  // and now does not understand top level options
347
397
  // .option('-v, --version').command('version')
348
398
  // so we have to manually catch '-v, --version'
349
- return showVersions();
399
+ return showVersions(args);
350
400
  }
351
401
 
352
402
  debug('program parsing arguments');
353
403
  return program.parse(args);
354
404
  }
355
405
 
356
- };
406
+ }; // @ts-ignore
357
407
 
358
408
  if (!module.parent) {
359
409
  logger.error('This CLI module should be required from another Node module');
package/lib/errors.js CHANGED
@@ -225,24 +225,6 @@ const childProcessKilled = (eventName, signal) => {
225
225
  };
226
226
  };
227
227
 
228
- const removed = {
229
- CYPRESS_BINARY_VERSION: {
230
- description: stripIndent`
231
- The environment variable CYPRESS_BINARY_VERSION has been renamed to CYPRESS_INSTALL_BINARY as of version ${chalk.green('3.0.0')}
232
- `,
233
- solution: stripIndent`
234
- You should set CYPRESS_INSTALL_BINARY instead.
235
- `
236
- },
237
- CYPRESS_SKIP_BINARY_INSTALL: {
238
- description: stripIndent`
239
- The environment variable CYPRESS_SKIP_BINARY_INSTALL has been removed as of version ${chalk.green('3.0.0')}
240
- `,
241
- solution: stripIndent`
242
- To skip the binary install, set CYPRESS_INSTALL_BINARY=0
243
- `
244
- }
245
- };
246
228
  const CYPRESS_RUN_BINARY = {
247
229
  notValid: value => {
248
230
  const properFormat = `**/${state.getPlatformExecutable()}`;
@@ -404,7 +386,6 @@ module.exports = {
404
386
  failedUnzip,
405
387
  invalidCypressEnv,
406
388
  invalidCacheDirectory,
407
- removed,
408
389
  CYPRESS_RUN_BINARY,
409
390
  smokeTestFailure,
410
391
  childProcessKilled,
package/lib/exec/run.js CHANGED
@@ -78,13 +78,6 @@ const processRunOptions = (options = {}) => {
78
78
  args.push('--browser', options.browser);
79
79
  }
80
80
 
81
- if (options.ci) {
82
- // push to display the deprecation message
83
- args.push('--ci'); // also automatically record
84
-
85
- args.push('--record', true);
86
- }
87
-
88
81
  if (options.ciBuildId) {
89
82
  args.push('--ci-build-id', options.ciBuildId);
90
83
  }
@@ -124,7 +117,7 @@ const processRunOptions = (options = {}) => {
124
117
 
125
118
  if (options.key == null) {
126
119
  debug('--key is not set, looking up environment variable CYPRESS_RECORD_KEY');
127
- options.key = util.getEnv('CYPRESS_RECORD_KEY') || util.getEnv('CYPRESS_CI_KEY');
120
+ options.key = util.getEnv('CYPRESS_RECORD_KEY');
128
121
  } // if we have a key assume we're in record mode
129
122
 
130
123
 
@@ -150,7 +143,7 @@ const processRunOptions = (options = {}) => {
150
143
  // already in ci mode, then send it up
151
144
 
152
145
 
153
- if (options.record != null && !options.ci) {
146
+ if (options.record != null) {
154
147
  args.push('--record', options.record);
155
148
  } // if we have a specific reporter push that into the args
156
149
 
@@ -34,11 +34,23 @@ const getVersions = () => {
34
34
  }
35
35
 
36
36
  return state.getBinaryDir();
37
- }).then(state.getBinaryPkgVersionAsync).then(binaryVersion => {
38
- return {
37
+ }).then(state.getBinaryPkgAsync).then(pkg => {
38
+ const versions = {
39
+ binary: state.getBinaryPkgVersion(pkg),
40
+ electronVersion: state.getBinaryElectronVersion(pkg),
41
+ electronNodeVersion: state.getBinaryElectronNodeVersion(pkg)
42
+ };
43
+ debug('binary versions %o', versions);
44
+ return versions;
45
+ }).then(binaryVersions => {
46
+ const versions = {
39
47
  package: util.pkgVersion(),
40
- binary: binaryVersion || 'not installed'
48
+ binary: binaryVersions.binary || 'not installed',
49
+ electronVersion: binaryVersions.electronVersion || 'not found',
50
+ electronNodeVersion: binaryVersions.electronNodeVersion || 'not found'
41
51
  };
52
+ debug('combined versions %o', versions);
53
+ return versions;
42
54
  });
43
55
  };
44
56
 
@@ -219,15 +219,6 @@ const downloadAndUnzip = ({
219
219
  };
220
220
 
221
221
  const start = (options = {}) => {
222
- // handle deprecated / removed
223
- if (util.getEnv('CYPRESS_BINARY_VERSION')) {
224
- return throwFormErrorText(errors.removed.CYPRESS_BINARY_VERSION)();
225
- }
226
-
227
- if (util.getEnv('CYPRESS_SKIP_BINARY_INSTALL')) {
228
- return throwFormErrorText(errors.removed.CYPRESS_SKIP_BINARY_INSTALL)();
229
- }
230
-
231
222
  debug('installing with options %j', options);
232
223
 
233
224
  _.defaults(options, {
@@ -279,7 +270,7 @@ const start = (options = {}) => {
279
270
  ${err.message}
280
271
  `);
281
272
  }).then(() => {
282
- return Promise.all([state.getBinaryPkgVersionAsync(binaryDir), getVersionSpecifier()]);
273
+ return Promise.all([state.getBinaryPkgAsync(binaryDir).then(state.getBinaryPkgVersion), getVersionSpecifier()]);
283
274
  }).then(([binaryVersion, versionSpecifier]) => {
284
275
  if (!binaryUrlOverride && versionSpecifier) {
285
276
  const computedBinaryUrl = getBinaryUrlFromPrereleaseNpmUrl(versionSpecifier);
@@ -8,6 +8,8 @@ const path = require('path');
8
8
 
9
9
  const untildify = require('untildify');
10
10
 
11
+ const R = require('ramda');
12
+
11
13
  const debug = require('debug')('cypress:cli');
12
14
 
13
15
  const fs = require('../fs');
@@ -183,8 +185,13 @@ const writeBinaryVerifiedAsync = (verified, binaryDir) => {
183
185
  const getPathToExecutable = binaryDir => {
184
186
  return path.join(binaryDir, getPlatformExecutable());
185
187
  };
188
+ /**
189
+ * Resolves with an object read from the binary app package.json file.
190
+ * If the file does not exist resolves with null
191
+ */
192
+
186
193
 
187
- const getBinaryPkgVersionAsync = binaryDir => {
194
+ const getBinaryPkgAsync = binaryDir => {
188
195
  const pathToPackageJson = getBinaryPkgPath(binaryDir);
189
196
  debug('Reading binary package.json from:', pathToPackageJson);
190
197
  return fs.pathExistsAsync(pathToPackageJson).then(exists => {
@@ -192,15 +199,22 @@ const getBinaryPkgVersionAsync = binaryDir => {
192
199
  return null;
193
200
  }
194
201
 
195
- return fs.readJsonAsync(pathToPackageJson).get('version');
202
+ return fs.readJsonAsync(pathToPackageJson);
196
203
  });
197
204
  };
198
205
 
206
+ const getBinaryPkgVersion = R.propOr(null, 'version');
207
+ const getBinaryElectronVersion = R.propOr(null, 'electronVersion');
208
+ const getBinaryElectronNodeVersion = R.propOr(null, 'electronNodeVersion');
199
209
  module.exports = {
200
210
  getPathToExecutable,
201
211
  getPlatformExecutable,
202
- getBinaryPkgVersionAsync,
212
+ // those names start to sound like Java
213
+ getBinaryElectronNodeVersion,
214
+ getBinaryElectronVersion,
215
+ getBinaryPkgVersion,
203
216
  getBinaryVerifiedAsync,
217
+ getBinaryPkgAsync,
204
218
  getBinaryPkgPath,
205
219
  getBinaryDir,
206
220
  getCacheDir,
@@ -284,7 +284,9 @@ const start = (options = {}) => {
284
284
  }).tap(() => {
285
285
  return debug('binaryDir is ', binaryDir);
286
286
  }).then(() => {
287
- return state.getBinaryPkgVersionAsync(binaryDir);
287
+ return state.getBinaryPkgAsync(binaryDir);
288
+ }).then(pkg => {
289
+ return state.getBinaryPkgVersion(pkg);
288
290
  }).then(binaryVersion => {
289
291
  if (!binaryVersion) {
290
292
  debug('no Cypress binary found for cli version ', packageVersion);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cypress",
3
- "version": "5.6.0",
3
+ "version": "6.2.0",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "postinstall": "node index.js --exec install",
@@ -6,3 +6,24 @@ interface EventEmitter extends EventEmitter2 {
6
6
  emitMap: (eventName: string, args: any[]) => Array<(...args: any[]) => any>
7
7
  emitThen: (eventName: string, args: any[]) => Bluebird.BluebirdStatic
8
8
  }
9
+
10
+ // Copied from https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/node/events.d.ts
11
+ // to avoid type conflict.
12
+ interface NodeEventEmitter {
13
+ addListener(event: string | symbol, listener: (...args: any[]) => void): this
14
+ on(event: string | symbol, listener: (...args: any[]) => void): this
15
+ once(event: string | symbol, listener: (...args: any[]) => void): this
16
+ removeListener(event: string | symbol, listener: (...args: any[]) => void): this
17
+ off(event: string | symbol, listener: (...args: any[]) => void): this
18
+ removeAllListeners(event?: string | symbol): this
19
+ setMaxListeners(n: number): this
20
+ getMaxListeners(): number
21
+ listeners(event: string | symbol): Array<(...args: any[]) => void>
22
+ rawListeners(event: string | symbol): Array<(...args: any[]) => void>
23
+ emit(event: string | symbol, ...args: any[]): boolean
24
+ listenerCount(type: string | symbol): number
25
+ // Added in Node 6...
26
+ prependListener(event: string | symbol, listener: (...args: any[]) => void): this
27
+ prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this
28
+ eventNames(): Array<string | symbol>
29
+ }
@@ -1,3 +1,5 @@
1
+ /// <reference path="./cypress-npm-api.d.ts" />
2
+
1
3
  declare namespace Cypress {
2
4
  type FileContents = string | any[] | object
3
5
  type HistoryDirection = 'back' | 'forward'
@@ -116,6 +118,17 @@ declare namespace Cypress {
116
118
  */
117
119
  type CypressSpecType = 'integration' | 'component'
118
120
 
121
+ /**
122
+ * A Cypress spec.
123
+ */
124
+ interface Spec {
125
+ name: string // "config_passing_spec.js"
126
+ relative: string // "cypress/integration/config_passing_spec.js" or "__all" if clicked all specs button
127
+ absolute: string // "/Users/janelane/app/cypress/integration/config_passing_spec.js"
128
+ specFilter?: string // optional spec filter used by the user
129
+ specType?: CypressSpecType
130
+ }
131
+
119
132
  /**
120
133
  * Window type for Application Under Test(AUT)
121
134
  */
@@ -164,6 +177,9 @@ declare namespace Cypress {
164
177
  */
165
178
  minimatch: typeof Minimatch.minimatch
166
179
  /**
180
+ * @deprecated Will be removed in a future version.
181
+ * Consider including your own datetime formatter in your tests.
182
+ *
167
183
  * Cypress automatically includes moment.js and exposes it as Cypress.moment.
168
184
  *
169
185
  * @see https://on.cypress.io/moment
@@ -224,23 +240,17 @@ declare namespace Cypress {
224
240
  /**
225
241
  * Currently executing spec file.
226
242
  * @example
227
- ```
228
- Cypress.spec
229
- // {
230
- // name: "config_passing_spec.coffee",
231
- // relative: "cypress/integration/config_passing_spec.coffee",
232
- // absolute: "/users/smith/projects/web/cypress/integration/config_passing_spec.coffee"
233
- // specType: "integration"
234
- // }
235
- ```
243
+ * ```
244
+ * Cypress.spec
245
+ * // {
246
+ * // name: "config_passing_spec.coffee",
247
+ * // relative: "cypress/integration/config_passing_spec.coffee",
248
+ * // absolute: "/users/smith/projects/web/cypress/integration/config_passing_spec.coffee"
249
+ * // specType: "integration"
250
+ * // }
251
+ * ```
236
252
  */
237
- spec: {
238
- name: string // "config_passing_spec.coffee"
239
- relative: string // "cypress/integration/config_passing_spec.coffee" or "__all" if clicked all specs button
240
- absolute: string
241
- specFilter?: string // optional spec filter used by the user
242
- specType?: CypressSpecType
243
- }
253
+ spec: Spec
244
254
 
245
255
  /**
246
256
  * Information about the browser currently running the tests
@@ -421,7 +431,7 @@ declare namespace Cypress {
421
431
  /**
422
432
  * Returns a boolean indicating whether an element is hidden.
423
433
  */
424
- isHidden(element: JQuery | HTMLElement): boolean
434
+ isHidden(element: JQuery | HTMLElement, methodName?: string, options?: object): boolean
425
435
  /**
426
436
  * Returns a boolean indicating whether an element can receive focus.
427
437
  */
@@ -474,7 +484,7 @@ declare namespace Cypress {
474
484
  getContainsSelector(text: string, filter?: string): JQuery.Selector
475
485
  getFirstDeepestElement(elements: HTMLElement[], index?: number): HTMLElement
476
486
  getWindowByElement(element: JQuery | HTMLElement): JQuery | HTMLElement
477
- getReasonIsHidden(element: JQuery | HTMLElement): string
487
+ getReasonIsHidden(element: JQuery | HTMLElement, options?: object): string
478
488
  getFirstScrollableParent(element: JQuery | HTMLElement): JQuery | HTMLElement
479
489
  getFirstFixedOrStickyPositionParent(element: JQuery | HTMLElement): JQuery | HTMLElement
480
490
  getFirstStickyPositionParent(element: JQuery | HTMLElement): JQuery | HTMLElement
@@ -1477,8 +1487,9 @@ declare namespace Cypress {
1477
1487
  root<E extends Node = HTMLHtmlElement>(options?: Partial<Loggable>): Chainable<JQuery<E>> // can't do better typing unless we ignore the `.within()` case
1478
1488
 
1479
1489
  /**
1480
- * Use `cy.route()` to manage the behavior of network requests.
1490
+ * @deprecated Use `cy.intercept()` instead.
1481
1491
  *
1492
+ * Use `cy.route()` to manage the behavior of network requests.
1482
1493
  * @see https://on.cypress.io/route
1483
1494
  * @example
1484
1495
  * cy.server()
@@ -1486,6 +1497,8 @@ declare namespace Cypress {
1486
1497
  */
1487
1498
  route(url: string | RegExp, response?: string | object): Chainable<null>
1488
1499
  /**
1500
+ * @deprecated Use `cy.intercept()` instead.
1501
+ *
1489
1502
  * Spy or stub request with specific method and url.
1490
1503
  *
1491
1504
  * @see https://on.cypress.io/route
@@ -1496,6 +1509,8 @@ declare namespace Cypress {
1496
1509
  */
1497
1510
  route(method: string, url: string | RegExp, response?: string | object): Chainable<null>
1498
1511
  /**
1512
+ * @deprecated Use `cy.intercept()` instead.
1513
+ *
1499
1514
  * Set a route by returning an object literal from a callback function.
1500
1515
  * Functions that return a Promise will automatically be awaited.
1501
1516
  *
@@ -1514,6 +1529,8 @@ declare namespace Cypress {
1514
1529
  */
1515
1530
  route(fn: () => RouteOptions): Chainable<null>
1516
1531
  /**
1532
+ * @deprecated Use `cy.intercept()` instead.
1533
+ *
1517
1534
  * Spy or stub a given route.
1518
1535
  *
1519
1536
  * @see https://on.cypress.io/route
@@ -1581,6 +1598,8 @@ declare namespace Cypress {
1581
1598
  select(value: string | string[], options?: Partial<SelectOptions>): Chainable<Subject>
1582
1599
 
1583
1600
  /**
1601
+ * @deprecated Use `cy.intercept()` instead.
1602
+ *
1584
1603
  * Start a server to begin routing responses to `cy.route()` and `cy.request()`.
1585
1604
  *
1586
1605
  * @example
@@ -2013,50 +2032,6 @@ declare namespace Cypress {
2013
2032
  * cy.wait(1000) // wait for 1 second
2014
2033
  */
2015
2034
  wait(ms: number, options?: Partial<Loggable & Timeoutable>): Chainable<Subject>
2016
- /**
2017
- * Wait for a specific XHR to respond.
2018
- *
2019
- * @see https://on.cypress.io/wait
2020
- * @param {string} alias - Name of the alias to wait for.
2021
- *
2022
- ```
2023
- // Wait for the route aliased as 'getAccount' to respond
2024
- // without changing or stubbing its response
2025
- cy.server()
2026
- cy.route('/accounts/*').as('getAccount')
2027
- cy.visit('/accounts/123')
2028
- cy.wait('@getAccount').then((xhr) => {
2029
- // we can now access the low level xhr
2030
- // that contains the request body,
2031
- // response body, status, etc
2032
- })
2033
- ```
2034
- */
2035
- wait(alias: string, options?: Partial<Loggable & Timeoutable & TimeoutableXHR>): Chainable<WaitXHR>
2036
- /**
2037
- * Wait for list of XHR requests to complete.
2038
- *
2039
- * @see https://on.cypress.io/wait
2040
- * @param {string[]} aliases - An array of aliased routes as defined using the `.as()` command.
2041
- *
2042
- ```
2043
- // wait for 3 XHR requests to complete
2044
- cy.server()
2045
- cy.route('users/*').as('getUsers')
2046
- cy.route('activities/*').as('getActivities')
2047
- cy.route('comments/*').as('getComments')
2048
- cy.visit('/dashboard')
2049
-
2050
- cy.wait(['@getUsers', '@getActivities', '@getComments'])
2051
- .then((xhrs) => {
2052
- // xhrs will now be an array of matching XHR's
2053
- // xhrs[0] <-- getUsers
2054
- // xhrs[1] <-- getActivities
2055
- // xhrs[2] <-- getComments
2056
- })
2057
- ```
2058
- */
2059
- wait(alias: string[], options?: Partial<Loggable & Timeoutable & TimeoutableXHR>): Chainable<WaitXHR[]>
2060
2035
 
2061
2036
  /**
2062
2037
  * Get the window object of the page that is currently active.
@@ -2322,20 +2297,46 @@ declare namespace Cypress {
2322
2297
  force: boolean
2323
2298
  }
2324
2299
 
2300
+ type scrollBehaviorOptions = false | 'center' | 'top' | 'bottom' | 'nearest'
2301
+
2302
+ /**
2303
+ * Options to affect Actionability checks
2304
+ * @see https://docs.cypress.io/guides/core-concepts/interacting-with-elements.html#Actionability
2305
+ */
2306
+ interface ActionableOptions extends Forceable {
2307
+ /**
2308
+ * Whether to wait for elements to finish animating before executing commands
2309
+ *
2310
+ * @default true
2311
+ */
2312
+ waitForAnimations: boolean
2313
+ /**
2314
+ * The distance in pixels an element must exceed over time to be considered animating
2315
+ * @default 5
2316
+ */
2317
+ animationDistanceThreshold: number
2318
+ /**
2319
+ * Viewport position to which an element should be scrolled prior to action commands. Setting `false` disables scrolling.
2320
+ *
2321
+ * @default 'top'
2322
+ */
2323
+ scrollBehavior: scrollBehaviorOptions
2324
+ }
2325
+
2325
2326
  interface BlurOptions extends Loggable, Forceable { }
2326
2327
 
2327
- interface CheckOptions extends Loggable, Timeoutable, Forceable {
2328
+ interface CheckOptions extends Loggable, Timeoutable, ActionableOptions {
2328
2329
  interval: number
2329
2330
  }
2330
2331
 
2331
- interface ClearOptions extends Loggable, Timeoutable, Forceable {
2332
+ interface ClearOptions extends Loggable, Timeoutable, ActionableOptions {
2332
2333
  interval: number
2333
2334
  }
2334
2335
 
2335
2336
  /**
2336
2337
  * Object to change the default behavior of .click().
2337
2338
  */
2338
- interface ClickOptions extends Loggable, Timeoutable, Forceable {
2339
+ interface ClickOptions extends Loggable, Timeoutable, ActionableOptions {
2339
2340
  /**
2340
2341
  * Serially click multiple elements
2341
2342
  *
@@ -2563,6 +2564,11 @@ declare namespace Cypress {
2563
2564
  * @default true
2564
2565
  */
2565
2566
  waitForAnimations: boolean
2567
+ /**
2568
+ * Viewport position to which an element should be scrolled prior to action commands. Setting `false` disables scrolling.
2569
+ * @default 'top'
2570
+ */
2571
+ scrollBehavior: scrollBehaviorOptions
2566
2572
  /**
2567
2573
  * Firefox version 79 and below only: The number of tests that will run between forced garbage collections.
2568
2574
  * If a number is supplied, it will apply to `run` mode and `open` mode.
@@ -2571,16 +2577,16 @@ declare namespace Cypress {
2571
2577
  */
2572
2578
  firefoxGcInterval: Nullable<number | { runMode: Nullable<number>, openMode: Nullable<number> }>
2573
2579
  /**
2574
- * Enables AST-based JS/HTML rewriting. This may fix issues caused by the existing regex-based JS/HTML replacement
2575
- * algorithm.
2580
+ * Allows listening to the `before:run`, `after:run`, `before:spec`, and `after:spec` events in the plugins file.
2576
2581
  * @default false
2577
2582
  */
2578
- experimentalSourceRewriting: boolean
2583
+ experimentalRunEvents: boolean
2579
2584
  /**
2580
- * Enables `cy.route2`, which can be used to dynamically intercept/stub/await any HTTP request or response (XHRs, fetch, beacons, etc.)
2585
+ * Enables AST-based JS/HTML rewriting. This may fix issues caused by the existing regex-based JS/HTML replacement
2586
+ * algorithm.
2581
2587
  * @default false
2582
2588
  */
2583
- experimentalNetworkStubbing: boolean
2589
+ experimentalSourceRewriting: boolean
2584
2590
  /**
2585
2591
  * Number of times to retry a failed test.
2586
2592
  * If a number is set, tests will retry in both runMode and openMode.
@@ -2598,7 +2604,7 @@ declare namespace Cypress {
2598
2604
  includeShadowDom: boolean
2599
2605
  }
2600
2606
 
2601
- interface TestConfigOverrides extends Partial<Pick<ConfigOptions, 'baseUrl' | 'defaultCommandTimeout' | 'taskTimeout' | 'animationDistanceThreshold' | 'waitForAnimations' | 'viewportHeight' | 'viewportWidth' | 'requestTimeout' | 'execTimeout' | 'env' | 'responseTimeout' | 'retries' | 'includeShadowDom'>> {
2607
+ interface TestConfigOverrides extends Partial<Pick<ConfigOptions, 'animationDistanceThreshold' | 'baseUrl' | 'defaultCommandTimeout' | 'env' | 'execTimeout' | 'includeShadowDom' | 'requestTimeout' | 'responseTimeout' | 'retries' | 'scrollBehavior' | 'taskTimeout' | 'viewportHeight' | 'viewportWidth' | 'waitForAnimations'>> {
2602
2608
  browser?: IsBrowserMatcher | IsBrowserMatcher[]
2603
2609
  }
2604
2610
 
@@ -2794,7 +2800,7 @@ declare namespace Cypress {
2794
2800
  *
2795
2801
  * @see https://on.cypress.io/type
2796
2802
  */
2797
- interface TypeOptions extends Loggable, Timeoutable {
2803
+ interface TypeOptions extends Loggable, Timeoutable, ActionableOptions {
2798
2804
  /**
2799
2805
  * Delay after each keypress (ms)
2800
2806
  *
@@ -2808,12 +2814,6 @@ declare namespace Cypress {
2808
2814
  * @default true
2809
2815
  */
2810
2816
  parseSpecialCharSequences: boolean
2811
- /**
2812
- * Forces the action, disables waiting for actionability
2813
- *
2814
- * @default false
2815
- */
2816
- force: boolean
2817
2817
  /**
2818
2818
  * Keep a modifier activated between commands
2819
2819
  *
@@ -2906,7 +2906,7 @@ declare namespace Cypress {
2906
2906
  /**
2907
2907
  * Options to change the default behavior of .trigger()
2908
2908
  */
2909
- interface TriggerOptions extends Loggable, Timeoutable, Forceable {
2909
+ interface TriggerOptions extends Loggable, Timeoutable, ActionableOptions {
2910
2910
  /**
2911
2911
  * Whether the event bubbles
2912
2912
  *
@@ -4982,7 +4982,7 @@ declare namespace Cypress {
4982
4982
  dimensions?: Dimensions
4983
4983
  }
4984
4984
 
4985
- interface FileObject {
4985
+ interface FileObject extends NodeEventEmitter {
4986
4986
  filePath: string
4987
4987
  outputPath: string
4988
4988
  shouldWatch: boolean
@@ -4999,9 +4999,31 @@ declare namespace Cypress {
4999
4999
  [key: string]: Task
5000
5000
  }
5001
5001
 
5002
+ interface SystemDetails {
5003
+ osName: string
5004
+ osVersion: string
5005
+ }
5006
+
5007
+ interface BeforeRunDetails {
5008
+ browser: Browser
5009
+ config: ConfigOptions
5010
+ cypressVersion: string
5011
+ group?: string
5012
+ parallel: boolean
5013
+ runUrl?: string
5014
+ specs: Spec[]
5015
+ specPattern: string[]
5016
+ system: SystemDetails
5017
+ tag?: string
5018
+ }
5019
+
5002
5020
  interface PluginEvents {
5003
- (action: 'before:browser:launch', fn: (browser: Browser, browserLaunchOptions: BrowserLaunchOptions) => void | BrowserLaunchOptions | Promise<BrowserLaunchOptions>): void
5021
+ (action: 'after:run', fn: (results: CypressCommandLine.CypressRunResult | CypressCommandLine.CypressFailedRunResult) => void | Promise<void>): void
5004
5022
  (action: 'after:screenshot', fn: (details: ScreenshotDetails) => void | AfterScreenshotReturnObject | Promise<AfterScreenshotReturnObject>): void
5023
+ (action: 'after:spec', fn: (spec: Spec, results: CypressCommandLine.RunResult) => void | Promise<void>): void
5024
+ (action: 'before:run', fn: (runDetails: BeforeRunDetails) => void | Promise<void>): void
5025
+ (action: 'before:spec', fn: (spec: Spec) => void | Promise<void>): void
5026
+ (action: 'before:browser:launch', fn: (browser: Browser, browserLaunchOptions: BrowserLaunchOptions) => void | BrowserLaunchOptions | Promise<BrowserLaunchOptions>): void
5005
5027
  (action: 'file:preprocessor', fn: (file: FileObject) => string | Promise<string>): void
5006
5028
  (action: 'task', tasks: Tasks): void
5007
5029
  }
@@ -5255,7 +5277,8 @@ declare namespace Cypress {
5255
5277
  duration: number
5256
5278
  headers: { [key: string]: string }
5257
5279
  isOkStatusCode: boolean
5258
- redirectedToUrl: string
5280
+ redirects?: string[]
5281
+ redirectedToUrl?: string
5259
5282
  requestHeaders: { [key: string]: string }
5260
5283
  status: number
5261
5284
  statusText: string
@@ -70,7 +70,7 @@ type Method =
70
70
  | 'unsubscribe'
71
71
 
72
72
  export namespace CyHttpMessages {
73
- interface BaseMessage {
73
+ export interface BaseMessage {
74
74
  body?: any
75
75
  headers: { [key: string]: string }
76
76
  url: string
@@ -178,8 +178,9 @@ export type NumberMatcher = number | number[]
178
178
  /**
179
179
  * Request/response cycle.
180
180
  */
181
- export interface Request {
181
+ export interface Interception {
182
182
  id: string
183
+ routeHandlerId: string
183
184
  /* @internal */
184
185
  log: any
185
186
  request: CyHttpMessages.IncomingRequest
@@ -191,16 +192,20 @@ export interface Request {
191
192
  response?: CyHttpMessages.IncomingResponse
192
193
  /* @internal */
193
194
  responseHandler?: HttpResponseInterceptor
195
+ /**
196
+ * The error that occurred during this request.
197
+ */
198
+ error?: Error
194
199
  /**
195
200
  * Was `cy.wait()` used to wait on the response to this request?
196
201
  * @internal
197
202
  */
198
203
  responseWaited: boolean
199
204
  /* @internal */
200
- state: RequestState
205
+ state: InterceptionState
201
206
  }
202
207
 
203
- export type RequestState =
208
+ export type InterceptionState =
204
209
  'Received' |
205
210
  'Intercepted' |
206
211
  'ResponseReceived' |
@@ -214,7 +219,8 @@ export interface Route {
214
219
  options: RouteMatcherOptions
215
220
  handler: RouteHandler
216
221
  hitCount: number
217
- requests: { [key: string]: Request }
222
+ requests: { [key: string]: Interception }
223
+ command: any
218
224
  }
219
225
 
220
226
  export interface RouteMap { [key: string]: Route }
@@ -224,13 +230,9 @@ export interface RouteMap { [key: string]: Route }
224
230
  */
225
231
  export type RouteMatcher = StringMatcher | RouteMatcherOptions
226
232
 
227
- export interface RouteMatcherCompatOptions {
228
- response?: string | object
229
- }
230
-
231
233
  export type RouteMatcherOptions = RouteMatcherOptionsGeneric<StringMatcher>
232
234
 
233
- export interface RouteMatcherOptionsGeneric<S> extends RouteMatcherCompatOptions {
235
+ export interface RouteMatcherOptionsGeneric<S> {
234
236
  /**
235
237
  * Match against the username and password used in HTTP Basic authentication.
236
238
  */
@@ -248,6 +250,11 @@ export interface RouteMatcherOptionsGeneric<S> extends RouteMatcherCompatOptions
248
250
  * If 'false', only HTTP requests will be matched.
249
251
  */
250
252
  https?: boolean
253
+ /**
254
+ * If `true`, will match the supplied `url` against incoming `path`s.
255
+ * Requires a `url` argument. Cannot be used with a `path` argument.
256
+ */
257
+ matchUrlAgainstPath?: boolean
251
258
  /**
252
259
  * Match against the request's HTTP method.
253
260
  * @default '*'
@@ -328,41 +335,112 @@ export interface GenericStaticResponse<Fixture, Body> {
328
335
  */
329
336
  export type StringMatcher = GlobPattern | RegExp
330
337
 
338
+ interface WaitOptions {
339
+ /**
340
+ * Displays the command in the Command Log
341
+ *
342
+ * @default true
343
+ */
344
+ log: boolean
345
+ /**
346
+ * Time to wait for the request (ms)
347
+ *
348
+ * @default {@link Timeoutable#timeout}
349
+ * @see https://on.cypress.io/configuration#Timeouts
350
+ */
351
+ requestTimeout: number
352
+ /**
353
+ * Time to wait for the response (ms)
354
+ *
355
+ * @default {@link Timeoutable#timeout}
356
+ * @see https://on.cypress.io/configuration#Timeouts
357
+ */
358
+ responseTimeout: number
359
+ /**
360
+ * Time to wait (ms)
361
+ *
362
+ * @default defaultCommandTimeout
363
+ * @see https://on.cypress.io/configuration#Timeouts
364
+ */
365
+ timeout: number
366
+ }
367
+
331
368
  declare global {
332
369
  namespace Cypress {
333
370
  interface Chainable<Subject = any> {
334
371
  /**
335
- * Use `cy.route2()` to stub and intercept HTTP requests and responses.
372
+ * Use `cy.intercept()` to stub and intercept HTTP requests and responses.
336
373
  *
337
- * Note: this command is only available if you have set the `experimentalNetworkStubbing`
338
- * configuration option to `true`.
339
- *
340
- * @see https://on.cypress.io/route2
374
+ * @see https://on.cypress.io/intercept
341
375
  * @example
342
- * cy.route2('https://localhost:7777/users', [{id: 1, name: 'Pat'}])
376
+ * cy.intercept('https://localhost:7777/users', [{id: 1, name: 'Pat'}])
343
377
  * @example
344
- * cy.route2('https://localhost:7777/protected-endpoint', (req) => {
378
+ * cy.intercept('https://localhost:7777/protected-endpoint', (req) => {
345
379
  * req.headers['authorization'] = 'basic fooabc123'
346
380
  * })
347
381
  * @example
348
- * cy.route2('https://localhost:7777/some-response', (req) => {
382
+ * cy.intercept('https://localhost:7777/some-response', (req) => {
349
383
  * req.reply(res => {
350
384
  * res.body = 'some new body'
351
385
  * })
352
386
  * })
353
387
  */
354
- route2(url: RouteMatcher, response?: RouteHandler): Chainable<null>
388
+ intercept(url: RouteMatcher, response?: RouteHandler): Chainable<null>
355
389
  /**
356
- * Use `cy.route2()` to stub and intercept HTTP requests and responses.
390
+ * Use `cy.intercept()` to stub and intercept HTTP requests and responses.
357
391
  *
358
- * Note: this command is only available if you have set the `experimentalNetworkStubbing`
359
- * configuration option to `true`.
360
- *
361
- * @see https://on.cypress.io/route2
392
+ * @see https://on.cypress.io/intercept
362
393
  * @example
363
- * cy.route2('GET', 'http://foo.com/fruits', ['apple', 'banana', 'cherry'])
394
+ * cy.intercept('GET', 'http://foo.com/fruits', ['apple', 'banana', 'cherry'])
395
+ */
396
+ intercept(method: Method, url: RouteMatcher, response?: RouteHandler): Chainable<null>
397
+ /**
398
+ * @deprecated Use `cy.intercept()` instead.
399
+ */
400
+ route2(url: RouteMatcher, response?: RouteHandler): Chainable<null>
401
+ /**
402
+ * @deprecated Use `cy.intercept()` instead.
364
403
  */
365
404
  route2(method: Method, url: RouteMatcher, response?: RouteHandler): Chainable<null>
405
+ /**
406
+ * Wait for a specific request to complete.
407
+ *
408
+ * @see https://on.cypress.io/wait
409
+ * @param {string} alias - Name of the alias to wait for.
410
+ *
411
+ ```
412
+ // Wait for the route aliased as 'getAccount' to respond
413
+ // without changing or stubbing its response
414
+ cy.intercept('https://api.example.com/accounts/*').as('getAccount')
415
+ cy.visit('/accounts/123')
416
+ cy.wait('@getAccount').then((interception) => {
417
+ // we can now access the low level request
418
+ // that contains the request body,
419
+ // response body, status, etc
420
+ })
421
+ ```
422
+ */
423
+ wait(alias: string, options?: Partial<WaitOptions>): Chainable<Interception>
424
+ /**
425
+ * Wait for list of requests to complete.
426
+ *
427
+ * @see https://on.cypress.io/wait
428
+ * @param {string[]} aliases - An array of aliased routes as defined using the `.as()` command.
429
+ *
430
+ ```
431
+ // wait for 3 XHR requests to complete
432
+ cy.intercept('users/*').as('getUsers')
433
+ cy.intercept('activities/*').as('getActivities')
434
+ cy.intercept('comments/*').as('getComments')
435
+ cy.visit('/dashboard')
436
+
437
+ cy.wait(['@getUsers', '@getActivities', '@getComments'])
438
+ .then((interceptions) => {
439
+ // intercepts will now be an array of matching HTTP requests
440
+ })
441
+ ```
442
+ */
443
+ wait(alias: string[], options?: Partial<WaitOptions>): Chainable<Interception[]>
366
444
  }
367
445
  }
368
446
  }