Skip to content

Commit

Permalink
fix: add isErrorLike (nodejs#1570)
Browse files Browse the repository at this point in the history
  • Loading branch information
KhafraDev authored and crysmags committed Feb 27, 2024
1 parent 21480c0 commit be0119d
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 11 deletions.
7 changes: 4 additions & 3 deletions lib/fetch/index.js
Expand Up @@ -33,7 +33,8 @@ const {
isBlobLike,
sameOrigin,
isCancelled,
isAborted
isAborted,
isErrorLike
} = require('./util')
const { kState, kHeaders, kGuard, kRealm } = require('./symbols')
const assert = require('assert')
Expand Down Expand Up @@ -1854,7 +1855,7 @@ async function httpNetworkFetch (
timingInfo.decodedBodySize += bytes?.byteLength ?? 0

// 6. If bytes is failure, then terminate fetchParams’s controller.
if (bytes instanceof Error) {
if (isErrorLike(bytes)) {
fetchParams.controller.terminate(bytes)
return
}
Expand Down Expand Up @@ -1894,7 +1895,7 @@ async function httpNetworkFetch (
// 3. Otherwise, if stream is readable, error stream with a TypeError.
if (isReadable(stream)) {
fetchParams.controller.controller.error(new TypeError('terminated', {
cause: reason instanceof Error ? reason : undefined
cause: isErrorLike(reason) ? reason : undefined
}))
}
}
Expand Down
15 changes: 8 additions & 7 deletions lib/fetch/response.js
Expand Up @@ -10,7 +10,8 @@ const {
isCancelled,
isAborted,
isBlobLike,
serializeJavascriptValueToJSONString
serializeJavascriptValueToJSONString,
isErrorLike
} = require('./util')
const {
redirectStatus,
Expand Down Expand Up @@ -347,15 +348,15 @@ function makeResponse (init) {
}

function makeNetworkError (reason) {
const isError = isErrorLike(reason)
return makeResponse({
type: 'error',
status: 0,
error:
reason instanceof Error
? reason
: new Error(reason ? String(reason) : reason, {
cause: reason instanceof Error ? reason : undefined
}),
error: isError
? reason
: new Error(reason ? String(reason) : reason, {
cause: isError ? reason : undefined
}),
aborted: reason && reason.name === 'AbortError'
})
}
Expand Down
10 changes: 9 additions & 1 deletion lib/fetch/util.js
Expand Up @@ -82,6 +82,13 @@ function isFileLike (object) {
)
}

function isErrorLike (object) {
return object instanceof Error || (
object?.constructor?.name === 'Error' ||
object?.constructor?.name === 'DOMException'
)
}

// Check whether |statusText| is a ByteString and
// matches the Reason-Phrase token production.
// RFC 2616: https://tools.ietf.org/html/rfc2616
Expand Down Expand Up @@ -469,5 +476,6 @@ module.exports = {
makeIterator,
isValidHeaderName,
isValidHeaderValue,
hasOwn
hasOwn,
isErrorLike
}
44 changes: 44 additions & 0 deletions test/jest/instanceof-error.test.js
@@ -0,0 +1,44 @@
'use strict'

const { createServer } = require('http')
const { once } = require('events')

/* global expect, it, jest, AbortController */

// https://github.com/facebook/jest/issues/11607#issuecomment-899068995
jest.useRealTimers()

const runIf = (condition) => condition ? it : it.skip
const nodeMajor = Number(process.versions.node.split('.', 1)[0])

runIf(nodeMajor >= 16)('isErrorLike sanity check', () => {
const { isErrorLike } = require('../../lib/fetch/util')
const { DOMException } = require('../../lib/fetch/constants')
const error = new DOMException('')

// https://github.com/facebook/jest/issues/2549
expect(error instanceof Error).toBeFalsy()
expect(isErrorLike(error)).toBeTruthy()
})

runIf(nodeMajor >= 16)('Real use-case', async () => {
const { fetch } = require('../..')

const ac = new AbortController()
ac.abort()

const server = createServer((req, res) => {
res.end()
}).listen(0)

await once(server, 'listening')

const promise = fetch(`https://localhost:${server.address().port}`, {
signal: ac.signal
})

await expect(promise).rejects.toThrowError('The operation was aborted.')

server.close()
await once(server, 'close')
})

0 comments on commit be0119d

Please sign in to comment.