cypress 6.1.0 → 6.4.0

Sign up to get free protection for your applications and to get access to all the features.
package/lib/cli.js CHANGED
@@ -143,7 +143,7 @@ const descriptions = {
143
143
  tag: 'named tag(s) for recorded runs in the Cypress Dashboard',
144
144
  version: 'prints Cypress version'
145
145
  };
146
- const knownCommands = ['cache', 'help', '-h', '--help', 'install', 'open', 'run', 'verify', '-v', '--version', 'version', 'info'];
146
+ const knownCommands = ['cache', 'help', '-h', '--help', 'install', 'open', 'open-ct', 'run', 'verify', '-v', '--version', 'version', 'info'];
147
147
 
148
148
  const text = description => {
149
149
  if (!descriptions[description]) {
@@ -322,6 +322,16 @@ module.exports = {
322
322
 
323
323
  require('./exec/run').start(parseVariableOpts(fnArgs, args)).then(util.exit).catch(util.logErrorExit1);
324
324
  });
325
+ program // TODO make this command public once CT will be merged completely
326
+ .command('open-ct', {
327
+ hidden: true
328
+ }).usage('[options]').description('Opens Cypress component testing interactive mode.').option('-b, --browser <browser-path>', text('browserOpenMode')).option('-c, --config <config>', text('config')).option('-C, --config-file <config-file>', text('configFile')).option('-d, --detached [bool]', text('detached'), coerceFalse).option('-e, --env <env>', text('env')).option('--global', text('global')).option('-p, --port <port>', text('port')).option('-P, --project <project-path>', text('project')).option('--dev', text('dev'), coerceFalse).action(opts => {
329
+ debug('opening Cypress');
330
+
331
+ require('./exec/open').start(util.parseOpts(opts), {
332
+ isComponentTesting: true
333
+ }).catch(util.logErrorExit1);
334
+ });
325
335
  program.command('open').usage('[options]').description('Opens Cypress in the interactive GUI.').option('-b, --browser <browser-path>', text('browserOpenMode')).option('-c, --config <config>', text('config')).option('-C, --config-file <config-file>', text('configFile')).option('-d, --detached [bool]', text('detached'), coerceFalse).option('-e, --env <env>', text('env')).option('--global', text('global')).option('-p, --port <port>', text('port')).option('-P, --project <project-path>', text('project')).option('--dev', text('dev'), coerceFalse).action(opts => {
326
336
  debug('opening Cypress');
327
337
 
package/lib/exec/open.js CHANGED
@@ -9,7 +9,11 @@ const spawn = require('./spawn');
9
9
  const verify = require('../tasks/verify');
10
10
 
11
11
  module.exports = {
12
- start(options = {}) {
12
+ start(options = {}, {
13
+ isComponentTesting
14
+ } = {
15
+ isComponentTesting: false
16
+ }) {
13
17
  if (!util.isInstalledGlobally() && !options.global && !options.project) {
14
18
  options.project = process.cwd();
15
19
  }
@@ -40,6 +44,10 @@ module.exports = {
40
44
  args.push('--project', options.project);
41
45
  }
42
46
 
47
+ if (isComponentTesting) {
48
+ args.push('--componentTesting');
49
+ }
50
+
43
51
  debug('opening from options %j', options);
44
52
  debug('command line arguments %j', args);
45
53
 
@@ -14,7 +14,9 @@ const {
14
14
 
15
15
  const Table = require('cli-table3');
16
16
 
17
- const moment = require('moment');
17
+ const dayjs = require('dayjs');
18
+
19
+ const relativeTime = require('dayjs/plugin/relativeTime');
18
20
 
19
21
  const chalk = require('chalk');
20
22
 
@@ -22,8 +24,9 @@ const _ = require('lodash');
22
24
 
23
25
  const getFolderSize = require('./get-folder-size');
24
26
 
25
- const Bluebird = require('bluebird'); // output colors for the table
27
+ const Bluebird = require('bluebird');
26
28
 
29
+ dayjs.extend(relativeTime); // output colors for the table
27
30
 
28
31
  const colors = {
29
32
  titles: chalk.white,
@@ -123,7 +126,7 @@ const getCachedVersions = showSize => {
123
126
  return binary;
124
127
  }
125
128
 
126
- const accessed = moment(lastAccessedTime).fromNow();
129
+ const accessed = dayjs(lastAccessedTime).fromNow();
127
130
  binary.accessed = accessed;
128
131
  return binary;
129
132
  }, e => {
package/lib/util.js CHANGED
@@ -212,7 +212,7 @@ const dequote = str => {
212
212
  };
213
213
 
214
214
  const parseOpts = opts => {
215
- opts = _.pick(opts, 'browser', 'cachePath', 'cacheList', 'cacheClear', 'cachePrune', 'ciBuildId', 'config', 'configFile', 'cypressVersion', 'destination', 'detached', 'dev', 'exit', 'env', 'force', 'global', 'group', 'headed', 'headless', 'key', 'path', 'parallel', 'port', 'project', 'quiet', 'reporter', 'reporterOptions', 'record', 'spec', 'tag');
215
+ opts = _.pick(opts, 'browser', 'cachePath', 'cacheList', 'cacheClear', 'cachePrune', 'ciBuildId', 'componentTesting', 'config', 'configFile', 'cypressVersion', 'destination', 'detached', 'dev', 'exit', 'env', 'force', 'global', 'group', 'headed', 'headless', 'key', 'path', 'parallel', 'port', 'project', 'quiet', 'reporter', 'reporterOptions', 'record', 'spec', 'tag');
216
216
 
217
217
  if (opts.exit) {
218
218
  opts = _.omit(opts, 'exit');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cypress",
3
- "version": "6.1.0",
3
+ "version": "6.4.0",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "postinstall": "node index.js --exec install",
@@ -21,6 +21,7 @@
21
21
  "cli-table3": "~0.6.0",
22
22
  "commander": "^5.1.0",
23
23
  "common-tags": "^1.8.0",
24
+ "dayjs": "^1.9.3",
24
25
  "debug": "^4.1.1",
25
26
  "eventemitter2": "^6.4.2",
26
27
  "execa": "^4.0.2",
@@ -35,7 +36,7 @@
35
36
  "lodash": "^4.17.19",
36
37
  "log-symbols": "^4.0.0",
37
38
  "minimist": "^1.2.5",
38
- "moment": "^2.27.0",
39
+ "moment": "^2.29.1",
39
40
  "ospath": "^1.2.2",
40
41
  "pretty-bytes": "^5.4.1",
41
42
  "ramda": "~0.26.1",
@@ -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
  */
@@ -227,23 +240,17 @@ declare namespace Cypress {
227
240
  /**
228
241
  * Currently executing spec file.
229
242
  * @example
230
- ```
231
- Cypress.spec
232
- // {
233
- // name: "config_passing_spec.coffee",
234
- // relative: "cypress/integration/config_passing_spec.coffee",
235
- // absolute: "/users/smith/projects/web/cypress/integration/config_passing_spec.coffee"
236
- // specType: "integration"
237
- // }
238
- ```
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
+ * ```
239
252
  */
240
- spec: {
241
- name: string // "config_passing_spec.coffee"
242
- relative: string // "cypress/integration/config_passing_spec.coffee" or "__all" if clicked all specs button
243
- absolute: string
244
- specFilter?: string // optional spec filter used by the user
245
- specType?: CypressSpecType
246
- }
253
+ spec: Spec
247
254
 
248
255
  /**
249
256
  * Information about the browser currently running the tests
@@ -274,7 +281,7 @@ declare namespace Cypress {
274
281
  // {defaultCommandTimeout: 10000, pageLoadTimeout: 30000, ...}
275
282
  ```
276
283
  */
277
- config(): ResolvedConfigOptions
284
+ config(): ResolvedConfigOptions & RuntimeConfigOptions
278
285
  /**
279
286
  * Returns one configuration value.
280
287
  * @see https://on.cypress.io/config
@@ -2472,6 +2479,11 @@ declare namespace Cypress {
2472
2479
  * @default "cypress/integration"
2473
2480
  */
2474
2481
  integrationFolder: string
2482
+ /**
2483
+ * Path to folder where files downloaded during a test are saved
2484
+ * @default "cypress/downloads"
2485
+ */
2486
+ downloadsFolder: string
2475
2487
  /**
2476
2488
  * If set to `system`, Cypress will try to find a `node` executable on your path to use when executing your plugins. Otherwise, Cypress will use the Node version bundled with Cypress.
2477
2489
  * @default "bundled"
@@ -2569,12 +2581,22 @@ declare namespace Cypress {
2569
2581
  * @default { runMode: 1, openMode: null }
2570
2582
  */
2571
2583
  firefoxGcInterval: Nullable<number | { runMode: Nullable<number>, openMode: Nullable<number> }>
2584
+ /**
2585
+ * Allows listening to the `before:run`, `after:run`, `before:spec`, and `after:spec` events in the plugins file.
2586
+ * @default false
2587
+ */
2588
+ experimentalRunEvents: boolean
2572
2589
  /**
2573
2590
  * Enables AST-based JS/HTML rewriting. This may fix issues caused by the existing regex-based JS/HTML replacement
2574
2591
  * algorithm.
2575
2592
  * @default false
2576
2593
  */
2577
2594
  experimentalSourceRewriting: boolean
2595
+ /**
2596
+ * Generate and save commands directly to your test suite by interacting with your app as an end user would.
2597
+ * @default false
2598
+ */
2599
+ experimentalStudio: boolean
2578
2600
  /**
2579
2601
  * Number of times to retry a failed test.
2580
2602
  * If a number is set, tests will retry in both runMode and openMode.
@@ -2592,7 +2614,111 @@ declare namespace Cypress {
2592
2614
  includeShadowDom: boolean
2593
2615
  }
2594
2616
 
2595
- interface TestConfigOverrides extends Partial<Pick<ConfigOptions, 'baseUrl' | 'defaultCommandTimeout' | 'taskTimeout' | 'animationDistanceThreshold' | 'waitForAnimations' | 'viewportHeight' | 'viewportWidth' | 'requestTimeout' | 'execTimeout' | 'env' | 'responseTimeout' | 'retries' | 'includeShadowDom'>> {
2617
+ /**
2618
+ * Options appended to config object on runtime.
2619
+ */
2620
+ interface RuntimeConfigOptions {
2621
+ /**
2622
+ * CPU architecture, from Node `os.arch()`
2623
+ *
2624
+ * @see https://nodejs.org/api/os.html#os_os_arch
2625
+ */
2626
+ arch: string
2627
+ /**
2628
+ * The list of hosts to be blocked
2629
+ */
2630
+ blockHosts: null | string | string[]
2631
+ /**
2632
+ * The browser Cypress is running on.
2633
+ */
2634
+ browser: Browser
2635
+ /**
2636
+ * Available browsers found on your system.
2637
+ */
2638
+ browsers: Browser[]
2639
+ /**
2640
+ * Path to folder containing component test files.
2641
+ */
2642
+ componentFolder: string
2643
+ /**
2644
+ * Whether component testing is enabled.
2645
+ */
2646
+ experimentalComponentTesting: boolean
2647
+ /**
2648
+ * Hosts mappings to IP addresses.
2649
+ */
2650
+ hosts: null | string[]
2651
+ /**
2652
+ * Whether Cypress was launched via 'cypress open' (interactive mode)
2653
+ */
2654
+ isInteractive: boolean
2655
+ /**
2656
+ * Whether Cypress will search for and replace
2657
+ * obstructive JS code in .js or .html files.
2658
+ *
2659
+ * @see https://on.cypress.io/configuration#modifyObstructiveCode
2660
+ */
2661
+ modifyObstructiveCode: boolean
2662
+ /**
2663
+ * The platform Cypress is running on.
2664
+ */
2665
+ platform: 'linux' | 'darwin' | 'win32'
2666
+ /**
2667
+ * A unique ID for the project used for recording
2668
+ */
2669
+ projectId: null | string
2670
+ /**
2671
+ * Path to the support folder.
2672
+ */
2673
+ supportFolder: string
2674
+ /**
2675
+ * Glob pattern to determine what test files to load.
2676
+ */
2677
+ testFiles: string
2678
+ /**
2679
+ * The user agent the browser sends in all request headers.
2680
+ */
2681
+ userAgent: null | string
2682
+ /**
2683
+ * The Cypress version being used.
2684
+ */
2685
+ version: string
2686
+
2687
+ // Internal or Unlisted at server/lib/config_options
2688
+ autoOpen: boolean
2689
+ browserUrl: string
2690
+ clientRoute: string
2691
+ configFile: string
2692
+ cypressEnv: string
2693
+ integrationExampleName: string
2694
+ integrationExamplePath: string
2695
+ isNewProject: boolean
2696
+ isTextTerminal: boolean
2697
+ morgan: boolean
2698
+ namespace: string
2699
+ parentTestsFolder: string
2700
+ parentTestsFolderDisplay: string
2701
+ projectName: string
2702
+ projectRoot: string
2703
+ proxyUrl: string
2704
+ report: boolean
2705
+ reporterRoute: string
2706
+ reporterUrl: string
2707
+ socketId: null | string
2708
+ socketIoCookie: string
2709
+ socketIoRoute: string
2710
+ spec: {
2711
+ absolute: string
2712
+ name: string
2713
+ relative: string
2714
+ specFilter: null | string
2715
+ specType: 'integration' | 'component'
2716
+ }
2717
+ xhrRoute: string
2718
+ xhrUrl: string
2719
+ }
2720
+
2721
+ interface TestConfigOverrides extends Partial<Pick<ConfigOptions, 'animationDistanceThreshold' | 'baseUrl' | 'defaultCommandTimeout' | 'env' | 'execTimeout' | 'includeShadowDom' | 'requestTimeout' | 'responseTimeout' | 'retries' | 'scrollBehavior' | 'taskTimeout' | 'viewportHeight' | 'viewportWidth' | 'waitForAnimations'>> {
2596
2722
  browser?: IsBrowserMatcher | IsBrowserMatcher[]
2597
2723
  }
2598
2724
 
@@ -4970,7 +5096,7 @@ declare namespace Cypress {
4970
5096
  dimensions?: Dimensions
4971
5097
  }
4972
5098
 
4973
- interface FileObject {
5099
+ interface FileObject extends NodeEventEmitter {
4974
5100
  filePath: string
4975
5101
  outputPath: string
4976
5102
  shouldWatch: boolean
@@ -4987,9 +5113,31 @@ declare namespace Cypress {
4987
5113
  [key: string]: Task
4988
5114
  }
4989
5115
 
5116
+ interface SystemDetails {
5117
+ osName: string
5118
+ osVersion: string
5119
+ }
5120
+
5121
+ interface BeforeRunDetails {
5122
+ browser: Browser
5123
+ config: ConfigOptions
5124
+ cypressVersion: string
5125
+ group?: string
5126
+ parallel: boolean
5127
+ runUrl?: string
5128
+ specs: Spec[]
5129
+ specPattern: string[]
5130
+ system: SystemDetails
5131
+ tag?: string
5132
+ }
5133
+
4990
5134
  interface PluginEvents {
4991
- (action: 'before:browser:launch', fn: (browser: Browser, browserLaunchOptions: BrowserLaunchOptions) => void | BrowserLaunchOptions | Promise<BrowserLaunchOptions>): void
5135
+ (action: 'after:run', fn: (results: CypressCommandLine.CypressRunResult | CypressCommandLine.CypressFailedRunResult) => void | Promise<void>): void
4992
5136
  (action: 'after:screenshot', fn: (details: ScreenshotDetails) => void | AfterScreenshotReturnObject | Promise<AfterScreenshotReturnObject>): void
5137
+ (action: 'after:spec', fn: (spec: Spec, results: CypressCommandLine.RunResult) => void | Promise<void>): void
5138
+ (action: 'before:run', fn: (runDetails: BeforeRunDetails) => void | Promise<void>): void
5139
+ (action: 'before:spec', fn: (spec: Spec) => void | Promise<void>): void
5140
+ (action: 'before:browser:launch', fn: (browser: Browser, browserLaunchOptions: BrowserLaunchOptions) => void | BrowserLaunchOptions | Promise<BrowserLaunchOptions>): void
4993
5141
  (action: 'file:preprocessor', fn: (file: FileObject) => string | Promise<string>): void
4994
5142
  (action: 'task', tasks: Tasks): void
4995
5143
  }
@@ -95,9 +95,9 @@ export namespace CyHttpMessages {
95
95
  */
96
96
  send(): void
97
97
  /**
98
- * Wait for `delayMs` milliseconds before sending the response to the client.
98
+ * Wait for `delay` milliseconds before sending the response to the client.
99
99
  */
100
- delay: (delayMs: number) => IncomingHttpResponse
100
+ delay: (delay: number) => IncomingHttpResponse
101
101
  /**
102
102
  * Serve the response at `throttleKbps` kilobytes per second.
103
103
  */
@@ -180,6 +180,7 @@ export type NumberMatcher = number | number[]
180
180
  */
181
181
  export interface Interception {
182
182
  id: string
183
+ routeHandlerId: string
183
184
  /* @internal */
184
185
  log: any
185
186
  request: CyHttpMessages.IncomingRequest
@@ -191,6 +192,10 @@ export interface Interception {
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
@@ -215,6 +220,7 @@ export interface Route {
215
220
  handler: RouteHandler
216
221
  hitCount: number
217
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 '*'
@@ -288,8 +295,9 @@ export type RouteHandler = string | StaticResponse | RouteHandlerController | ob
288
295
  export type StaticResponse = GenericStaticResponse<string, string | object> & {
289
296
  /**
290
297
  * Milliseconds to delay before the response is sent.
298
+ * @deprecated Use `delay` instead of `delayMs`.
291
299
  */
292
- delayMs?: number
300
+ delayMs?: number
293
301
  }
294
302
 
295
303
  export interface GenericStaticResponse<Fixture, Body> {
@@ -321,6 +329,10 @@ export interface GenericStaticResponse<Fixture, Body> {
321
329
  * Kilobits per second to send 'body'.
322
330
  */
323
331
  throttleKbps?: number
332
+ /**
333
+ * Milliseconds to delay before the response is sent.
334
+ */
335
+ delay?: number
324
336
  }
325
337
 
326
338
  /**