Skip to content

Commit 0473432

Browse files
authored
feat(nightwatch): check user's installed browser versions on scaffolding / before running tests (vuejs#4563)
1 parent dcd8d94 commit 0473432

File tree

8 files changed

+168
-7
lines changed

8 files changed

+168
-7
lines changed
Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,29 @@
1+
const { installedBrowsers } = require('@vue/cli-shared-utils')
2+
13
module.exports = api => {
24
api.render('./template', {
35
hasTS: api.hasPlugin('typescript')
46
})
57

8+
// Use devDependencies to store latest version number so as to automate update
9+
const devDeps = require('../package.json').devDependencies
10+
const geckodriver = devDeps.geckodriver
11+
12+
// chromedriver major version bumps every 6 weeks following Chrome
13+
// so there may be a mismatch between
14+
// user's installed browser version and the default provided version
15+
// fallback to the devDependencies version in case detection fails
16+
const chromedriver = installedBrowsers.chrome
17+
? installedBrowsers.chrome.match(/^(\d+)\./)[1]
18+
: devDeps.chromedriver
19+
620
api.extendPackage({
721
scripts: {
822
'test:e2e': 'vue-cli-service test:e2e'
923
},
1024
devDependencies: {
11-
chromedriver: '^76.0.1',
12-
geckodriver: '^1.16.2'
25+
chromedriver,
26+
geckodriver
1327
}
1428
})
1529
}

packages/@vue/cli-plugin-e2e-nightwatch/index.js

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
const fs = require('fs')
2+
const { installedBrowsers, info, warn, error, chalk, execa } = require('@vue/cli-shared-utils')
23

34
module.exports = (api, options) => {
4-
const { info, chalk, execa } = require('@vue/cli-shared-utils')
5-
65
api.registerCommand('test:e2e', {
76
description: 'run end-to-end tests with nightwatch',
87
usage: 'vue-cli-service test:e2e [options]',
@@ -20,6 +19,28 @@ module.exports = (api, options) => {
2019
`All Nightwatch CLI options are also supported.\n` +
2120
chalk.yellow(`https://nightwatchjs.org/guide/running-tests/#command-line-options`)
2221
}, (args, rawArgs) => {
22+
if (args.env && args.env.includes('firefox')) {
23+
try {
24+
require('geckodriver')
25+
} catch (e) {
26+
error(`To run e2e tests in Firefox, you need to install ${chalk.yellow.bold('geckodriver')} first.`)
27+
process.exit(1)
28+
}
29+
}
30+
if (installedBrowsers.chrome) {
31+
const userVersion = installedBrowsers.chrome
32+
const driverVersion = require('chromedriver').version
33+
34+
const userMajor = userVersion.match(/^(\d+)\./)[1]
35+
const driverMajor = driverVersion.match(/^(\d+)\./)[1]
36+
37+
if (userMajor !== driverMajor) {
38+
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)}.`)
39+
warn(`There may be incompatibilities between them.`)
40+
warn(`Please update your ${chalk.cyan.bold('chromedriver')} dependency to match the ${chalk.cyan.bold('Chrome')} version.`)
41+
}
42+
}
43+
2344
const argsToRemove = ['url', 'mode', 'headless', 'use-selenium', 'parallel']
2445
argsToRemove.forEach((toRemove) => removeArg(rawArgs, toRemove))
2546

packages/@vue/cli-plugin-e2e-nightwatch/nightwatch.config.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
const path = require('path')
44
const deepmerge = require('deepmerge')
55
const chromedriver = require('chromedriver')
6-
const geckodriver = require('geckodriver')
6+
7+
// user may have not installed geckodriver
8+
let geckodriver = {}
9+
try {
10+
geckodriver = require('geckodriver')
11+
} catch (e) {}
712

813
const userOptions = JSON.parse(process.env.VUE_NIGHTWATCH_USER_OPTIONS || '{}')
914
const useSelenium = process.env.VUE_NIGHTWATCH_USE_SELENIUM === '1'
@@ -51,7 +56,7 @@ const defaultSettings = {
5156
}
5257
},
5358
webdriver: useSelenium ? {} : {
54-
server_path: require('geckodriver').path,
59+
server_path: geckodriver.path,
5560
port: 4444
5661
}
5762
}

packages/@vue/cli-plugin-e2e-nightwatch/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@
4242
"peerDependenciesMeta": {
4343
"selenium-server": {
4444
"optional": true
45+
},
46+
"geckodriver": {
47+
"optional": true
4548
}
4649
}
4750
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const { installedBrowsers } = require('@vue/cli-shared-utils')
2+
3+
module.exports = [
4+
{
5+
name: 'webdrivers',
6+
type: `checkbox`,
7+
message: `Pick browsers to run end-to-end test on`,
8+
choices: [
9+
{
10+
name: `Chrome`,
11+
value: 'chrome',
12+
checked: true
13+
},
14+
{
15+
name: 'Firefox',
16+
value: 'firefox',
17+
// check the "Firefox" option if user has installed it
18+
checked: !!installedBrowsers.firefox
19+
}
20+
]
21+
}
22+
]

packages/@vue/cli-shared-utils/lib/env.js

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,72 @@ function checkPnpm (result) {
129129
exports.isWindows = process.platform === 'win32'
130130
exports.isMacintosh = process.platform === 'darwin'
131131
exports.isLinux = process.platform === 'linux'
132+
133+
const browsers = {}
134+
let hasCheckedBrowsers = false
135+
136+
function tryRun (cmd) {
137+
try {
138+
return execSync(cmd, {
139+
stdio: [0, 'pipe', 'ignore']
140+
}).toString().trim()
141+
} catch (e) {
142+
return ''
143+
}
144+
}
145+
146+
function getLinuxAppVersion (binary) {
147+
return tryRun(`${binary} --version`).replace(/^.* ([^ ]*)/g, '$1')
148+
}
149+
150+
function getMacAppVersion (bundleIdentifier) {
151+
const bundlePath = tryRun(`mdfind "kMDItemCFBundleIdentifier=='${bundleIdentifier}'"`)
152+
153+
if (bundlePath) {
154+
return tryRun(`/usr/libexec/PlistBuddy -c Print:CFBundleShortVersionString ${
155+
bundlePath.replace(/(\s)/g, '\\ ')
156+
}/Contents/Info.plist`)
157+
}
158+
}
159+
160+
Object.defineProperty(exports, 'installedBrowsers', {
161+
enumerable: true,
162+
get () {
163+
if (hasCheckedBrowsers) {
164+
return browsers
165+
}
166+
hasCheckedBrowsers = true
167+
168+
if (exports.isLinux) {
169+
browsers.chrome = getLinuxAppVersion('google-chrome')
170+
browsers.firefox = getLinuxAppVersion('firefox')
171+
} else if (exports.isMacintosh) {
172+
browsers.chrome = getMacAppVersion('com.google.Chrome')
173+
browsers.firefox = getMacAppVersion('org.mozilla.firefox')
174+
} else if (exports.isWindows) {
175+
// get chrome stable version
176+
// https://stackoverflow.com/a/51773107/2302258
177+
const chromeQueryResult = tryRun(
178+
'reg query "HKLM\\Software\\Google\\Update\\Clients\\{8A69D345-D564-463c-AFF1-A69D9E530F96}" /v pv /reg:32'
179+
) || tryRun(
180+
'reg query "HKCU\\Software\\Google\\Update\\Clients\\{8A69D345-D564-463c-AFF1-A69D9E530F96}" /v pv /reg:32'
181+
)
182+
if (chromeQueryResult) {
183+
const matched = chromeQueryResult.match(/REG_SZ\s+(\S*)$/)
184+
browsers.chrome = matched && matched[1]
185+
}
186+
187+
// get firefox version
188+
// https://community.spiceworks.com/topic/111518-how-to-determine-version-of-installed-firefox-in-windows-batchscript
189+
const ffQueryResult = tryRun(
190+
'reg query "HKLM\\Software\\Mozilla\\Mozilla Firefox" /v CurrentVersion'
191+
)
192+
if (ffQueryResult) {
193+
const matched = ffQueryResult.match(/REG_SZ\s+(\S*)$/)
194+
browsers.firefox = matched && matched[1]
195+
}
196+
}
197+
198+
return browsers
199+
}
200+
})

packages/@vue/cli/lib/promptModules/__tests__/e2e.spec.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ test('nightwatch', async () => {
4444
message: 'Pick a E2E testing solution',
4545
choices: ['Cypress', 'Nightwatch'],
4646
choose: 1
47+
},
48+
{
49+
message: 'Pick browsers to run end-to-end test on',
50+
choice: ['Chrome', 'Firefox'],
51+
check: [0, 1]
4752
}
4853
]
4954

packages/@vue/cli/lib/promptModules/e2e.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const { installedBrowsers } = require('@vue/cli-shared-utils')
2+
13
module.exports = cli => {
24
cli.injectFeature({
35
name: 'E2E Testing',
@@ -20,13 +22,33 @@ module.exports = cli => {
2022
short: 'Cypress'
2123
},
2224
{
23-
name: 'Nightwatch (Selenium-based)',
25+
name: 'Nightwatch (WebDriver-based)',
2426
value: 'nightwatch',
2527
short: 'Nightwatch'
2628
}
2729
]
2830
})
2931

32+
cli.injectPrompt({
33+
name: 'webdrivers',
34+
when: answers => answers.e2e === 'nightwatch',
35+
type: `checkbox`,
36+
message: `Pick browsers to run end-to-end test on`,
37+
choices: [
38+
{
39+
name: `Chrome`,
40+
value: 'chrome',
41+
checked: true
42+
},
43+
{
44+
name: 'Firefox',
45+
value: 'firefox',
46+
// check the "Firefox" option if user has installed it
47+
checked: !!installedBrowsers.firefox
48+
}
49+
]
50+
})
51+
3052
cli.onPromptComplete((answers, options) => {
3153
if (answers.e2e === 'cypress') {
3254
options.plugins['@vue/cli-plugin-e2e-cypress'] = {}

0 commit comments

Comments
 (0)