-
Notifications
You must be signed in to change notification settings - Fork 6
/
index.js
106 lines (94 loc) · 2.97 KB
/
index.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
/**
* @typedef {import('net').AddressInfo} AddressInfo
* @typedef {import('http').IncomingMessage} IncomingMessage
* @typedef {import('http').ServerResponse} ServerResponse
* @typedef {import('axios').AxiosAdapter} AxiosAdapter
* @typedef {import('axios').AxiosInstance} AxiosInstance
* @typedef {import('axios').AxiosStatic} AxiosStatic
*/
const { Server, createServer } = require('http')
const { URL } = require('url')
const axios = /** @type {AxiosStatic} */(/** @type {unknown} */(require('axios')))
const defaultAdapter = /** @type {AxiosAdapter} */(axios.getAdapter(axios.defaults.adapter))
/**
* @callback RequestListener
* @param {IncomingMessage} request
* @param {ServerResponse} response
*/
/** @typedef {RequestListener | Server} Handler */
/**
* @param {string} urlString the url to tell.
* @returns {boolean} whether the url is absolute url.
*/
const isAbsoluteUrl = (urlString) => {
const url = new URL(urlString, 'http://axiosist/')
return url.host !== 'axiosist'
}
/**
* @param {Handler} handler A handler for axiosist, may be a request listener or a http server.
* @returns {AxiosAdapter} The axios adapter would used in adapter options of axios.
*/
const createAdapter = handler => config => new Promise((resolve, reject) => {
const urlField = isAbsoluteUrl(config.url || '') ? 'url' : 'baseURL'
const url = new URL(config[urlField] || '', 'http://axiosist/')
// Forcely set protocol to HTTP
url.protocol = 'http'
// Apply original host to request header
/** @type {any} */
const headers = config.headers
if (url.host !== 'axiosist' && headers.host == null) {
headers.host = url.host
}
const server = handler instanceof Server ? handler : createServer(handler)
const listening = server.listening
;/** @type {Promise<void>} */ (
new Promise(resolve => {
if (listening) {
resolve()
} else {
server.listen(0, '127.0.0.1', resolve)
}
})
).then(
() => {
const address = /** @type {AddressInfo} */(server.address())
url.host = '127.0.0.1'
url.port = address.port.toString()
config[urlField] = url.toString()
return defaultAdapter(config)
}
).then(
(response) => {
if (listening) {
return response
} else {
return new Promise(resolve => {
server.close(() => resolve(response))
})
}
},
(error) => {
if (listening) {
throw error
} else {
return new Promise((resolve, reject) => {
server.close(() => reject(error))
})
}
}
).then(resolve, reject)
})
/**
* @param {Handler} handler A handler, may be a request listener or a http server.
* @returns {AxiosInstance} The axios instance would use for test.
*/
const axiosist = handler => {
return axios.create({
adapter: createAdapter(handler),
validateStatus: () => true,
maxRedirects: 0
})
}
module.exports = axiosist
module.exports.default = axiosist
module.exports.createAdapter = createAdapter