diff --git a/.eslintignore b/.eslintignore index 8d87b1d..510731c 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1,2 @@ node_modules/* +index.d.ts diff --git a/.eslintrc b/.eslintrc index 68fb544..63de477 100644 --- a/.eslintrc +++ b/.eslintrc @@ -35,7 +35,7 @@ "semi-spacing": 0, "no-multi-spaces": 0, "eqeqeq": 0, - "no-mixed-requires": 0, + "no-mixed-requires": 0 }, "env": { "node": true diff --git a/.gitignore b/.gitignore index 8d5dba1..5790d18 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ sftp-config.json yarn.lock +package-lock.json coverage/ node_modules/ diff --git a/.travis.yml b/.travis.yml index 37f8d8a..f22a5d9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,14 +2,15 @@ sudo: false language: node_js node_js: - - "4" - "6" - "8" - - "9" + - "10" + - "12" os: - osx - linux +- windows install: - travis_retry npm install @@ -18,8 +19,8 @@ script: - uname -a - node --version - npm --version - - npm run ci-lint - - npm run ci-test + - if [ "$TRAVIS_OS_NAME" != "windows" ]; then npm run ci-lint; fi + - if [ "$TRAVIS_OS_NAME" = "windows" ]; then npm run test; else npm run ci-test; fi - npm run check after_success: diff --git a/Readme.md b/Readme.md index 9874b5f..12983e7 100644 --- a/Readme.md +++ b/Readme.md @@ -6,13 +6,12 @@ The API of this library is inspired by the [XMLHttpRequest-2 FormData Interface] [xhr2-fd]: http://dev.w3.org/2006/webapi/XMLHttpRequest-2/Overview.html#the-formdata-interface -[![Linux Build](https://img.shields.io/travis/form-data/form-data/master.svg?label=linux:4.x-9.x)](https://travis-ci.org/form-data/form-data) -[![MacOS Build](https://img.shields.io/travis/form-data/form-data/master.svg?label=macos:4.x-9.x)](https://travis-ci.org/form-data/form-data) -[![Windows Build](https://img.shields.io/appveyor/ci/alexindigo/form-data/master.svg?label=windows:4.x-9.x)](https://ci.appveyor.com/project/alexindigo/form-data) +[![Linux Build](https://img.shields.io/travis/form-data/form-data/master.svg?label=linux:6.x-12.x)](https://travis-ci.org/form-data/form-data) +[![MacOS Build](https://img.shields.io/travis/form-data/form-data/master.svg?label=macos:6.x-12.x)](https://travis-ci.org/form-data/form-data) +[![Windows Build](https://img.shields.io/travis/form-data/form-data/master.svg?label=windows:6.x-12.x)](https://travis-ci.org/form-data/form-data) [![Coverage Status](https://img.shields.io/coveralls/form-data/form-data/master.svg?label=code+coverage)](https://coveralls.io/github/form-data/form-data?branch=master) [![Dependency Status](https://img.shields.io/david/form-data/form-data.svg)](https://david-dm.org/form-data/form-data) -[![bitHound Overall Score](https://www.bithound.io/github/form-data/form-data/badges/score.svg)](https://www.bithound.io/github/form-data/form-data) ## Install @@ -185,6 +184,107 @@ form.submit({ }); ``` +### Methods + +- [_Void_ append( **String** _field_, **Mixed** _value_ [, **Mixed** _options_] )](https://github.com/form-data/form-data#void-append-string-field-mixed-value--mixed-options-). +- [_Headers_ getHeaders( [**Headers** _userHeaders_] )](https://github.com/form-data/form-data#array-getheaders-array-userheaders-) +- [_String_ getBoundary()](https://github.com/form-data/form-data#string-getboundary) +- [_Void_ setBoundary()](https://github.com/form-data/form-data#void-setboundary) +- [_Buffer_ getBuffer()](https://github.com/form-data/form-data#buffer-getbuffer) +- [_Integer_ getLengthSync()](https://github.com/form-data/form-data#integer-getlengthsync) +- [_Integer_ getLength( **function** _callback_ )](https://github.com/form-data/form-data#integer-getlength-function-callback-) +- [_Boolean_ hasKnownLength()](https://github.com/form-data/form-data#boolean-hasknownlength) +- [_Request_ submit( _params_, **function** _callback_ )](https://github.com/form-data/form-data#request-submit-params-function-callback-) +- [_String_ toString()](https://github.com/form-data/form-data#string-tostring) + +#### _Void_ append( **String** _field_, **Mixed** _value_ [, **Mixed** _options_] ) +Append data to the form. You can submit about any format (string, integer, boolean, buffer, etc.). However, Arrays are not supported and need to be turned into strings by the user. +```javascript +var form = new FormData(); +form.append( 'my_string', 'my value' ); +form.append( 'my_integer', 1 ); +form.append( 'my_boolean', true ); +form.append( 'my_buffer', new Buffer(10) ); +form.append( 'my_array_as_json', JSON.stringify( ['bird','cute'] ) ) +``` + +You may provide a string for options, or an object. +```javascript +// Set filename by providing a string for options +form.append( 'my_file', fs.createReadStream('/foo/bar.jpg'), 'bar.jpg' ); + +// provide an object. +form.append( 'my_file', fs.createReadStream('/foo/bar.jpg'), {filename: 'bar.jpg', contentType: 'image/jpeg', knownLength: 19806} ); +``` + +#### _Headers_ getHeaders( [**Headers** _userHeaders_] ) +This method adds the correct `content-type` header to the provided array of `userHeaders`. + +#### _String_ getBoundary() +Return the boundary of the formData. By default, the boundary consists of 26 `-` followed by 24 numbers +for example: +```javascript +--------------------------515890814546601021194782 +``` + +#### _Void_ setBoundary(String _boundary_) +Set the boundary string, overriding the default behavior described above. + +_Note: The boundary must be unique and may not appear in the data._ + +#### _Buffer_ getBuffer() +Return the full formdata request package, as a Buffer. You can insert this Buffer in e.g. Axios to send multipart data. +```javascript +var form = new FormData(); +form.append( 'my_buffer', Buffer.from([0x4a,0x42,0x20,0x52,0x6f,0x63,0x6b,0x73]) ); +form.append( 'my_file', fs.readFileSync('/foo/bar.jpg') ); + +axios.post( 'https://example.com/path/to/api', + form.getBuffer(), + form.getHeaders() + ) +``` +**Note:** Because the output is of type Buffer, you can only append types that are accepted by Buffer: *string, Buffer, ArrayBuffer, Array, or Array-like Object*. A ReadStream for example will result in an error. + +#### _Integer_ getLengthSync() +Same as `getLength` but synchronous. + +_Note: getLengthSync __doesn't__ calculate streams length._ + +#### _Integer_ getLength( **function** _callback_ ) +Returns the `Content-Length` async. The callback is used to handle errors and continue once the length has been calculated +```javascript +this.getLength(function(err, length) { + if (err) { + this._error(err); + return; + } + + // add content length + request.setHeader('Content-Length', length); + + ... +}.bind(this)); +``` + +#### _Boolean_ hasKnownLength() +Checks if the length of added values is known. + +#### _Request_ submit( _params_, **function** _callback_ ) +Submit the form to a web application. +```javascript +var form = new FormData(); +form.append( 'my_string', 'Hello World' ); + +form.submit( 'http://example.com/', function(err, res) { + // res – response object (http.IncomingMessage) // + res.resume(); +} ); +``` + +#### _String_ toString() +Returns the form data as a string. Don't use this if you are sending files or buffers, use `getBuffer()` instead. + ### Integration with other libraries #### Request @@ -224,12 +324,34 @@ fetch('http://example.com', { method: 'POST', body: form }) }); ``` +#### axios + +In Node.js you can post a file using [axios](https://github.com/axios/axios): +```javascript +const form = new FormData(); +const stream = fs.createReadStream(PATH_TO_FILE); + +form.append('image', stream); + +// In Node.js environment you need to set boundary in the header field 'Content-Type' by calling method `getHeaders` +const formHeaders = form.getHeaders(); + +axios.post('http://example.com', form, { + headers: { + ...formHeaders, + }, +}) +.then(response => response) +.catch(error => error) +``` + ## Notes - ```getLengthSync()``` method DOESN'T calculate length for streams, use ```knownLength``` options as workaround. - ```getLength(cb)``` will send an error as first parameter of callback if stream length cannot be calculated (e.g. send in custom streams w/o using ```knownLength```). - ```sbumit``` will not add `content-length` if form length is unknown or not calculable. - Starting version `2.x` FormData has dropped support for `node@0.10.x`. +- Starting version `3.x` FormData has dropped support for `node@4.x`. ## License diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index eac9c92..0000000 --- a/appveyor.yml +++ /dev/null @@ -1,21 +0,0 @@ -environment: - matrix: - - nodejs_version: '4' - - nodejs_version: '6' - - nodejs_version: '8' - - nodejs_version: '9' -platform: - - x86 - - x64 -install: - - ps: Install-Product node $env:nodejs_version $env:platform - - npm -g install npm@2 - - set PATH=%APPDATA%\npm;%PATH% - - npm install -test_script: - - node --version - - npm --version - - npm run test -build: off -matrix: - fast_finish: true diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..295e9e9 --- /dev/null +++ b/index.d.ts @@ -0,0 +1,62 @@ +// Definitions by: Carlos Ballesteros Velasco +// Leon Yu +// BendingBender +// Maple Miao + +/// +import * as stream from 'stream'; +import * as http from 'http'; + +export = FormData; + +// Extracted because @types/node doesn't export interfaces. +interface ReadableOptions { + highWaterMark?: number; + encoding?: string; + objectMode?: boolean; + read?(this: stream.Readable, size: number): void; + destroy?(this: stream.Readable, error: Error | null, callback: (error: Error | null) => void): void; + autoDestroy?: boolean; +} + +interface Options extends ReadableOptions { + writable?: boolean; + readable?: boolean; + dataSize?: number; + maxDataSize?: number; + pauseStreams?: boolean; +} + +declare class FormData extends stream.Readable { + constructor(options?: Options); + append(key: string, value: any, options?: FormData.AppendOptions | string): void; + getHeaders(userHeaders?: FormData.Headers): FormData.Headers; + submit( + params: string | FormData.SubmitOptions, + callback?: (error: Error | null, response: http.IncomingMessage) => void + ): http.ClientRequest; + getBuffer(): Buffer; + setBoundary(boundary: string): void; + getBoundary(): string; + getLength(callback: (err: Error | null, length: number) => void): void; + getLengthSync(): number; + hasKnownLength(): boolean; +} + +declare namespace FormData { + interface Headers { + [key: string]: any; + } + + interface AppendOptions { + header?: string | Headers; + knownLength?: number; + filename?: string; + filepath?: string; + contentType?: string; + } + + interface SubmitOptions extends http.RequestOptions { + protocol?: 'https:' | 'http:'; + } +} diff --git a/lib/form_data.js b/lib/form_data.js index 82c7b5a..18dc819 100644 --- a/lib/form_data.js +++ b/lib/form_data.js @@ -26,7 +26,7 @@ util.inherits(FormData, CombinedStream); */ function FormData(options) { if (!(this instanceof FormData)) { - return new FormData(); + return new FormData(options); } this._overheadLength = 0; @@ -231,7 +231,7 @@ FormData.prototype._getContentDisposition = function(value, options) { filename = path.basename(options.filename || value.name || value.path); } else if (value.readable && value.hasOwnProperty('httpVersion')) { // or try http response - filename = path.basename(value.client._httpMessage.path); + filename = path.basename(value.client._httpMessage.path || ''); } if (filename) { @@ -306,6 +306,10 @@ FormData.prototype.getHeaders = function(userHeaders) { return formHeaders; }; +FormData.prototype.setBoundary = function(boundary) { + this._boundary = boundary; +}; + FormData.prototype.getBoundary = function() { if (!this._boundary) { this._generateBoundary(); @@ -314,6 +318,32 @@ FormData.prototype.getBoundary = function() { return this._boundary; }; +FormData.prototype.getBuffer = function() { + var dataBuffer = new Buffer.alloc( 0 ); + var boundary = this.getBoundary(); + + // Create the form content. Add Line breaks to the end of data. + for (var i = 0, len = this._streams.length; i < len; i++) { + if (typeof this._streams[i] !== 'function') { + + // Add content to the buffer. + if(Buffer.isBuffer(this._streams[i])) { + dataBuffer = Buffer.concat( [dataBuffer, this._streams[i]]); + }else { + dataBuffer = Buffer.concat( [dataBuffer, Buffer.from(this._streams[i])]); + } + + // Add break after content. + if (typeof this._streams[i] !== 'string' || this._streams[i].substring( 2, boundary.length + 2 ) !== boundary) { + dataBuffer = Buffer.concat( [dataBuffer, Buffer.from(FormData.LINE_BREAK)] ); + } + } + } + + // Add the footer and return the Buffer object. + return Buffer.concat( [dataBuffer, Buffer.from(this._lastBoundary())] ); +}; + FormData.prototype._generateBoundary = function() { // This generates a 50 character boundary similar to those used by Firefox. // They are optimized for boyer-moore parsing. @@ -439,8 +469,19 @@ FormData.prototype.submit = function(params, cb) { this.pipe(request); if (cb) { - request.on('error', cb); - request.on('response', cb.bind(this, null)); + var onResponse; + + var callback = function (error, responce) { + request.removeListener('error', callback); + request.removeListener('response', onResponse); + + return cb.call(this, error, responce); + }; + + onResponse = callback.bind(this, null); + + request.on('error', callback); + request.on('response', onResponse); } }.bind(this)); diff --git a/package.json b/package.json index a21f4b3..6f1ebf0 100644 --- a/package.json +++ b/package.json @@ -2,20 +2,21 @@ "author": "Felix Geisendörfer (http://debuggable.com/)", "name": "form-data", "description": "A library to create readable \"multipart/form-data\" streams. Can be used to submit forms and file uploads to other web applications.", - "version": "2.3.2", + "version": "3.0.0", "repository": { "type": "git", "url": "git://github.com/form-data/form-data.git" }, "main": "./lib/form_data", "browser": "./lib/browser", + "typings": "./index.d.ts", "scripts": { "pretest": "rimraf coverage test/tmp", "test": "istanbul cover test/run.js", "posttest": "istanbul report lcov text", "lint": "eslint lib/*.js test/*.js test/integration/*.js", "report": "istanbul report lcov text", - "ci-lint": "is-node-modern 6 && npm run lint || is-node-not-modern 6", + "ci-lint": "is-node-modern 8 && npm run lint || is-node-not-modern 8", "ci-test": "npm run test && npm run browser && npm run report", "predebug": "rimraf coverage test/tmp", "debug": "verbose=1 ./test/run.js", @@ -34,19 +35,20 @@ "check" ], "engines": { - "node": ">= 0.12" + "node": ">= 6" }, "dependencies": { "asynckit": "^0.4.0", - "combined-stream": "1.0.6", + "combined-stream": "^1.0.8", "mime-types": "^2.1.12" }, "devDependencies": { + "@types/node": "^12.0.10", "browserify": "^13.1.1", "browserify-istanbul": "^2.0.0", - "coveralls": "^2.11.14", - "cross-spawn": "^4.0.2", - "eslint": "^3.9.1", + "coveralls": "^3.0.4", + "cross-spawn": "^6.0.5", + "eslint": "^6.0.1", "fake": "^0.2.2", "far": "^0.0.7", "formidable": "^1.0.17", @@ -54,12 +56,13 @@ "is-node-modern": "^1.0.0", "istanbul": "^0.4.5", "obake": "^0.1.2", - "phantomjs-prebuilt": "^2.1.13", + "puppeteer": "^1.19.0", "pkgfiles": "^2.3.0", "pre-commit": "^1.1.3", - "request": "2.76.0", - "rimraf": "^2.5.4", - "tape": "^4.6.2" + "request": "^2.88.0", + "rimraf": "^2.7.1", + "tape": "^4.6.2", + "typescript": "^3.5.2" }, "license": "MIT" } diff --git a/test/fixture/cert.pem b/test/fixture/cert.pem index dadbd8f..910ee2f 100644 --- a/test/fixture/cert.pem +++ b/test/fixture/cert.pem @@ -1,11 +1,32 @@ -----BEGIN CERTIFICATE----- -MIIBnDCCAUYCCQCgIldFYidw0zANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJV -UzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVBhbG8gQWx0bzERMA8GA1UEChMIRm9y -bURhdGExEjAQBgNVBAMTCWxvY2FsaG9zdDAeFw0xNTA2MTMxMzA3MTBaFw00MjEw -MjgxMzA3MTBaMFUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTESMBAGA1UEBxMJ -UGFsbyBBbHRvMREwDwYDVQQKEwhGb3JtRGF0YTESMBAGA1UEAxMJbG9jYWxob3N0 -MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAOkE8JJzLQbVEo/vRVRqiwNEbiuEooJA -099h1IJLtsPJVphSDBTtE0FLB0YIzT7bG44Drm/975XEZjoQ9TmYbTMCAwEAATAN -BgkqhkiG9w0BAQUFAANBALSDmvKXb4cE622OdSRrDsnr8xUosetsAGSlGauWBKgc -DNQhP6wSQHTAJT8wiVgSPYwnhcnzkZlwzdfMHMtzFIc= +MIIFfzCCA2egAwIBAgIJALeHtgIY/UKcMA0GCSqGSIb3DQEBCwUAMFUxCzAJBgNV +BAYTAk5MMQswCQYDVQQIDAJPVjESMBAGA1UEBwwJUGFsbyBBbHRvMREwDwYDVQQK +DAhGb3JtRGF0YTESMBAGA1UEAwwJbG9jYWxob3N0MCAXDTE5MDMyMDExNTI1NVoY +DzIwNTkwMzEwMTE1MjU1WjBVMQswCQYDVQQGEwJOTDELMAkGA1UECAwCT1YxEjAQ +BgNVBAcMCVBhbG8gQWx0bzERMA8GA1UECgwIRm9ybURhdGExEjAQBgNVBAMMCWxv +Y2FsaG9zdDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALHtx1z8nZIr +kQo8UbeLxv+S38xHwYSSCHzJBAXGx6PMTFcXdvDvvFrbf772/Gq76tfWtthao+nu +0n14aWepVSucltRUpfwTXau5knoN5J9EL+FbLwfFIUGLEdjnky7UOdtFLN2SYM0B +O5/+Nk+ywtBMzXMXHb0sJ0lrNPM8AOD57sIJ/KcqjG33bCgx0GLxuLmLwNupvDNp +p3lIvghgTKIOWRKyVOGPpM25DNvI8OT+ldj0KV7y3xJPtNdMcu0bZ+fapJSb48UN +koiQb8jxRnl295MAb82piohsLeZE0HGpwT/CWwvUxqgBahDJDmYVBaK9JVEvcMiz +wt+wy+xHd9TrgyfrHmBuHKWpgQPbumfWh2OzEeyF1N9dbAbgQ7Tmo/L6zz576Q2x +7Ee5tuyX1apEEpXM5fHxMcM04kHuyz3wqUe4U//LOPmoJ4oAUpkMC/8QMluAFK4i +1yZAw1kB0B4UbLkTIqJYvI3uEzzWe4Q33kVn1AyNBOLXw79t4ZFfhEf6oU0Zjyqp +OBNs81imLtgQU4L+D1Rt6aIL8BMhpSM9dGG2ujXqwhZnqtgVuSMY8gI7N+Hjg433 +hdxbvpzl0HjnruWvoXDKOWv08sYJhtMqclRQRGDSmxdwps+f5Iocap9AN2wfDmeO +cHJohZyw+8l/L2MAp19xJGfN2wRsVrOrAgMBAAGjUDBOMB0GA1UdDgQWBBR+hImn +BxHZ03bONEdB6JPPyo0kGDAfBgNVHSMEGDAWgBR+hImnBxHZ03bONEdB6JPPyo0k +GDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQAhpfrm79WQuMbudbIz +pOjp26OO51cM4CKzH2vUXdgzjNEDHL2JwN0MiLHK0vwT5SkH1uoHRvECHIG8FHrA +t9ky7W0Xw4vza9pC5GJEcCHVFGEaPJVXA7+fg5JCjejeWV1PU1LsMLBibbikVFUN +JXTbKLL1EWbDLSX4ICJEyc3fptYB/w/lpDZqiKF2uIm2LSubo+fRg3D1mCexsXv1 +nl2g9eZkx6uhUl7yq8o5lB6Ejzr1t5npA8w0RlYpvMwagqSfblM7UgvcrEW6Cusl +ICELrCY/mfZwKvTgIRrj4Te19ARgXwkrG0KxcgDb+UCBaIca79t53AbpHVVrVPh6 +hXHOQrRMjf0taFILPJYn6RcC08zx7FCet4x5WqX4900yRZX7Lr0VLDZI8/c1gf0j +PsTA9JqARiQG8qeM5abLxSiXGPypYNkBlbf9H8WDpJgxRNK9RszogNhKdPkYzv0b +HgHrAOels9u3roR+wNVIy2PX+LFeSnfUCJjJZEeqs5ewpP9vgBxVIzszO2lZu1oq +uUEoFRPnIDA3TsYLzjw9MNMH0CeKUv+83QX7C9UuSyNdKZIgq2z/ABclgBtyFDSX +6EAL5WP55CCCiIG93A0y84rALIS7mPVBzVnxzRY96M2Ifs8GCwMi2Q5ykcVIPkyR +HVi0h+PsbIWC9+H9Ljl2vgu0cw== -----END CERTIFICATE----- diff --git a/test/fixture/key.pem b/test/fixture/key.pem index 250d668..b34edab 100644 --- a/test/fixture/key.pem +++ b/test/fixture/key.pem @@ -1,9 +1,51 @@ -----BEGIN RSA PRIVATE KEY----- -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 -----END RSA PRIVATE KEY----- diff --git a/test/integration/test-get-buffer.js b/test/integration/test-get-buffer.js new file mode 100644 index 0000000..cca6fa0 --- /dev/null +++ b/test/integration/test-get-buffer.js @@ -0,0 +1,54 @@ +var common = require('../common'); +var assert = common.assert; + +var FormData = require(common.dir.lib + '/form_data'); + +(function testTypeIsBuffer() { + var form = new FormData(); + form.append( 'String', 'Some random string' ); + var buffer = form.getBuffer(); + + assert.equal(typeof buffer === 'object' && Buffer.isBuffer(buffer), true); +})(); + +(function testBufferIsValid() { + var form = new FormData(); + + var stringName = 'String'; + var stringValue = 'This is a random string'; + var intName = 'Int'; + var intValue = 1549873167987; + var bufferName = 'Buffer'; + var bufferValue = Buffer.from([0x00,0x4a,0x45,0x46,0x46,0x52,0x45,0x59,0x255]); + + // Fill the formData object + form.append( stringName, stringValue ); + form.append( intName, intValue ); + form.append( bufferName, bufferValue ); + + // Get the resulting Buffer + var buffer = form.getBuffer(); + + // Generate expected code. + var boundary = form.getBoundary(); + var expected = Buffer.concat( [ + Buffer.from( '--' + boundary + FormData.LINE_BREAK + + 'Content-Disposition: form-data; name="' + stringName + '"' + FormData.LINE_BREAK + + FormData.LINE_BREAK + + stringValue + FormData.LINE_BREAK + + '--' + boundary + FormData.LINE_BREAK + + 'Content-Disposition: form-data; name="' + intName + '"' + FormData.LINE_BREAK + + FormData.LINE_BREAK + + intValue + FormData.LINE_BREAK + + '--' + boundary + FormData.LINE_BREAK + + 'Content-Disposition: form-data; name="' + bufferName + '"' + FormData.LINE_BREAK + + 'Content-Type: application/octet-stream' + FormData.LINE_BREAK + + FormData.LINE_BREAK), + bufferValue, + Buffer.from( FormData.LINE_BREAK + '--' + boundary + '--' + FormData.LINE_BREAK ) + ] ); + + // Test if the buffer content, equals the expected buffer. + assert.equal(buffer.length, expected.length); + assert.equal(buffer.toString('hex'), expected.toString('hex')); +})(); diff --git a/test/integration/test-set-boundary.js b/test/integration/test-set-boundary.js new file mode 100644 index 0000000..f1d8820 --- /dev/null +++ b/test/integration/test-set-boundary.js @@ -0,0 +1,23 @@ +var common = require('../common'); +var assert = common.assert; + +var FormData = require(common.dir.lib + '/form_data'); + +(function testSetBoundary() { + var userBoundary = '---something'; + var form = new FormData(); + form.setBoundary(userBoundary); + + assert.equal(form.getBoundary(), userBoundary); +})(); + +(function testUniqueBoundaryPerFormAfterSet() { + var userBoundary = '---something'; + var formA = new FormData(); + formA.setBoundary(userBoundary); + + var formB = new FormData(); + + assert.equal(formA.getBoundary(), userBoundary); + assert.notEqual(formA.getBoundary(), formB.getBoundary()); +})();