diff --git a/CHANGELOG.md b/CHANGELOG.md index 2595fc66c..c440389a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/docs/support_files/attachments.md b/docs/support_files/attachments.md index b428d3435..b4d1afa93 100644 --- a/docs/support_files/attachments.md +++ b/docs/support_files/attachments.md @@ -65,6 +65,19 @@ 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: @@ -75,8 +88,7 @@ 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'); }); } }); diff --git a/features/attachments.feature b/features/attachments.feature index 3d721f7de..86bf33ae5 100644 --- a/features/attachments.feature +++ b/features/attachments.feature @@ -28,6 +28,20 @@ Feature: Attachments | DATA | MEDIA TYPE | MEDIA ENCODING | | iVBORw== | image/png | BASE64 | + Scenario: Attach a string that is already base64 encoded + Given a file named "features/support/hooks.js" with: + """ + const {Before} = require('@cucumber/cucumber') + + Before(function() { + this.attach(Buffer.from([137, 80, 78, 71]).toString('base64'), 'base64:image/png') + }) + """ + When I run cucumber-js + Then scenario "some scenario" "Before" hook has the attachments: + | DATA | MEDIA TYPE | MEDIA ENCODING | + | iVBORw== | image/png | BASE64 | + Scenario: Attach a stream (callback) Given a file named "features/support/hooks.js" with: """ diff --git a/src/runtime/attachment_manager/index.ts b/src/runtime/attachment_manager/index.ts index 4257569b1..8c4a4967c 100644 --- a/src/runtime/attachment_manager/index.ts +++ b/src/runtime/attachment_manager/index.ts @@ -51,10 +51,17 @@ export default class AttachmentManager { if (doesNotHaveValue(mediaType)) { mediaType = 'text/plain' } - this.createStringAttachment(data, { - encoding: messages.Attachment.ContentEncoding.IDENTITY, - contentType: mediaType, - }) + if (mediaType.startsWith('base64:')) { + this.createStringAttachment(data, { + encoding: messages.Attachment.ContentEncoding.BASE64, + contentType: mediaType.replace('base64:', ''), + }) + } else { + this.createStringAttachment(data, { + encoding: messages.Attachment.ContentEncoding.IDENTITY, + contentType: mediaType, + }) + } } else { throw Error( 'Invalid attachment data: must be a buffer, readable stream, or string' diff --git a/src/runtime/attachment_manager/index_spec.ts b/src/runtime/attachment_manager/index_spec.ts index d72c97583..482cd8f84 100644 --- a/src/runtime/attachment_manager/index_spec.ts +++ b/src/runtime/attachment_manager/index_spec.ts @@ -204,6 +204,34 @@ describe('AttachmentManager', () => { }) }) + describe('with media type, already base64 encoded', () => { + it('adds the data and media', function () { + // Arrange + const attachments: IAttachment[] = [] + const attachmentManager = new AttachmentManager((x) => + attachments.push(x) + ) + + // Act + const result = attachmentManager.create( + Buffer.from('my string', 'utf8').toString('base64'), + 'base64:text/special' + ) + + // Assert + expect(result).to.eql(undefined) + expect(attachments).to.eql([ + { + data: 'bXkgc3RyaW5n', + media: { + contentType: 'text/special', + encoding: messages.Attachment.ContentEncoding.BASE64, + }, + }, + ]) + }) + }) + describe('without mime type', () => { it('adds the data with the default mime type', function () { // Arrange