Skip to content

Commit

Permalink
Merge branch 'badeball:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
VidhiRambhia authored Nov 6, 2023
2 parents ba4dc23 + 17ee4f3 commit 4fee78f
Show file tree
Hide file tree
Showing 29 changed files with 1,180 additions and 311 deletions.
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,30 @@

All notable changes to this project will be documented in this file.

## v19.0.1

- Fix type members to account for scenario hook names, fixes [#1113](https://github.com/badeball/cypress-cucumber-preprocessor/issues/1113).

## v19.0.0

Breaking changes:

- Run `After(..)` hooks in reversed order of definition. This is in line with how cucumber-js behaves.

- Updated all dependencies, including `@cucumber/cucumber` to v10.

- String literal attachments are now base64-encoded in JSON reports, ref. [cucumber/cucumber-js#2261](https://github.com/cucumber/cucumber-js/pull/2261).

Other changes:

- Scenario hooks (`Before(..)` and `After(..)`) are now invoked with an object containing a bunch of relevant data. This is in line with how cucumber-js behaves.

- Hooks may now be optionally named. This is in line with how cucumber-js behaves.

- Omit outputting internal task to the command log when using `attach(..)`.

- Add an [API](docs/json-report.md#attachments-node-environment) for adding attachments from the Node environment, fixes [#1089](https://github.com/badeball/cypress-cucumber-preprocessor/issues/1089).

## v18.0.6

- Make the compile output play nicer with ESM, relates to [#1093](https://github.com/badeball/cypress-cucumber-preprocessor/issues/1093).
Expand Down
55 changes: 46 additions & 9 deletions docs/cucumber-basics.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,30 @@
[← Back to documentation](readme.md)

# Expressions
# Table of Contents <!-- omit from toc -->

- [Step definitions](#step-definitions)
- [Expressions](#expressions)
- [Arguments](#arguments)
- [Custom parameter types](#custom-parameter-types)
- [Pending steps](#pending-steps)
- [Skipped steps](#skipped-steps)
- [Nested steps](#nested-steps)
- [Hooks](#hooks)
- [Scenario hooks](#scenario-hooks)
- [Step hooks](#step-hooks)
- [Named hooks](#named-hooks)

# Step definitions

## Expressions

A step definition’s *expression* can either be a regular expression or a [cucumber expression](https://github.com/cucumber/cucumber-expressions#readme). The examples in this section use cucumber expressions. If you prefer to use regular expressions, each *capture group* from the match will be passed as arguments to the step definition’s function.

```ts
Given("I have {int} cukes in my belly", (cukes: number) => {});
```

# Arguments
## Arguments

Steps can be accompanied by [doc strings](https://cucumber.io/docs/gherkin/reference/#doc-strings) or [data tables](https://cucumber.io/docs/gherkin/reference/#data-tables), both which will be passed to the step definition as the last argument, as shown below.

Expand All @@ -34,7 +50,7 @@ Given(/^a table step$/, (table: DataTable) => {

See [here](https://github.com/cucumber/cucumber-js/blob/main/docs/support_files/data_table_interface.md) for `DataTable`'s interface.

# Custom parameter types
## Custom parameter types

Custom parameter types can be registered using `defineParameterType()`. They share the same scope as tests and you can invoke `defineParameterType()` anywhere you define steps, though the order of definition is unimportant. The table below explains the various arguments you can pass when defining a parameter type.

Expand All @@ -44,7 +60,7 @@ Custom parameter types can be registered using `defineParameterType()`. They sha
| `regexp` | A regexp that will match the parameter. May include capture groups.
| `transformer` | A function or method that transforms the match from the regexp. Must have arity 1 if the regexp doesn't have any capture groups. Otherwise the arity must match the number of capture groups in `regexp`. |

# Pending steps
## Pending steps

You can return `"pending"` from a step defintion or a chain to mark a step as pending. This will halt the execution and Cypress will report the test as "skipped". This is generally used for marking steps as "unimplemented" and allows you to commit unfinished work without breaking the test suite.

Expand All @@ -66,7 +82,7 @@ When("a step", () => {
});
```

# Skipped steps
## Skipped steps

You can return `"skipped"` from a step defintion or a chain to mark a step as pending. This will halt the execution and Cypress will report the test as "skipped". This however is generally used for conditionally short circuiting a test.

Expand All @@ -88,7 +104,7 @@ When("a step", () => {
});
```

# Nested steps
## Nested steps

You can invoke other steps from a step using `Step()`, as shown below.

Expand Down Expand Up @@ -123,7 +139,11 @@ When("I fill in the entire form", function () {
});
```

# Scenario hooks
# Hooks

There are two types of hooks, scenario hooks and step hooks, each explained below.

## Scenario hooks

`Before()` and `After()` is similar to Cypress' `beforeEach()` and `afterEach()`, but they can be selected to conditionally run based on the tags of each scenario, as shown below. Furthermore, failure in these hooks does **not** result in remaining tests being skipped. This is contrary to Cypress' `beforeEach` and `afterEach`.

Expand All @@ -148,9 +168,13 @@ Before({ tags: "@foo and @bar" }, function () {
Before({ tags: "@foo or @bar" }, function () {
// This hook will be executed before scenarios tagged with @foo or @bar.
});

Before(function ({ pickle, gherkinDocument, testCaseStartedId }) {
// Scenario hooks are invoked with an object containing a bunch of relevant data.
});
```

# Step hooks
## Step hooks

`BeforeStep()` and `AfterStep()` are hooks invoked before and after each step, respectively. These too can be selected to conditionally run based on the tags of each scenario, as shown below.

Expand All @@ -176,9 +200,22 @@ BeforeStep({ tags: "@foo or @bar" }, function () {
// This hook will be executed before steps in scenarios tagged with @foo or @bar.
});

BeforeStep(function ({ pickle, pickleStep, gherkinDocument, result, testCaseStartedId, testStepId }) {
BeforeStep(function ({ pickle, pickleStep, gherkinDocument, testCaseStartedId, testStepId }) {
// Step hooks are invoked with an object containing a bunch of relevant data.
});
```

[^1]: This discrepancy between the preprocessor and cucumber-js is currently considered to be unsolvable, as explained [here](https://github.com/badeball/cypress-cucumber-preprocessor/issues/824#issuecomment-1561492281).

## Named hooks

Both scenario hooks and step hooks can optionally be named. Names are displayed in the command log, as well as in [messages reports](messages-report.md).

```ts
import { Before, BeforeStep, After, AfterStep } from "@badeball/cypress-cucumber-preprocessor";

Before({ name: "foo" }, function () {});
BeforeStep({ name: "bar" }, function () {});
After({ name: "baz" }, function () {});
AfterStep({ name: "qux" }, function () {});
```
58 changes: 56 additions & 2 deletions docs/json-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ The report is outputted to `cucumber-report.json` in the project directory, but

Screenshots are automatically added to JSON reports, including that of failed tests (unless you have disabled `screenshotOnRunFailure`).

## Attachments
## Attachments (browser environment)

Text, images and other data can be added to the output of the messages and JSON reports with attachments.
Text, images and other data can be added to the output of the messages and JSON reports with attachments, using the browser API explained below.

```ts
import { Given, attach } from "@badeball/cypress-cucumber-preprocessor";
Expand Down Expand Up @@ -59,3 +59,57 @@ Given("a step", function() {
attach("Zm9vYmFy", "base64:text/plain");
});
```

## Attachments (node environment)

Similar to the browser API explained above, attachments can also be added using a Node API. This is less typical and only required in specific scenarios. This API is available through the `onAfterStep` option in `addCucumberPreprocessorPlugin`, like shown below. The Node API mimicks the options found in the browser API.

```ts
await addCucumberPreprocessorPlugin(on, config, {
onAfterStep({ wasLastStep, attach }) {
attach("foobar");
}
});
```

By default, text is saved with a MIME type of text/plain. You can also specify a different MIME type.

```ts
await addCucumberPreprocessorPlugin(on, config, {
onAfterStep({ wasLastStep, attach }) {
attach('{ "name": "foobar" }', "application/json");
}
});
```

Images and other binary data can be attached using a Buffer. The data will be base64 encoded in the output.

```ts
await addCucumberPreprocessorPlugin(on, config, {
onAfterStep({ wasLastStep, attach }) {
attach(Buffer.from("foobar"), "text/plain");
}
});
```

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

```ts
await addCucumberPreprocessorPlugin(on, config, {
onAfterStep({ wasLastStep, attach }) {
attach("Zm9vYmFy", "base64:text/plain");
}
});
```

A `wasLastStep` option is available if you need to attach something at the end of the test.

```ts
await addCucumberPreprocessorPlugin(on, config, {
onAfterStep({ wasLastStep, attach }) {
if (wasLastStep) {
attach("foobar");
}
}
});
```
69 changes: 0 additions & 69 deletions features/attachments.feature

This file was deleted.

68 changes: 68 additions & 0 deletions features/attachments_browser.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
Feature: attachments

Background:
Given additional preprocessor configuration
"""
{
"json": {
"enabled": true
}
}
"""

Rule: it should support a variety of options

Scenario: string identity
Given a file named "cypress/e2e/a.feature" with:
"""
Feature: a feature
Scenario: a scenario
Given a step
"""
And a file named "cypress/support/step_definitions/steps.js" with:
"""
const { Given, attach } = require("@badeball/cypress-cucumber-preprocessor");
Given("a step", function() {
attach("foobar")
})
"""
When I run cypress
Then it passes
And there should be a JSON output similar to "fixtures/attachments/string.json"

Scenario: array buffer
Given a file named "cypress/e2e/a.feature" with:
"""
Feature: a feature
Scenario: a scenario
Given a step
"""
And a file named "cypress/support/step_definitions/steps.js" with:
"""
const { Given, attach } = require("@badeball/cypress-cucumber-preprocessor");
Given("a step", function() {
attach(new TextEncoder().encode("foobar").buffer, "text/plain")
})
"""
When I run cypress
Then it passes
And there should be a JSON output similar to "fixtures/attachments/string.json"

Scenario: string encoded
Given a file named "cypress/e2e/a.feature" with:
"""
Feature: a feature
Scenario: a scenario
Given a step
"""
And a file named "cypress/support/step_definitions/steps.js" with:
"""
const { fromByteArray } = require("base64-js");
const { Given, attach } = require("@badeball/cypress-cucumber-preprocessor");
Given("a step", function() {
attach(fromByteArray(new TextEncoder().encode("foobar")), "base64:text/plain")
})
"""
When I run cypress
Then it passes
And there should be a JSON output similar to "fixtures/attachments/string.json"
Loading

0 comments on commit 4fee78f

Please sign in to comment.