-
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathmod.ts
142 lines (135 loc) · 4.04 KB
/
mod.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
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
139
140
141
142
import { assertEquals, assertMatch, parseMediaType } from './deps.ts'
import type {
FetchFunction,
HandlerOrListener,
MakeFetchResponse,
} from './types.ts'
const fetchEndpoint = async (
port: number,
url: string | URL,
params?: RequestInit,
) => {
const res = await fetch(`http://localhost:${port}${url}`, params)
let data: unknown
const ct = res.headers.get('Content-Type')
if (ct === null) return { data: await res.text(), res }
const [mediaType] = parseMediaType(ct)
if (mediaType === 'application/json') data = await res.json()
else if (mediaType.includes('text')) data = await res.text()
else data = await res.arrayBuffer()
return { res, data }
}
const makeFetchPromise = (handlerOrListener: HandlerOrListener) => {
if ('addr' in handlerOrListener) {
const port = handlerOrListener.addr.port
const resp = (url: URL | string = '', params?: RequestInit) => {
return new Promise<{ res: Response; data?: unknown }>((resolve) => {
setTimeout(async () => {
const { res, data } = await fetchEndpoint(port, url, params)
resolve({ res, data })
return handlerOrListener.shutdown()
})
})
}
return { resp, port }
} else {
const server = Deno.serve({ port: 0 }, handlerOrListener)
const resp = async (url: URL | string = '', params?: RequestInit) => {
const res = await fetchEndpoint(server.addr.port, url, params)
await server.shutdown()
return res
}
return { resp, port: server.addr.port }
}
}
export const makeFetch = (h: HandlerOrListener): FetchFunction => {
const { resp, port } = makeFetchPromise(h)
async function fetch(url: string | URL, options?: RequestInit) {
const { res, data } = await resp(url, options)
const expectStatus = (a: number, b?: string) => {
assertEquals(
res.status,
a,
`expected to have status code ${a} but was ${res.status}`,
)
if (typeof b !== 'undefined') {
assertEquals(res.statusText, b)
}
return {
expect: expectAll,
expectStatus,
expectHeader,
expectBody,
}
}
const expectHeader = (a: string, b: string | RegExp | null | string[]) => {
const header = res.headers.get(a)
if (b instanceof RegExp) {
if (header === null) {
throw new Error(`expected header ${header} to not be empty`)
}
assertMatch(
header,
b,
`expected header ${a} to match regexp ${b}, got ${header}`,
)
} else if (Array.isArray(b)) {
if (header === null) {
throw new Error(`expected header ${header} to not be empty`)
}
assertEquals(
header,
b.join(','),
`expected header ${a} to match ${b.join(', ')}, got ${header}`,
)
} else {
assertEquals(
header,
b,
`expected to have header ${a} ${
header === null ? 'empty' : `with value ${b}, got ${header}`
}`,
)
}
return {
expect: expectAll,
expectStatus,
expectHeader,
expectBody,
}
}
const expectBody = (a: unknown) => {
if (a instanceof RegExp) {
assertMatch(
data as string,
a,
`Expected body to match regexp ${a}, got ${data}`,
)
} else assertEquals(data, a, `Expected to have body ${a}, got ${data}`)
}
// deno-lint-ignore no-explicit-any
const expectAll = (a: unknown, b?: any) => {
if (typeof a === 'number') {
expectStatus(a, b)
} else if (typeof a === 'string' && typeof b !== 'undefined') {
expectHeader(a, b)
} else {
expectBody(a)
}
return {
expect: expectAll,
expectStatus,
expectHeader,
expectBody,
}
}
const result = res as MakeFetchResponse
result.port = port
result.expectBody = expectBody
result.expect = expectAll
result.expectHeader = expectHeader
result.expectStatus = expectStatus
return result
}
return fetch
}