forked from nodejs/undici
-
Notifications
You must be signed in to change notification settings - Fork 0
/
abort.js
138 lines (105 loc) · 3.5 KB
/
abort.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
'use strict'
const { test } = require('tap')
const { fetch } = require('../..')
const { createServer } = require('http')
const { once } = require('events')
const { ReadableStream } = require('stream/web')
const { DOMException } = require('../../lib/fetch/constants')
const { AbortController: NPMAbortController } = require('abort-controller')
/* global AbortController */
test('parallel fetch with the same AbortController works as expected', async (t) => {
const body = {
fixes: 1389,
bug: 'Ensure request is not aborted before enqueueing bytes into stream.'
}
const server = createServer((req, res) => {
res.statusCode = 200
res.end(JSON.stringify(body))
})
t.teardown(server.close.bind(server))
const abortController = new AbortController()
async function makeRequest () {
const result = await fetch(`http://localhost:${server.address().port}`, {
signal: abortController.signal
}).then(response => response.json())
abortController.abort()
return result
}
server.listen(0)
await once(server, 'listening')
const requests = Array.from({ length: 10 }, makeRequest)
const result = await Promise.allSettled(requests)
// since the requests are running parallel, any of them could resolve first.
// therefore we cannot rely on the order of the requests sent.
const { resolved, rejected } = result.reduce((a, b) => {
if (b.status === 'rejected') {
a.rejected.push(b)
} else {
a.resolved.push(b)
}
return a
}, { resolved: [], rejected: [] })
t.equal(rejected.length, 9) // out of 10 requests, only 1 should succeed
t.equal(resolved.length, 1)
t.ok(rejected.every(rej => rej.reason?.code === DOMException.ABORT_ERR))
t.same(resolved[0].value, body)
t.end()
})
// https://github.com/web-platform-tests/wpt/blob/fd8aeb1bb2eb33bc43f8a5bbc682b0cff6075dfe/fetch/api/abort/general.any.js#L474-L507
test('Readable stream synchronously cancels with AbortError if aborted before reading', async (t) => {
const server = createServer((req, res) => {
res.write('')
res.end()
}).listen(0)
t.teardown(server.close.bind(server))
await once(server, 'listening')
const controller = new AbortController()
const signal = controller.signal
controller.abort()
let cancelReason
const body = new ReadableStream({
pull (controller) {
controller.enqueue(new Uint8Array([42]))
},
cancel (reason) {
cancelReason = reason
}
})
const fetchPromise = fetch(`http://localhost:${server.address().port}`, {
body,
signal,
method: 'POST',
headers: {
'Content-Type': 'text/plain'
}
})
t.ok(cancelReason, 'Cancel called sync')
t.equal(cancelReason.constructor, DOMException)
t.equal(cancelReason.name, 'AbortError')
await t.rejects(fetchPromise, { name: 'AbortError' })
const fetchErr = await fetchPromise.catch(e => e)
t.equal(cancelReason, fetchErr, 'Fetch rejects with same error instance')
t.end()
})
test('Allow the usage of custom implementation of AbortController', async (t) => {
const body = {
fixes: 1605
}
const server = createServer((req, res) => {
res.statusCode = 200
res.end(JSON.stringify(body))
})
t.teardown(server.close.bind(server))
server.listen(0)
await once(server, 'listening')
const controller = new NPMAbortController()
const signal = controller.signal
controller.abort()
try {
await fetch(`http://localhost:${server.address().port}`, {
signal
})
} catch (e) {
t.equal(e.code, DOMException.ABORT_ERR)
}
})