Completed
Push — dev ( 249398...dac991 )
by Fike
39s
created

test/suites/integration/Execution/Executor.spec.js   F

Complexity

Total Complexity 89
Complexity/F 2.17

Size

Lines of Code 237
Function Count 41

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 0
wmc 89
nc 1
mnd 1
bc 46
fnc 41
dl 0
loc 237
rs 3.12
bpm 1.1218
cpm 2.1707
noi 2
c 1
b 0
f 0

2 Functions

Rating   Name   Duplication   Size   Complexity  
B Executor.spec.js ➔ describe(ꞌUnitꞌ) 0 222 1
A Executor.spec.js ➔ branchStopper 0 3 1

How to fix   Complexity   

Complexity

Complex classes like test/suites/integration/Execution/Executor.spec.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/* eslint-env mocha */
2
/* eslint-disable no-unused-expressions */
3
4
var Sinon = require('sinon')
5
var Chai = require('chai')
6
var expect = Chai.expect
7
8
Chai.use(require('chai-as-promised'))
9
10
var Executor = require('../../../../lib/Execution/Executor').Executor
11
var SDK = require('@ama-team/voxengine-sdk')
12
var CancellationToken = SDK.Concurrent.CancellationToken
13
var TimeoutException = SDK.Concurrent.TimeoutException
14
15
var branchStopper = function () {
16
  throw new Error('This logical path should not have been taken')
17
}
18
19
describe('Unit', function () {
20
  describe('/Execution', function () {
21
    describe('/Executor.js', function () {
22
      describe('.Executor', function () {
23
        var factory = function (ctx) {
24
          return new Executor(ctx)
25
        }
26
27
        var callable
28
        var context
29
        var executor
30
31
        var autoFactory = function () {
32
          executor = factory(context)
33
          return executor
34
        }
35
36
        beforeEach(function () {
37
          callable = Sinon.stub()
38
          context = {}
39
          autoFactory()
40
        })
41
42
        describe('#execute()', function () {
43
          it('passes context and arguments', function () {
44
            var ctx = {x: 12}
45
            var args = [1, 2, 3]
46
            var result = ['uno', 'duo', 'tres']
47
            callable.returns(result)
48
            expect(factory(ctx).execute(callable, args)).to.eq(result)
49
            expect(callable.callCount).to.eq(1)
50
            expect(callable.getCall(0).thisValue).to.eq(ctx)
51
            for (var i = 0; i < args.length; i++) {
52
              expect(callable.getCall(0).args[i]).to.eq(args[i])
53
            }
54
          })
55
56
          it('doesn\'t catch errors', function () {
57
            var error = new Error()
58
            callable.throws(error)
59
            var lambda = function () {
60
              return factory().execute(callable)
61
            }
62
            expect(lambda).to.throw(error)
63
          })
64
        })
65
66
        describe('#promise()', function () {
67
          it('passes context and arguments', function () {
68
            var ctx = {x: 12}
69
            var args = [1, 2, 3]
70
            var result = ['uno', 'duo', 'tres']
71
            callable.returns(result)
72
            return factory(ctx)
73
              .promise(callable, args)
74
              .then(function (value) {
75
                expect(value).to.eq(result)
76
                expect(callable.callCount).to.eq(1)
77
                expect(callable.getCall(0).thisValue).to.eq(ctx)
78
                for (var i = 0; i < args.length; i++) {
79
                  expect(callable.getCall(0).args[i]).to.eq(args[i])
80
                }
81
              })
82
          })
83
84
          it('catches error and rejects promise with it', function () {
85
            var error = new Error()
86
            callable.throws(error)
87
            return factory(null)
88
              .promise(callable)
89
              .then(function () {
90
                throw new Error('This branch should not have been executed')
91
              }, function (reason) {
92
                expect(reason).to.eq(error)
93
              })
94
          })
95
        })
96
97
        describe('#runHandler()', function () {
98
          var callable
99
          var onTimeout
100
          var onTimeoutTimeout
101
          var handler
102
103
          var autoHandlerFactory = function () {
104
            handler = {
105
              id: 'handler',
106
              handler: callable,
107
              timeout: null,
108
              onTimeout: {
109
                id: 'onHandlerTimeout',
110
                handler: onTimeout,
111
                timeout: null,
112
                onTimeout: {
113
                  id: 'onOnHandlerTimeoutTimeout',
114
                  handler: onTimeoutTimeout,
115
                  timeout: null
116
                }
117
              }
118
            }
119
            return handler
120
          }
121
122
          beforeEach(function () {
123
            callable = Sinon.stub().returns(1)
124
            onTimeout = Sinon.stub().returns(2)
125
            onTimeoutTimeout = Sinon.stub().returns(3)
126
            autoHandlerFactory()
127
          })
128
129
          it('performs standard, no-error, no-timeout run', function () {
130
            var args = [1, 2]
131
            var result = autoFactory().runHandler(handler, args)
132
            return result
133
              .then(function (result) {
134
                expect(result).to.eq(1)
135
                expect(callable.callCount).to.eq(1)
136
                expect(callable.getCall(0).thisValue).to.eq(context)
137
                for (var i = 0; i < args.length; i++) {
138
                  expect(callable.getCall(0).args[i]).to.eq(args[i])
139
                }
140
                expect(callable.getCall(0).args[args.length]).to.be.instanceOf(CancellationToken)
141
                expect(onTimeout.callCount).to.eq(0)
142
              })
143
          })
144
145
          it('delegates work to onTimeout handler in case of timeout', function () {
146
            var args = [1, 2]
147
            callable.returns(new Promise(function () {}))
148
            autoHandlerFactory()
149
            handler.timeout = 0
150
            var result = autoFactory().runHandler(handler, args)
151
            return result
152
              .then(function (value) {
153
                expect(value).to.eq(2)
154
                expect(callable.callCount).to.eq(1)
155
                expect(onTimeout.callCount).to.eq(1)
156
                expect(onTimeout.getCall(0).thisValue).to.eq(context)
157
                for (var i = 0; i < args.length; i++) {
158
                  expect(onTimeout.getCall(0).args[i]).to.eq(args[i])
159
                }
160
                expect(onTimeout.getCall(0).args[args.length]).to.be.instanceOf(CancellationToken)
161
                expect(onTimeout.getCall(0).args[args.length + 1]).to.be.instanceOf(TimeoutException)
162
                expect(onTimeoutTimeout.callCount).to.eq(0)
163
              })
164
          })
165
166
          it('delegates work to onTimeoutTimeout handler in case of multiple timeouts', function () {
167
            var args = [1, 2]
168
            callable.returns(new Promise(function () {}))
169
            onTimeout.returns(new Promise(function () {}))
170
            autoHandlerFactory()
171
            handler.timeout = 0
172
            handler.onTimeout.timeout = 0
173
            var result = autoFactory().runHandler(handler, args)
174
            return result
175
              .then(function (value) {
176
                expect(value).to.eq(3)
177
                expect(callable.callCount).to.eq(1)
178
                expect(onTimeout.callCount).to.eq(1)
179
                expect(onTimeoutTimeout.callCount).to.eq(1)
180
                expect(onTimeoutTimeout.getCall(0).thisValue).to.eq(context)
181
                for (var i = 0; i < args.length; i++) {
182
                  expect(onTimeoutTimeout.getCall(0).args[i]).to.eq(args[i])
183
                }
184
                expect(onTimeoutTimeout.getCall(0).args[args.length]).to.be.instanceOf(CancellationToken)
185
                expect(onTimeoutTimeout.getCall(0).args[args.length + 1]).to.be.instanceOf(TimeoutException)
186
                expect(onTimeoutTimeout.getCall(0).args[args.length + 2]).to.be.instanceOf(TimeoutException)
187
              })
188
          })
189
190
          it('rejects with timeout error if every part of chain times out', function () {
191
            callable.returns(new Promise(function () {}))
192
            onTimeout.returns(new Promise(function () {}))
193
            onTimeoutTimeout.returns(new Promise(function () {}))
194
            autoHandlerFactory()
195
            handler.timeout = 0
196
            handler.onTimeout.timeout = 0
197
            handler.onTimeout.onTimeout.timeout = 0
198
            return autoFactory()
199
              .runHandler(handler)
200
              .then(branchStopper, function (e) {
201
                expect(e).to.be.instanceOf(TimeoutException)
202
              })
203
          })
204
205
          it('cancels token on timeout', function () {
206
            callable.returns(new Promise(function () {}))
207
            autoHandlerFactory()
208
            handler.timeout = 0
209
            return autoFactory()
210
              .runHandler(handler)
211
              .then(function () {
212
                expect(callable.callCount).to.eq(1)
213
                var token = callable.getCall(0).args[0]
214
                expect(token).to.be.instanceOf(CancellationToken)
215
                expect(token.isCancelled()).to.be.true
0 ignored issues
show
introduced by
The result of the property access to expect(token.isCancelled()).to.be.true is not used.
Loading history...
216
              })
217
          })
218
219
          it('creates tokens dependent on passed one', function () {
220
            callable = Sinon.spy(function (token) {
221
              // token is a natural thenable
222
              return token
223
            })
224
            autoHandlerFactory()
225
            var token = new CancellationToken()
226
            var promise = autoFactory().runHandler(handler, [], token)
227
            token.cancel()
228
            return promise
229
              .then(function () {
230
                expect(callable.callCount).to.eq(1)
231
                var token = callable.getCall(0).args[0]
232
                expect(token).to.be.instanceOf(CancellationToken)
233
                expect(token.isCancelled()).to.be.true
0 ignored issues
show
introduced by
The result of the property access to expect(token.isCancelled()).to.be.true is not used.
Loading history...
234
              })
235
          })
236
        })
237
      })
238
    })
239
  })
240
})
241