拦截器是 ts-axios 库一个非常实用的功能,接下来我们来编写它的测试代码。

测试代码编写

test/interceptor.spec.ts

  1. import axios, { AxiosRequestConfig, AxiosResponse } from '../src/index'
  2. import { getAjaxRequest } from './helper'
  3. describe('interceptors', () => {
  4. beforeEach(() => {
  5. jasmine.Ajax.install()
  6. })
  7. afterEach(() => {
  8. jasmine.Ajax.uninstall()
  9. })
  10. test('should add a request interceptor', () => {
  11. const instance = axios.create()
  12. instance.interceptors.request.use((config: AxiosRequestConfig) => {
  13. config.headers.test = 'added by interceptor'
  14. return config
  15. })
  16. instance('/foo')
  17. return getAjaxRequest().then(request => {
  18. expect(request.requestHeaders.test).toBe('added by interceptor')
  19. })
  20. })
  21. test('should add a request interceptor that returns a new config object', () => {
  22. const instance = axios.create()
  23. instance.interceptors.request.use(() => {
  24. return {
  25. url: '/bar',
  26. method: 'post'
  27. }
  28. })
  29. instance('/foo')
  30. return getAjaxRequest().then(request => {
  31. expect(request.method).toBe('POST')
  32. expect(request.url).toBe('/bar')
  33. })
  34. })
  35. test('should add a request interceptor that returns a promise', done => {
  36. const instance = axios.create()
  37. instance.interceptors.request.use((config: AxiosRequestConfig) => {
  38. return new Promise(resolve => {
  39. setTimeout(() => {
  40. config.headers.async = 'promise'
  41. resolve(config)
  42. }, 10)
  43. })
  44. })
  45. instance('/foo')
  46. setTimeout(() => {
  47. getAjaxRequest().then(request => {
  48. expect(request.requestHeaders.async).toBe('promise')
  49. done()
  50. })
  51. }, 100)
  52. })
  53. test('should add multiple request interceptors', () => {
  54. const instance = axios.create()
  55. instance.interceptors.request.use(config => {
  56. config.headers.test1 = '1'
  57. return config
  58. })
  59. instance.interceptors.request.use(config => {
  60. config.headers.test2 = '2'
  61. return config
  62. })
  63. instance.interceptors.request.use(config => {
  64. config.headers.test3 = '3'
  65. return config
  66. })
  67. instance('/foo')
  68. return getAjaxRequest().then(request => {
  69. expect(request.requestHeaders.test1).toBe('1')
  70. expect(request.requestHeaders.test2).toBe('2')
  71. expect(request.requestHeaders.test3).toBe('3')
  72. })
  73. })
  74. test('should add a response interceptor', done => {
  75. let response: AxiosResponse
  76. const instance = axios.create()
  77. instance.interceptors.response.use(data => {
  78. data.data = data.data + ' - modified by interceptor'
  79. return data
  80. })
  81. instance('/foo').then(data => {
  82. response = data
  83. })
  84. getAjaxRequest().then(request => {
  85. request.respondWith({
  86. status: 200,
  87. responseText: 'OK'
  88. })
  89. setTimeout(() => {
  90. expect(response.data).toBe('OK - modified by interceptor')
  91. done()
  92. }, 100)
  93. })
  94. })
  95. test('should add a response interceptor that returns a new data object', done => {
  96. let response: AxiosResponse
  97. const instance = axios.create()
  98. instance.interceptors.response.use(() => {
  99. return {
  100. data: 'stuff',
  101. headers: null,
  102. status: 500,
  103. statusText: 'ERR',
  104. request: null,
  105. config: {}
  106. }
  107. })
  108. instance('/foo').then(res => {
  109. response = res
  110. })
  111. getAjaxRequest().then(request => {
  112. request.respondWith({
  113. status: 200,
  114. responseText: 'OK'
  115. })
  116. setTimeout(() => {
  117. expect(response.data).toBe('stuff')
  118. expect(response.headers).toBeNull()
  119. expect(response.status).toBe(500)
  120. expect(response.statusText).toBe('ERR')
  121. expect(response.request).toBeNull()
  122. expect(response.config).toEqual({})
  123. done()
  124. }, 100)
  125. })
  126. })
  127. test('should add a response interceptor that returns a promise', done => {
  128. let response: AxiosResponse
  129. const instance = axios.create()
  130. instance.interceptors.response.use(data => {
  131. return new Promise(resolve => {
  132. // do something async
  133. setTimeout(() => {
  134. data.data = 'you have been promised!'
  135. resolve(data)
  136. }, 10)
  137. })
  138. })
  139. instance('/foo').then(res => {
  140. response = res
  141. })
  142. getAjaxRequest().then(request => {
  143. request.respondWith({
  144. status: 200,
  145. responseText: 'OK'
  146. })
  147. setTimeout(() => {
  148. expect(response.data).toBe('you have been promised!')
  149. done()
  150. }, 100)
  151. })
  152. })
  153. test('should add multiple response interceptors', done => {
  154. let response: AxiosResponse
  155. const instance = axios.create()
  156. instance.interceptors.response.use(data => {
  157. data.data = data.data + '1'
  158. return data
  159. })
  160. instance.interceptors.response.use(data => {
  161. data.data = data.data + '2'
  162. return data
  163. })
  164. instance.interceptors.response.use(data => {
  165. data.data = data.data + '3'
  166. return data
  167. })
  168. instance('/foo').then(data => {
  169. response = data
  170. })
  171. getAjaxRequest().then(request => {
  172. request.respondWith({
  173. status: 200,
  174. responseText: 'OK'
  175. })
  176. setTimeout(() => {
  177. expect(response.data).toBe('OK123')
  178. done()
  179. }, 100)
  180. })
  181. })
  182. test('should allow removing interceptors', done => {
  183. let response: AxiosResponse
  184. let intercept
  185. const instance = axios.create()
  186. instance.interceptors.response.use(data => {
  187. data.data = data.data + '1'
  188. return data
  189. })
  190. intercept = instance.interceptors.response.use(data => {
  191. data.data = data.data + '2'
  192. return data
  193. })
  194. instance.interceptors.response.use(data => {
  195. data.data = data.data + '3'
  196. return data
  197. })
  198. instance.interceptors.response.eject(intercept)
  199. instance.interceptors.response.eject(5)
  200. instance('/foo').then(data => {
  201. response = data
  202. })
  203. getAjaxRequest().then(request => {
  204. request.respondWith({
  205. status: 200,
  206. responseText: 'OK'
  207. })
  208. setTimeout(() => {
  209. expect(response.data).toBe('OK13')
  210. done()
  211. }, 100)
  212. })
  213. })
  214. })

运行测试后我们发现在测试用例 should add a request interceptor that returns a new config object 报错了,是代码运行的报错,而不是测试期望结果的报错,顺着报错信息,我们可以找到报错原因。
core/xhr.ts 中,执行到 processHeaders 中的 Object.keys(headers).forEach 代码报错,因为我们在拦截器对请求配置做了修改,导致 headers 为空,所以报错。
于是我们在解构赋值 headers 的时候,给它添加默认值即可。

  1. const {
  2. // ...
  3. headers = {}
  4. } = config

再次运行测试,发现全部测试通过。
至此,我们完成了 ts-axios 库对拦截器模块的单元测试,下节课我们来测试 mergeConfig 模块的业务逻辑。