secure cookie error crash (#2685)

- fixes #1264 
- fixes #1321 
- fixes #1799  
- fixes #2689
- fixes #2688
- fixes #2687 	
- fixes #2686
This commit is contained in:
Brian Mann
2018-11-01 12:34:37 -04:00
committed by GitHub
parent b6519258d2
commit 2333d04a54
245 changed files with 5045 additions and 2955 deletions
+8
View File
@@ -10,6 +10,7 @@ const cache = require('./tasks/cache')
// we want to print help for the current command and exit with an error
function unknownOption (flag, type = 'option') {
if (this._allowUnknownOption) return
logger.error()
logger.error(` error: unknown ${type}:`, flag)
logger.error()
@@ -87,6 +88,7 @@ function includesVersion (args) {
function showVersions () {
debug('printing Cypress version')
return require('./exec/versions')
.getVersions()
.then((versions = {}) => {
@@ -187,6 +189,7 @@ module.exports = {
const defaultOpts = { force: true, welcomeMessage: false }
const parsedOpts = parseOpts(opts)
const options = _.extend(parsedOpts, defaultOpts)
require('./tasks/verify')
.start(options)
.catch(util.logErrorExit1)
@@ -203,6 +206,7 @@ module.exports = {
if (opts.command || !_.includes(['list', 'path', 'clear'], opts)) {
unknownOption.call(this, `cache ${opts}`, 'sub-command')
}
cache[opts]()
})
@@ -219,10 +223,12 @@ module.exports = {
// Deprecated Catches
const firstCommand = args[2]
if (!_.includes(knownCommands, firstCommand)) {
debug('unknown command %s', firstCommand)
logger.error('Unknown command', `"${firstCommand}"`)
program.outputHelp()
return util.exit(1)
}
@@ -233,7 +239,9 @@ module.exports = {
// so we have to manually catch '-v, --version'
return showVersions()
}
debug('program parsing arguments')
return program.parse(args)
},
}
+2
View File
@@ -11,6 +11,7 @@ const util = require('./util')
const cypressModuleApi = {
open (options = {}) {
options = util.normalizeModuleOptions(options)
return open.start(options)
},
@@ -31,6 +32,7 @@ const cypressModuleApi = {
message: 'Could not find Cypress test run results',
}
}
return output
})
})
+32 -19
View File
@@ -25,16 +25,19 @@ const failedUnzip = {
`,
}
const missingApp = (binaryDir) => ({
description: `No version of Cypress is installed in: ${chalk.cyan(binaryDir)}`,
solution: stripIndent`
const missingApp = (binaryDir) => {
return {
description: `No version of Cypress is installed in: ${chalk.cyan(binaryDir)}`,
solution: stripIndent`
\nPlease reinstall Cypress by running: ${chalk.cyan('cypress install')}
`,
})
}
}
const binaryNotExecutable = (executable) => ({
description: `Cypress cannot run because the binary does not have executable permissions: ${executable}`,
solution: stripIndent`\n
const binaryNotExecutable = (executable) => {
return {
description: `Cypress cannot run because the binary does not have executable permissions: ${executable}`,
solution: stripIndent`\n
Reasons this may happen:
- node was installed as 'root' or with 'sudo'
@@ -42,12 +45,13 @@ const binaryNotExecutable = (executable) => ({
Please check that you have the appropriate user permissions.
`,
})
}
}
const notInstalledCI = (executable) => ({
description: 'The cypress npm package is installed, but the Cypress binary is missing.',
solution: stripIndent`\n
const notInstalledCI = (executable) => {
return {
description: 'The cypress npm package is installed, but the Cypress binary is missing.',
solution: stripIndent`\n
We expected the binary to be installed here: ${chalk.cyan(executable)}
Reasons it may be missing:
@@ -61,7 +65,8 @@ const notInstalledCI = (executable) => ({
${chalk.blue('https://on.cypress.io/not-installed-ci-error')}
`,
})
}
}
const nonZeroExitCodeXvfb = {
description: 'XVFB exited with a non zero exit code.',
@@ -146,6 +151,7 @@ const removed = {
const CYPRESS_RUN_BINARY = {
notValid: (value) => {
const properFormat = `**/${state.getPlatformExecutable()}`
return {
description: `Could not run binary set by environment variable CYPRESS_RUN_BINARY=${value}`,
solution: `Ensure the environment variable is a path to the Cypress binary, matching ${properFormat}`,
@@ -155,15 +161,19 @@ const CYPRESS_RUN_BINARY = {
function getPlatformInfo () {
return util.getOsVersionAsync()
.then((version) => stripIndent`
.then((version) => {
return stripIndent`
Platform: ${os.platform()} (${version})
Cypress Version: ${util.pkgVersion()}
`)
`
})
}
function addPlatformInformation (info) {
return getPlatformInfo()
.then((platform) => merge(info, { platform }))
.then((platform) => {
return merge(info, { platform })
})
}
function formErrorText (info, msg) {
@@ -216,13 +226,16 @@ function formErrorText (info, msg) {
const raise = (text) => {
const err = new Error(text)
err.known = true
throw err
}
const throwFormErrorText = (info) => (msg) => {
return formErrorText(info, msg)
.then(raise)
const throwFormErrorText = (info) => {
return (msg) => {
return formErrorText(info, msg)
.then(raise)
}
}
module.exports = {
+4 -2
View File
@@ -88,6 +88,7 @@ module.exports = {
options.env = _.extend({}, options.env, overrides)
const child = cp.spawn(executable, args, options)
child.on('close', resolve)
child.on('error', reject)
@@ -137,8 +138,9 @@ module.exports = {
return xvfb.start()
.then(userFriendlySpawn)
.finally(xvfb.stop)
} else {
return userFriendlySpawn()
}
return userFriendlySpawn()
},
}
+3
View File
@@ -11,11 +11,13 @@ const getVersions = () => {
if (util.getEnv('CYPRESS_RUN_BINARY')) {
let envBinaryPath = path.resolve(util.getEnv('CYPRESS_RUN_BINARY'))
return state.parseRealPlatformBinaryFolderAsync(envBinaryPath)
.then((envBinaryDir) => {
if (!envBinaryDir) {
return throwFormErrorText(errors.CYPRESS_RUN_BINARY.notValid(envBinaryPath))()
}
debug('CYPRESS_RUN_BINARY has binaryDir:', envBinaryDir)
return envBinaryDir
@@ -24,6 +26,7 @@ const getVersions = () => {
return throwFormErrorText(errors.CYPRESS_RUN_BINARY.notValid(envBinaryPath))(err.message)
})
}
return state.getBinaryDir()
})
.then(state.getBinaryPkgVersionAsync)
+3
View File
@@ -22,6 +22,7 @@ module.exports = {
start () {
debug('Starting XVFB')
return xvfb.startAsync()
.catch({ nonZeroExitCode: true }, throwFormErrorText(errors.nonZeroExitCodeXvfb))
.catch((err) => {
@@ -35,6 +36,7 @@ module.exports = {
stop () {
debug('Stopping XVFB')
return xvfb.stopAsync()
},
@@ -48,6 +50,7 @@ module.exports = {
.then(R.T)
.catch((err) => {
debug('Could not verify xvfb: %s', err.message)
return false
})
.finally(xvfb.stopAsync)
+6 -1
View File
@@ -3,7 +3,9 @@ const chalk = require('chalk')
let logs = []
const logLevel = () => (process.env.npm_config_loglevel || 'notice')
const logLevel = () => {
return (process.env.npm_config_loglevel || 'notice')
}
const error = (...messages) => {
logs.push(messages.join(' '))
@@ -12,12 +14,14 @@ const error = (...messages) => {
const warn = (...messages) => {
if (logLevel() === 'silent') return
logs.push(messages.join(' '))
console.log(chalk.yellow(...messages)) // eslint-disable-line no-console
}
const log = (...messages) => {
if (logLevel() === 'silent' || logLevel() === 'warn') return
logs.push(messages.join(' '))
console.log(...messages) // eslint-disable-line no-console
}
@@ -26,6 +30,7 @@ const log = (...messages) => {
// on each one to allow easy unit testing for specific message
const logLines = (text) => {
const lines = text.split('\n')
R.forEach(log, lines)
}
+1
View File
@@ -5,6 +5,7 @@ const util = require('../util')
const path = () => {
logger.log(state.getCacheDir())
return undefined
}
+13 -3
View File
@@ -32,27 +32,32 @@ const prepend = (urlPath) => {
const endpoint = url.resolve(getBaseUrl(), urlPath)
const platform = os.platform()
const arch = os.arch()
return `${endpoint}?platform=${platform}&arch=${arch}`
}
const getUrl = (version) => {
if (is.url(version)) {
debug('version is already an url', version)
return version
}
return version ? prepend(`desktop/${version}`) : prepend('desktop')
}
const statusMessage = (err) =>
(err.statusCode
const statusMessage = (err) => {
return (err.statusCode
? [err.statusCode, err.statusMessage].join(' - ')
: err.toString())
}
const prettyDownloadErr = (err, version) => {
const msg = stripIndent`
URL: ${getUrl(version)}
${statusMessage(err)}
`
debug(msg)
return throwFormErrorText(errors.failedDownload)(msg)
@@ -72,6 +77,7 @@ const downloadFromUrl = ({ url, downloadDestination, progress }) => {
url,
followRedirect (response) {
const version = response.headers['x-version']
debug('redirect version:', version)
if (version) {
// set the version in options if we have one.
@@ -136,11 +142,15 @@ const start = ({ version, downloadDestination, progress }) => {
if (!downloadDestination) {
la(is.unemptyString(downloadDestination), 'missing download dir', arguments)
}
if (!progress) {
progress = { onProgress: () => ({}) }
progress = { onProgress: () => {
return {}
} }
}
const url = getUrl(version)
progress.throttle = 100
debug('needed Cypress version: %s', version)
+39 -17
View File
@@ -81,6 +81,7 @@ const downloadAndUnzip = ({ version, installDir, downloadDir }) => {
return download.start({ version, downloadDestination, progress })
.then((redirectVersion) => {
if (redirectVersion) version = redirectVersion
debug(`finished downloading file: ${downloadDestination}`)
})
.then(() => {
@@ -105,6 +106,7 @@ const downloadAndUnzip = ({ version, installDir, downloadDir }) => {
const cleanup = () => {
debug('removing zip file %s', downloadDestination)
return fs.removeAsync(downloadDestination)
}
@@ -145,12 +147,14 @@ const start = (options = {}) => {
const pkgVersion = util.pkgVersion()
let needVersion = pkgVersion
debug('version in package.json is', needVersion)
// let this environment variable reset the binary version we need
if (util.getEnv('CYPRESS_INSTALL_BINARY')) {
const envVarVersion = util.getEnv('CYPRESS_INSTALL_BINARY')
debug('using environment variable CYPRESS_INSTALL_BINARY %s', envVarVersion)
if (envVarVersion === '0') {
@@ -159,6 +163,7 @@ const start = (options = {}) => {
stripIndent`
${chalk.yellow('Note:')} Skipping binary installation: Environment variable CYPRESS_INSTALL_BINARY = 0.`)
logger.log()
return Promise.resolve()
}
@@ -173,6 +178,7 @@ const start = (options = {}) => {
if (util.getEnv('CYPRESS_CACHE_FOLDER')) {
const envCache = util.getEnv('CYPRESS_CACHE_FOLDER')
logger.log(
stripIndent`
${chalk.yellow('Note:')} Overriding Cypress cache directory to: ${chalk.cyan(envCache)}
@@ -194,11 +200,14 @@ const start = (options = {}) => {
${err.message}
`)
})
.then(() => state.getBinaryPkgVersionAsync(binaryDir))
.then(() => {
return state.getBinaryPkgVersionAsync(binaryDir)
})
.then((binaryVersion) => {
if (!binaryVersion) {
debug('no binary installed under cli version')
return true
}
@@ -212,22 +221,24 @@ const start = (options = {}) => {
if (options.force) {
debug('performing force install over existing binary')
return true
}
if ((binaryVersion === needVersion) || !util.isSemver(needVersion)) {
// our version matches, tell the user this is a noop
alreadyInstalledMsg()
return false
}
return true
})
.then((shouldInstall) => {
// noop if we've been told not to download
if (!shouldInstall) {
debug('Not downloading or installing binary')
return
}
@@ -254,6 +265,7 @@ const start = (options = {}) => {
}
const possibleFile = util.formAbsolutePath(needVersion)
debug('checking local file', possibleFile, 'cwd', process.cwd())
return fs.pathExistsAsync(possibleFile)
@@ -263,16 +275,19 @@ const start = (options = {}) => {
if (exists && path.extname(possibleFile) === '.zip') {
return possibleFile
}
return false
})
})
.then((pathToLocalFile) => {
if (pathToLocalFile) {
const absolutePath = path.resolve(needVersion)
debug('found local file at', absolutePath)
debug('skipping download')
const rendererOptions = getRendererOptions()
return new Listr([unzipTask({
progress: {
throttle: 100,
@@ -292,10 +307,13 @@ const start = (options = {}) => {
debug('preparing to download and unzip version ', needVersion, 'to path', installDir)
const downloadDir = os.tmpdir()
return downloadAndUnzip({ version: needVersion, installDir, downloadDir })
})
// delay 1 sec for UX, unless we are testing
.then(() => Promise.delay(1000))
.then(() => {
return Promise.delay(1000)
})
.then(displayCompletionMsg)
})
}
@@ -304,22 +322,24 @@ module.exports = {
start,
}
const unzipTask = ({ zipFilePath, installDir, progress, rendererOptions }) => ({
title: util.titleize('Unzipping Cypress'),
task: (ctx, task) => {
const unzipTask = ({ zipFilePath, installDir, progress, rendererOptions }) => {
return {
title: util.titleize('Unzipping Cypress'),
task: (ctx, task) => {
// as our unzip progresses indicate the status
progress.onProgress = progessify(task, 'Unzipping Cypress')
progress.onProgress = progessify(task, 'Unzipping Cypress')
return unzip.start({ zipFilePath, installDir, progress })
.then(() => {
util.setTaskTitle(
task,
util.titleize(chalk.green('Unzipped Cypress')),
rendererOptions.renderer
)
})
},
})
return unzip.start({ zipFilePath, installDir, progress })
.then(() => {
util.setTaskTitle(
task,
util.titleize(chalk.green('Unzipped Cypress')),
rendererOptions.renderer
)
})
},
}
}
const progessify = (task, title) => {
// return higher order function
@@ -342,9 +362,11 @@ const progessify = (task, title) => {
// the default
const getRendererOptions = () => {
let renderer = util.isCi() ? verbose : 'default'
if (logger.logLevel() === 'silent') {
renderer = 'silent'
}
return {
renderer,
}
+12 -1
View File
@@ -8,6 +8,7 @@ const util = require('../util')
const getPlatformExecutable = () => {
const platform = os.platform()
switch (platform) {
case 'darwin': return 'Contents/MacOS/Cypress'
case 'linux': return 'Cypress'
@@ -19,6 +20,7 @@ const getPlatformExecutable = () => {
const getPlatFormBinaryFolder = () => {
const platform = os.platform()
switch (platform) {
case 'darwin': return 'Cypress.app'
case 'linux': return 'Cypress'
@@ -30,6 +32,7 @@ const getPlatFormBinaryFolder = () => {
const getBinaryPkgPath = (binaryDir) => {
const platform = os.platform()
switch (platform) {
case 'darwin': return path.join(binaryDir, 'Contents', 'Resources', 'app', 'package.json')
case 'linux': return path.join(binaryDir, 'resources', 'app', 'package.json')
@@ -52,11 +55,14 @@ const getVersionDir = (version = util.pkgVersion()) => {
const getCacheDir = () => {
let cache_directory = util.getCacheDir()
if (util.getEnv('CYPRESS_CACHE_FOLDER')) {
const envVarCacheDir = util.getEnv('CYPRESS_CACHE_FOLDER')
debug('using environment variable CYPRESS_CACHE_FOLDER %s', envVarCacheDir)
cache_directory = path.resolve(envVarCacheDir)
}
return cache_directory
}
@@ -67,9 +73,11 @@ const parseRealPlatformBinaryFolderAsync = (binaryPath) => {
if (!realPath.toString().endsWith(getPlatformExecutable())) {
return false
}
if (os.platform() === 'darwin') {
return path.resolve(realPath, '..', '..', '..')
}
return path.resolve(realPath, '..')
})
}
@@ -86,6 +94,7 @@ const getBinaryStateContentsAsync = (binaryDir) => {
return fs.readJsonAsync(getBinaryStatePath(binaryDir))
.catch({ code: 'ENOENT' }, SyntaxError, () => {
debug('could not read binary_state.json file')
return {}
})
}
@@ -119,18 +128,20 @@ const getPathToExecutable = (binaryDir) => {
const getBinaryPkgVersionAsync = (binaryDir) => {
const pathToPackageJson = getBinaryPkgPath(binaryDir)
debug('Reading binary package.json from:', pathToPackageJson)
return fs.pathExistsAsync(pathToPackageJson)
.then((exists) => {
if (!exists) {
return null
}
return fs.readJsonAsync(pathToPackageJson)
.get('version')
})
}
module.exports = {
getPathToExecutable,
getPlatformExecutable,
+12 -6
View File
@@ -27,6 +27,7 @@ const unzip = ({ zipFilePath, installDir, progress }) => {
return new Promise((resolve, reject) => {
return yauzl.open(zipFilePath, (err, zipFile) => {
if (err) return reject(err)
// debug('zipfile.paths:', zipFile)
// zipFile.on('entry', debug)
// debug(zipFile.readEntry())
@@ -34,7 +35,6 @@ const unzip = ({ zipFilePath, installDir, progress }) => {
debug('zipFile entries count', total)
const started = new Date()
let percent = 0
@@ -59,7 +59,9 @@ const unzip = ({ zipFilePath, installDir, progress }) => {
const unzipWithNode = () => {
const endFn = (err) => {
if (err) { return reject(err) }
if (err) {
return reject(err)
}
return resolve()
}
@@ -81,10 +83,9 @@ const unzip = ({ zipFilePath, installDir, progress }) => {
const copyingFileRe = /^copying file/
const sp = cp.spawn('ditto', ['-xkV', zipFilePath, installDir])
sp.on('error', () =>
// f-it just unzip with node
unzipWithNode()
)
sp.on('error', unzipWithNode)
sp.on('close', (code) => {
if (code === 0) {
@@ -125,12 +126,17 @@ const unzip = ({ zipFilePath, installDir, progress }) => {
const start = ({ zipFilePath, installDir, progress }) => {
la(is.unemptyString(installDir), 'missing installDir')
if (!progress) progress = { onProgress: () => ({}) }
if (!progress) {
progress = { onProgress: () => {
return {}
} }
}
return fs.pathExists(installDir)
.then((exists) => {
if (exists) {
debug('removing existing unzipped binary', installDir)
return fs.removeAsync(installDir)
}
})
+31 -11
View File
@@ -7,7 +7,6 @@ const { stripIndent } = require('common-tags')
const Promise = require('bluebird')
const logSymbols = require('log-symbols')
const { throwFormErrorText, errors } = require('../errors')
const util = require('../util')
const logger = require('../logger')
@@ -16,7 +15,9 @@ const state = require('./state')
const checkExecutable = (binaryDir) => {
const executable = state.getPathToExecutable(binaryDir)
debug('checking if executable exists', executable)
return util.isExecutableAsync(executable)
.then((isExecutable) => {
debug('Binary is executable? :', isExecutable)
@@ -28,6 +29,7 @@ const checkExecutable = (binaryDir) => {
if (util.isCi()) {
return throwFormErrorText(errors.notInstalledCI(executable))()
}
return throwFormErrorText(errors.missingApp(binaryDir))(stripIndent`
Cypress executable not found at: ${chalk.cyan(executable)}
`)
@@ -37,31 +39,37 @@ const checkExecutable = (binaryDir) => {
const runSmokeTest = (binaryDir) => {
debug('running smoke test')
const cypressExecPath = state.getPathToExecutable(binaryDir)
debug('using Cypress executable %s', cypressExecPath)
const onXvfbError = (err) => {
debug('caught xvfb error %s', err.message)
return throwFormErrorText(errors.missingXvfb)(`Caught error trying to run XVFB: "${err.message}"`)
}
const onSmokeTestError = (err) => {
debug('Smoke test failed:', err)
return throwFormErrorText(errors.missingDependency)(err.stderr || err.message)
}
const needsXvfb = xvfb.isNeeded()
debug('needs XVFB?', needsXvfb)
const spawn = () => {
const random = _.random(0, 1000)
const args = ['--smoke-test', `--ping=${random}`]
const smokeTestCommand = `${cypressExecPath} ${args.join(' ')}`
debug('smoke test command:', smokeTestCommand)
return Promise.resolve(util.exec(cypressExecPath, args))
.catch(onSmokeTestError)
.then((result) => {
const smokeTestReturned = result.stdout
debug('smoke test stdout "%s"', smokeTestReturned)
if (!util.stdoutLineMatches(String(random), smokeTestReturned)) {
@@ -85,15 +93,15 @@ const runSmokeTest = (binaryDir) => {
return xvfb.stop()
.catch(onXvfbError)
})
} else {
return spawn()
}
return spawn()
}
function testBinary (version, binaryDir) {
debug('running binary verification check', version)
logger.log(stripIndent`
It looks like this is your first time using Cypress: ${chalk.cyan(version)}
`)
@@ -104,18 +112,19 @@ function testBinary (version, binaryDir) {
// the verbose renderer else use
// the default
let renderer = util.isCi() ? verbose : 'default'
if (logger.logLevel() === 'silent') renderer = 'silent'
const rendererOptions = {
renderer,
}
const tasks = new Listr([
{
title: util.titleize('Verifying Cypress can run', chalk.gray(binaryDir)),
task: (ctx, task) => {
debug('clearing out the verified version')
return state.clearBinaryStateAsync(binaryDir)
.then(() => {
return Promise.all([
@@ -125,6 +134,7 @@ function testBinary (version, binaryDir) {
})
.then(() => {
debug('write verified: true')
return state.writeBinaryVerifiedAsync(true, binaryDir)
})
.then(() => {
@@ -151,6 +161,7 @@ const maybeVerify = (installedVersion, binaryDir, options = {}) => {
debug('is Verified ?', isVerified)
let shouldVerify = !isVerified
// force verify if options.force
if (options.force) {
debug('force verify')
@@ -182,6 +193,7 @@ const start = (options = {}) => {
const parseBinaryEnvVar = () => {
const envBinaryPath = util.getEnv('CYPRESS_RUN_BINARY')
debug('CYPRESS_RUN_BINARY exists, =', envBinaryPath)
logger.log(stripIndent`
${chalk.yellow('Note:')} You have set the environment variable: ${chalk.white('CYPRESS_RUN_BINARY=')}${chalk.cyan(envBinaryPath)}:
@@ -199,11 +211,14 @@ const start = (options = {}) => {
`)
}
})
.then(() => state.parseRealPlatformBinaryFolderAsync(envBinaryPath))
.then(() => {
return state.parseRealPlatformBinaryFolderAsync(envBinaryPath)
})
.then((envBinaryDir) => {
if (!envBinaryDir) {
return throwFormErrorText(errors.CYPRESS_RUN_BINARY.notValid(envBinaryPath))()
}
debug('CYPRESS_RUN_BINARY has binaryDir:', envBinaryDir)
binaryDir = envBinaryDir
@@ -213,20 +228,26 @@ const start = (options = {}) => {
})
}
return Promise.try(() => {
debug('checking environment variables')
if (util.getEnv('CYPRESS_RUN_BINARY')) {
return parseBinaryEnvVar()
}
})
.then(() => checkExecutable(binaryDir))
.tap(() => debug('binaryDir is ', binaryDir))
.then(() => state.getBinaryPkgVersionAsync(binaryDir))
.then(() => {
return checkExecutable(binaryDir)
})
.tap(() => {
return debug('binaryDir is ', binaryDir)
})
.then(() => {
return state.getBinaryPkgVersionAsync(binaryDir)
})
.then((binaryVersion) => {
if (!binaryVersion) {
debug('no Cypress binary found for cli version ', packageVersion)
return throwFormErrorText(errors.missingApp(binaryDir))(`
Cannot read binary version from: ${chalk.cyan(state.getBinaryPkgPath(binaryDir))}
`)
@@ -247,7 +268,6 @@ const start = (options = {}) => {
These versions may not work properly together.
`)
logger.log()
}
+18 -4
View File
@@ -29,6 +29,7 @@ function normalizeModuleOptions (options = {}) {
function stdoutLineMatches (expectedLine, stdout) {
const lines = stdout.split('\n').map(R.trim)
const lineMatches = R.equals(expectedLine)
return lines.some(lineMatches)
}
@@ -179,11 +180,16 @@ const util = {
return Promise.try(() => {
if (os.platform() === 'linux') {
return getosAsync()
.then((osInfo) => [osInfo.dist, osInfo.release].join(' - '))
.catch(() => os.release())
} else {
return os.release()
.then((osInfo) => {
return [osInfo.dist, osInfo.release].join(' - ')
})
.catch(() => {
return os.release()
})
}
return os.release()
})
},
@@ -195,6 +201,7 @@ const util = {
if (path.isAbsolute(filename)) {
return filename
}
return path.join(process.cwd(), '..', '..', filename)
},
@@ -202,18 +209,25 @@ const util = {
const envVar = process.env[varName]
const configVar = process.env[`npm_config_${varName}`]
const packageConfigVar = process.env[`npm_package_config_${varName}`]
if (envVar) {
debug(`Using ${varName} from environment variable`)
return envVar
}
if (configVar) {
debug(`Using ${varName} from npm config`)
return configVar
}
if (packageConfigVar) {
debug(`Using ${varName} from package.json config`)
return packageConfigVar
}
return undefined
},
+2 -1
View File
@@ -51,7 +51,8 @@ function makeUserPackageFile () {
.then((json) => {
return fs.outputJsonAsync(packageJsonDest, json, {
spaces: 2,
}).then(() => json) // returning package json object makes it easy to test
})
.return(json) // returning package json object makes it easy to test
})
}
+6 -4
View File
@@ -7,11 +7,13 @@ const la = require('lazy-ass')
const is = require('check-more-types')
const R = require('ramda')
const hasVersion = (json) =>
la(is.semver(json.version), 'cannot find version', json)
const hasVersion = (json) => {
return la(is.semver(json.version), 'cannot find version', json)
}
const hasAuthor = (json) =>
la(json.author === 'Brian Mann', 'wrong author name', json)
const hasAuthor = (json) => {
return la(json.author === 'Brian Mann', 'wrong author name', json)
}
const changeVersion = R.assoc('version', 'x.y.z')
+23 -15
View File
@@ -19,46 +19,55 @@ describe('cli', function () {
sinon.stub(process, 'exit')
sinon.stub(util, 'exit')
sinon.stub(util, 'logErrorExit1')
this.exec = (args) => cli.init(`node test ${args}`.split(' '))
this.exec = (args) => {
return cli.init(`node test ${args}`.split(' '))
}
})
context('unknown option', () => {
// note it shows help for that specific command
it('shows help', () =>
execa('bin/cypress', ['open', '--foo']).then((result) => {
it('shows help', () => {
return execa('bin/cypress', ['open', '--foo']).then((result) => {
snapshot('shows help for open --foo', result)
})
}
)
it('shows help for run command', () =>
execa('bin/cypress', ['run', '--foo']).then((result) => {
it('shows help for run command', () => {
return execa('bin/cypress', ['run', '--foo']).then((result) => {
snapshot('shows help for run --foo', result)
})
}
)
})
context('help command', () => {
it('shows help', () =>
execa('bin/cypress', ['help']).then(snapshot)
it('shows help', () => {
return execa('bin/cypress', ['help']).then(snapshot)
}
)
it('shows help for -h', () =>
execa('bin/cypress', ['-h']).then(snapshot)
it('shows help for -h', () => {
return execa('bin/cypress', ['-h']).then(snapshot)
}
)
it('shows help for --help', () =>
execa('bin/cypress', ['--help']).then(snapshot)
it('shows help for --help', () => {
return execa('bin/cypress', ['--help']).then(snapshot)
}
)
})
context('unknown command', () => {
it('shows usage and exits', () =>
execa('bin/cypress', ['foo']).then(snapshot)
it('shows usage and exits', () => {
return execa('bin/cypress', ['foo']).then(snapshot)
}
)
})
context('cypress version', function () {
const binaryDir = '/binary/dir'
beforeEach(function () {
sinon.stub(state, 'getBinaryDir').returns(binaryDir)
})
@@ -136,6 +145,7 @@ describe('cli', function () {
it('run.start with options + catches errors', function (done) {
const err = new Error('foo')
run.start.rejects(err)
this.exec('run')
@@ -261,7 +271,6 @@ describe('cli', function () {
})
})
it('install calls install.start without forcing', function () {
sinon.stub(install, 'start').resolves()
this.exec('install')
@@ -287,7 +296,6 @@ describe('cli', function () {
})
context('cypress verify', function () {
it('verify calls verify.start with force: true', function () {
sinon.stub(verify, 'start').resolves()
this.exec('verify')
+5
View File
@@ -21,6 +21,7 @@ describe('cypress', function () {
const getCallArgs = R.path(['lastCall', 'args', 0])
const getStartArgs = () => {
expect(open.start).to.be.called
return getCallArgs(open.start)
}
@@ -48,10 +49,12 @@ describe('cypress', function () {
context('.run', function () {
let outputPath
beforeEach(function () {
outputPath = path.join(os.tmpdir(), 'cypress/monorepo/cypress_spec/output.json')
sinon.stub(tmp, 'fileAsync').resolves(outputPath)
sinon.stub(run, 'start').resolves()
return fs.outputJsonAsync(outputPath, {
code: 0,
failingTests: [],
@@ -62,10 +65,12 @@ describe('cypress', function () {
const normalizeCallArgs = (args) => {
expect(args.outputPath).to.equal(outputPath)
delete args.outputPath
return args
}
const getStartArgs = () => {
expect(run.start).to.be.called
return normalizeCallArgs(getCallArgs(run.start))
}
+6 -4
View File
@@ -14,14 +14,16 @@ describe('errors', function () {
})
describe('individual', () => {
it('has the following errors', () =>
snapshot(Object.keys(errors))
it('has the following errors', () => {
return snapshot(Object.keys(errors))
}
)
})
context('.errors.formErrorText', function () {
it('returns fully formed text message', () =>
snapshot(formErrorText(missingXvfb))
it('returns fully formed text message', () => {
return snapshot(formErrorText(missingXvfb))
}
)
})
})
+16
View File
@@ -24,24 +24,28 @@ describe('util', () => {
it('matches entire output', () => {
const line = '444'
expect(stdoutLineMatches(line, line)).to.be.true
})
it('matches a line in output', () => {
const line = '444'
const stdout = ['start', line, 'something else'].join('\n')
expect(stdoutLineMatches(line, stdout)).to.be.true
})
it('matches a trimmed line in output', () => {
const line = '444'
const stdout = ['start', ` ${line} `, 'something else'].join('\n')
expect(stdoutLineMatches(line, stdout)).to.be.true
})
it('does not find match', () => {
const line = '445'
const stdout = ['start', '444', 'something else'].join('\n')
expect(stdoutLineMatches(line, stdout)).to.be.false
})
})
@@ -53,6 +57,7 @@ describe('util', () => {
const options = {
foo: 'bar',
}
snapshot('others_unchanged', normalizeModuleOptions(options))
})
@@ -60,6 +65,7 @@ describe('util', () => {
const options = {
env: 'foo=bar',
}
snapshot('env_as_string', normalizeModuleOptions(options))
})
@@ -71,6 +77,7 @@ describe('util', () => {
host: 'kevin.dev.local',
},
}
snapshot('env_as_object', normalizeModuleOptions(options))
})
@@ -81,6 +88,7 @@ describe('util', () => {
watchForFileChanges: false,
},
}
snapshot('config_as_object', normalizeModuleOptions(options))
})
@@ -91,6 +99,7 @@ describe('util', () => {
toConsole: true,
},
}
snapshot('reporter_options_as_object', normalizeModuleOptions(options))
})
@@ -100,6 +109,7 @@ describe('util', () => {
'a', 'b', 'c',
],
}
snapshot('spec_as_array', normalizeModuleOptions(options))
})
@@ -107,6 +117,7 @@ describe('util', () => {
const options = {
spec: 'x,y,z',
}
snapshot('spec_as_string', normalizeModuleOptions(options))
})
})
@@ -250,6 +261,7 @@ describe('util', () => {
it('does nothing if debug is not enabled', () => {
const log = sinon.spy()
log.enabled = false
util.printNodeOptions(log)
expect(log).not.have.been.called
@@ -257,6 +269,7 @@ describe('util', () => {
it('prints message when debug is enabled', () => {
const log = sinon.spy()
log.enabled = true
util.printNodeOptions(log)
expect(log).to.be.calledWith('NODE_OPTIONS is not set')
@@ -270,6 +283,7 @@ describe('util', () => {
it('does nothing if debug is not enabled', () => {
const log = sinon.spy()
log.enabled = false
util.printNodeOptions(log)
expect(log).not.have.been.called
@@ -277,6 +291,7 @@ describe('util', () => {
it('prints value when debug is enabled', () => {
const log = sinon.spy()
log.enabled = true
util.printNodeOptions(log)
expect(log).to.be.calledWith('NODE_OPTIONS=%s', 'foo')
@@ -287,6 +302,7 @@ describe('util', () => {
describe('.getOsVersionAsync', () => {
let util
let getos = sinon.stub().resolves(['distro-release'])
beforeEach(() => {
util = proxyquire(`${lib}/util`, { getos })
})
+4 -1
View File
@@ -43,7 +43,9 @@ function throwIfFnNotStubbed (stub, method) {
err.stack = _
.chain(err.stack)
.split('\n')
.reject((str) => _.includes(str, 'sinon'))
.reject((str) => {
return _.includes(str, 'sinon')
})
.join('\n')
.value()
@@ -52,6 +54,7 @@ function throwIfFnNotStubbed (stub, method) {
}
const $stub = sinon.stub
sinon.stub = function (obj, method) {
/* eslint-disable prefer-rest-params */
const stub = $stub.apply(this, arguments)