### 彪哥

爱好前端

- 初识 TypeScript

- TypeScript 常用语法

- ts-axios 项目初始化

- ts-axios 基础功能实现

- ts-axios 异常情况处理

- ts-axios 接口扩展

- ts-axios 拦截器实现

- ts-axios 配置化实现

- ts-axios 取消功能实现

- ts-axios 更多功能实现

- ts-axios 单元测试

  - 前言
  - Jest 安装和配置
  - 辅助模块单元测试
  - 请求模块单元测试
  - headers 模块单元测试
  - Axios 实例模块单元测试
  - 拦截器模块单元测试
  - mergeConfig 模块单元测试
  - 请求取消模块单元测试
    - Cancel 类单元测试
    - CancelToken 类单元测试
    - Cancel 业务逻辑单元测试
  - 剩余模块单元测试

- ts-axios 部署与发布

- 《TypeScript 从零实现 axios》
- ts-axios 单元测试

HuangYi
2020-01-05
目录

# 请求取消模块单元测试

# # 请求取消模块单元测试

请求取消模块是 `ts-axios` 库核心流程其中一个分支，也是非常重要的模块，我们将从基础库和业务流程模块 2 个方面去编写单元测试。

## # Cancel 类单元测试

`cancel/Cancel.spec.ts`：

    import Cancel, { isCancel } from '../../src/cancel/Cancel'

    describe('cancel:Cancel', () => {
      test('should returns correct result when message is specified', () => {
        const cancel = new Cancel('Operation has been canceled.')
        expect(cancel.message).toBe('Operation has been canceled.')
      })

      test('should returns true if value is a Cancel', () => {
        expect(isCancel(new Cancel())).toBeTruthy()
      })

      test('should returns false if value is not a Cancel', () => {
        expect(isCancel({ foo: 'bar' })).toBeFalsy()
      })
    })

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

## # CancelToken 类单元测试

`cancel/CancelToken.spec.ts`：

    import CancelToken from '../../src/cancel/CancelToken'
    import Cancel from '../../src/cancel/Cancel'
    import { Canceler } from '../../src/types'

    describe('CancelToken', () => {
      describe('reason', () => {
        test('should returns a Cancel if cancellation has been requested', () => {
          let cancel: Canceler
          let token = new CancelToken(c => {
            cancel = c
          })
          cancel!('Operation has been canceled.')
          expect(token.reason).toEqual(expect.any(Cancel))
          expect(token.reason!.message).toBe('Operation has been canceled.')
        })

        test('should has no side effect if call cancellation for multi times', () => {
          let cancel: Canceler
          let token = new CancelToken(c => {
            cancel = c
          })
          cancel!('Operation has been canceled.')
          cancel!('Operation has been canceled.')
          expect(token.reason).toEqual(expect.any(Cancel))
          expect(token.reason!.message).toBe('Operation has been canceled.')
        })

        test('should returns undefined if cancellation has not been requested', () => {
          const token = new CancelToken(() => {
            // do nothing
          })
          expect(token.reason).toBeUndefined()
        })
      })

      describe('promise', () => {
        test('should returns a Promise that resolves when cancellation is requested', done => {
          let cancel: Canceler
          const token = new CancelToken(c => {
            cancel = c
          })
          token.promise.then(value => {
            expect(value).toEqual(expect.any(Cancel))
            expect(value.message).toBe('Operation has been canceled.')
            done()
          })
          cancel!('Operation has been canceled.')
        })
      })

      describe('throwIfRequested', () => {
        test('should throws if cancellation has been requested', () => {
          let cancel: Canceler
          const token = new CancelToken(c => {
            cancel = c
          })
          cancel!('Operation has been canceled.')
          try {
            token.throwIfRequested()
            fail('Expected throwIfRequested to throw.')
          } catch (thrown) {
            if (!(thrown instanceof Cancel)) {
              fail('Expected throwIfRequested to throw a Cancel, but test threw ' + thrown + '.')
            }
            expect(thrown.message).toBe('Operation has been canceled.')
          }
        })

        test('should does not throw if cancellation has not been requested', () => {
          const token = new CancelToken(() => {
            // do nothing
          })
          token.throwIfRequested()
        })
      })

      describe('source', () => {
        test('should returns an object containing token and cancel function', () => {
          const source = CancelToken.source()
          expect(source.token).toEqual(expect.any(CancelToken))
          expect(source.cancel).toEqual(expect.any(Function))
          expect(source.token.reason).toBeUndefined()
          source.cancel('Operation has been canceled.')
          expect(source.token.reason).toEqual(expect.any(Cancel))
          expect(source.token.reason!.message).toBe('Operation has been canceled.')
        })
      })
    })

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

注意，这里我们使用了 `fail` 函数表示一个测试的失败，这个并未在 Jest 文档中体现，但它是一个可以用的 API。

## # Cancel 业务逻辑单元测试

`cancel.spec.ts`：

    import axios from '../src/index'
    import { getAjaxRequest } from './helper'

    describe('cancel', () => {
      const CancelToken = axios.CancelToken
      const Cancel = axios.Cancel

      beforeEach(() => {
        jasmine.Ajax.install()
      })

      afterEach(() => {
        jasmine.Ajax.uninstall()
      })

      describe('when called before sending request', () => {
        test('should rejects Promise with a Cancel object', () => {
          const source = CancelToken.source()
          source.cancel('Operation has been canceled.')

          return axios
            .get('/foo', {
              cancelToken: source.token
            })
            .catch(reason => {
              expect(reason).toEqual(expect.any(Cancel))
              expect(reason.message).toBe('Operation has been canceled.')
            })
        })
      })

      describe('when called after request has been sent', () => {
        test('should rejects Promise with a Cancel object', done => {
          const source = CancelToken.source()
          axios
            .get('/foo/bar', {
              cancelToken: source.token
            })
            .catch(reason => {
              expect(reason).toEqual(expect.any(Cancel))
              expect(reason.message).toBe('Operation has been canceled.')
              done()
            })

          getAjaxRequest().then(request => {
            source.cancel('Operation has been canceled.')
            setTimeout(() => {
              request.respondWith({
                status: 200,
                responseText: 'OK'
              })
            }, 100)
          })
        })

        test('calls abort on request object', done => {
          const source = CancelToken.source()
          let request: any
          axios
            .get('/foo/bar', {
              cancelToken: source.token
            })
            .catch(() => {
              expect(request.statusText).toBe('abort')
              done()
            })

          getAjaxRequest().then(req => {
            source.cancel()
            request = req
          })
        })
      })

      describe('when called after response has been received', () => {
        test('should not cause unhandled rejection', done => {
          const source = CancelToken.source()
          axios
            .get('/foo', {
              cancelToken: source.token
            })
            .then(() => {
              window.addEventListener('unhandledrejection', () => {
                done.fail('Unhandled rejection.')
              })
              source.cancel()
              setTimeout(done, 100)
            })

          getAjaxRequest().then(request => {
            request.respondWith({
              status: 200,
              responseText: 'OK'
            })
          })
        })
      })
    })

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

注意这里我们使用了 `done.fail` 表示了一个异常的结束，这个并未在 Jest 文档中体现，但它是一个可以用的 API。

至此，我们完成了取消模块相关业务逻辑的单元测试，我们测试覆盖率达到了阈值，测试已经通过了。但是扔未达到我们的目标，还有很多 feature 是没有覆盖到的。接下来我们就完成剩余 feature 的编写单元测试。

编辑
(opens new window)
#TypeScript
上次更新: 2022/12/14, 19:36:42
mergeConfig 模块单元测试
剩余模块单元测试

← mergeConfig 模块单元测试 剩余模块单元测试→

最近更新

  01
Git修改分支名
08-11

  02
CSS给table的tbody添加滚动条
06-29

  03
我做了一个手写春联小网页，祝大家虎年暴富 原创
01-28

更多文章>

Copyright © 2016-2022 Hesb | MIT License

- 跟随系统
- 浅色模式
- 深色模式
- 阅读模式