cypress 12.0.2 → 12.2.0

Sign up to get free protection for your applications and to get access to all the features.
package/lib/errors.js CHANGED
@@ -1,23 +1,19 @@
1
1
  "use strict";
2
2
 
3
3
  const chalk = require('chalk');
4
-
5
4
  const {
6
5
  stripIndent,
7
6
  stripIndents
8
7
  } = require('common-tags');
9
-
10
8
  const la = require('lazy-ass');
11
-
12
9
  const is = require('check-more-types');
13
-
14
10
  const util = require('./util');
15
-
16
11
  const state = require('./tasks/state');
17
-
18
12
  const docsUrl = 'https://on.cypress.io';
19
13
  const requiredDependenciesUrl = `${docsUrl}/required-dependencies`;
20
- const runDocumentationUrl = `${docsUrl}/cypress-run`; // TODO it would be nice if all error objects could be enforced via types
14
+ const runDocumentationUrl = `${docsUrl}/cypress-run`;
15
+
16
+ // TODO it would be nice if all error objects could be enforced via types
21
17
  // to only have description + solution properties
22
18
 
23
19
  const hr = '----------';
@@ -25,8 +21,9 @@ const genericErrorSolution = stripIndent`
25
21
  Search for an existing issue or open a GitHub issue at
26
22
 
27
23
  ${chalk.blue(util.issuesUrl)}
28
- `; // common errors Cypress application can encounter
24
+ `;
29
25
 
26
+ // common errors Cypress application can encounter
30
27
  const unknownError = {
31
28
  description: 'Unknown Cypress CLI error',
32
29
  solution: genericErrorSolution
@@ -64,7 +61,6 @@ const failedUnzipWindowsMaxPathLength = {
64
61
 
65
62
  Read here for solutions to this problem: https://on.cypress.io/win-max-path-length-error`
66
63
  };
67
-
68
64
  const missingApp = binaryDir => {
69
65
  return {
70
66
  description: `No version of Cypress is installed in: ${chalk.cyan(binaryDir)}`,
@@ -73,7 +69,6 @@ const missingApp = binaryDir => {
73
69
  `
74
70
  };
75
71
  };
76
-
77
72
  const binaryNotExecutable = executable => {
78
73
  return {
79
74
  description: `Cypress cannot run because this binary file does not have executable permissions here:\n\n${executable}`,
@@ -89,7 +84,6 @@ const binaryNotExecutable = executable => {
89
84
  `
90
85
  };
91
86
  };
92
-
93
87
  const notInstalledCI = executable => {
94
88
  return {
95
89
  description: 'The cypress npm package is installed, but the Cypress binary is missing.',
@@ -109,7 +103,6 @@ const notInstalledCI = executable => {
109
103
  `
110
104
  };
111
105
  };
112
-
113
106
  const nonZeroExitCodeXvfb = {
114
107
  description: 'Xvfb exited with a non zero exit code.',
115
108
  solution: stripIndent`
@@ -130,7 +123,6 @@ const missingXvfb = {
130
123
  If you are using Docker, we provide containers with all required dependencies installed.
131
124
  `
132
125
  };
133
-
134
126
  const smokeTestFailure = (smokeTestCommand, timedOut) => {
135
127
  return {
136
128
  description: `Cypress verification ${timedOut ? 'timed out' : 'failed'}.`,
@@ -142,11 +134,9 @@ const smokeTestFailure = (smokeTestCommand, timedOut) => {
142
134
  `
143
135
  };
144
136
  };
145
-
146
137
  const invalidSmokeTestDisplayError = {
147
138
  code: 'INVALID_SMOKE_TEST_DISPLAY_ERROR',
148
139
  description: 'Cypress verification failed.',
149
-
150
140
  solution(msg) {
151
141
  return stripIndent`
152
142
  Cypress failed to start after spawning a new Xvfb server.
@@ -164,7 +154,6 @@ const invalidSmokeTestDisplayError = {
164
154
  Please refer to the error above for more detail.
165
155
  `;
166
156
  }
167
-
168
157
  };
169
158
  const missingDependency = {
170
159
  description: 'Cypress failed to start.',
@@ -226,6 +215,7 @@ const invalidConfigFile = {
226
215
  description: '`--config-file` cannot be false.',
227
216
  solution: 'Either pass a relative path to a valid Cypress config file or remove this option.'
228
217
  };
218
+
229
219
  /**
230
220
  * This error happens when CLI detects that the child Test Runner process
231
221
  * was killed with a signal, like SIGBUS
@@ -233,14 +223,12 @@ const invalidConfigFile = {
233
223
  * @param {'close'|'event'} eventName Child close event name
234
224
  * @param {string} signal Signal that closed the child process, like "SIGBUS"
235
225
  */
236
-
237
226
  const childProcessKilled = (eventName, signal) => {
238
227
  return {
239
228
  description: `The Test Runner unexpectedly exited via a ${chalk.cyan(eventName)} event with signal ${chalk.cyan(signal)}`,
240
229
  solution: solutionUnknown
241
230
  };
242
231
  };
243
-
244
232
  const CYPRESS_RUN_BINARY = {
245
233
  notValid: value => {
246
234
  const properFormat = `**/${state.getPlatformExecutable()}`;
@@ -250,14 +238,15 @@ const CYPRESS_RUN_BINARY = {
250
238
  };
251
239
  }
252
240
  };
253
-
254
241
  function addPlatformInformation(info) {
255
242
  return util.getPlatformInfo().then(platform => {
256
- return { ...info,
243
+ return {
244
+ ...info,
257
245
  platform
258
246
  };
259
247
  });
260
248
  }
249
+
261
250
  /**
262
251
  * Given an error object (see the errors above), forms error message text with details,
263
252
  * then resolves with Error instance you can throw or reject with.
@@ -270,8 +259,6 @@ function addPlatformInformation(info) {
270
259
  return getError(errorObject).then(reject)
271
260
  ```
272
261
  */
273
-
274
-
275
262
  function getError(errorObject) {
276
263
  return formErrorText(errorObject).then(errorMessage => {
277
264
  const err = new Error(errorMessage);
@@ -279,23 +266,21 @@ function getError(errorObject) {
279
266
  return err;
280
267
  });
281
268
  }
269
+
282
270
  /**
283
271
  * Forms nice error message with error and platform information,
284
272
  * and if possible a way to solve it. Resolves with a string.
285
273
  */
286
-
287
-
288
274
  function formErrorText(info, msg, prevMessage) {
289
275
  return addPlatformInformation(info).then(obj => {
290
276
  const formatted = [];
291
-
292
277
  function add(msg) {
293
278
  formatted.push(stripIndents(msg));
294
279
  }
280
+ la(is.unemptyString(obj.description), 'expected error description to be text', obj.description);
295
281
 
296
- la(is.unemptyString(obj.description), 'expected error description to be text', obj.description); // assuming that if there the solution is a function it will handle
282
+ // assuming that if there the solution is a function it will handle
297
283
  // error message and (optional previous error message)
298
-
299
284
  if (is.fn(obj.solution)) {
300
285
  const text = obj.solution(msg, prevMessage);
301
286
  la(is.unemptyString(text), 'expected solution to be text', text);
@@ -313,7 +298,6 @@ function formErrorText(info, msg, prevMessage) {
313
298
  ${obj.solution}
314
299
 
315
300
  `);
316
-
317
301
  if (msg) {
318
302
  add(`
319
303
  ${hr}
@@ -323,13 +307,11 @@ function formErrorText(info, msg, prevMessage) {
323
307
  `);
324
308
  }
325
309
  }
326
-
327
310
  add(`
328
311
  ${hr}
329
312
 
330
313
  ${obj.platform}
331
314
  `);
332
-
333
315
  if (obj.footer) {
334
316
  add(`
335
317
 
@@ -338,37 +320,31 @@ function formErrorText(info, msg, prevMessage) {
338
320
  ${obj.footer}
339
321
  `);
340
322
  }
341
-
342
323
  return formatted.join('\n\n');
343
324
  });
344
325
  }
345
-
346
326
  const raise = info => {
347
327
  return text => {
348
328
  const err = new Error(text);
349
-
350
329
  if (info.code) {
351
330
  err.code = info.code;
352
331
  }
353
-
354
332
  err.known = true;
355
333
  throw err;
356
334
  };
357
335
  };
358
-
359
336
  const throwFormErrorText = info => {
360
337
  return (msg, prevMessage) => {
361
338
  return formErrorText(info, msg, prevMessage).then(raise(info));
362
339
  };
363
340
  };
341
+
364
342
  /**
365
343
  * Forms full error message with error and OS details, prints to the error output
366
344
  * and then exits the process.
367
345
  * @param {ErrorInformation} info Error information {description, solution}
368
346
  * @example return exitWithError(errors.invalidCypressEnv)('foo')
369
347
  */
370
-
371
-
372
348
  const exitWithError = info => {
373
349
  return msg => {
374
350
  return formErrorText(info, msg).then(text => {
@@ -378,7 +354,6 @@ const exitWithError = info => {
378
354
  });
379
355
  };
380
356
  };
381
-
382
357
  module.exports = {
383
358
  raise,
384
359
  exitWithError,
package/lib/exec/info.js CHANGED
@@ -2,55 +2,43 @@
2
2
 
3
3
  /* eslint-disable no-console */
4
4
  const spawn = require('./spawn');
5
-
6
5
  const util = require('../util');
7
-
8
6
  const state = require('../tasks/state');
9
-
10
7
  const os = require('os');
11
-
12
8
  const chalk = require('chalk');
13
-
14
9
  const prettyBytes = require('pretty-bytes');
10
+ const _ = require('lodash');
15
11
 
16
- const _ = require('lodash'); // color for numbers and show values
17
-
18
-
19
- const g = chalk.green; // color for paths
20
-
12
+ // color for numbers and show values
13
+ const g = chalk.green;
14
+ // color for paths
21
15
  const p = chalk.cyan;
22
- const red = chalk.red; // urls
23
-
24
- const link = chalk.blue.underline; // to be exported
16
+ const red = chalk.red;
17
+ // urls
18
+ const link = chalk.blue.underline;
25
19
 
20
+ // to be exported
26
21
  const methods = {};
27
-
28
22
  methods.findProxyEnvironmentVariables = () => {
29
23
  return _.pick(process.env, ['HTTP_PROXY', 'HTTPS_PROXY', 'NO_PROXY']);
30
24
  };
31
-
32
25
  const maskSensitiveVariables = obj => {
33
- const masked = { ...obj
26
+ const masked = {
27
+ ...obj
34
28
  };
35
-
36
29
  if (masked.CYPRESS_RECORD_KEY) {
37
30
  masked.CYPRESS_RECORD_KEY = '<redacted>';
38
31
  }
39
-
40
32
  return masked;
41
33
  };
42
-
43
34
  methods.findCypressEnvironmentVariables = () => {
44
35
  const isCyVariable = (val, key) => key.startsWith('CYPRESS_');
45
-
46
36
  return _.pickBy(process.env, isCyVariable);
47
37
  };
48
-
49
38
  const formatCypressVariables = () => {
50
39
  const vars = methods.findCypressEnvironmentVariables();
51
40
  return maskSensitiveVariables(vars);
52
41
  };
53
-
54
42
  methods.start = async (options = {}) => {
55
43
  const args = ['--mode=info'];
56
44
  await spawn.start(args, {
@@ -58,33 +46,26 @@ methods.start = async (options = {}) => {
58
46
  });
59
47
  console.log();
60
48
  const proxyVars = methods.findProxyEnvironmentVariables();
61
-
62
49
  if (_.isEmpty(proxyVars)) {
63
50
  console.log('Proxy Settings: none detected');
64
51
  } else {
65
52
  console.log('Proxy Settings:');
66
-
67
53
  _.forEach(proxyVars, (value, key) => {
68
54
  console.log('%s: %s', key, g(value));
69
55
  });
70
-
71
56
  console.log();
72
57
  console.log('Learn More: %s', link('https://on.cypress.io/proxy-configuration'));
73
58
  console.log();
74
59
  }
75
-
76
60
  const cyVars = formatCypressVariables();
77
-
78
61
  if (_.isEmpty(cyVars)) {
79
62
  console.log('Environment Variables: none detected');
80
63
  } else {
81
64
  console.log('Environment Variables:');
82
-
83
65
  _.forEach(cyVars, (value, key) => {
84
66
  console.log('%s: %s', key, g(value));
85
67
  });
86
68
  }
87
-
88
69
  console.log();
89
70
  console.log('Application Data:', p(util.getApplicationDataFolder()));
90
71
  console.log('Browser Profiles:', p(util.getApplicationDataFolder('browsers')));
@@ -96,7 +77,6 @@ methods.start = async (options = {}) => {
96
77
  console.log('Cypress Version: %s', g(util.pkgVersion()), isStable ? g('(stable)') : red('(pre-release)'));
97
78
  console.log('System Platform: %s (%s)', g(os.platform()), g(osVersion));
98
79
  console.log('System Memory: %s free %s', g(prettyBytes(os.totalmem())), g(prettyBytes(os.freemem())));
99
-
100
80
  if (!buildInfo) {
101
81
  console.log();
102
82
  console.log('This is the', red('development'), '(un-built) Cypress CLI.');
@@ -109,5 +89,4 @@ methods.start = async (options = {}) => {
109
89
  console.log(' Commit Date:', g(buildInfo.commitDate));
110
90
  }
111
91
  };
112
-
113
92
  module.exports = methods;
package/lib/exec/open.js CHANGED
@@ -1,21 +1,17 @@
1
1
  "use strict";
2
2
 
3
3
  const debug = require('debug')('cypress:cli');
4
-
5
4
  const util = require('../util');
6
-
7
5
  const spawn = require('./spawn');
8
-
9
6
  const verify = require('../tasks/verify');
10
-
11
7
  const {
12
8
  processTestingType,
13
9
  checkConfigFile
14
10
  } = require('./shared');
15
-
16
11
  const {
17
12
  exitWithError
18
13
  } = require('../errors');
14
+
19
15
  /**
20
16
  * Maps options collected by the CLI
21
17
  * and forms list of CLI arguments to the server.
@@ -25,8 +21,6 @@ const {
25
21
  *
26
22
  * @returns {string[]} list of CLI arguments
27
23
  */
28
-
29
-
30
24
  const processOpenOptions = (options = {}) => {
31
25
  // In addition to setting the project directory, setting the project option
32
26
  // here ultimately decides whether cypress is run in global mode or not.
@@ -37,55 +31,42 @@ const processOpenOptions = (options = {}) => {
37
31
  if (!util.isInstalledGlobally() && !options.global && !options.project) {
38
32
  options.project = process.cwd();
39
33
  }
40
-
41
34
  const args = [];
42
-
43
35
  if (options.config) {
44
36
  args.push('--config', options.config);
45
37
  }
46
-
47
38
  if (options.configFile !== undefined) {
48
39
  checkConfigFile(options);
49
40
  args.push('--config-file', options.configFile);
50
41
  }
51
-
52
42
  if (options.browser) {
53
43
  args.push('--browser', options.browser);
54
44
  }
55
-
56
45
  if (options.env) {
57
46
  args.push('--env', options.env);
58
47
  }
59
-
60
48
  if (options.port) {
61
49
  args.push('--port', options.port);
62
50
  }
63
-
64
51
  if (options.project) {
65
52
  args.push('--project', options.project);
66
53
  }
67
-
68
54
  if (options.global) {
69
55
  args.push('--global', options.global);
70
56
  }
71
-
72
57
  if (options.inspect) {
73
58
  args.push('--inspect');
74
59
  }
75
-
76
60
  if (options.inspectBrk) {
77
61
  args.push('--inspectBrk');
78
62
  }
79
-
80
63
  args.push(...processTestingType(options));
81
64
  debug('opening from options %j', options);
82
65
  debug('command line arguments %j', args);
83
66
  return args;
84
67
  };
85
-
86
68
  module.exports = {
87
69
  processOpenOptions,
88
-
89
70
  start(options = {}) {
90
71
  function open() {
91
72
  try {
@@ -98,16 +79,12 @@ module.exports = {
98
79
  if (err.details) {
99
80
  return exitWithError(err.details)();
100
81
  }
101
-
102
82
  throw err;
103
83
  }
104
84
  }
105
-
106
85
  if (options.dev) {
107
86
  return open();
108
87
  }
109
-
110
88
  return verify.start().then(open);
111
89
  }
112
-
113
90
  };
package/lib/exec/run.js CHANGED
@@ -1,44 +1,36 @@
1
1
  "use strict";
2
2
 
3
3
  const _ = require('lodash');
4
-
5
4
  const debug = require('debug')('cypress:cli:run');
6
-
7
5
  const util = require('../util');
8
-
9
6
  const spawn = require('./spawn');
10
-
11
7
  const verify = require('../tasks/verify');
12
-
13
8
  const {
14
9
  exitWithError,
15
10
  errors
16
11
  } = require('../errors');
17
-
18
12
  const {
19
13
  processTestingType,
20
14
  throwInvalidOptionError,
21
15
  checkConfigFile
22
16
  } = require('./shared');
17
+
23
18
  /**
24
19
  * Typically a user passes a string path to the project.
25
20
  * But "cypress open" allows using `false` to open in global mode,
26
21
  * and the user can accidentally execute `cypress run --project false`
27
22
  * which should be invalid.
28
23
  */
29
-
30
-
31
24
  const isValidProject = v => {
32
25
  if (typeof v === 'boolean') {
33
26
  return false;
34
27
  }
35
-
36
28
  if (v === '' || v === 'false' || v === 'true') {
37
29
  return false;
38
30
  }
39
-
40
31
  return true;
41
32
  };
33
+
42
34
  /**
43
35
  * Maps options collected by the CLI
44
36
  * and forms list of CLI arguments to the server.
@@ -48,129 +40,105 @@ const isValidProject = v => {
48
40
  *
49
41
  * @returns {string[]} list of CLI arguments
50
42
  */
51
-
52
-
53
43
  const processRunOptions = (options = {}) => {
54
44
  debug('processing run options %o', options);
55
-
56
45
  if (!isValidProject(options.project)) {
57
46
  debug('invalid project option %o', {
58
47
  project: options.project
59
48
  });
60
49
  return throwInvalidOptionError(errors.invalidRunProjectPath);
61
50
  }
62
-
63
51
  const args = ['--run-project', options.project];
64
-
65
52
  if (options.browser) {
66
53
  args.push('--browser', options.browser);
67
54
  }
68
-
69
55
  if (options.ciBuildId) {
70
56
  args.push('--ci-build-id', options.ciBuildId);
71
57
  }
72
-
73
58
  if (options.config) {
74
59
  args.push('--config', options.config);
75
60
  }
76
-
77
61
  if (options.configFile !== undefined) {
78
62
  checkConfigFile(options);
79
63
  args.push('--config-file', options.configFile);
80
64
  }
81
-
82
65
  if (options.env) {
83
66
  args.push('--env', options.env);
84
67
  }
85
-
86
68
  if (options.exit === false) {
87
69
  args.push('--no-exit');
88
70
  }
89
-
90
71
  if (options.group) {
91
72
  args.push('--group', options.group);
92
73
  }
93
-
94
74
  if (options.headed) {
95
75
  args.push('--headed', options.headed);
96
76
  }
97
-
98
77
  if (options.headless) {
99
78
  if (options.headed) {
100
79
  return throwInvalidOptionError(errors.incompatibleHeadlessFlags);
101
80
  }
102
-
103
81
  args.push('--headed', !options.headless);
104
- } // if key is set use that - else attempt to find it by environment variable
105
-
82
+ }
106
83
 
84
+ // if key is set use that - else attempt to find it by environment variable
107
85
  if (options.key == null) {
108
86
  debug('--key is not set, looking up environment variable CYPRESS_RECORD_KEY');
109
87
  options.key = util.getEnv('CYPRESS_RECORD_KEY');
110
- } // if we have a key assume we're in record mode
111
-
88
+ }
112
89
 
90
+ // if we have a key assume we're in record mode
113
91
  if (options.key) {
114
92
  args.push('--key', options.key);
115
93
  }
116
-
117
94
  if (options.outputPath) {
118
95
  args.push('--output-path', options.outputPath);
119
96
  }
120
-
121
97
  if (options.parallel) {
122
98
  args.push('--parallel');
123
99
  }
124
-
125
100
  if (options.port) {
126
101
  args.push('--port', options.port);
127
102
  }
128
-
129
103
  if (options.quiet) {
130
104
  args.push('--quiet');
131
- } // if record is defined and we're not
132
- // already in ci mode, then send it up
133
-
105
+ }
134
106
 
107
+ // if record is defined and we're not
108
+ // already in ci mode, then send it up
135
109
  if (options.record != null) {
136
110
  args.push('--record', options.record);
137
- } // if we have a specific reporter push that into the args
138
-
111
+ }
139
112
 
113
+ // if we have a specific reporter push that into the args
140
114
  if (options.reporter) {
141
115
  args.push('--reporter', options.reporter);
142
- } // if we have a specific reporter push that into the args
143
-
116
+ }
144
117
 
118
+ // if we have a specific reporter push that into the args
145
119
  if (options.reporterOptions) {
146
120
  args.push('--reporter-options', options.reporterOptions);
147
- } // if we have specific spec(s) push that into the args
148
-
121
+ }
149
122
 
123
+ // if we have specific spec(s) push that into the args
150
124
  if (options.spec) {
151
125
  args.push('--spec', options.spec);
152
126
  }
153
-
154
127
  if (options.tag) {
155
128
  args.push('--tag', options.tag);
156
129
  }
157
-
158
130
  if (options.inspect) {
159
131
  args.push('--inspect');
160
132
  }
161
-
162
133
  if (options.inspectBrk) {
163
134
  args.push('--inspectBrk');
164
135
  }
165
-
166
136
  args.push(...processTestingType(options));
167
137
  return args;
168
138
  };
169
-
170
139
  module.exports = {
171
140
  processRunOptions,
172
141
  isValidProject,
173
-
174
142
  // resolves with the number of failed tests
175
143
  start(options = {}) {
176
144
  _.defaults(options, {
@@ -180,7 +148,6 @@ module.exports = {
180
148
  reporterOptions: null,
181
149
  project: process.cwd()
182
150
  });
183
-
184
151
  function run() {
185
152
  try {
186
153
  const args = processRunOptions(options);
@@ -192,16 +159,12 @@ module.exports = {
192
159
  if (err.details) {
193
160
  return exitWithError(err.details)();
194
161
  }
195
-
196
162
  throw err;
197
163
  }
198
164
  }
199
-
200
165
  if (options.dev) {
201
166
  return run();
202
167
  }
203
-
204
168
  return verify.start().then(run);
205
169
  }
206
-
207
170
  };