mirror of
https://github.com/cypress-io/cypress.git
synced 2026-01-30 11:00:35 -06:00
* update schemas and runs fixture, @jennifer-shehane can you update the desktop gui views? thx * update runs list view to match updated api schemas * fix humanTime refactor
218 lines
5.4 KiB
JavaScript
218 lines
5.4 KiB
JavaScript
/* eslint-disable no-console */
|
|
|
|
// this file is a little cypress test runner helper
|
|
// so that we can utilize our own monorepo when testing
|
|
// things like the driver, or desktop-gui, or reporter
|
|
|
|
require('@packages/coffee/register')
|
|
|
|
const _ = require('lodash')
|
|
const cp = require('child_process')
|
|
const path = require('path')
|
|
const minimist = require('minimist')
|
|
const Promise = require('bluebird')
|
|
const xvfb = require('../cli/lib/exec/xvfb')
|
|
const la = require('lazy-ass')
|
|
const is = require('check-more-types')
|
|
const fs = Promise.promisifyAll(require('fs-extra'))
|
|
const { existsSync } = require('fs')
|
|
const { basename } = require('path')
|
|
|
|
const humanTime = require('../packages/server/lib/util/human_time.coffee')
|
|
|
|
const glob = Promise.promisify(require('glob'))
|
|
|
|
const options = minimist(process.argv.slice(2))
|
|
|
|
const started = new Date()
|
|
|
|
let numFailed = 0
|
|
|
|
// turn this back on for driver + desktop gui tests
|
|
// TODO how does this work?! I don't see where the copying can possible happen
|
|
process.env.COPY_CIRCLE_ARTIFACTS = 'true'
|
|
|
|
const isCircle = process.env.CI === 'true' && process.env.CIRCLECI === 'true'
|
|
|
|
// matches the value in circle.yml "store_artifacts" command
|
|
const artifactsFolder = '/tmp/artifacts'
|
|
|
|
// let us pass in project or resolve it to process.cwd() and dir
|
|
options.project = options.project || path.resolve(process.cwd(), options.dir || '')
|
|
console.log('options.project', options.project)
|
|
|
|
const prepareArtifactsFolder = () => {
|
|
if (!isCircle) {
|
|
return Promise.resolve()
|
|
}
|
|
console.log('Making folder %s', artifactsFolder)
|
|
return fs.ensureDirAsync(artifactsFolder)
|
|
}
|
|
|
|
const fileExists = (name) => Promise.resolve(existsSync(name))
|
|
|
|
const copyScreenshots = (name) => () => {
|
|
la(is.unemptyString(name), 'missing name', name)
|
|
|
|
const screenshots = path.join(options.project, 'cypress', 'screenshots')
|
|
return fileExists(screenshots)
|
|
.then((exists) => {
|
|
if (!exists) {
|
|
return
|
|
}
|
|
|
|
console.log('Copying screenshots for %s from %s', name, screenshots)
|
|
const destination = path.join(artifactsFolder, name)
|
|
|
|
return fs.ensureDirAsync(destination)
|
|
.then(() =>
|
|
fs.copyAsync(screenshots, destination, {
|
|
overwrite: true,
|
|
})
|
|
)
|
|
})
|
|
}
|
|
|
|
const copyVideos = (name) => () => {
|
|
const videos = path.join(options.project, 'cypress', 'videos')
|
|
return fileExists(videos)
|
|
.then((exists) => {
|
|
if (!exists) {
|
|
return
|
|
}
|
|
|
|
console.log('Copying videos for %s from %s', name, videos)
|
|
const destination = path.join(artifactsFolder, name)
|
|
return fs.ensureDirAsync(destination)
|
|
.then(() =>
|
|
fs.copyAsync(videos, destination, {
|
|
overwrite: true,
|
|
})
|
|
)
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Copies artifacts (screenshots, videos) if configured into a subfolder
|
|
*
|
|
* @param {string} name Spec base name
|
|
*/
|
|
const copyArtifacts = (name) => () => {
|
|
if (!isCircle) {
|
|
return Promise.resolve()
|
|
}
|
|
return copyScreenshots(name)().then(copyVideos(name))
|
|
}
|
|
|
|
function isLoadBalanced (options) {
|
|
return _.isNumber(options.index) && _.isNumber(options.parallel)
|
|
}
|
|
|
|
function spawn (cmd, args, opts) {
|
|
return new Promise((resolve, reject) => {
|
|
cp.spawn(cmd, args, opts)
|
|
.on('exit', resolve)
|
|
.on('error', reject)
|
|
})
|
|
}
|
|
|
|
_.defaults(options, {
|
|
dir: '',
|
|
glob: 'cypress/integration/**/*',
|
|
})
|
|
|
|
// normalize and set to absolute path based on process.cwd
|
|
options.glob = path.resolve(options.project, options.glob)
|
|
|
|
const runSpec = (spec) => {
|
|
console.log('\nRunning spec', spec)
|
|
la(is.unemptyString(spec), 'missing spec filename', spec)
|
|
|
|
// get the path to xvfb-maybe binary
|
|
// const cmd = path.join(__dirname, '..', 'node_modules', '.bin', 'xvfb-maybe')
|
|
|
|
const configFile = path.join(__dirname, '..', 'mocha-reporter-config.json')
|
|
|
|
const args = [
|
|
// '-as',
|
|
// '\"-screen 0 1280x720x16\"',
|
|
// '--',
|
|
// 'node',
|
|
path.resolve('..', '..', 'scripts', 'start.js'), // launch root monorepo start
|
|
'--run-project',
|
|
options.project,
|
|
'--spec',
|
|
spec,
|
|
'--reporter',
|
|
path.resolve(__dirname, '..', 'node_modules', 'mocha-multi-reporters'),
|
|
'--reporter-options',
|
|
`configFile=${configFile}`,
|
|
]
|
|
|
|
if (options.browser) {
|
|
args.push('--browser', options.browser)
|
|
}
|
|
|
|
return spawn('node', args, { stdio: 'inherit' })
|
|
.then((code) => {
|
|
console.log(`${spec} exited with code`, code)
|
|
|
|
numFailed += code
|
|
})
|
|
.then(copyArtifacts(basename(spec)))
|
|
.catch((err) => {
|
|
console.log(err)
|
|
throw err
|
|
})
|
|
}
|
|
|
|
function run () {
|
|
console.log('Specs found:')
|
|
|
|
return glob(options.glob, {
|
|
nodir: true,
|
|
realpath: true,
|
|
})
|
|
.tap(prepareArtifactsFolder)
|
|
.then((specs = []) => {
|
|
if (options.spec) {
|
|
return _.filter(specs, (spec) => {
|
|
return spec.includes(options.spec)
|
|
})
|
|
}
|
|
|
|
if (isLoadBalanced(options)) {
|
|
// take the total number of specs and divide by our
|
|
// total number of parallel nodes, ceiling the number
|
|
const size = Math.ceil(specs.length / options.parallel)
|
|
|
|
// chunk the specs by the total nodes
|
|
// and then just grab this index's specs
|
|
return _.chunk(specs, size)[options.index]
|
|
}
|
|
|
|
return specs
|
|
})
|
|
.tap(console.log)
|
|
.each(runSpec)
|
|
.then(() => {
|
|
const duration = new Date() - started
|
|
|
|
console.log('')
|
|
console.log('Total duration:', humanTime.long(duration))
|
|
console.log('Exiting with final code:', numFailed)
|
|
|
|
process.exit(numFailed)
|
|
})
|
|
}
|
|
|
|
const needsXvfb = xvfb.isNeeded()
|
|
|
|
if (needsXvfb) {
|
|
return xvfb.start()
|
|
.then(run)
|
|
.finally(xvfb.stop)
|
|
} else {
|
|
return run()
|
|
}
|