Skip to content

Commit 6568b46

Browse files
author
Igor Muchychka
authored
feat: Add support for single feature file and single scenario execution
2 parents f44ae1b + 246a63a commit 6568b46

5 files changed

Lines changed: 303 additions & 26 deletions

File tree

.all-contributorsrc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,13 @@
165165
"avatar_url": "https://avatars3.githubusercontent.com/u/689118?v=4",
166166
"profile": "http://www.goshine-dev.co.uk/",
167167
"contributions": []
168+
},
169+
{
170+
"login": "marikaner",
171+
"name": "marikaner",
172+
"avatar_url": "https://avatars1.githubusercontent.com/u/868536?v=4",
173+
"profile": "https://github.com/marikaner",
174+
"contributions": []
168175
}
169176
]
170177
}

lib/nightwatch-api.js

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,23 @@ module.exports = class NightwatchApi {
153153
this.modulePaths = modulePaths
154154
}
155155

156+
isSingleFeatureFile (featureFile) {
157+
let stat
158+
try {
159+
stat = fs.statSync(featureFile)
160+
} catch (err) {
161+
featureFile = featureFile.replace(/:\d+$/, '')
162+
if (!featureFile.match(/\.feature$/)) featureFile += '.feature'
163+
try {
164+
stat = fs.statSync(featureFile)
165+
} catch (err) {
166+
throw new Error(`Feature file or folder ${featureFile} was not found!`)
167+
}
168+
}
169+
170+
return stat.isFile()
171+
}
172+
156173
overrideOriginalSourceGetter (convert) {
157174
const self = this
158175
const originalClientRunnerGetTestSource = Nightwatch.ClientRunner.prototype.getTestSource
@@ -163,14 +180,13 @@ module.exports = class NightwatchApi {
163180
const originalSettings = cloneDeep(this.settings)
164181

165182
if (this.argv._source && this.argv._source.length) {
166-
this.argv._source[0] = convert(this.argv._source[0])
183+
this.argv._source = this.argv._source.map(convert)
167184
} else if (this.argv.test) {
168185
this.argv.test = convert(this.argv.test)
169186
} else {
170187
this.settings.src_folders = self.modulePaths
171188
}
172189
self.nightwatchArgv = this.argv
173-
174190
self.testSource = Nightwatch.ClientRunner.prototype.getTestSource.apply(this, arguments)
175191

176192
if (this.parallelMode) {
@@ -182,6 +198,14 @@ module.exports = class NightwatchApi {
182198
this.settings.src_folders = this.settings.src_folders || []
183199
return Nightwatch.ClientRunner.prototype.getTestSource.apply(this, arguments)
184200
}
201+
202+
Nightwatch.ClientRunner.prototype.singleSourceFile = function () {
203+
if (this.singleTestRun()) {
204+
return self.isSingleFeatureFile(this.argv.test)
205+
}
206+
207+
return (Array.isArray(this.argv._source) && this.argv._source.length === 1) && self.isSingleFeatureFile(this.argv._source[0])
208+
}
185209
}
186210

187211
addHookTests (revert) {

lib/runner.js

Lines changed: 78 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,58 @@ module.exports = class Runner {
1515
this.originalFeaturePath = {}
1616
}
1717

18-
generateDummyTestModules () {
19-
this.featureFiles.forEach((featureSource) => {
20-
const featureFiles = glob.sync(path.join(featureSource, '**/*.feature'))
18+
getSourceFile (featureSource) {
19+
if (featureSource.startsWith('@')) {
20+
return featureSource.substr(1, featureSource.length - 1)
21+
}
22+
return featureSource
23+
}
2124

22-
featureFiles.forEach((featureFile) => {
23-
const dummyTestModuleFile = this.featurePathToDummyPath(featureFile)
24-
mkdirp.sync(path.dirname(dummyTestModuleFile))
25-
fs.writeFileSync(dummyTestModuleFile, '')
25+
getFeatureFilesFromRerunFile (rerunFile) {
26+
const data = fs.readFileSync(this.getSourceFile(rerunFile))
27+
return data.toString()
28+
.split('\n')
29+
.map(featurePath => featurePath.trim().replace(/(:\d*)/g, ''))
30+
// filter empty paths
31+
.filter(featurePath => featurePath)
32+
}
33+
34+
getFeatureDirectories () {
35+
return this.featureFiles
36+
.map(featureSource => {
37+
if (featureSource.startsWith('@')) {
38+
return this.getFeatureFilesFromRerunFile(featureSource)
39+
.map(featurePath => path.dirname(featurePath))
40+
} else if (fs.statSync(featureSource).isDirectory()) {
41+
return featureSource
42+
}
43+
return path.dirname(featureSource)
2644
})
45+
// flatten
46+
.reduce((paths, currentPaths) => paths.concat(currentPaths), [])
47+
}
48+
49+
getFeatureFiles () {
50+
return this.featureFiles
51+
.map(featureSource => {
52+
if (featureSource.startsWith('@')) {
53+
return this.getFeatureFilesFromRerunFile(featureSource)
54+
} else if (fs.statSync(featureSource).isDirectory()) {
55+
return glob.sync(path.join(featureSource, '**/*.feature'))
56+
}
57+
return [featureSource]
58+
})
59+
// flatten
60+
.reduce((paths, currentPaths) => paths.concat(currentPaths), [])
61+
// make unique list
62+
.filter((featureFilePath, idx, paths) => paths.indexOf(featureFilePath === idx))
63+
}
64+
65+
generateDummyTestModules () {
66+
this.getFeatureFiles().forEach((featureFile) => {
67+
const dummyTestModuleFile = this.featurePathToDummyPath(featureFile)
68+
mkdirp.sync(path.dirname(dummyTestModuleFile))
69+
fs.writeFileSync(dummyTestModuleFile, '')
2770
})
2871
}
2972

@@ -42,11 +85,26 @@ module.exports = class Runner {
4285
}
4386

4487
featurePathToDummyPath (featureFile) {
45-
if (!featureFile.match(/\.feature$/)) featureFile += '.feature'
88+
const lineNumberMatch = featureFile.match(/:(\d+)$/)
89+
let lineNumber
90+
if (lineNumberMatch) {
91+
lineNumber = parseInt(lineNumberMatch[1])
92+
featureFile = featureFile.replace(/:\d+$/, '')
93+
}
94+
try {
95+
fs.statSync(featureFile)
96+
} catch (err) {
97+
if (!featureFile.match(/\.feature$/)) featureFile += '.feature'
98+
try {
99+
fs.statSync(featureFile)
100+
} catch (err) {
101+
throw new Error(`Feature file or folder ${featureFile} was not found!`)
102+
}
103+
}
46104

47105
const dummyPath = path.join(dummyTestModulesFolder, featureFile.replace(/\.feature$/, '.js'))
48106

49-
this.originalFeaturePath[dummyPath] = featureFile
107+
this.originalFeaturePath[dummyPath] = lineNumber ? `${featureFile}:${lineNumber}` : featureFile
50108

51109
return dummyPath
52110
}
@@ -92,14 +150,17 @@ module.exports = class Runner {
92150
this.cucumberApi = new CucumberApi(options)
93151
this.jsonReport = this.cucumberApi.getJSONReportName(options.cucumberArgs)
94152
this.featureFiles = this.cucumberApi.getFeatureFiles(options.cucumberArgs)
95-
this.featureFiles.forEach((featureSource) => {
96-
try {
97-
fs.statSync(featureSource)
98-
} catch (err) {
99-
throw new Error(`Feature source ${featureSource} doesn't exists`)
100-
}
101-
})
102-
const dummyPaths = this.featureFiles.map((srcPath) => path.join(dummyTestModulesFolder, srcPath))
153+
this.featureFiles
154+
.map(this.getSourceFile)
155+
.forEach((featureSource) => {
156+
try {
157+
fs.statSync(featureSource)
158+
} catch (err) {
159+
throw new Error(`Feature source ${featureSource} doesn't exists`)
160+
}
161+
})
162+
163+
const dummyPaths = this.getFeatureDirectories().map(srcPath => path.join(dummyTestModulesFolder, srcPath))
103164

104165
this.generateDummyTestModules()
105166

site/data/index.md

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,65 @@ For more examples check out the [example repository](https://github.com/mucsi96/
103103

104104
# Running tests
105105

106-
You can run the test by executing
106+
You can run the tests by executing
107107

108108
```bash
109109
node_modules/.bin/nightwatch
110110
```
111111

112112
![alt-tag](https://raw.githubusercontent.com/mucsi96/nightwatch-cucumber/master/img/nightwatch-cucumber-output.png)
113113

114+
Using NPM scripts its more easy. Let's assume you have following `package.json`.
115+
116+
```json
117+
{
118+
...
119+
"scripts": {
120+
"test": "nightwatch",
121+
...
122+
}
123+
...
124+
}
125+
```
126+
127+
You can run the tests by executing
128+
129+
```bash
130+
npm test
131+
```
132+
133+
### Executing individual feature files or scenarios
134+
135+
Single feature file
136+
137+
```bash
138+
npm test -- features/google-search.feature
139+
```
140+
141+
or
142+
143+
```bash
144+
npm test -- features/google-search
145+
```
146+
147+
Multiple feature files
148+
149+
```bash
150+
npm test -- features/google-search features/duckduckgo-search
151+
```
152+
153+
Single feature file and one folder
154+
155+
```bash
156+
npm test -- features/google/google-search features/duckduckgo
157+
```
158+
159+
Single scenario by its line number
160+
161+
```bash
162+
npm test -- features/google-search.feature:11
163+
```
164+
114165
# Features
115166

116167
## Supported Nightwatch command line options
@@ -123,8 +174,8 @@ node_modules/.bin/nightwatch
123174
| `--env` | `-e` || default | Which testing environment to use - defined in nightwatch.conf.js |
124175
| `--verbose` | || | Shows extended selenium command logging during the session |
125176
| `--version` | `-v` || | Shows the version number |
126-
| `--test` | `-t` | 🚧 | | Runs only the specified test suite/module. By default the runner will attempt to run all tests in the src_folders settings folder(s) and their subfolders. |
127-
| `--testcase` | | 🚧 | | Used only together with --test. Runs the specified testcase from the current suite/module. |
177+
| `--test` | `-t` | | | Runs only the specified feature file. By default the runner will attempt to run all feature files. |
178+
| `--testcase` | | | | Used only together with --test. Runs the specified testcase from the current suite/module. |
128179
| `--group` | `-g` || | Runs only the specified group of tests (subfolder). Tests are grouped by being placed in the same subfolder. |
129180
| `--skipgroup` | `-s` || | Skip one or several (comma separated) group of tests. |
130181
| `--filter` | `-f` | 🚧 | | Specify a filter (glob expression) as the file name format to use when loading the test files. |
@@ -230,8 +281,11 @@ As input you need to provide a Cucumber JSON report generated by this package. Y
230281
```json
231282
{
232283
...
233-
"test": "nightwatch",
234-
"posttest": "node create-html-report.js",
284+
"scripts": {
285+
"test": "nightwatch",
286+
"posttest": "node create-html-report.js",
287+
...
288+
}
235289
...
236290
}
237291
```

0 commit comments

Comments
 (0)