Skip to content

Commit

Permalink
support YAML for config files (#2199)
Browse files Browse the repository at this point in the history
* chore: load json files with fsw

* chore: add yaml dependency

* chore: add new featue for yaml

* feat: parse yaml files

* feat: add yaml extensions to defaults

* chore: update docs

* chore: refactor a bit

* chore: lint issues

* update CHANGELOG.md

* go back to node 12 compatible yaml version
  • Loading branch information
davidjgoss committed Dec 21, 2022
1 parent 79ba4bd commit 0240308
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 10 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
Please see [CONTRIBUTING.md](https://github.com/cucumber/cucumber/blob/master/CONTRIBUTING.md) on how to contribute to Cucumber.

## [Unreleased]
### Added
- Add support for YAML as a configuration file format ([#2199](https://github.com/cucumber/cucumber-js/pull/2199))

## [8.9.1] - 2022-12-16
### Fixed
Expand Down
13 changes: 12 additions & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ You can keep your configuration in a file. Cucumber will look for one of these f
- `cucumber.cjs`
- `cucumber.mjs`
- `cucumber.json`
- `cucumber.yaml`
- `cucumber.yml`

You can also put your file somewhere else and tell Cucumber via the `--config` CLI option:

Expand Down Expand Up @@ -45,11 +47,20 @@ And the same in JSON format:
{
"default": {
"parallel": 2,
"format": ["html:cucumber-report.html"]
"format": ["html:cucumber-report.html"]
}
}
```

And the same in YAML format:

```yaml
default:
parallel: 2
format:
- "html:cucumber-report.html"
```

Cucumber also supports the configuration being a string of options in the style of the CLI, though this isn't recommended:

```js
Expand Down
16 changes: 16 additions & 0 deletions features/profiles.feature
Original file line number Diff line number Diff line change
Expand Up @@ -117,3 +117,19 @@ Feature: default command line arguments
1 step (1 skipped)
<duration-stat>
"""

Scenario: using a YAML file
Given a file named ".cucumber-rc.yaml" with:
"""
default:
dryRun: true
"""
When I run cucumber-js with `--config .cucumber-rc.yaml`
Then it outputs the text:
"""
-
1 scenario (1 skipped)
1 step (1 skipped)
<duration-stat>
"""
14 changes: 14 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@
"util-arity": "^1.1.0",
"verror": "^1.10.0",
"xmlbuilder": "^15.1.1",
"yaml": "1.10.2",
"yup": "^0.32.11"
},
"devDependencies": {
Expand Down
36 changes: 27 additions & 9 deletions src/configuration/from_file.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import stringArgv from 'string-argv'
import fs from 'fs'
import path from 'path'
import YAML from 'yaml'
import { promisify } from 'util'
import { pathToFileURL } from 'url'
import { IConfiguration } from './types'
import { mergeConfigurations } from './merge_configurations'
Expand Down Expand Up @@ -44,16 +47,31 @@ async function loadFile(
file: string
): Promise<Record<string, any>> {
const filePath: string = path.join(cwd, file)
const extension = path.extname(filePath)
let definitions
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
definitions = require(filePath)
} catch (error) {
if (error.code === 'ERR_REQUIRE_ESM') {
definitions = await importer(pathToFileURL(filePath))
} else {
throw error
}
switch (extension) {
case '.json':
definitions = JSON.parse(
await promisify(fs.readFile)(filePath, { encoding: 'utf-8' })
)
break
case '.yaml':
case '.yml':
definitions = YAML.parse(
await promisify(fs.readFile)(filePath, { encoding: 'utf-8' })
)
break
default:
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
definitions = require(filePath)
} catch (error) {
if (error.code === 'ERR_REQUIRE_ESM') {
definitions = await importer(pathToFileURL(filePath))
} else {
throw error
}
}
}
if (typeof definitions !== 'object') {
throw new Error(`Configuration file ${filePath} does not export an object`)
Expand Down
15 changes: 15 additions & 0 deletions src/configuration/from_file_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,20 @@ describe('fromFile', () => {
const result = await fromFile(logger, cwd, 'cucumber.json', ['p1'])
expect(result).to.deep.eq({ paths: ['other/path/*.feature'] })
})

it('should work with yaml', async () => {
const { logger, cwd } = await setup(
'cucumber.yaml',
`default:
p1:
paths:
- "other/path/*.feature"
`
)

const result = await fromFile(logger, cwd, 'cucumber.yaml', ['p1'])
expect(result).to.deep.eq({ paths: ['other/path/*.feature'] })
})
})
})
2 changes: 2 additions & 0 deletions src/configuration/locate_file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const DEFAULT_FILENAMES = [
'cucumber.cjs',
'cucumber.mjs',
'cucumber.json',
'cucumber.yaml',
'cucumber.yml',
]

export function locateFile(cwd: string): string | undefined {
Expand Down

0 comments on commit 0240308

Please sign in to comment.