Skip to content

feat(nightwatch): check user's installed browser versions on scaffolding / before running tests #4563

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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