Skip to content

Commit

Permalink
perf(util): improve isFormDataLike checks (#1875)
Browse files Browse the repository at this point in the history
  • Loading branch information
mateonunez authored Jan 21, 2023
1 parent 1813408 commit d7602f6
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 1 deletion.
17 changes: 16 additions & 1 deletion lib/core/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -354,8 +354,23 @@ function ReadableStreamFrom (iterable) {
)
}

// The chunk should be a FormData instance and contains
// all the required methods.
function isFormDataLike (chunk) {
return chunk && chunk.constructor && chunk.constructor.name === 'FormData'
return (chunk &&
chunk.constructor && chunk.constructor.name === 'FormData' &&
typeof chunk === 'object' &&
(typeof chunk.append === 'function' &&
typeof chunk.delete === 'function' &&
typeof chunk.get === 'function' &&
typeof chunk.getAll === 'function' &&
typeof chunk.has === 'function' &&
typeof chunk.set === 'function' &&
typeof chunk.entries === 'function' &&
typeof chunk.keys === 'function' &&
typeof chunk.values === 'function' &&
typeof chunk.forEach === 'function')
)
}

const kEnumerableProperty = Object.create(null)
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
"cronometro": "^1.0.5",
"delay": "^5.0.0",
"docsify-cli": "^4.4.3",
"form-data": "^4.0.0",
"formdata-node": "^4.3.1",
"https-pem": "^3.0.0",
"husky": "^8.0.1",
Expand Down
80 changes: 80 additions & 0 deletions test/fetch/formdata.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ const { test } = require('tap')
const { FormData, File, Response } = require('../../')
const { Blob: ThirdPartyBlob } = require('formdata-node')
const { Blob } = require('buffer')
const { isFormDataLike } = require('../../lib/core/util')
const ThirdPartyFormDataInvalid = require('form-data')

test('arg validation', (t) => {
const form = new FormData()
Expand Down Expand Up @@ -285,6 +287,84 @@ test('formData.constructor.name', (t) => {
t.end()
})

test('formData should be an instance of FormData', (t) => {
t.plan(3)

t.test('Invalid class FormData', (t) => {
class FormData {
constructor () {
this.data = []
}

append (key, value) {
this.data.push([key, value])
}

get (key) {
return this.data.find(([k]) => k === key)
}
}

const form = new FormData()
t.equal(isFormDataLike(form), false)
t.end()
})

t.test('Invalid function FormData', (t) => {
function FormData () {
const data = []
return {
append (key, value) {
data.push([key, value])
},
get (key) {
return data.find(([k]) => k === key)
}
}
}

const form = new FormData()
t.equal(isFormDataLike(form), false)
t.end()
})

test('Invalid third-party FormData', (t) => {
const form = new ThirdPartyFormDataInvalid()
t.equal(isFormDataLike(form), false)
t.end()
})

t.test('Valid FormData', (t) => {
const form = new FormData()
t.equal(isFormDataLike(form), true)
t.end()
})
})

test('FormData should be compatible with third-party libraries', (t) => {
t.plan(1)

class FormData {
constructor () {
this.data = []
}

append () {}
delete () {}
get () {}
getAll () {}
has () {}
set () {}
entries () {}
keys () {}
values () {}
forEach () {}
}

const form = new FormData()
t.equal(isFormDataLike(form), true)
})

test('arguments', (t) => {
t.equal(FormData.constructor.length, 1)
t.equal(FormData.prototype.append.length, 2)
Expand Down

0 comments on commit d7602f6

Please sign in to comment.