mirror of
https://github.com/vuejs/vue-cli.git
synced 2026-01-12 01:59:42 -06:00
181 lines
5.2 KiB
JavaScript
181 lines
5.2 KiB
JavaScript
const fs = require('fs')
|
|
const { installedBrowsers, info, warn, error, chalk, execa } = require('@vue/cli-shared-utils')
|
|
|
|
module.exports = (api, options) => {
|
|
api.registerCommand('test:e2e', {
|
|
description: 'run end-to-end tests with nightwatch',
|
|
usage: 'vue-cli-service test:e2e [options]',
|
|
options: {
|
|
'--url': 'run end-to-end tests against given url instead of auto-starting dev server',
|
|
'--config': 'use custom nightwatch config file (overrides internals)',
|
|
'--headless': 'use chrome or firefox in headless mode',
|
|
'--parallel': 'enable parallel mode via test workers (only available in chromedriver)',
|
|
'--use-selenium': 'use Selenium standalone server instead of chromedriver or geckodriver',
|
|
'-e, --env': 'specify comma-delimited browser envs to run in (default: chrome)',
|
|
'-t, --test': 'specify a test to run by name',
|
|
'-f, --filter': 'glob to filter tests by filename'
|
|
},
|
|
details:
|
|
`All Nightwatch CLI options are also supported.\n` +
|
|
chalk.yellow(`https://nightwatchjs.org/guide/running-tests/#command-line-options`)
|
|
}, (args, rawArgs) => {
|
|
if (args.env && args.env.includes('firefox')) {
|
|
try {
|
|
require('geckodriver')
|
|
} catch (e) {
|
|
error(`To run e2e tests in Firefox, you need to install ${chalk.yellow.bold('geckodriver')} first.`)
|
|
process.exit(1)
|
|
}
|
|
}
|
|
if (installedBrowsers.chrome) {
|
|
const userVersion = installedBrowsers.chrome
|
|
const driverVersion = require('chromedriver').version
|
|
|
|
const userMajor = userVersion.match(/^(\d+)\./)[1]
|
|
const driverMajor = driverVersion.match(/^(\d+)\./)[1]
|
|
|
|
if (userMajor !== driverMajor) {
|
|
warn(`Local ${chalk.cyan.bold('Chrome')} version is ${chalk.cyan.bold(userMajor)}, but the installed ${chalk.cyan.bold('chromedriver')} is for version ${chalk.cyan.bold(driverMajor)}.`)
|
|
warn(`There may be incompatibilities between them.`)
|
|
warn(`Please update your ${chalk.cyan.bold('chromedriver')} dependency to match the ${chalk.cyan.bold('Chrome')} version.`)
|
|
}
|
|
}
|
|
|
|
// remove args
|
|
;['url', 'mode'].forEach(toRemove => removeArg(rawArgs, toRemove))
|
|
// remove flags
|
|
;['headless', 'use-selenium', 'parallel'].forEach(toRemove => removeArg(rawArgs, toRemove, 0))
|
|
|
|
return Promise.all([
|
|
startDevServer(args, api),
|
|
loadNightwatchConfig(rawArgs, api)
|
|
]).then((results) => {
|
|
const { server, url } = results[0]
|
|
let content = args.headless ? 'in headless mode' : ''
|
|
if (args.parallel) {
|
|
content += ' with concurrency'
|
|
}
|
|
|
|
info(`Running end-to-end tests ${content}...`)
|
|
|
|
// expose dev server url to tests
|
|
process.env.VUE_DEV_SERVER_URL = url
|
|
|
|
if (rawArgs.indexOf('--env') === -1 && rawArgs.indexOf('-e') === -1) {
|
|
rawArgs.push('--env', 'chrome')
|
|
}
|
|
|
|
if (args['use-selenium']) {
|
|
process.env.VUE_NIGHTWATCH_USE_SELENIUM = '1'
|
|
}
|
|
|
|
if (args.headless) {
|
|
process.env.VUE_NIGHTWATCH_HEADLESS = '1'
|
|
}
|
|
|
|
if (args.parallel) {
|
|
process.env.VUE_NIGHTWATCH_CONCURRENT = '1'
|
|
}
|
|
|
|
const nightWatchBinPath = require.resolve('nightwatch/bin/nightwatch')
|
|
const runner = execa(nightWatchBinPath, rawArgs, { stdio: 'inherit' })
|
|
if (server) {
|
|
runner.on('exit', () => server.close())
|
|
runner.on('error', () => server.close())
|
|
}
|
|
|
|
if (process.env.VUE_CLI_TEST) {
|
|
runner.on('exit', code => {
|
|
process.exit(code)
|
|
})
|
|
}
|
|
|
|
return runner
|
|
})
|
|
})
|
|
}
|
|
|
|
module.exports.defaultModes = {
|
|
'test:e2e': 'production'
|
|
}
|
|
|
|
function startDevServer (args, api) {
|
|
const { url } = args
|
|
|
|
if (url) {
|
|
return Promise.resolve({ url })
|
|
}
|
|
|
|
return api.service.run('serve')
|
|
}
|
|
|
|
async function loadNightwatchConfig (rawArgs, api) {
|
|
if (rawArgs.indexOf('--config') === -1) {
|
|
// expose user options to config file
|
|
let userOptions
|
|
const configFiles = [
|
|
'nightwatch.config.js',
|
|
'nightwatch.conf.js',
|
|
'nightwatch.json'
|
|
].map((entry) => api.resolve(entry))
|
|
|
|
const userOptionsPath = await findAsync(configFiles, fileExists)
|
|
|
|
if (userOptionsPath) {
|
|
userOptions = require(userOptionsPath)
|
|
}
|
|
|
|
process.env.VUE_NIGHTWATCH_USER_OPTIONS = JSON.stringify(userOptions || {})
|
|
|
|
rawArgs.push('--config', require.resolve('./nightwatch.conf.js'))
|
|
}
|
|
}
|
|
|
|
async function findAsync (arr, callback) {
|
|
while (arr.length) {
|
|
const item = arr.shift()
|
|
const result = await callback(item)
|
|
|
|
if (result) {
|
|
return item
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
async function fileExists (path) {
|
|
try {
|
|
const stats = await checkPath(path)
|
|
|
|
return stats.isFile()
|
|
} catch (err) {
|
|
if (err.code === 'ENOENT') {
|
|
return false
|
|
}
|
|
|
|
throw err
|
|
}
|
|
}
|
|
|
|
function checkPath (source) {
|
|
return new Promise(function (resolve, reject) {
|
|
fs.stat(source, function (err, stat) {
|
|
if (err) {
|
|
return reject(err)
|
|
}
|
|
|
|
resolve(stat)
|
|
})
|
|
})
|
|
}
|
|
|
|
function removeArg (rawArgs, argToRemove, offset = 1) {
|
|
const matchRE = new RegExp(`^--${argToRemove}`)
|
|
const equalRE = new RegExp(`^--${argToRemove}=`)
|
|
const i = rawArgs.findIndex(arg => matchRE.test(arg))
|
|
if (i > -1) {
|
|
rawArgs.splice(i, offset + (equalRE.test(rawArgs[i]) ? 0 : 1))
|
|
}
|
|
}
|