Skip to content
This repository was archived by the owner on Jun 19, 2022. It is now read-only.

Commit ad5f416

Browse files
committed
Add attach(), similar to that from cucumber-js
1 parent 09d0495 commit ad5f416

File tree

11 files changed

+235
-4
lines changed

11 files changed

+235
-4
lines changed

docs/json-report.md

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,66 @@ JSON reports can be enabled using the `json.enabled` property. The preprocessor
1010
}
1111
```
1212

13-
This **requires** you to have downloaded and installed the [cucumber-json-formatter](https://github.com/cucumber/common/tree/main/json-formatter) **yourself**. Arch Linux users can install it from [AUR](https://aur.archlinux.org/packages/cucumber-json-formatter).
13+
This **requires** you to have registered this module in your [plugin file](https://docs.cypress.io/guides/core-concepts/writing-and-organizing-tests#Plugins-file), as shown below.
14+
15+
```ts
16+
import { addCucumberPreprocessorPlugin } from "@badeball/cypress-cucumber-preprocessor";
17+
18+
export default (
19+
on: Cypress.PluginEvents,
20+
config: Cypress.PluginConfigOptions
21+
): Cypress.PluginConfigOptions => {
22+
await addCucumberPreprocessorPlugin(on, config);
23+
24+
// Make sure to return the config object as it might have been modified by the plugin.
25+
return config;
26+
}
27+
```
28+
29+
This also **requires** you to have downloaded and installed the [cucumber-json-formatter](https://github.com/cucumber/common/tree/main/json-formatter) **yourself**. Arch Linux users can install it from [AUR](https://aur.archlinux.org/packages/cucumber-json-formatter).
1430

1531
The location of the executable is configurable through the `json.formatter` property, but it will by default search for `cucumber-json-formatter` in your `PATH`.
1632

1733
The report is outputted to `cucumber-report.json` in the project directory, but can be configured through the `json.output` property.
34+
35+
## Attachments
36+
37+
Text, images and other data can be added to the output of the messages and JSON reports with attachments.
38+
39+
```ts
40+
import { Given, attach } from "@badeball/cypress-cucumber-preprocessor";
41+
42+
Given("a step", function() {
43+
attach("foobar");
44+
});
45+
```
46+
47+
By default, text is saved with a MIME type of text/plain. You can also specify a different MIME type.
48+
49+
```ts
50+
import { Given, attach } from "@badeball/cypress-cucumber-preprocessor";
51+
52+
Given("a step", function() {
53+
attach('{ "name": "foobar" }', "application/json");
54+
});
55+
```
56+
57+
Images and other binary data can be attached using a ArrayBuffer. The data will be base64 encoded in the output.
58+
59+
```ts
60+
import { Given, attach } from "@badeball/cypress-cucumber-preprocessor";
61+
62+
Given("a step", function() {
63+
attach(new TextEncoder().encode("foobar").buffer, "text/plain");
64+
});
65+
```
66+
67+
If you've already got a base64-encoded string, you can prefix your mime type with `base64:` to indicate this.
68+
69+
```ts
70+
import { Given, attach } from "@badeball/cypress-cucumber-preprocessor";
71+
72+
Given("a step", function() {
73+
attach("Zm9vYmFy", "base64:text/plain");
74+
});
75+
```

features/attachments.feature

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
Feature: attachments
2+
3+
Background:
4+
Given additional preprocessor configuration
5+
"""
6+
{
7+
"json": {
8+
"enabled": true
9+
}
10+
}
11+
"""
12+
And I've ensured cucumber-json-formatter is installed
13+
14+
Scenario: string identity
15+
Given a file named "cypress/integration/a.feature" with:
16+
"""
17+
Feature: a feature
18+
Scenario: a scenario
19+
Given a step
20+
"""
21+
And a file named "cypress/support/step_definitions/steps.js" with:
22+
"""
23+
const { Given, attach } = require("@badeball/cypress-cucumber-preprocessor");
24+
Given("a step", function() {
25+
attach("foobar")
26+
})
27+
"""
28+
When I run cypress
29+
Then it passes
30+
And there should be a JSON output similar to "fixtures/attachments/string.json"
31+
32+
Scenario: array buffer
33+
Given a file named "cypress/integration/a.feature" with:
34+
"""
35+
Feature: a feature
36+
Scenario: a scenario
37+
Given a step
38+
"""
39+
And a file named "cypress/support/step_definitions/steps.js" with:
40+
"""
41+
const { Given, attach } = require("@badeball/cypress-cucumber-preprocessor");
42+
Given("a step", function() {
43+
attach(new TextEncoder().encode("foobar").buffer, "text/plain")
44+
})
45+
"""
46+
When I run cypress
47+
Then it passes
48+
And there should be a JSON output similar to "fixtures/attachments/string.json"
49+
50+
Scenario: string encoded
51+
Given a file named "cypress/integration/a.feature" with:
52+
"""
53+
Feature: a feature
54+
Scenario: a scenario
55+
Given a step
56+
"""
57+
And a file named "cypress/support/step_definitions/steps.js" with:
58+
"""
59+
const { fromByteArray } = require("base64-js");
60+
const { Given, attach } = require("@badeball/cypress-cucumber-preprocessor");
61+
Given("a step", function() {
62+
attach(fromByteArray(new TextEncoder().encode("foobar")), "base64:text/plain")
63+
})
64+
"""
65+
When I run cypress
66+
Then it passes
67+
And there should be a JSON output similar to "fixtures/attachments/string.json"
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
[
2+
{
3+
"description": "",
4+
"elements": [
5+
{
6+
"description": "",
7+
"id": "a-feature;a-scenario",
8+
"keyword": "Scenario",
9+
"line": 2,
10+
"name": "a scenario",
11+
"steps": [
12+
{
13+
"keyword": "Given ",
14+
"line": 3,
15+
"name": "a step",
16+
"result": {
17+
"status": "passed"
18+
},
19+
"match": {
20+
"location": "not available:0"
21+
},
22+
"embeddings": [
23+
{
24+
"data": "Zm9vYmFy",
25+
"mime_type": "text/plain"
26+
}
27+
]
28+
}
29+
],
30+
"type": "scenario"
31+
}
32+
],
33+
"id": "a-feature",
34+
"keyword": "Feature",
35+
"line": 1,
36+
"name": "a feature",
37+
"uri": "cypress/integration/a.feature"
38+
}
39+
]

features/json_report.feature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,4 +177,4 @@ Feature: JSON formatter
177177
"""
178178
When I run cypress
179179
Then it passes
180-
And there should be a JSON output similar to "fixtures/screenshot.json"
180+
And there should be a JSON output similar to "fixtures/attachments/screenshot.json"

features/step_definitions/json_steps.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ Then(
8787
if (process.env.WRITE_FIXTURES) {
8888
await fs.writeFile(
8989
absoluteExpectedJsonpath,
90-
JSON.stringify(actualJsonOutput, null, 2)
90+
JSON.stringify(actualJsonOutput, null, 2) + "\n"
9191
);
9292
} else {
9393
const expectedJsonOutput = JSON.parse(

lib/add-cucumber-preprocessor-plugin.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@ import {
1717
ICypressConfiguration,
1818
} from "@badeball/cypress-configuration";
1919

20-
import { TASK_APPEND_MESSAGES, TASK_TEST_STEP_STARTED } from "./constants";
20+
import {
21+
TASK_APPEND_MESSAGES,
22+
TASK_CREATE_STRING_ATTACHMENT,
23+
TASK_TEST_STEP_STARTED,
24+
} from "./constants";
2125

2226
import { resolve } from "./preprocessor-configuration";
2327

@@ -125,6 +129,23 @@ export default async function addCucumberPreprocessorPlugin(
125129
currentTestStepStartedId = testStepStartedId;
126130
return true;
127131
},
132+
133+
[TASK_CREATE_STRING_ATTACHMENT]: async ({ data, mediaType, encoding }) => {
134+
const message: messages.IEnvelope = {
135+
attachment: {
136+
testStepId: currentTestStepStartedId,
137+
body: data,
138+
mediaType: mediaType,
139+
contentEncoding: encoding,
140+
},
141+
};
142+
143+
await fs.writeFile(messagesPath, JSON.stringify(message) + "\n", {
144+
flag: "a",
145+
});
146+
147+
return true;
148+
},
128149
});
129150

130151
const tags = getTags(config.env);

lib/constants.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@ export const TASK_APPEND_MESSAGES =
33

44
export const TASK_TEST_STEP_STARTED =
55
"cypress-cucumber-preprocessor:test-step-started";
6+
7+
export const TASK_CREATE_STRING_ATTACHMENT =
8+
"cypress-cucumber-preprocessor:create-string-attachment";

lib/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export const defineParameterType = createUnimplementation(
4646
Methods.defineParameterType
4747
);
4848
export const Step = createUnimplementation(Methods.Step);
49+
export const attach = createUnimplementation(Methods.attach);
4950

5051
export function defineBefore(options: { tags?: string }, fn: IHookBody): void;
5152
export function defineBefore(fn: IHookBody): void;

lib/methods.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1+
import { fromByteArray } from "base64-js";
2+
3+
import { TASK_CREATE_STRING_ATTACHMENT } from "./constants";
4+
15
import DataTable from "./data_table";
6+
27
import { getRegistry } from "./registry";
38

49
import {
@@ -56,6 +61,42 @@ function defineAfter(
5661
}
5762
}
5863

64+
function createStringAttachment(
65+
data: string,
66+
mediaType: string,
67+
encoding: "BASE64" | "IDENTITY"
68+
) {
69+
cy.task(TASK_CREATE_STRING_ATTACHMENT, {
70+
data,
71+
mediaType,
72+
encoding,
73+
});
74+
}
75+
76+
export function attach(data: string | ArrayBuffer, mediaType?: string) {
77+
if (typeof data === "string") {
78+
mediaType = mediaType ?? "text/plain";
79+
80+
if (mediaType.startsWith("base64:")) {
81+
createStringAttachment(data, mediaType.replace("base64:", ""), "BASE64");
82+
} else {
83+
createStringAttachment(data, mediaType ?? "text/plain", "IDENTITY");
84+
}
85+
} else if (data instanceof ArrayBuffer) {
86+
if (typeof mediaType !== "string") {
87+
throw Error("ArrayBuffer attachments must specify a media type");
88+
}
89+
90+
createStringAttachment(
91+
fromByteArray(new Uint8Array(data)),
92+
mediaType,
93+
"BASE64"
94+
);
95+
} else {
96+
throw Error("Invalid attachment data: must be a ArrayBuffer or string");
97+
}
98+
}
99+
59100
export {
60101
defineStep as Given,
61102
defineStep as When,

0 commit comments

Comments
 (0)