Skip to content

Commit

Permalink
Merge branch 'master' into skipped-typings
Browse files Browse the repository at this point in the history
  • Loading branch information
davidjgoss authored Feb 2, 2021
2 parents 4033331 + 6489d97 commit 7a59836
Show file tree
Hide file tree
Showing 32 changed files with 402 additions and 255 deletions.
24 changes: 8 additions & 16 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Please see [CONTRIBUTING.md](https://github.com/cucumber/cucumber/blob/master/CO

### Added

- Support attachments that are already base64-encoded via a prefix on the MIME type e.g. `this.attach(base64String, 'base64:image/png')` ([#1552](https://github.com/cucumber/cucumber-js/pull/1552))

### Changed

### Deprecated
Expand Down Expand Up @@ -39,18 +41,7 @@ Please see [CONTRIBUTING.md](https://github.com/cucumber/cucumber/blob/master/CO

## [7.0.0-rc.0] (2020-09-14)

Starting with version 7, the npm module has been changed from `cucumber` to `@cucumber/cucumber`

### Migration guide

- `npm uninstall cucumber`
- `npm install --save-dev @cucumber/cucumber`
- require/import `@cucumber/cucumber` instead of `cucumber`
- TypeScript
- Replace `TableDefinition` with `DataTable`
- `npm uninstall @types/cucumber`

If anything is missing from the migration guide, please submit an issue.
See the [migration guide](./docs/migration.md) for details of how to migrate from 6.x.x.

### New Features

Expand All @@ -62,21 +53,22 @@ If anything is missing from the migration guide, please submit an issue.

### Breaking changes

* The npm module has changed name from `cucumber` to `@cucumber/cucumber`
* Your `require` / `import` statements must be changed from `cucumber` to `@cucumber/cucumber`
* The npm module has changed name from `cucumber` to `@cucumber/cucumber` - `require`/`import` statements must be changed from `cucumber` to `@cucumber/cucumber`
* TypeScript users must rename `TableDefinition` to `DataTable`
* Drop support for Node.js 8, add support for Node.js 14
* Formatters
* Events are now based on [cucumber-messages](https://github.com/cucumber/cucumber/tree/master/messages)
* `event-protocol` formatter has been removed and replaced with `message`
* Custom formatters will need to migrate
* `json` formatter is deprecated and will be removed in next major release. Custom formatters should migrate to use the `message` formatter, or the [standalone JSON formatter](https://github.com/cucumber/cucumber/tree/master/json-formatter) as a stopgap.
* Remove long-deprecated `typeName` from options object for `defineParameterType` in favour of `name`
* Parallel runtime environment variables renamed for inclusivity:
* `CUCUMBER_TOTAL_SLAVES` is now `CUCUMBER_TOTAL_WORKERS`
* `CUCUMBER_SLAVE_ID` is now `CUCUMBER_WORKER_ID`
* Custom formatters are now loaded via the regular require paths relative to the current directory, unless it begins with a dot (e.g. `--format=./relpath/to/formatter`). Previously this was always loaded as a file relative to the current directory.

### Deprecations

* `json` formatter is deprecated and will be removed in next major release. Custom formatters should migrate to use the `message` formatter, or the [standalone JSON formatter](https://github.com/cucumber/cucumber/tree/master/json-formatter) as a stopgap.

### Bug fixes

* don't execute BeforeAll and AfterAll hooks when in dry-run
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ Cucumber.js is available as an npm module.
$ npm install @cucumber/cucumber
```

If you're upgrading from 6.x.x or below, see the [migration guide](./docs/migration.md).

### 6.x.x and below

``` shell
Expand Down
48 changes: 31 additions & 17 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,26 +43,33 @@ _Note that once you specify any `--require` options, the defaults described abov
## Formats

Use `--format <TYPE[:PATH]>` to specify the format of the output.
If PATH is not supplied, the formatter prints to `stdout`.
If PATH is supplied, it prints to the given file.

The `TYPE` can be one of:
* The name of one of the built-in formatters (below) e.g. `progress`
* A module/package name e.g. `@cucumber/pretty-formatter`
* A relative path to a local formatter implementation e.g. `./my-customer-formatter.js`

If `PATH` is not supplied, the formatter prints to `stdout`.
If `PATH` is supplied, it prints to the given file.

This option may be used multiple times in order to output different formats to different files.
If multiple formats are specified with the same output, only the last is used.

### Built-in formatters

* message - prints each [message](https://github.com/cucumber/cucumber/tree/master/cucumber-messages) in NDJSON form, which can then be consumed by other tools.
* html - prints a rich HTML report to a standalone page
* json - prints the feature as JSON. *Note: this formatter is deprecated and will be removed in the next major release. Where you need a structured data representation of your test run, it's best to use the `message` formatter. For legacy tools that depend on the deprecated JSON format, a standalone formatter is available (see https://github.com/cucumber/cucumber/tree/master/json-formatter).
* progress - prints one character per scenario (default).
* progress-bar - prints a progress bar and outputs errors/warnings along the way.
* rerun - prints the paths of any non-passing scenarios ([example](/features/rerun_formatter.feature))
* **message** - prints each [message](https://github.com/cucumber/cucumber/tree/master/cucumber-messages) in NDJSON form, which can then be consumed by other tools.
* **html** - prints a rich HTML report to a standalone page
* **json** - prints the feature as JSON. *Note: this formatter is deprecated and will be removed in the next major release. Where you need a structured data representation of your test run, it's best to use the `message` formatter. For legacy tools that depend on the deprecated JSON format, a standalone formatter is available (see https://github.com/cucumber/cucumber/tree/master/json-formatter).
* **progress** - prints one character per scenario (default).
* **progress-bar** - prints a progress bar and outputs errors/warnings along the way.
* **rerun** - prints the paths of any non-passing scenarios ([example](/features/rerun_formatter.feature))
* suggested use: add the rerun formatter to your default profile and the output file to your `.gitignore`.
* After a failed run, remove any arguments used for selecting feature files and add the rerun file in order to rerun just failed scenarios. The rerun file must start with an `@` sign in order for cucumber to parse it as a rerun file instead of a feature file.
* Use with `--fail-fast` to rerun the failure and the remaining features.
* snippets - prints just the code snippets for undefined steps.
* summary - prints a summary only, after all scenarios were executed.
* usage - prints a table with data about step definitions usage.
* usage-json - prints the step definitions usage data as JSON.
* **snippets** - prints just the code snippets for undefined steps.
* **summary** - prints a summary only, after all scenarios were executed.
* **usage** - prints a table with data about step definitions usage.
* **usage-json** - prints the step definitions usage data as JSON.

### Officially-supported standalone formatters

Expand Down Expand Up @@ -113,16 +120,23 @@ This is useful when one needs to rerun failed tests locally by copying a line fr
The default separator is a newline character.
Note that the rerun file parser can only work with the default separator for now.

## Parallel (experimental)
## Parallel

You can run your scenarios in parallel with `--parallel <NUMBER_OF_WORKERS>`. Each worker is run in a separate Node process and receives the following env variables:

You can run your scenarios in parallel with `--parallel <NUMBER_OF_WORKERS>`. Each worker is run in a separate node process and receives the following env variables:
* `CUCUMBER_PARALLEL` - set to 'true'
* `CUCUMBER_TOTAL_WORKERS` - set to the number of workers
* `CUCUMBER_WORKER_ID` - ID for worker ('0', '1', '2', etc.)

**Notes**
* The reported runtime from the summary formatter is the total time from running the steps and thus be higher than the runtime for the command. The command runtime can be measured with other tools (time / Measure-Command)
* Prior to 5.0.2, printing to `stdout` (using `console.log` or other means) will cause an error, because the worker processes communicate with the coordinator process over `stdout`. Instead print to `stderr` (using `console.error` or other means). In versions 5.0.2 and newer, processes communicate with IPC and this is no longer an issue.
### Timing

When using parallel mode, the last line of the summary output differentiates between real time elapsed during the test run and aggregate time spent actually running steps:

```
73 scenarios (73 passed)
512 steps (512 passed)
0m51.627s (executing steps: 4m51.228s)
```

## Profiles

Expand Down
6 changes: 5 additions & 1 deletion docs/custom_formatters.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ See a couple examples [here](/features/custom_formatter.feature) and the built i

## Extending Built-Ins

The base `Formatter` does very little aside from saving some of the options on the instance. You can extend the `SummaryFormatter` (as the `ProgressFormatter` and `PrettyFormatter` do) in order to get the same error reporting at the end.
The base `Formatter` does very little aside from saving some of the options on the instance. You can extend the `SummaryFormatter` (as the `ProgressFormatter` does) in order to get the same error reporting at the end.

`formatterHelpers` are also exposed to give some of the functionality in more modular pieces.

If there is any other formatter functionality you would like access to, please create an [issue](https://github.com/cucumber/cucumber-js).

## Distribution

If you want to share your formatter with other users, [publish it as an npm package](https://docs.npmjs.com/packages-and-modules/contributing-packages-to-the-registry) and make sure your formatter class is the default export of the entry point defined in `package.json` - that way users will be able to just reference it by the package name when running cucumber-js, once they've added it as a dependency.
29 changes: 27 additions & 2 deletions docs/faq.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,37 @@
# Frequently Asked Questions

#### The world instance isn’t available in my hooks or step definitions.
## The world instance isn’t available in my hooks or step definitions.

This has frequently been caused by the use of ES6 arrow functions.
If you are using the world instance (which is bound to `this`) in a step definition, then you cannot use ES6 arrow functions for step definitions or hooks because they bind `this` to the current context which prevents the world instance from being injected.

#### Why do my definition patterns need to be globally unique instead of unique only within `Given`, `When`, `Then`?
## Why do my definition patterns need to be globally unique instead of unique only within `Given`, `When`, `Then`?

To encourage a ubiquitous, non-ambiguous domain language.
Using the same language to mean different things is basically the definition of ambiguous.
If you have similar `Given` and `Then` patterns, try adding the word “should” to `Then` patterns.

## Why am I seeing `The "from" argument must be of type string. Received type undefined`?

If when running cucumber-js you see an error with a stack trace like:

```
TypeError [ERR_INVALID_ARG_TYPE]: The "from" argument must be of type string. Received type undefined
at validateString (internal/validators.js:125:11)
at Object.relative (path.js:1162:5)
...
```

This usually an effect of one of:

- Your project depends on cucumber-js, and also has a dependency (in `node_modules`) that depends on cucumber-js at a different version
- You have a package that depends (even as a dev dependency) on cucumber-js linked (via `npm link` or `yarn link`)

These cases can cause two different instances of cucumber-js to be in play at runtime, which causes errors.

If removing the duplicate dependency is not possible, you can work around this by using [import-cwd](https://www.npmjs.com/package/import-cwd) so your support code always requires cucumber-js from the current working directory (i.e. your host project):

```js
const importCwd = require('import-cwd')
const { Given, When, Then } = importCwd('@cucumber/cucumber')
```
50 changes: 50 additions & 0 deletions docs/migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Migrating to cucumber-js 7.x.x

## Package Name

cucumber-js is now published at `@cucumber/cucumber` instead of `cucumber`. To upgrade, you'll need to remove the old package and add the new one:

```shell
$ npm rm cucumber
$ npm install --save-dev @cucumber/cucumber
```

You'll need to update any `import`/`require` statements in your support code to use the new package name.

(The executable is still `cucumber-js` though.)

## Formatters

The underlying event/data model for cucumber-js is now [cucumber-messages](https://github.com/cucumber/cucumber/tree/master/messages), a shared standard across all official Cucumber implementations. This replaces the old "event protocol".

If you maintain any custom formatters, you'll need to refactor them to work with the new model. The basics of a `Formatter` class are the same, and the `EventDataCollector` is still there to help you with tracking down data, but the names of events and shape of their data is different. It's worth checking out the implementations of the built-in formatters if you need a pointer.

We now support referring to custom formatters on the path by module/package name, for example:

```shell
$ cucumber-js --format @cucumber/pretty-formatter
```

This does mean that if you want to point to a local formatter implementation (i.e. not a Node module) then you should ensure it's a relative path starting with `./`.

## Parallel

The parallel mode previously used problematic "master"/"slave" naming that we've dropped in favour of "coordinator" and "worker". This is mostly an internal detail, but is also reflected in the names of some environment variables you might be using:

* `CUCUMBER_TOTAL_SLAVES` is now `CUCUMBER_TOTAL_WORKERS`
* `CUCUMBER_SLAVE_ID` is now `CUCUMBER_WORKER_ID`

## TypeScript

*(You can skip this part if you don't use TypeScript in your projects.)*

Where before we relied on the community-authored `@types/cucumber` package, cucumber-js is now built with TypeScript and as such includes its own typings, so you can drop your dependency on the separate package:

```shell
$ npm rm @types/cucumber
```

There are a few minor differences to be aware of:

- The type for data tables was named `TableDefinition` - it's now named `DataTable`
- `World` was typed as an interface, but it's actually a class - you should `extend` it when [building a custom formatter](./custom_formatters.md)
18 changes: 9 additions & 9 deletions docs/nodejs_example.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
## Setup

- Install [Node.js](https://nodejs.org) (6 or higher)
- Install [Node.js](https://nodejs.org) (10 or higher)
- Install Cucumber modules with [yarn](https://yarnpkg.com/en/) **or** [npm](https://www.npmjs.com/)

```
yarn add -D cucumber@latest
yarn add -D npm install @cucumber/cucumber
npm i -D cucumber@latest
npm i -D npm install @cucumber/cucumber
```

* Add the following files
Expand Down Expand Up @@ -37,7 +37,7 @@

```javascript
// features/support/world.js
const { setWorldConstructor } = require("cucumber");
const { setWorldConstructor } = require("@cucumber/cucumber");

class CustomWorld {
constructor() {
Expand All @@ -58,18 +58,18 @@

```javascript
// features/support/steps.js
const { Given, When, Then } = require("cucumber");
const assert = require("assert").strict
const { Given, When, Then } = require("@cucumber/cucumber");
const assert = require("assert").strict;
Given("a variable set to {int}", function(number) {
Given("a variable set to {int}", function (number) {
this.setTo(number);
});
When("I increment the variable by {int}", function(number) {
When("I increment the variable by {int}", function (number) {
this.incrementBy(number);
});
Then("the variable should contain {int}", function(number) {
Then("the variable should contain {int}", function (number) {
assert.equal(this.variable, number);
});
```
Expand Down
2 changes: 1 addition & 1 deletion docs/support_files/api_reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## API Reference

Each method can be destructed from the object returned by `require('cucumber')`.
Each method can be destructed from the object returned by `require('@cucumber/cucumber')`.

---

Expand Down
28 changes: 20 additions & 8 deletions docs/support_files/attachments.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ which the default world constructor assigns to `this.attach`. If using a custom
you need to do this as well if you want to add attachments.

```javascript
var {After} = require('cucumber');
var {After} = require('@cucumber/cucumber');

After(function () {
this.attach('Some text');
Expand All @@ -17,7 +17,7 @@ By default, text is saved with a MIME type of `text/plain`. You can also specif
a different MIME type:

```javascript
var {After} = require('cucumber');
var {After} = require('@cucumber/cucumber');

After(function () {
this.attach('{"name": "some JSON"}', 'application/json');
Expand All @@ -29,7 +29,7 @@ The data will be `base64` encoded in the output.
You should wait for the stream to be read before continuing by providing a callback or waiting for the returned promise to resolve.

```javascript
var {After, Status} = require('cucumber');
var {After, Status} = require('@cucumber/cucumber');

// Passing a callback
After(function (testCase, callback) {
Expand All @@ -55,7 +55,7 @@ Images and binary data can also be attached using a [Buffer](https://nodejs.org/
The data will be `base64` encoded in the output.

```javascript
var {After, Status} = require('cucumber');
var {After, Status} = require('@cucumber/cucumber');

After(function (testCase) {
if (testCase.result.status === Status.FAILED) {
Expand All @@ -65,18 +65,30 @@ After(function (testCase) {
});
```

If you've already got a base64-encoded string, you can prefix your mime type with `base64:` to indicate this:

```javascript
var {After, Status} = require('@cucumber/cucumber');

After(function (testCase) {
if (testCase.result.status === Status.FAILED) {
var base64String = getScreenshotOfError();
this.attach(base64String, 'base64:image/png');
}
});
```

Here is an example of saving a screenshot using [Selenium WebDriver](https://www.npmjs.com/package/selenium-webdriver)
when a scenario fails:

```javascript
var {After, Status} = require('cucumber');
var {After, Status} = require('@cucumber/cucumber');

After(function (testCase) {
var world = this;
if (testCase.result.status === Status.FAILED) {
return webDriver.takeScreenshot().then(function(screenShot) {
// screenShot is a base-64 encoded PNG
world.attach(screenShot, 'image/png');
world.attach(screenShot, 'base64:image/png');
});
}
});
Expand Down Expand Up @@ -104,7 +116,7 @@ Given(/^a basic step$/, function() {
You can log useful information from your support code with the simple `log` function:

```javascript
var {After} = require('cucumber');
var {After} = require('@cucumber/cucumber');

After(function () {
this.log('Something interesting happened!');
Expand Down
Loading

0 comments on commit 7a59836

Please sign in to comment.