Skip to content
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

config: support configuration as objects #1952

Merged
merged 57 commits into from
Mar 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
dee627a
add testing for esm format
davidjgoss Feb 23, 2022
1c533e8
handle both types somewhat awkwardly
davidjgoss Feb 23, 2022
ad9d6f0
convert to file url (will be needed for windows)
davidjgoss Feb 23, 2022
d265ffd
Merge branch 'main' into feat/config-import
davidjgoss Mar 2, 2022
010a37f
fix catch clause
davidjgoss Mar 3, 2022
03df338
move some types around
davidjgoss Mar 3, 2022
a2d9311
more moving
davidjgoss Mar 3, 2022
764f301
start to build out configuration module
davidjgoss Mar 3, 2022
d1f8951
whoops dont need this one
davidjgoss Mar 3, 2022
a7874f8
add default config
davidjgoss Mar 3, 2022
e0bd615
add todo comment
davidjgoss Mar 3, 2022
59256cf
wip fromFile
davidjgoss Mar 3, 2022
c416579
merge main
davidjgoss Mar 3, 2022
a7459f6
make a start on file loading
davidjgoss Mar 3, 2022
030bbf1
progress on profiles and merging
davidjgoss Mar 3, 2022
3caeb64
add lodash.mergewith
davidjgoss Mar 3, 2022
3916a65
WIP remove validation from argv parser
davidjgoss Mar 3, 2022
c91efda
expand this test a bit
davidjgoss Mar 4, 2022
7ef8db6
a note about strings for later
davidjgoss Mar 4, 2022
8226f34
moar test
davidjgoss Mar 4, 2022
5c5f3c3
more on merge
davidjgoss Mar 5, 2022
d519534
start to rework parser
davidjgoss Mar 7, 2022
799f760
remove defaults, fix array merging
davidjgoss Mar 7, 2022
e4aa809
simplify
davidjgoss Mar 7, 2022
9a5878d
handle mergeable tag strings
davidjgoss Mar 7, 2022
4a62e10
merge json nicely
davidjgoss Mar 7, 2022
c6cbf6f
progress
davidjgoss Mar 7, 2022
17819ca
change profile feature to sometimes use objects
davidjgoss Mar 7, 2022
a308cff
last argument wins when specifying stdout formatter
davidjgoss Mar 7, 2022
802fe45
Merge branch 'main' into feat/config-import
davidjgoss Mar 8, 2022
4b10c42
use new config loading mechanism with object support
davidjgoss Mar 8, 2022
288edf8
ensure all array types are merged correctly
davidjgoss Mar 8, 2022
000a069
rename
davidjgoss Mar 8, 2022
ae708e5
handle tag expressions correctly when merging
davidjgoss Mar 9, 2022
10fe985
add validation for retry config
davidjgoss Mar 9, 2022
5a8e961
validate config objects against schema, handle default profile correctly
davidjgoss Mar 9, 2022
af54d05
update message on retry config validation
davidjgoss Mar 9, 2022
aea3511
move and simplify some types
davidjgoss Mar 9, 2022
0c681fc
more moving and renaming
davidjgoss Mar 10, 2022
d9d47e1
rework - less defaulting
davidjgoss Mar 10, 2022
16d6fa0
dogfood loadConfiguration in tests
davidjgoss Mar 10, 2022
000069d
dogfood loadConfiguration in cli, shrink api surface
davidjgoss Mar 11, 2022
e5ccce9
add -i shorthand for --import
davidjgoss Mar 11, 2022
4e14290
support json config file
davidjgoss Mar 11, 2022
0fc765f
fix pickle order typing
davidjgoss Mar 11, 2022
3a7970b
overhaul documentation
davidjgoss Mar 13, 2022
ad6ea28
change our own config to json
davidjgoss Mar 13, 2022
befcd9c
simplify config handing in cli
davidjgoss Mar 13, 2022
27e3c41
simplify typing
davidjgoss Mar 13, 2022
5b87d8e
add changelog entry
davidjgoss Mar 13, 2022
ae77a17
fix typo
davidjgoss Mar 13, 2022
26d6289
whoops
davidjgoss Mar 13, 2022
1aeb7ef
add --force-exit alias for --exit, rename property on object
davidjgoss Mar 14, 2022
397cc9d
single source of `isTruthyString`
davidjgoss Mar 14, 2022
73c5fa4
correct wrong format name
davidjgoss Mar 14, 2022
1a3cbd3
remove pointless reindent
davidjgoss Mar 14, 2022
280d694
add tests for other formats in from_file_spec.ts
davidjgoss Mar 14, 2022
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Please see [CONTRIBUTING.md](https://github.com/cucumber/cucumber/blob/master/CO
See [./docs/cli.md#printing-attachments-details](https://github.com/cucumber/cucumber-js/blob/main/docs/cli.md#printing-attachments-details) for more info.
([#1136](https://github.com/cucumber/cucumber-js/issues/1136)
[#1721](https://github.com/cucumber/cucumber-js/pull/1721))
- Support for configuration to be objects instead of argv strings, and for configuration files in ESM and JSON formats ([#1952](https://github.com/cucumber/cucumber-js/pull/1952))

### Fixed
- Warn users who are on an unsupported node version ([#1922](https://github.com/cucumber/cucumber-js/pull/1922))
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ If you learn best by example, we have [a repo with several example projects](htt
The following documentation is for `main`, which might contain some unreleased features. See below the documentation for older versions.

* [CLI](/docs/cli.md)
* [Configuration](/docs/configuration.md)
* Support Files
* [World](/docs/support_files/world.md)
* [Step Definitions](/docs/support_files/step_definitions.md)
Expand All @@ -56,14 +57,17 @@ The following documentation is for `main`, which might contain some unreleased f
* [Attachments](/docs/support_files/attachments.md)
* [API Reference](/docs/support_files/api_reference.md)
* Guides
* [Dry Run](./docs/dry_run.md)
* [Dry run](./docs/dry_run.md)
* [ES Modules](./docs/esm.md)
* [Failing fast](./docs/fail_fast.md)
* [Filtering](./docs/filtering.md)
* [Formatters](./docs/formatters.md)
* [Running in parallel](./docs/parallel.md)
* [Profiles](./docs/profiles.md)
* [Rerunning just failures](./docs/rerun.md)
* [Retrying flaky scenarios](./docs/retry.md)
* [Snippets for undefined steps](./docs/snippets.md)
* [Transpiling (from TypeScript etc)](./docs/transpiling.md)
* [FAQ](/docs/faq.md)

### Documentation for older versions
Expand Down
22 changes: 19 additions & 3 deletions compatibility/cck_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import { ignorableKeys } from '../features/support/formatter_output_helpers'
import * as messages from '@cucumber/messages'
import * as messageStreams from '@cucumber/message-streams'
import util from 'util'
import { runCucumber } from '../src/api'
import { IRunConfiguration } from '../src/configuration'
import { runCucumber, IRunnableConfiguration } from '../src/api'
import { Envelope } from '@cucumber/messages'

const asyncPipeline = util.promisify(pipeline)
Expand All @@ -30,9 +29,13 @@ describe('Cucumber Compatibility Kit', () => {
const actualMessages: Envelope[] = []
const stdout = new PassThrough()
const stderr = new PassThrough()
const runConfiguration: IRunConfiguration = {
const runConfiguration: IRunnableConfiguration = {
sources: {
defaultDialect: 'en',
paths: [`${CCK_FEATURES_PATH}/${suiteName}/${suiteName}${extension}`],
names: [],
tagExpression: '',
order: 'defined',
},
support: {
requireModules: ['ts-node/register'],
Expand All @@ -42,7 +45,20 @@ describe('Cucumber Compatibility Kit', () => {
importPaths: [],
},
runtime: {
dryRun: false,
failFast: false,
filterStacktraces: true,
parallel: 0,
retry: suiteName === 'retry' ? 2 : 0,
retryTagFilter: '',
strict: true,
worldParameters: {},
},
formats: {
stdout: 'summary',
files: {},
options: {},
publish: false,
},
}
await runCucumber(
Expand Down
14 changes: 0 additions & 14 deletions cucumber.js

This file was deleted.

20 changes: 20 additions & 0 deletions cucumber.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A good example of what configuration can look like now.

"default": {
"requireModule": [
"ts-node/register"
],
"require": [
"features/**/*.ts"
],
"format": [
"progress-bar",
"rerun:@rerun.txt",
"usage:reports/usage.txt",
"message:reports/messages.ndjson",
"html:reports/html-formatter.html"
],
"retry": 2,
"retryTagFilter": "@flaky",
"publishQuiet": true
}
}
187 changes: 34 additions & 153 deletions docs/cli.md
Original file line number Diff line number Diff line change
@@ -1,178 +1,59 @@
# CLI

Cucumber.js includes an executable file to run the features. After installing Cucumber in your project, you can run it with:
Cucumber includes an executable file to run your scenarios. After installing the `@cucumber/cucumber` package, you can run it directly:

``` shell
$ ./node_modules/.bin/cucumber-js
```

**Note on global installs:** Cucumber does not work when installed globally because cucumber
needs to be required in your support files and globally installed modules cannot be required.

## Running specific features

* Specify a [glob](https://github.com/isaacs/node-glob) pattern
* `$ cucumber-js features/**/*.feature`
* Specify a feature directory
* `$ cucumber-js features/dir`
* Specify a feature file
* `$ cucumber-js features/my_feature.feature`
* Specify a scenario by its line number
* `$ cucumber-js features/my_feature.feature:3`
* Specify a scenario by its name matching a regular expression
* `$ cucumber-js --name "topic 1"`
* `$ cucumber-js --name "^start.+end$"`
* If used multiple times, the scenario name needs to match only one of the names supplied
* To escape special regex characters in scenario name, use backslash e.g., `\(Scenario Name\)`
* Use [Tags](#tags)

## Loading support files

By default, the following files are loaded:
* If the features live in a `features` directory (at any level)
* `features/**/*.(js|mjs)`
* Otherwise
* `<DIR>/**/*.(js|mjs)` for each directory containing the selected features
Or via a [`package.json` script](https://docs.npmjs.com/cli/v8/using-npm/scripts):

With the defaults described above, `.js` files are loaded via `require()`, whereas `.mjs` files are loaded via `import()`.

Alternatively, you can use either or both of these options to explicitly load support files before executing the features:
```json
{
"scripts": {
"cucumber": "cucumber-js"
}
}
```

- `--require <GLOB|DIR|FILE>` - loads via `require()` (legacy)
- `--import <GLOB|DIR|FILE>` - loads via `import()`
Or via [npx](https://docs.npmjs.com/cli/v8/commands/npx):

Both options use [glob](https://github.com/isaacs/node-glob) patterns and may be used multiple times in order to e.g. load files from several different locations.
``` shell
$ npx cucumber-js
```

_Note that once you specify any `--require` or `--import` options, the defaults described above are no longer applied._
**Note on global installs:** Cucumber does not work when installed globally because `@cucumber/cucumber`
needs to be required in your support files and globally installed modules cannot be required.

## Formats
## Options

Use `--format <TYPE[:PATH]>` to specify the format of the output.
All the [standard configuration options](./configuration.md#options) can be provided via the CLI.

See [Formatters](./formatters.md).
Additionally, there are a few options that are specific to the CLI:

### Officially-supported standalone formatters
| Option | Type | Repeatable | Description |
|--------------------|------------|------------|-----------------------------------------------------------------------------------------|
| `--config`, `-c` | `string` | No | Path to your configuration file - see [Files](./configuration.md#files) |
| `--profile`, `-p` | `string[]` | Yes | Profiles from which to include configuration - see [Profiles](./profiles.md) |
| `--version`, `-v` | `boolean` | No | Print the currently installed version of Cucumber, then exit immediately |
| `--i18n-keywords` | `string` | No | Print the Gherkin keywords for the given ISO-639-1 language code, then exit immediately |
| `--i18n-languages` | `boolean` | No | Print the supported languages for Gherkin, then exit immediately |

* [@cucumber/pretty-formatter](https://www.npmjs.com/package/@cucumber/pretty-formatter) - prints the feature with inline results, colours and custom themes.
To see the available options for your installed version, run:

### Format Options
```shell
$ cucumber-js --help
```

You can pass in format options with `--format-options <JSON>`.
## Exiting

See [Formatters](./formatters.md).
By default, cucumber exits when the event loop drains. Use the `forceExit` configuration option in order to force shutdown of the event loop when the test run has finished:

## Exiting
- In a configuration file `{ forceExit: true }`
- On the CLI `$ cucumber-js --force-exit`

By default, cucumber exits when the event loop drains. Use the `--exit` flag in order to force shutdown of the event loop when the test run has finished. This is discouraged, as fixing the issues that causes the hang is a better long term solution. Some potential resources for that are:
This is discouraged, as fixing the issues that causes the hang is a better long term solution. Some potential resources for that are:
* [Node.js guide to debugging](https://nodejs.org/en/docs/inspector/)
* NPM package [why-is-node-running](https://www.npmjs.com/package/why-is-node-running)
* [Node.js Async Hooks](https://nodejs.org/dist/latest-v8.x/docs/api/async_hooks.html)
* Isolating what scenario or scenarios causes the hang

## --no-strict

disable _strict_ mode.

By default, cucumber works in _strict_ mode, meaning it will fail if there are pending steps.

## Parallel

See [Parallel](./parallel.md).

## Printing Attachments Details

Printing attachments details can be disabled with
`--fomat-options '{"printAttachments": false}'`.

This option applies to the progress formatter and the summary formatter.

## Profiles

See [Profiles](./profiles.md).

## Tags

Use `--tags <EXPRESSION>` to run specific features or scenarios. This option is repeatable and the expressions will be merged with an `and` operator.
`<EXPRESSION>` is a [cucumber tag expression](https://docs.cucumber.io/cucumber/api/#tag-expressions).

## --fail-fast

abort the run on first failure (default: false)

By default, cucumber-js runs the entire suite and reports all the failures. This flag allows a developer workflow where you work on one failure at a time. Combining this feature with rerun files allows you to work through all failures in an efficient manner.

A note on using in conjunction with `--retry`: we consider a test case to have failed if it exhausts retries and still fails, but passed if it passes on a retry having failed previous attempts, so `--fail-fast` does still allow retries to happen.

## Retry failing tests

See [Retry](./retry.md)

## Transpilation

Step definitions and support files can be written in other languages that transpile to JavaScript.

### Simple ES6 support

For instance, for ES6 support with [Babel](https://babeljs.io/) 7 add:

```
--require-module @babel/register
```

This will effectively call `require('@babel/register')` prior to requiring any support files.

If your files end with an extension other than `js`, make sure to also include the `--require` option to state the required support files. For example, if using [CoffeeScript](https://www.npmjs.com/package/coffeescript):

```
--require-module coffeescript/register --require 'features/**/*.coffee'
```

### TypeScript

Your `tsconfig.json` should have the `resolveJsonModule` compiler option switched on. Other than that, a pretty standard TypeScript setup should work as expected.

#### With ts-node

If you are using [ts-node](https://github.com/TypeStrong/ts-node):

```
--require-module ts-node/register --require 'step-definitions/**/*.ts'
```

> ⚠️ Some TypeScript setups use `esnext` modules by default,
> which doesn't marry well with Node. You may consider using commonjs instead.
> See how to add [extra configuration](#extra-configuration) below.

#### With babel

If you are using babel with [@babel/preset-typescript](https://babeljs.io/docs/en/babel-preset-typescript):

```
--require-module @babel/register --require 'step-definitions/**/*.ts'
```

### Extra Configuration

Sometimes the required module (say `@ts-node/register`) needs extra configuration. For example, you might want to configure it such that it prevents the compiled JS being written out to files, and pass some compiler options. In such cases, create a script (say, `tests.setup.js`):

```js
require('ts-node').register({
transpileOnly: true,
compilerOptions: {
"module": "commonjs",
"resolveJsonModule": true,
},
});
```

And then require it using the `--require` option:

```
--require tests.setup.js --require 'features/**/*.ts'
```

Note that the first `--require tests.setup.js` overrides the default require glob, so we'll need to `--require` our support code explicitly too.

## World Parameters

See [World](./support_files/world.md).
Loading