mirror of
https://github.com/cypress-io/cypress.git
synced 2026-04-27 10:19:26 -05:00
070fceff20
* WIP: add cli info command to list detected browsers * print found browsers * change to list * start work on info command calling into binary * move info command into binary * print OS info during cypress info command * add binary cache path to info command * add browser profile path * add memory * get browser profile path without partition * pick real browsers as examples * output same info as desired * better names * changed colors * add list of cached binary versions * do not put stable into name * add underlined link * conditionally show profile path, only if the folder exists * do not list cached binaries * human-friendly memory print * print env proxy vars * print CYPRESS_ env variables * use _.sample * update order * store cypress info output on CI as HTML page artifact * add percy CLI screenshots * sanitize cypress info command * store CLI snapshots in cli/visual-snapshots folder * update cli unit snapshot * add cli unit test * start e2e testing for cypress info * add test with proxy and cypress vars * make sure we call the binary * stricter start check * start unit testing modes info * test info mode browser print * add test for profile path * add cypress info command to test binary Circle job * add cypress info to test-binary-as-specific-user circle * print cypress info --dev on circle and on appveyor * update .gitignore * move error in environment load to debug
271 lines
7.3 KiB
JavaScript
271 lines
7.3 KiB
JavaScript
require('./environment')
|
|
|
|
// we are not requiring everything up front
|
|
// to optimize how quickly electron boots while
|
|
// in dev or linux production. the reasoning is
|
|
// that we likely may need to spawn a new child process
|
|
// and its a huge waste of time (about 1.5secs) of
|
|
// synchronous requires the first go around just to
|
|
// essentially do it all again when we boot the correct
|
|
// mode.
|
|
|
|
const R = require('ramda')
|
|
const Promise = require('bluebird')
|
|
const debug = require('debug')('cypress:server:cypress')
|
|
const argsUtils = require('./util/args')
|
|
|
|
const warning = (code) => {
|
|
return require('./errors').warning(code)
|
|
}
|
|
|
|
const exit = (code = 0) => {
|
|
// TODO: we shouldn't have to do this
|
|
// but cannot figure out how null is
|
|
// being passed into exit
|
|
debug('about to exit with code', code)
|
|
|
|
return process.exit(code)
|
|
}
|
|
|
|
const exit0 = () => {
|
|
return exit(0)
|
|
}
|
|
|
|
const exitErr = (err) => {
|
|
// log errors to the console
|
|
// and potentially raygun
|
|
// and exit with 1
|
|
debug('exiting with err', err)
|
|
|
|
return require('./errors').logException(err)
|
|
.then(() => {
|
|
debug('calling exit 1')
|
|
|
|
return exit(1)
|
|
})
|
|
}
|
|
|
|
module.exports = {
|
|
isCurrentlyRunningElectron () {
|
|
return require('./util/electron-app').isRunning()
|
|
},
|
|
|
|
runElectron (mode, options) {
|
|
// wrap all of this in a promise to force the
|
|
// promise interface - even if it doesn't matter
|
|
// in dev mode due to cp.spawn
|
|
return Promise.try(() => {
|
|
// if we have the electron property on versions
|
|
// that means we're already running in electron
|
|
// like in production and we shouldn't spawn a new
|
|
// process
|
|
if (this.isCurrentlyRunningElectron()) {
|
|
// if we weren't invoked from the CLI
|
|
// then display a warning to the user
|
|
if (!options.invokedFromCli) {
|
|
warning('INVOKED_BINARY_OUTSIDE_NPM_MODULE')
|
|
}
|
|
|
|
// just run the gui code directly here
|
|
// and pass our options directly to main
|
|
debug('running Electron currently')
|
|
|
|
return require('./modes')(mode, options)
|
|
}
|
|
|
|
return new Promise((resolve) => {
|
|
debug('starting Electron')
|
|
const cypressElectron = require('@packages/electron')
|
|
|
|
const fn = (code) => {
|
|
// juggle up the totalFailed since our outer
|
|
// promise is expecting this object structure
|
|
debug('electron finished with', code)
|
|
|
|
if (mode === 'smokeTest') {
|
|
return resolve(code)
|
|
}
|
|
|
|
return resolve({ totalFailed: code })
|
|
}
|
|
|
|
const args = require('./util/args').toArray(options)
|
|
|
|
debug('electron open arguments %o', args)
|
|
|
|
return cypressElectron.open('.', args, fn)
|
|
})
|
|
})
|
|
},
|
|
|
|
openProject (options) {
|
|
// this code actually starts a project
|
|
// and is spawned from nodemon
|
|
return require('./open_project').open(options.project, options)
|
|
},
|
|
|
|
start (argv = []) {
|
|
debug('starting cypress with argv %o', argv)
|
|
|
|
// if the CLI passed "--" somewhere, we need to remove it
|
|
// for https://github.com/cypress-io/cypress/issues/5466
|
|
argv = R.without('--', argv)
|
|
|
|
let options
|
|
|
|
try {
|
|
options = argsUtils.toObject(argv)
|
|
} catch (argumentsError) {
|
|
debug('could not parse CLI arguments: %o', argv)
|
|
|
|
// note - this is promise-returned call
|
|
return exitErr(argumentsError)
|
|
}
|
|
|
|
debug('from argv %o got options %o', argv, options)
|
|
|
|
if (options.headless) {
|
|
// --headless is same as --headed false
|
|
if (options.headed) {
|
|
throw new Error('Impossible options: both headless and headed are true')
|
|
}
|
|
|
|
options.headed = false
|
|
}
|
|
|
|
if (options.runProject && !options.headed) {
|
|
debug('scaling electron app in headless mode')
|
|
// scale the electron browser window
|
|
// to force retina screens to not
|
|
// upsample their images when offscreen
|
|
// rendering
|
|
require('./util/electron-app').scale()
|
|
}
|
|
|
|
// make sure we have the appData folder
|
|
return require('./util/app_data').ensure()
|
|
.then(() => {
|
|
// else determine the mode by
|
|
// the passed in arguments / options
|
|
// and normalize this mode
|
|
let mode = options.mode || 'interactive'
|
|
|
|
if (options.version) {
|
|
mode = 'version'
|
|
} else if (options.smokeTest) {
|
|
mode = 'smokeTest'
|
|
} else if (options.returnPkg) {
|
|
mode = 'returnPkg'
|
|
} else if (options.logs) {
|
|
mode = 'logs'
|
|
} else if (options.clearLogs) {
|
|
mode = 'clearLogs'
|
|
} else if (options.getKey) {
|
|
mode = 'getKey'
|
|
} else if (options.generateKey) {
|
|
mode = 'generateKey'
|
|
} else if (!(options.exitWithCode == null)) {
|
|
mode = 'exitWithCode'
|
|
} else if (options.runProject) {
|
|
// go into headless mode when running
|
|
// until completion + exit
|
|
mode = 'run'
|
|
}
|
|
|
|
return this.startInMode(mode, options)
|
|
})
|
|
},
|
|
|
|
startInMode (mode, options) {
|
|
debug('starting in mode %s with options %o', mode, options)
|
|
|
|
switch (mode) {
|
|
case 'version':
|
|
return require('./modes/pkg')(options)
|
|
.get('version')
|
|
.then((version) => {
|
|
return console.log(version) // eslint-disable-line no-console
|
|
}).then(exit0)
|
|
.catch(exitErr)
|
|
|
|
case 'info':
|
|
return require('./modes/info')(options)
|
|
.then(exit0)
|
|
.catch(exitErr)
|
|
|
|
case 'smokeTest':
|
|
return this.runElectron(mode, options)
|
|
.then((pong) => {
|
|
if (!this.isCurrentlyRunningElectron()) {
|
|
return pong
|
|
}
|
|
|
|
if (pong === options.ping) {
|
|
return 0
|
|
}
|
|
|
|
return 1
|
|
}).then(exit)
|
|
.catch(exitErr)
|
|
|
|
case 'returnPkg':
|
|
return require('./modes/pkg')(options)
|
|
.then((pkg) => {
|
|
return console.log(JSON.stringify(pkg)) // eslint-disable-line no-console
|
|
}).then(exit0)
|
|
.catch(exitErr)
|
|
|
|
case 'logs':
|
|
// print the logs + exit
|
|
return require('./gui/logs').print()
|
|
.then(exit0)
|
|
.catch(exitErr)
|
|
|
|
case 'clearLogs':
|
|
// clear the logs + exit
|
|
return require('./gui/logs').clear()
|
|
.then(exit0)
|
|
.catch(exitErr)
|
|
|
|
case 'getKey':
|
|
// print the key + exit
|
|
return require('./project').getSecretKeyByPath(options.projectRoot)
|
|
.then((key) => {
|
|
return console.log(key) // eslint-disable-line no-console
|
|
}).then(exit0)
|
|
.catch(exitErr)
|
|
|
|
case 'generateKey':
|
|
// generate + print the key + exit
|
|
return require('./project').generateSecretKeyByPath(options.projectRoot)
|
|
.then((key) => {
|
|
return console.log(key) // eslint-disable-line no-console
|
|
}).then(exit0)
|
|
.catch(exitErr)
|
|
|
|
case 'exitWithCode':
|
|
return require('./modes/exit')(options)
|
|
.then(exit)
|
|
.catch(exitErr)
|
|
|
|
case 'run':
|
|
// run headlessly and exit
|
|
// with num of totalFailed
|
|
return this.runElectron(mode, options)
|
|
.get('totalFailed')
|
|
.then(exit)
|
|
.catch(exitErr)
|
|
|
|
case 'interactive':
|
|
return this.runElectron(mode, options)
|
|
|
|
case 'openProject':
|
|
// open + start the project
|
|
return this.openProject(options)
|
|
|
|
default:
|
|
throw new Error(`Cannot start. Invalid mode: '${mode}'`)
|
|
}
|
|
},
|
|
}
|