mirror of
https://github.com/cypress-io/cypress.git
synced 2026-04-24 07:59:12 -05:00
29841f32b9
* chore: rename errors.js -> errors.ts * refactor: type safety on errors * refactor: add err_template for consistent error formatting * fix a few system tests * fix tests; update snapshots * Fix types * normalize snapshot - remove chalk ansi colors * more unit test fixes * more system test fixes * circleci build * backtick always in stdout, fix error formatting and failing snapshots * refactor: create @packages/errors * fix import * fix import * fixing build / tests * remove extraneous file * move warnIfExplicitCiBuildId * fix build / tests * Fix * error, type fixes, documentation, standardize child process error serialization * fix import * build errors on install * wrote specs generating visual images of all errors * remove unused dep * sanitize stack traces * add image diffing - if base images don't exist, create them - if base images don't match and local, overwrite them, if in CI throw - if base images are stale and local, delete them, if in CI throw * remove Courier New + MesloLGS NF font * type fixes, remove Bluebird, general cleanup * TS Cleanup * skip typecheck on tests for now * yarn.lock * fix @types/chai version * fix yarn.lock * Different version of mocha types so it isnt patched * errors spec snapshot * CI fix * fixes * store snapshot images in circle artifacts * dont change artifact destination prefix * use Courier Prime * antialias the text * decrease pixelmatch threshold, fail in CI only when changed pixels > 100 * increase timeout * overflow: hidden, remove new Promise, add debug logging Co-Authored-By: Tim Griesser <tgriesser@gmail.com> * run unit tests w/ concurrency=1 * unique window per file * disable app hardware acceleration + use in process gpu + single process * do not do image diffing - conditionally convert html to images - store html snapshots - do not store images in git * store snapshot html * Merge branch 'tgriesser/chore/refactor-errors' of https://github.com/cypress-io/cypress into tgriesser/chore/refactor-errors * remove concurrency * fix assertion * fixing ci * Link in readme * pass the browsers to listItems * fix: build @packages/errors in CI, defer import to prevent errors locally * Merge branch 'develop' into tgriesser/chore/refactor-errors * develop: chore: fix cypress npm package artifact upload path (#20023) chore(driver): move cy.within logic into it's own file (#20036) chore: update automerge workflows (#19982) fix(selectFile): use target window's File/DataTransfer classes (#20003) chore: Update Chrome (stable) to 98.0.4758.80 and Chrome (beta) to 98.0.4758.80 (#19995) fix: Adjust ffmpeg CLI args for performance (#19983) build: allow unified to run cypress on Apple Silicon (arm64) (backport #19067 to 9.x) (#19968) * fix run-if-ci.sh * remove dead code * Mark the .html files as generated in gitattributes * fix running single error case, slice out more of the brittle stack * remove additional brittle stack line * firefox web security error * nest inside of describe * reformat and redesign errors * more error cleanup and standardization * additional formatting of errors, code cleanup, refactoring * update ansi colors to match terminal colors * cleanup remaining loose ends, update several errors, compact excess formatters * fix types * additional formatting, remove TODO's, ensure no [object Object] in output * add test for 412 server response on invalid schema * update unknown dashboard error on creating run * use fs.access instead of fs.stat for perf * added PLUGINS_FILE_NOT_FOUND error - separated out from PLUGINS_FILE_ERROR - add system tests for both cases - update snapshots - remove stack trace from PLUGINS_FILE_NOT_FOUND fka PLUGINS_FILE_ERROR * add plugins system test around plugins synchronously throwing on require * remove forcing process.cwd() to be packages/server, update affected code - this was a long needed hangover from very old code that was doing unnecessary things due to respawning electron from node and handling various entrypoints into booting cypress - this also makes the root yarn dev and dev-debug work correctly because options.cwd is set correctly now * perf: lazy load chalk * remove excessive line since the file exists but is invalid * fix types * add system test when plugins function throws a synchronous error * create new PLUGINS_INVALID_EVENT_ERROR, wire it up correctly for error template use - properly pass error instance from child to ensure proper user stack frames - move error display code into the right place * only show a single stack trace, either originalError or internal cypressError * push error html snapshots * fix tests, types * fix test * fix failing tests * fix tests * fixes lots of broken tests * more test fixes * fixes more tests * fix type checking * wip: consistent handling of interpolated values * feat: fixing up errors, added simple error comparison tool * wrapping up error formatting * Fixes for unit tests * fix PLUGINS_VALIDATION_ERROR * fix fs.readdir bug, show rows even if there's only markdown formatting [SKIP CI] * when in base-list, show full width of errors * Fix type errors * added searching and filtering for files based on error name * fix: system tests * updated NO_SPECS_FOUND error to properly join searched folder + pattern - join patterns off of process.cwd, not projectRoot - highlight original specPattern in yellow, baseDir in blue - add tests * fixes failing tests * fix test * preserve original spec pattern, display relative to projectRoot for terminal banner * make the nodeVersion path display in gray, not white * fix tests, pass right variables * fix chrome:canary snapshots * update snapshots * update snapshot * strip newlines caused by "Still waiting to connect to {browser}..." * don't remove the snapshotHtmlFolder in CI, add additional verification snapshots match to error keys symmetrically * update snapshot * update snapshot * update snapshot * update snapshot * update snapshot * update snapshot * update gitignore * fix snapshot * update snapshot html * update logic for parsing the resolve pattern matching, add tests * update snapshots * update snapshot * update snapshot * update snapshot * fix failing test * fix: error_message_spec * fix snapshot * run each variant through an it(...) so multiple failures are received * add newlines to multiline formatters, add fmt.stringify, allow format overrides * stringify invalid return values from plugins * move config validation errors into packages/errors, properly highlight and stringify values * add component testing yarn commands * fix the arrow not showing on details * fix typescript error * fixed lots of poorly written tests that weren't actually testing anything. created settings validation error when given a string validation result. * fixes tests * fixes tests, adds new error template for validating within an array list (for browser validation) * remove dupe line * fix copy for consistency, update snapshots * remove redundant errors, standardize formatting and phrasing * more formatting * remove excess snapshots * prune out excessive error snapshot html files when not in CI * add missing tests, add case for when config validation fails without a fileType * fixes test * update snapshot * update snapshot * update snapshot * sort uniqErrors + errorKeys prior to assertion - assert one by one * add system test for binding to an event with the wrong handler * fixes tests * set more descriptive errors when setting invalid plugin events, or during plugin event validation * remove duplicate PLUGINS_EVENT_ERROR, collapse into existing error * use the same multiline formatting as @packages/errors * standardize verbiage and highlighting for consistency * fix incorrect error path * fixes tests, standardized and condensed more language * Update packages/errors/src/errors.ts Co-authored-by: Ryan Manuel <ryanm@cypress.io> * Update guides/error-handling.md Co-authored-by: Ryan Manuel <ryanm@cypress.io> * Update guides/error-handling.md Co-authored-by: Ryan Manuel <ryanm@cypress.io> * added some final todo's * fix types Co-authored-by: Tim Griesser <tgriesser10@gmail.com> Co-authored-by: Tim Griesser <tgriesser@gmail.com> Co-authored-by: Ryan Manuel <ryanm@cypress.io>
283 lines
7.6 KiB
JavaScript
283 lines
7.6 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 Promise = require('bluebird')
|
|
const debug = require('debug')('cypress:server:cypress')
|
|
const { getPublicConfigKeys } = require('@packages/config')
|
|
const argsUtils = require('./util/args')
|
|
const { openProject } = require('../lib/open_project')
|
|
|
|
const warning = (code, args) => {
|
|
return require('./errors').warning(code, args)
|
|
}
|
|
|
|
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 showWarningForInvalidConfig = (options) => {
|
|
const publicConfigKeys = getPublicConfigKeys()
|
|
const invalidConfigOptions = require('lodash').keys(options.config).reduce((invalid, option) => {
|
|
if (!publicConfigKeys.find((configKey) => configKey === option)) {
|
|
invalid.push(option)
|
|
}
|
|
|
|
return invalid
|
|
}, [])
|
|
|
|
if (invalidConfigOptions.length && options.invokedFromCli) {
|
|
return warning('INVALID_CONFIG_OPTION', invalidConfigOptions)
|
|
}
|
|
}
|
|
|
|
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')
|
|
}
|
|
|
|
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)
|
|
|
|
// const mainEntryFile = require.main.filename
|
|
const serverMain = require('./cwd')()
|
|
|
|
return cypressElectron.open(serverMain, args, fn)
|
|
})
|
|
})
|
|
},
|
|
|
|
openProject (options) {
|
|
// this code actually starts a project
|
|
// and is spawned from nodemon
|
|
openProject.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 = argv.filter((val) => val !== '--')
|
|
|
|
let options
|
|
|
|
try {
|
|
options = argsUtils.toObject(argv)
|
|
|
|
showWarningForInvalidConfig(options)
|
|
} 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.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 '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)
|
|
.then((results) => {
|
|
if (results.runs) {
|
|
const isCanceled = results.runs.filter((run) => run.skippedSpec).length
|
|
|
|
if (isCanceled) {
|
|
// eslint-disable-next-line no-console
|
|
console.log(require('chalk').magenta('\n Exiting with non-zero exit code because the run was canceled.'))
|
|
|
|
return 1
|
|
}
|
|
}
|
|
|
|
return results.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}'`)
|
|
}
|
|
},
|
|
}
|