Skip to content

Commit aea9e8b

Browse files
authored
support attachments with filenames (#2297)
1 parent 0518bb3 commit aea9e8b

File tree

11 files changed

+336
-91
lines changed

11 files changed

+336
-91
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
88
Please see [CONTRIBUTING.md](./CONTRIBUTING.md) on how to contribute to Cucumber.
99

1010
## [Unreleased]
11+
### Added
12+
- Support attachments with filenames ([#2297](https://github.com/cucumber/cucumber-js/pull/2297))
1113

1214
## [9.2.0] - 2023-06-22
1315
### Added

compatibility/features/attachments/attachments.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,26 @@ When('the {word} png is attached', async function (filename) {
8686
'image/png'
8787
)
8888
})
89+
90+
When(
91+
'a PDF document is attached with a filename',
92+
async function (this: World) {
93+
await this.attach(
94+
fs.createReadStream(
95+
path.join(
96+
process.cwd(),
97+
'node_modules',
98+
'@cucumber',
99+
'compatibility-kit',
100+
'features',
101+
'attachments',
102+
'document.pdf'
103+
)
104+
),
105+
{
106+
mediaType: 'application/pdf',
107+
fileName: 'document.pdf',
108+
}
109+
)
110+
}
111+
)

docs/support_files/attachments.md

Lines changed: 38 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -14,39 +14,52 @@ After(function () {
1414
```
1515

1616
By default, text is saved with a MIME type of `text/plain`. You can also specify
17-
a different MIME type:
17+
a different MIME type as part of a second argument:
1818

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

2222
After(function () {
23-
this.attach('{"name": "some JSON"}', 'application/json');
23+
this.attach('{"name": "some JSON"}', { mediaType: 'application/json' });
24+
});
25+
```
26+
27+
If you'd like, you can also specify a filename to be used if the attachment is made available to download as a file via a formatter:
28+
29+
```javascript
30+
var {After} = require('@cucumber/cucumber');
31+
32+
After(function () {
33+
this.attach('{"name": "some JSON"}', {
34+
mediaType: 'application/json',
35+
fileName: 'results.json'
36+
});
2437
});
2538
```
2639

2740
Images and other binary data can be attached using a [stream.Readable](https://nodejs.org/api/stream.html).
2841
The data will be `base64` encoded in the output.
29-
You should wait for the stream to be read before continuing by providing a callback or waiting for the returned promise to resolve.
42+
You should wait for the stream to be read before continuing by awaiting the returned promise or providing a callback.
3043

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

34-
// Passing a callback
35-
After(function (testCase, callback) {
47+
// Awaiting the promise
48+
After(async function (testCase) {
3649
if (testCase.result.status === Status.FAILED) {
3750
var stream = getScreenshotOfError();
38-
this.attach(stream, 'image/png', callback);
39-
}
40-
else {
41-
callback();
51+
await this.attach(stream, { mediaType: 'image/png' });
4252
}
4353
});
4454

45-
// Returning the promise
46-
After(function (testCase) {
55+
// Passing a callback
56+
After(function (testCase, callback) {
4757
if (testCase.result.status === Status.FAILED) {
4858
var stream = getScreenshotOfError();
49-
return this.attach(stream, 'image/png');
59+
this.attach(stream, { mediaType: 'image/png' }, callback);
60+
}
61+
else {
62+
callback();
5063
}
5164
});
5265
```
@@ -60,38 +73,23 @@ var {After, Status} = require('@cucumber/cucumber');
6073
After(function (testCase) {
6174
if (testCase.result.status === Status.FAILED) {
6275
var buffer = getScreenshotOfError();
63-
this.attach(buffer, 'image/png');
64-
}
65-
});
66-
```
67-
68-
If you've already got a base64-encoded string, you can prefix your mime type with `base64:` to indicate this:
69-
70-
```javascript
71-
var {After, Status} = require('@cucumber/cucumber');
72-
73-
After(function (testCase) {
74-
if (testCase.result.status === Status.FAILED) {
75-
var base64String = getScreenshotOfError();
76-
this.attach(base64String, 'base64:image/png');
76+
this.attach(buffer, { mediaType: 'image/png' });
7777
}
7878
});
7979
```
8080

81-
Here is an example of saving a screenshot using [Selenium WebDriver](https://www.npmjs.com/package/selenium-webdriver)
81+
If you've already got a base64-encoded string, you can prefix your mime type with `base64:` to indicate this. Here's an example of saving a screenshot using [Selenium WebDriver](https://www.npmjs.com/package/selenium-webdriver)
8282
when a scenario fails:
8383

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

87-
After(function (testCase) {
88-
var world = this;
87+
After(async function (testCase) {
8988
if (testCase.result.status === Status.FAILED) {
90-
return webDriver.takeScreenshot().then(function(screenShot) {
91-
world.attach(screenShot, 'base64:image/png');
92-
});
89+
const screenshot = await driver.takeScreenshot()
90+
this.attach(screenshot, { mediaType: 'base64:image/png' })
9391
}
94-
});
92+
})
9593
```
9694

9795
Attachments are also printed by the progress, progress-bar and summary formatters.
@@ -100,15 +98,20 @@ It can be used to debug scenarios, especially in parallel mode.
10098

10199
```javascript
102100
// Step definition
103-
Given(/^a basic step$/, function() {
101+
Given('a basic step', async function() {
104102
this.attach('Some info.')
105-
this.attach('{"some", "JSON"}}', 'application/json')
103+
this.attach('{"some": "JSON"}}', { mediaType: 'application/json' })
104+
this.attach((await driver.takeScreenshot()), {
105+
mediaType: 'base64:image/png',
106+
fileName: 'screenshot.png'
107+
})
106108
})
107109

108110
// Result format
109111
// ✔ Given a basic step # path:line
110112
// Attachment (text/plain): Some info.
111113
// Attachment (application/json)
114+
// Attachment (image/png): screenshot.png
112115
```
113116

114117
## Logging

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@
249249
"yup": "^0.32.11"
250250
},
251251
"devDependencies": {
252-
"@cucumber/compatibility-kit": "11.3.0",
252+
"@cucumber/compatibility-kit": "^12.0.0",
253253
"@cucumber/query": "12.0.1",
254254
"@microsoft/api-documenter": "7.19.27",
255255
"@microsoft/api-extractor": "7.33.7",

src/formatter/helpers/issue_helpers_spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -260,8 +260,8 @@ describe('IssueHelpers', () => {
260260
${figures.tick} Given attachment step1 # steps.ts:35
261261
Attachment (text/plain): Some info
262262
Attachment (application/json)
263-
Attachment (image/png)
264-
${figures.cross} When attachment step2 # steps.ts:41
263+
Attachment (image/png): screenshot.png
264+
${figures.cross} When attachment step2 # steps.ts:44
265265
Attachment (text/plain): Other info
266266
error
267267
- Then a passing step # steps.ts:29
@@ -290,7 +290,7 @@ describe('IssueHelpers', () => {
290290
reindent(`
291291
1) Scenario: my scenario # a.feature:2
292292
${figures.tick} Given attachment step1 # steps.ts:35
293-
${figures.cross} When attachment step2 # steps.ts:41
293+
${figures.cross} When attachment step2 # steps.ts:44
294294
error
295295
- Then a passing step # steps.ts:29
296296

src/formatter/helpers/test_case_attempt_formatter.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,13 @@ function formatStep({
6969
text += indentString(`${colorFn(argumentsText)}\n`, 4)
7070
}
7171
if (valueOrDefault(printAttachments, true)) {
72-
attachments.forEach(({ body, mediaType }) => {
73-
const message = mediaType === 'text/plain' ? `: ${body}` : ''
72+
attachments.forEach(({ body, mediaType, fileName }) => {
73+
let message = ''
74+
if (mediaType === 'text/plain') {
75+
message = `: ${body}`
76+
} else if (fileName) {
77+
message = `: ${fileName}`
78+
}
7479
text += indentString(`Attachment (${mediaType})${message}\n`, 4)
7580
})
7681
}

0 commit comments

Comments
 (0)