Skip to content

Commit 59adbd6

Browse files
beatfactorhaoqunjiang
authored andcommitted
feat: Upgrade Nightwatch to v1.2 and update bundled config and generated tests (vuejs#4541)
* feat: Upgraded Nightwatch to version 1.2; updated distributed config; added new cli flags: --headless, --parallel...; added support for running chromedriver and geckodriver standalone; added unit tests * docs: updated nightwatch plugin readme * feat: add chromedriver and geckodriver as peer dependencies * updated readme and driver depedencies * updated optional dependencies * fixed failing tests * updated generated tests * updated tests
1 parent d37d68a commit 59adbd6

File tree

17 files changed

+749
-86
lines changed

17 files changed

+749
-86
lines changed

packages/@vue/cli-plugin-e2e-nightwatch/README.md

Lines changed: 118 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,32 +6,138 @@
66

77
- **`vue-cli-service test:e2e`**
88

9-
run e2e tests with [NightwatchJS](http://nightwatchjs.org).
9+
Run end-to-end tests with [Nightwatch.js](https://nightwatchjs.org).
1010

1111
Options:
1212

1313
```
14-
--url run e2e tests against given url instead of auto-starting dev server
15-
--config use custom nightwatch config file (overrides internals)
16-
-e, --env specify comma-delimited browser envs to run in (default: chrome)
17-
-t, --test specify a test to run by name
18-
-f, --filter glob to filter tests by filename
14+
--url run the tests against given url instead of auto-starting dev server
15+
--config use custom nightwatch config file (overrides internals)
16+
--headless use chrome or firefox in headless mode
17+
--parallel enable parallel mode via test workers (only available in chromedriver)
18+
--use-selenium use Selenium standalone server instead of chromedriver or geckodriver
19+
-e, --env specify comma-delimited browser envs to run in (default: chrome)
20+
-t, --test specify a test to run by name
21+
-f, --filter glob to filter tests by filename
1922
```
2023

21-
> Note: this plugin currently uses Nightwatch v0.9.x. We are waiting for Nightwatch 1.0 to stabilize before upgrading.
24+
Additionally, all [Nightwatch CLI options](https://nightwatchjs.org/guide/running-tests/#command-line-options) are also supported.
25+
E.g.: `--verbose`, `--retries` etc.
26+
2227

23-
Additionally, [all Nightwatch CLI options are also supported](https://nightwatchjs.org/guide#command-line-options).
28+
## Project Structure
2429

25-
## Configuration
30+
The following structure will be generated when installing this plugin. There are examples for most testing concepts in Nightwatch available.
31+
32+
```
33+
tests/e2e/
34+
├── custom-assertions/
35+
| └── elementCount.js
36+
├── custom-commands/
37+
| ├── customExecute.js
38+
| ├── openHomepage.js
39+
| └── openHomepageClass.js
40+
├── page-objects/
41+
| └── homepage.js
42+
├── specs/
43+
| ├── test.js
44+
| └── test-with-pageobjects.js
45+
└── globals.js
46+
```
2647

27-
We've pre-configured Nightwatch to run with Chrome by default. If you wish to run e2e tests in additional browsers, you will need to add a `nightwatch.config.js` or `nightwatch.json` in your project root to configure additional browsers. The config will be merged into the [internal Nightwatch config](https://github.com/vuejs/vue-cli/blob/dev/packages/%40vue/cli-plugin-e2e-nightwatch/nightwatch.config.js).
48+
#### `specs`
49+
The main location where tests are located. Can contain sub-folders which can be targeted during the run using the `--group` argument. [More info](https://nightwatchjs.org/guide/running-tests/#test-groups).
2850

29-
Alternatively, you can completely replace the internal config with a custom config file using the `--config` option.
51+
#### `custom-assertions`
52+
Files located here are loaded automatically by Nightwatch and placed onto the `.assert` and `.verify` api namespaces to extend the Nightwatch built-in assertions. See [writing custom assertions](https://nightwatchjs.org/guide/extending-nightwatch/#writing-custom-assertions) for details.
53+
54+
#### `custom-commands`
55+
Files located here are loaded automatically by Nightwatch and placed onto the main `browser` api object to extend the built-in Nightwatch commands. See [writing custom commands](https://nightwatchjs.org/guide/extending-nightwatch/#writing-custom-commands) for details.
3056

31-
Consult Nightwatch docs for [configuration options](http://nightwatchjs.org/gettingstarted#settings-file) and how to [setup browser drivers](http://nightwatchjs.org/gettingstarted#browser-drivers-setup).
57+
#### `page objects`
58+
Working with page objects is a popular methodology in end-to-end UI testing. Files placed in this folder are automatically loaded onto the `.page` api namespace, with the name of the file being the name of the page object. See [working with page objects](https://nightwatchjs.org/guide/working-with-page-objects/) section for details.
59+
60+
#### `globals.js`
61+
The external globals file which can hold global properties or hooks. See [test globals](https://nightwatchjs.org/gettingstarted/configuration/#test-globals) section.
3262

3363
## Installing in an Already Created Project
3464

3565
``` sh
3666
vue add e2e-nightwatch
3767
```
68+
69+
## Configuration
70+
71+
We've pre-configured Nightwatch to run with Chrome by default. Firefox is also available via `--env firefox`. If you wish to run end-to-end tests in additional browsers (e.g. Safari, Microsoft Edge), you will need to add a `nightwatch.conf.js` or `nightwatch.json` in your project root to configure additional browsers. The config will be merged into the [internal Nightwatch config](https://github.com/vuejs/vue-cli/blob/dev/packages/%40vue/cli-plugin-e2e-nightwatch/nightwatch.config.js).
72+
73+
Alternatively, you can completely replace the internal config with a custom config file using the `--config` option.
74+
75+
Consult Nightwatch docs for [configuration options](https://nightwatchjs.org/gettingstarted/configuration/) and how to [setup browser drivers](http://nightwatchjs.org/gettingstarted#browser-drivers-setup).
76+
77+
## Running Tests
78+
79+
By default, all tests inside the `specs` folder will be run using Chrome. If you'd like to run end-to-end tests against Chrome (or Firefox) in headless mode, simply pass the `--headless` argument.
80+
81+
```sh
82+
$ vue-cli-service test:e2e
83+
```
84+
85+
**Running a single test**
86+
87+
To run a single test supply the filename path. E.g.:
88+
89+
```sh
90+
$ vue-cli-service test:e2e tests/e2e/specs/test.js
91+
```
92+
93+
**Skip Dev server auto-start**
94+
95+
If the development server is already running and you want to skip starting it automatically, pass the `--url` argument:
96+
97+
```sh
98+
$ vue-cli-service test:e2e --url http://localhost:8080/
99+
```
100+
101+
**Running in Firefox**
102+
103+
Support for running tests in Firefox is also available by default. Simply run the following (optionally add `--headless` to run Firefox in headless mode):
104+
105+
```sh
106+
$ vue-cli-service test:e2e --env firefox [--headless]
107+
```
108+
109+
**Running in Firefox and Chrome simultaneously**
110+
111+
You can also run the tests simultaneously in both browsers by supplying both test environments separated by a comma (",") - no spaces.
112+
113+
```sh
114+
$ vue-cli-service test:e2e --env firefox,chrome [--headless]
115+
```
116+
117+
**Running Tests in Parallel**
118+
119+
For a significantly faster test run, you can enable parallel test running when there are several test suites. Concurrency is performed at the file level and is distributed automatically per available CPU core.
120+
121+
For now, this is only available in Chromedriver. Read more about [parallel running](https://nightwatchjs.org/guide/running-tests/#parallel-running) in the Nightwatch docs.
122+
123+
```sh
124+
$ vue-cli-service test:e2e --parallel
125+
```
126+
127+
**Running with Selenium**
128+
129+
Since `v4`, the Selenium standalone server is not included anymore in this plugin and in most cases running with Selenium is not required since Nightwatch v1.0.
130+
131+
It is still possible to use the Selenium server, by following these steps:
132+
133+
__1.__ Install `selenium-server` NPM package:
134+
135+
```sh
136+
$ npm install selenium-server --save-dev
137+
```
138+
139+
__2.__ Run with `--use-selenium` cli argument:
140+
141+
```sh
142+
$ vue-cli-service test:e2e --use-selenium
143+
```
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* This file is copied during the firefox test inside the project folder and used to inspect the results
3+
*/
4+
const fs = require('fs')
5+
6+
module.exports = {
7+
reporter (results, cb) {
8+
fs.writeFile('test_results_gecko.json', JSON.stringify(results), cb)
9+
}
10+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* This file is copied during the test inside the project folder and used to inpsect the results
3+
*/
4+
const fs = require('fs')
5+
6+
module.exports = {
7+
afterEach (browser, cb) {
8+
fs.writeFile('test_settings.json', JSON.stringify(browser.options), cb)
9+
},
10+
11+
reporter (results, cb) {
12+
fs.writeFile('test_results.json', JSON.stringify(results), cb)
13+
}
14+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/**
2+
* This file is copied during the test inside the project folder
3+
*/
4+
module.exports = {
5+
globals_path: './tests/e2e/globals-gecko.js'
6+
}
Lines changed: 94 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,100 @@
1-
jest.setTimeout(40000)
1+
jest.setTimeout(process.env.APPVEYOR ? 300000 : 120000)
22

3+
const fs = require('fs-extra')
4+
const path = require('path')
35
const create = require('@vue/cli-test-utils/createTestProject')
46

5-
test('should work', async () => {
6-
const project = await create('e2e-nightwatch', {
7-
plugins: {
8-
'@vue/cli-plugin-babel': {},
9-
'@vue/cli-plugin-e2e-nightwatch': {}
7+
describe('nightwatch e2e plugin', () => {
8+
let project
9+
10+
beforeAll(async () => {
11+
project = await create('e2e-nightwatch', {
12+
plugins: {
13+
'@vue/cli-plugin-babel': {},
14+
'@vue/cli-plugin-e2e-nightwatch': {}
15+
}
16+
})
17+
18+
await fs.copy(path.join(__dirname, './lib/globals-generated.js'),
19+
path.join(project.dir, 'tests/e2e/globals-generated.js'))
20+
21+
const config = {
22+
globals_path: './tests/e2e/globals-generated.js'
1023
}
24+
await project.write('nightwatch.json', JSON.stringify(config))
25+
})
26+
27+
test('should run all tests successfully', async () => {
28+
await project.run(`vue-cli-service test:e2e --headless`)
29+
let results = await project.read('test_results.json')
30+
results = JSON.parse(results)
31+
expect(Object.keys(results.modules)).toEqual([
32+
'test-with-pageobjects',
33+
'test'
34+
])
35+
})
36+
37+
test('should run single test with custom nightwatch.json', async () => {
38+
await project.run(`vue-cli-service test:e2e --headless -t tests/e2e/specs/test.js`)
39+
let results = await project.read('test_results.json')
40+
results = JSON.parse(results)
41+
expect(Object.keys(results.modules)).toEqual([
42+
'test'
43+
])
44+
})
45+
46+
test('should run single test with custom nightwatch.json and selenium server', async () => {
47+
await project.run(`vue-cli-service test:e2e --headless --with-selenium -t tests/e2e/specs/test.js`)
48+
let results = await project.read('test_results.json')
49+
results = JSON.parse(results)
50+
51+
let testSettings = await project.read('test_settings.json')
52+
testSettings = JSON.parse(testSettings)
53+
54+
expect(testSettings).toHaveProperty('selenium')
55+
expect(testSettings.selenium.start_process).toStrictEqual(true)
56+
expect(testSettings.selenium).toHaveProperty('cli_args')
57+
expect(Object.keys(results.modules)).toEqual([
58+
'test'
59+
])
60+
})
61+
62+
test('should run tests in parallel', async () => {
63+
await project.run(`vue-cli-service test:e2e --headless --parallel`)
64+
let results = await project.read('test_results.json')
65+
results = JSON.parse(results)
66+
67+
let testSettings = await project.read('test_settings.json')
68+
testSettings = JSON.parse(testSettings)
69+
70+
expect(testSettings.parallel_mode).toStrictEqual(true)
71+
expect(testSettings.test_workers).toStrictEqual(true)
72+
73+
expect(Object.keys(results.modules).sort()).toEqual([
74+
'test', 'test-with-pageobjects'
75+
])
76+
})
77+
78+
// This test requires Firefox to be installed
79+
const testFn = process.env.APPVEYOR ? test.skip : test
80+
testFn('should run single test with custom nightwatch.conf.js in firefox', async () => {
81+
// nightwatch.conf.js take priority over nightwatch.json
82+
const copyConfig = fs.copy(path.join(__dirname, './lib/nightwatch.conf.js'),
83+
path.join(project.dir, 'nightwatch.conf.js'))
84+
85+
const copyGlobals = fs.copy(path.join(__dirname, './lib/globals-gecko.js'),
86+
path.join(project.dir, 'tests/e2e/globals-gecko.js'))
87+
88+
await Promise.all([copyConfig, copyGlobals])
89+
90+
await project.run(`vue-cli-service test:e2e --headless --env firefox -t tests/e2e/specs/test.js`)
91+
let results = await project.read('test_results_gecko.json')
92+
results = JSON.parse(results)
93+
94+
expect(Object.keys(results.modules)).toEqual([
95+
'test'
96+
])
97+
expect(results.modules.test).toHaveProperty('reportPrefix')
98+
expect(results.modules.test.reportPrefix).toMatch(/^FIREFOX_.+/)
1199
})
12-
await project.run(`vue-cli-service test:e2e`)
13100
})

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ module.exports = api => {
88
'test:e2e': 'vue-cli-service test:e2e'
99
},
1010
devDependencies: {
11-
chromedriver: '^74.0.0'
11+
chromedriver: '^76.0.1',
12+
geckodriver: '^1.16.2'
1213
}
1314
})
1415
}

packages/@vue/cli-plugin-e2e-nightwatch/generator/template/tests/e2e/custom-assertions/elementCount.js

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,27 @@
1-
// A custom Nightwatch assertion.
2-
// The assertion name is the filename.
3-
// Example usage:
4-
//
5-
// browser.assert.elementCount(selector, count)
6-
//
7-
// For more information on custom assertions see:
8-
// http://nightwatchjs.org/guide#writing-custom-assertions
1+
/**
2+
* A custom Nightwatch assertion. The assertion name is the filename.
3+
*
4+
* Example usage:
5+
* browser.assert.elementCount(selector, count)
6+
*
7+
* For more information on custom assertions see:
8+
* https://nightwatchjs.org/guide/extending-nightwatch/#writing-custom-assertions
9+
*
10+
*
11+
* @param {string|object} selectorOrObject
12+
* @param {number} count
13+
*/
14+
15+
exports.assertion = function elementCount (selectorOrObject, count) {
16+
let selector;
17+
18+
// when called from a page object element or section
19+
if (typeof selectorOrObject == 'object' && selectorOrObject.selector) {
20+
selector = selectorOrObject.selector
21+
} else {
22+
selector = selectorOrObject
23+
}
924

10-
exports.assertion = function elementCount (selector, count) {
1125
this.message = `Testing if element <${selector}> has count: ${count}`
1226
this.expected = count
1327
this.pass = val => val === count
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
* A very basic Nightwatch custom command. The command name is the filename and the
3+
* exported "command" function is the command.
4+
*
5+
* Example usage:
6+
* browser.customExecute(function() {
7+
* console.log('Hello from the browser window')
8+
* });
9+
*
10+
* For more information on writing custom commands see:
11+
* https://nightwatchjs.org/guide/extending-nightwatch/#writing-custom-commands
12+
*
13+
* @param {*} data
14+
*/
15+
exports.command = function(data) {
16+
// Other Nightwatch commands are available via "this"
17+
18+
// .execute() inject a snippet of JavaScript into the page for execution.
19+
// the executed script is assumed to be synchronous.
20+
//
21+
// See https://nightwatchjs.org/api/execute.html for more info.
22+
//
23+
this.execute(
24+
// The function argument is converted to a string and sent to the browser
25+
function(argData) {return argData;},
26+
27+
// The arguments for the function to be sent to the browser are specified in this array
28+
[data],
29+
30+
function(result) {
31+
// The "result" object contains the result from the what we have sent back from the browser window
32+
console.log('custom execute result:', result.value)
33+
}
34+
);
35+
36+
return this;
37+
};
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* A basic Nightwatch custom command which demonstrates usage of ES6 async/await instead of using callbacks.
3+
* The command name is the filename and the exported "command" function is the command.
4+
*
5+
* Example usage:
6+
* browser.openHomepage();
7+
*
8+
* For more information on writing custom commands see:
9+
* https://nightwatchjs.org/guide/extending-nightwatch/#writing-custom-commands
10+
*
11+
*/
12+
module.exports = {
13+
command: async function () {
14+
// Other Nightwatch commands are available via "this"
15+
// .init() simply calls .url() command with the value of the "launch_url" setting
16+
this.init();
17+
this.waitForElementVisible('#app');
18+
19+
const result = await this.elements('css selector', '#app ul');
20+
this.assert.strictEqual(result.value.length, 3);
21+
}
22+
};

0 commit comments

Comments
 (0)