-
Notifications
You must be signed in to change notification settings - Fork 39
/
Copy pathrequest.ts
108 lines (96 loc) · 2.8 KB
/
request.ts
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
export interface RequestMethod {
(url: string, opts?: RequestInit): Promise<Response>
}
export let request: RequestMethod
export function setRequestMethod(method: RequestMethod): void {
request = method
}
export interface RequestWaiter {
(status: number, body?: string, contentType?: string): Promise<void>
aborted?: true
}
export interface RequestMock {
andRespond(status: number, body?: string, contentType?: string): void
andWait(): RequestWaiter
}
interface RequestExpect {
contentType: string
response: string
status: number
url: string
wait: Promise<void>
waiter: RequestWaiter | undefined
}
let requestExpects: RequestExpect[] = []
let fetchMock: RequestMethod = async (url, opts = {}) => {
let expect = requestExpects.shift()
if (!expect) {
throw new Error(`Unexpected request ${url} ${JSON.stringify(opts)}`)
} else if (expect.url !== url) {
throw new Error(`Expected request ${expect.url} instead of ${url}`)
} else {
let throwError: (e: Error) => void
let waitForError = new Promise((resolve, reject) => {
throwError = reject
})
function abortCallback(): void {
if (expect?.waiter) expect.waiter.aborted = true
throwError(new DOMException('', 'AbortError'))
}
opts.signal?.addEventListener('abort', abortCallback)
await Promise.race([expect.wait, waitForError])
opts.signal?.removeEventListener('abort', abortCallback)
let response = new Response(expect.response, {
headers: { 'Content-Type': expect.contentType },
status: expect.status
})
Object.defineProperty(response, 'url', { value: url })
return response
}
}
export function mockRequest(): void {
requestExpects = []
setRequestMethod(fetchMock)
}
export function expectRequest(url: string): RequestMock {
let expect: RequestExpect = {
contentType: 'text/html',
response: '',
status: 200,
url,
wait: Promise.resolve(),
waiter: undefined
}
requestExpects.push(expect)
return {
andRespond(status, body = '', contentType = 'text/html') {
expect.contentType = contentType
expect.status = status
expect.response = body
},
andWait() {
let resolveWait: Function
expect.wait = new Promise(resolve => {
resolveWait = resolve
})
expect.waiter = (status, body = '', contentType = 'text/html') => {
expect.contentType = contentType
expect.status = status
expect.response = body
resolveWait()
return new Promise(resolve => {
setTimeout(resolve, 10)
})
}
return expect.waiter
}
}
}
export function checkAndRemoveRequestMock(): void {
if (requestExpects.length > 0) {
throw new Error(
'Test didn’t send requests: ' + requestExpects.map(i => i.url).join(', ')
)
}
setRequestMethod(fetch)
}