mirror of
https://github.com/cypress-io/cypress.git
synced 2026-05-13 02:40:22 -05:00
Merge branch 'master' of github.com:cypress-io/cypress-monorepo
This commit is contained in:
@@ -25,7 +25,7 @@ This will install this repo's direct dependencies as well as the dependencies fo
|
||||
Then, build all the packages and start the app:
|
||||
|
||||
```bash
|
||||
npm run all build-dev
|
||||
npm run all build
|
||||
npm start
|
||||
```
|
||||
|
||||
|
||||
+3
-1
@@ -50,7 +50,9 @@ module.exports = {
|
||||
.option('-e, --env <env>', text('env'))
|
||||
.option('-c, --config <config>', text('config'))
|
||||
.option('-b, --browser <browser name>', text('browser'))
|
||||
.action((opts) => require('./exec/run').start(parseOpts(opts)))
|
||||
.action((opts) =>
|
||||
require('./exec/run').start(parseOpts(opts)).then(process.exit)
|
||||
)
|
||||
|
||||
program
|
||||
.command('open')
|
||||
|
||||
+12
-3
@@ -18,9 +18,18 @@ module.exports = {
|
||||
options.outputPath = outputPath
|
||||
|
||||
return run.start(options)
|
||||
.then(() => {
|
||||
return fs.readJsonAsync(outputPath)
|
||||
})
|
||||
.then((failedTests) =>
|
||||
fs.readJsonAsync(outputPath, { throws: false })
|
||||
.then((output) => {
|
||||
if (!output) {
|
||||
return {
|
||||
failures: failedTests,
|
||||
message: 'Could not find Cypress test run results',
|
||||
}
|
||||
}
|
||||
return output
|
||||
})
|
||||
)
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ const Promise = require('bluebird')
|
||||
const request = require('request')
|
||||
const url = require('url')
|
||||
const debug = require('debug')('cypress:cli')
|
||||
const { formErrorText, errors } = require('./errors')
|
||||
const { formErrorText, errors } = require('../errors')
|
||||
const { stripIndent } = require('common-tags')
|
||||
const R = require('ramda')
|
||||
const pkg = require('../../package.json')
|
||||
|
||||
@@ -4,7 +4,7 @@ const os = require('os')
|
||||
const Promise = require('bluebird')
|
||||
const readline = require('readline')
|
||||
const yauzl = require('yauzl')
|
||||
const { formErrorText, errors } = require('./errors')
|
||||
const { formErrorText, errors } = require('../errors')
|
||||
const utils = require('./utils')
|
||||
|
||||
const fs = Promise.promisifyAll(require('fs-extra'))
|
||||
|
||||
@@ -11,7 +11,7 @@ const { stripIndent } = require('common-tags')
|
||||
const ProgressBar = require('progress')
|
||||
|
||||
const xvfb = require('../exec/xvfb')
|
||||
const { formErrorText, errors } = require('./errors')
|
||||
const { formErrorText, errors } = require('../errors')
|
||||
const packagePath = path.join(__dirname, '..', '..', 'package.json')
|
||||
const packageVersion = require(packagePath).version
|
||||
|
||||
|
||||
@@ -120,9 +120,18 @@ function formErrorText (info, error) {
|
||||
`)
|
||||
}
|
||||
|
||||
const raise = (text) => {
|
||||
throw new Error(text)
|
||||
}
|
||||
|
||||
const throwDetailedError = (info) => (error) =>
|
||||
formErrorText(info, error)
|
||||
.then(raise)
|
||||
|
||||
module.exports = {
|
||||
formError,
|
||||
formErrorText,
|
||||
throwDetailedError,
|
||||
errors: {
|
||||
missingXvfb,
|
||||
missingApp,
|
||||
+4
-3
@@ -1,5 +1,5 @@
|
||||
const _ = require('lodash')
|
||||
|
||||
const debug = require('debug')('cypress:cli')
|
||||
const downloadUtils = require('../download/utils')
|
||||
const spawn = require('./spawn')
|
||||
const path = require('path')
|
||||
@@ -76,11 +76,13 @@ const processRunOptions = (options = {}) => {
|
||||
|
||||
const run = (options) => () => {
|
||||
const args = processRunOptions(options)
|
||||
debug('run to spawn.start args %j', args)
|
||||
return spawn.start(args)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
processRunOptions,
|
||||
// resolves with the number of failed tests
|
||||
start (options = {}) {
|
||||
_.defaults(options, {
|
||||
key: null,
|
||||
@@ -90,7 +92,6 @@ module.exports = {
|
||||
project: process.cwd(),
|
||||
})
|
||||
|
||||
return downloadUtils.verify()
|
||||
.then(run(options))
|
||||
return downloadUtils.verify().then(run(options))
|
||||
},
|
||||
}
|
||||
|
||||
+11
-25
@@ -5,20 +5,12 @@ const debug = require('debug')('cypress:cli')
|
||||
|
||||
const downloadUtils = require('../download/utils')
|
||||
const xvfb = require('./xvfb')
|
||||
const { formErrorText, errors } = require('../download/errors')
|
||||
|
||||
const logAndFail = (info) => (err) => {
|
||||
const text = formErrorText(info, err)
|
||||
console.log(text) // eslint-disable-line no-console
|
||||
process.exit(1)
|
||||
}
|
||||
const { throwDetailedError, errors } = require('../errors')
|
||||
|
||||
module.exports = {
|
||||
start (args, options = {}) {
|
||||
args = [].concat(args)
|
||||
|
||||
const needsXvfb = xvfb.isNeeded()
|
||||
|
||||
_.defaults(options, {
|
||||
verify: false,
|
||||
detached: false,
|
||||
@@ -26,38 +18,32 @@ module.exports = {
|
||||
})
|
||||
|
||||
const spawn = () => {
|
||||
return new Promise((resolve) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const cypressPath = downloadUtils.getPathToExecutable()
|
||||
debug('spawning Cypress %s', cypressPath)
|
||||
debug('args %j', args)
|
||||
debug('some of the options %j', _.pick(options, ['verify', 'detached']))
|
||||
|
||||
const child = cp.spawn(cypressPath, args, options)
|
||||
if (needsXvfb) {
|
||||
//// make sure we close down xvfb
|
||||
//// when our spawned process exits
|
||||
child.on('close', xvfb.stop)
|
||||
}
|
||||
|
||||
//// when our spawned process exits
|
||||
//// make sure we kill our own process
|
||||
//// with its exit code (to bubble up errors)
|
||||
child.on('exit', process.exit)
|
||||
child.on('exit', resolve)
|
||||
child.on('error', reject)
|
||||
|
||||
if (options.detached) {
|
||||
child.unref()
|
||||
}
|
||||
|
||||
resolve(child)
|
||||
})
|
||||
}
|
||||
|
||||
const userFriendlySpawn = () =>
|
||||
spawn().catch(throwDetailedError(errors.unexpected))
|
||||
|
||||
const needsXvfb = xvfb.isNeeded()
|
||||
if (needsXvfb) {
|
||||
return xvfb.start()
|
||||
.then(spawn)
|
||||
.catch(logAndFail(errors.missingXvfb))
|
||||
.then(userFriendlySpawn)
|
||||
.finally(xvfb.stop)
|
||||
} else {
|
||||
return spawn()
|
||||
return userFriendlySpawn()
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@@ -3,12 +3,16 @@ const Promise = require('bluebird')
|
||||
const Xvfb = require('@cypress/xvfb')
|
||||
const R = require('ramda')
|
||||
const debug = require('debug')('cypress:cli')
|
||||
const { throwDetailedError, errors } = require('../errors')
|
||||
|
||||
const xvfb = Promise.promisifyAll(new Xvfb({ silent: true }))
|
||||
|
||||
module.exports = {
|
||||
_xvfb: xvfb, // expose for testing
|
||||
|
||||
start () {
|
||||
return xvfb.startAsync()
|
||||
.catch(throwDetailedError(errors.missingXvfb))
|
||||
},
|
||||
|
||||
stop () {
|
||||
|
||||
+12
-1
@@ -1,5 +1,6 @@
|
||||
require('./spec_helper')
|
||||
|
||||
const _ = require('lodash')
|
||||
const cli = require('../lib/cli')
|
||||
const download = require('../lib/download')
|
||||
const downloadUtils = require('../lib/download/utils')
|
||||
@@ -8,11 +9,21 @@ const open = require('../lib/exec/open')
|
||||
|
||||
describe('cli', function () {
|
||||
beforeEach(function () {
|
||||
this.sandbox.stub(process, 'exit')
|
||||
this.exec = (args) => cli.init().parse(`node test ${args}`.split(' '))
|
||||
})
|
||||
|
||||
it('exits when done', function (done) {
|
||||
this.sandbox.stub(run, 'start').resolves()
|
||||
this.exec('run --port 7878')
|
||||
_.defer(() => {
|
||||
expect(process.exit).to.be.calledOnce
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('run calls run#start with options', function () {
|
||||
this.sandbox.stub(run, 'start')
|
||||
this.sandbox.stub(run, 'start').resolves()
|
||||
this.exec('run --port 7878')
|
||||
expect(run.start).to.be.calledWith({ port: '7878' })
|
||||
})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
require('../spec_helper')
|
||||
|
||||
const os = require('os')
|
||||
const { errors, formError, formErrorText } = require('../../lib/download/errors')
|
||||
const { errors, formError, formErrorText } = require('../../lib/errors')
|
||||
const snapshot = require('snap-shot')
|
||||
const { omit } = require('ramda')
|
||||
|
||||
|
||||
@@ -40,8 +40,7 @@ describe('exec run', function () {
|
||||
|
||||
context('cli interface', function () {
|
||||
beforeEach(function () {
|
||||
this.sandbox.stub(run, 'start')
|
||||
|
||||
this.sandbox.stub(run, 'start').resolves()
|
||||
this.parse = (args) => cli.init().parse(`node test ${args}`.split(' '))
|
||||
})
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
require('../spec_helper')
|
||||
|
||||
const _ = require('lodash')
|
||||
const EE = require('events').EventEmitter
|
||||
const cp = require('child_process')
|
||||
|
||||
const downloadUtils = require('../../lib/download/utils')
|
||||
@@ -11,8 +9,9 @@ const spawn = require('../../lib/exec/spawn')
|
||||
describe('exec spawn', function () {
|
||||
beforeEach(function () {
|
||||
this.sandbox.stub(process, 'exit')
|
||||
this.spawnedProcess = _.extend(new EE(), {
|
||||
unref: this.sandbox.stub(),
|
||||
this.spawnedProcess = this.sandbox.stub({
|
||||
on: () => {},
|
||||
unref: () => {},
|
||||
})
|
||||
this.sandbox.stub(cp, 'spawn').returns(this.spawnedProcess)
|
||||
this.sandbox.stub(xvfb, 'start').resolves()
|
||||
@@ -23,12 +22,14 @@ describe('exec spawn', function () {
|
||||
|
||||
context('#spawn', function () {
|
||||
it('passes args + options to spawn', function () {
|
||||
this.spawnedProcess.on.withArgs('exit').yieldsAsync(0)
|
||||
return spawn.start('--foo', { foo: 'bar' }).then(() => {
|
||||
expect(cp.spawn).to.be.calledWithMatch('/path/to/cypress', ['--foo'], { foo: 'bar' })
|
||||
})
|
||||
})
|
||||
|
||||
it('starts xvfb when needed', function () {
|
||||
this.spawnedProcess.on.withArgs('exit').yieldsAsync(0)
|
||||
return spawn.start('--foo').then(() => {
|
||||
expect(xvfb.start).to.be.calledOnce
|
||||
})
|
||||
@@ -37,32 +38,50 @@ describe('exec spawn', function () {
|
||||
it('does not start xvfb when its not needed', function () {
|
||||
xvfb.isNeeded.returns(false)
|
||||
|
||||
this.spawnedProcess.on.withArgs('exit').yieldsAsync(0)
|
||||
return spawn.start('--foo').then(() => {
|
||||
expect(xvfb.start).not.to.be.called
|
||||
})
|
||||
})
|
||||
|
||||
it('stops xvfb when spawn closes', function () {
|
||||
this.spawnedProcess.on.withArgs('exit').yieldsAsync(0)
|
||||
this.spawnedProcess.on.withArgs('close').yields()
|
||||
return spawn.start('--foo').then(() => {
|
||||
this.spawnedProcess.emit('close')
|
||||
expect(xvfb.stop).to.be.calledOnce
|
||||
})
|
||||
})
|
||||
|
||||
it('exits with spawned exit code', function () {
|
||||
return spawn.start('--foo').then(() => {
|
||||
this.spawnedProcess.emit('exit', 10)
|
||||
expect(process.exit).to.be.calledWith(10)
|
||||
it('resolves with spawned exit code in the message', function () {
|
||||
this.spawnedProcess.on.withArgs('exit').yieldsAsync(10)
|
||||
|
||||
return spawn.start('--foo')
|
||||
.then((code) => {
|
||||
expect(code).to.equal(10)
|
||||
})
|
||||
})
|
||||
|
||||
it('rejects with error from spawn', function () {
|
||||
const msg = 'the error message'
|
||||
this.spawnedProcess.on.withArgs('error').yieldsAsync(new Error(msg))
|
||||
|
||||
return spawn.start('--foo')
|
||||
.then(() => {
|
||||
throw new Error('should have hit error handler but did not')
|
||||
}, (e) => {
|
||||
expect(e.message).to.include(msg)
|
||||
})
|
||||
})
|
||||
|
||||
it('unrefs if options.detached is true', function () {
|
||||
this.spawnedProcess.on.withArgs('exit').yieldsAsync(0)
|
||||
return spawn.start(null, { detached: true }).then(() => {
|
||||
expect(this.spawnedProcess.unref).to.be.calledOnce
|
||||
})
|
||||
})
|
||||
|
||||
it('does not unref by default', function () {
|
||||
this.spawnedProcess.on.withArgs('exit').yieldsAsync(0)
|
||||
return spawn.start().then(() => {
|
||||
expect(this.spawnedProcess.unref).not.to.be.called
|
||||
})
|
||||
|
||||
@@ -1,10 +1,27 @@
|
||||
require('../spec_helper')
|
||||
|
||||
const os = require('os')
|
||||
const xvfb = require('../../lib/exec/xvfb')
|
||||
|
||||
const os = require('os')
|
||||
|
||||
describe('exec xvfb', function () {
|
||||
context('#start', function () {
|
||||
it('passes', function () {
|
||||
this.sandbox.stub(xvfb._xvfb, 'startAsync').resolves()
|
||||
return xvfb.start()
|
||||
})
|
||||
|
||||
it('fails with error message', function () {
|
||||
const message = 'nope'
|
||||
this.sandbox.stub(xvfb._xvfb, 'startAsync').rejects(new Error(message))
|
||||
return xvfb.start()
|
||||
.then(() => {
|
||||
throw new Error('Should have thrown an error')
|
||||
}, (err) => {
|
||||
expect(err.message).to.include(message)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
context('#isNeeded', function () {
|
||||
afterEach(() => delete process.env.DISPLAY)
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ describe "Update Banner", ->
|
||||
it "modal has info about downloading new version", ->
|
||||
cy.get(".modal").contains("Download the new version")
|
||||
|
||||
it.only "opens download link when Download is clicked", ->
|
||||
it "opens download link when Download is clicked", ->
|
||||
cy.contains("Download the new version").click().then =>
|
||||
expect(@ipc.externalOpen).to.be.calledWith("https://download.cypress.io/desktop?os=linux64")
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ npm run lint
|
||||
#### For development
|
||||
|
||||
```bash
|
||||
npm run build-dev
|
||||
npm run build
|
||||
```
|
||||
|
||||
#### For production
|
||||
@@ -42,7 +42,7 @@ npm run build-prod
|
||||
### Watching
|
||||
|
||||
```bash
|
||||
npm run watch-dev
|
||||
npm run watch
|
||||
```
|
||||
|
||||
### Testing
|
||||
|
||||
Reference in New Issue
Block a user