Skip to content

Commit

Permalink
feat(nightwatch): check user's installed browser versions on scaffold…
Browse files Browse the repository at this point in the history
…ing / before running tests (#4563)
  • Loading branch information
haoqunjiang authored Sep 12, 2019
1 parent dcd8d94 commit 0473432
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 7 deletions.
18 changes: 16 additions & 2 deletions packages/@vue/cli-plugin-e2e-nightwatch/generator/index.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,29 @@
const { installedBrowsers } = require('@vue/cli-shared-utils')

module.exports = api => {
api.render('./template', {
hasTS: api.hasPlugin('typescript')
})

// Use devDependencies to store latest version number so as to automate update
const devDeps = require('../package.json').devDependencies
const geckodriver = devDeps.geckodriver

// chromedriver major version bumps every 6 weeks following Chrome
// so there may be a mismatch between
// user's installed browser version and the default provided version
// fallback to the devDependencies version in case detection fails
const chromedriver = installedBrowsers.chrome
? installedBrowsers.chrome.match(/^(\d+)\./)[1]
: devDeps.chromedriver

api.extendPackage({
scripts: {
'test:e2e': 'vue-cli-service test:e2e'
},
devDependencies: {
chromedriver: '^76.0.1',
geckodriver: '^1.16.2'
chromedriver,
geckodriver
}
})
}
25 changes: 23 additions & 2 deletions packages/@vue/cli-plugin-e2e-nightwatch/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
const fs = require('fs')
const { installedBrowsers, info, warn, error, chalk, execa } = require('@vue/cli-shared-utils')

module.exports = (api, options) => {
const { info, chalk, execa } = require('@vue/cli-shared-utils')

api.registerCommand('test:e2e', {
description: 'run end-to-end tests with nightwatch',
usage: 'vue-cli-service test:e2e [options]',
Expand All @@ -20,6 +19,28 @@ module.exports = (api, options) => {
`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.`)
}
}

const argsToRemove = ['url', 'mode', 'headless', 'use-selenium', 'parallel']
argsToRemove.forEach((toRemove) => removeArg(rawArgs, toRemove))

Expand Down
9 changes: 7 additions & 2 deletions packages/@vue/cli-plugin-e2e-nightwatch/nightwatch.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
const path = require('path')
const deepmerge = require('deepmerge')
const chromedriver = require('chromedriver')
const geckodriver = require('geckodriver')

// user may have not installed geckodriver
let geckodriver = {}
try {
geckodriver = require('geckodriver')
} catch (e) {}

const userOptions = JSON.parse(process.env.VUE_NIGHTWATCH_USER_OPTIONS || '{}')
const useSelenium = process.env.VUE_NIGHTWATCH_USE_SELENIUM === '1'
Expand Down Expand Up @@ -51,7 +56,7 @@ const defaultSettings = {
}
},
webdriver: useSelenium ? {} : {
server_path: require('geckodriver').path,
server_path: geckodriver.path,
port: 4444
}
}
Expand Down
3 changes: 3 additions & 0 deletions packages/@vue/cli-plugin-e2e-nightwatch/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@
"peerDependenciesMeta": {
"selenium-server": {
"optional": true
},
"geckodriver": {
"optional": true
}
}
}
22 changes: 22 additions & 0 deletions packages/@vue/cli-plugin-e2e-nightwatch/prompts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const { installedBrowsers } = require('@vue/cli-shared-utils')

module.exports = [
{
name: 'webdrivers',
type: `checkbox`,
message: `Pick browsers to run end-to-end test on`,
choices: [
{
name: `Chrome`,
value: 'chrome',
checked: true
},
{
name: 'Firefox',
value: 'firefox',
// check the "Firefox" option if user has installed it
checked: !!installedBrowsers.firefox
}
]
}
]
69 changes: 69 additions & 0 deletions packages/@vue/cli-shared-utils/lib/env.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,72 @@ function checkPnpm (result) {
exports.isWindows = process.platform === 'win32'
exports.isMacintosh = process.platform === 'darwin'
exports.isLinux = process.platform === 'linux'

const browsers = {}
let hasCheckedBrowsers = false

function tryRun (cmd) {
try {
return execSync(cmd, {
stdio: [0, 'pipe', 'ignore']
}).toString().trim()
} catch (e) {
return ''
}
}

function getLinuxAppVersion (binary) {
return tryRun(`${binary} --version`).replace(/^.* ([^ ]*)/g, '$1')
}

function getMacAppVersion (bundleIdentifier) {
const bundlePath = tryRun(`mdfind "kMDItemCFBundleIdentifier=='${bundleIdentifier}'"`)

if (bundlePath) {
return tryRun(`/usr/libexec/PlistBuddy -c Print:CFBundleShortVersionString ${
bundlePath.replace(/(\s)/g, '\\ ')
}/Contents/Info.plist`)
}
}

Object.defineProperty(exports, 'installedBrowsers', {
enumerable: true,
get () {
if (hasCheckedBrowsers) {
return browsers
}
hasCheckedBrowsers = true

if (exports.isLinux) {
browsers.chrome = getLinuxAppVersion('google-chrome')
browsers.firefox = getLinuxAppVersion('firefox')
} else if (exports.isMacintosh) {
browsers.chrome = getMacAppVersion('com.google.Chrome')
browsers.firefox = getMacAppVersion('org.mozilla.firefox')
} else if (exports.isWindows) {
// get chrome stable version
// https://stackoverflow.com/a/51773107/2302258
const chromeQueryResult = tryRun(
'reg query "HKLM\\Software\\Google\\Update\\Clients\\{8A69D345-D564-463c-AFF1-A69D9E530F96}" /v pv /reg:32'
) || tryRun(
'reg query "HKCU\\Software\\Google\\Update\\Clients\\{8A69D345-D564-463c-AFF1-A69D9E530F96}" /v pv /reg:32'
)
if (chromeQueryResult) {
const matched = chromeQueryResult.match(/REG_SZ\s+(\S*)$/)
browsers.chrome = matched && matched[1]
}

// get firefox version
// https://community.spiceworks.com/topic/111518-how-to-determine-version-of-installed-firefox-in-windows-batchscript
const ffQueryResult = tryRun(
'reg query "HKLM\\Software\\Mozilla\\Mozilla Firefox" /v CurrentVersion'
)
if (ffQueryResult) {
const matched = ffQueryResult.match(/REG_SZ\s+(\S*)$/)
browsers.firefox = matched && matched[1]
}
}

return browsers
}
})
5 changes: 5 additions & 0 deletions packages/@vue/cli/lib/promptModules/__tests__/e2e.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ test('nightwatch', async () => {
message: 'Pick a E2E testing solution',
choices: ['Cypress', 'Nightwatch'],
choose: 1
},
{
message: 'Pick browsers to run end-to-end test on',
choice: ['Chrome', 'Firefox'],
check: [0, 1]
}
]

Expand Down
24 changes: 23 additions & 1 deletion packages/@vue/cli/lib/promptModules/e2e.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const { installedBrowsers } = require('@vue/cli-shared-utils')

module.exports = cli => {
cli.injectFeature({
name: 'E2E Testing',
Expand All @@ -20,13 +22,33 @@ module.exports = cli => {
short: 'Cypress'
},
{
name: 'Nightwatch (Selenium-based)',
name: 'Nightwatch (WebDriver-based)',
value: 'nightwatch',
short: 'Nightwatch'
}
]
})

cli.injectPrompt({
name: 'webdrivers',
when: answers => answers.e2e === 'nightwatch',
type: `checkbox`,
message: `Pick browsers to run end-to-end test on`,
choices: [
{
name: `Chrome`,
value: 'chrome',
checked: true
},
{
name: 'Firefox',
value: 'firefox',
// check the "Firefox" option if user has installed it
checked: !!installedBrowsers.firefox
}
]
})

cli.onPromptComplete((answers, options) => {
if (answers.e2e === 'cypress') {
options.plugins['@vue/cli-plugin-e2e-cypress'] = {}
Expand Down

0 comments on commit 0473432

Please sign in to comment.