Skip to content

Commit 16b3beb

Browse files
committed
implement createPromise
multiple levels of anon funcs: PAINFUL. Had to use a captor to spec it, then b/c of how much setup there was i ended up with two layers of beforeEach to DRY it. not happy rn
1 parent 64e4fe9 commit 16b3beb

File tree

7 files changed

+139
-42
lines changed

7 files changed

+139
-42
lines changed

src/when/warn-if-promiseless.js renamed to src/log/ensure-promise.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import config from '../config'
22
import log from '../log'
33

4-
export default function warnIfPromiseless () {
4+
export default function ensurePromise (level) {
55
if (config().promiseConstructor == null) {
6-
log.warn('td.when', `\
6+
log[level]('td.when', `\
77
no promise constructor is set, so this \`thenResolve\` or \`thenReject\` stubbing
88
will fail if it's satisfied by an invocation on the test double. You can tell
99
testdouble.js which promise constructor to use with \`td.config\`, like so:

src/share/create-promise.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,14 @@
1-
export default function createPromise () {
1+
import config from '../config'
2+
import ensurePromise from '../log/ensure-promise'
3+
import callLater from '../share/call-later'
4+
5+
export default function createPromise (stubbing, willResolve) {
6+
const Promise = config().promiseConstructor
7+
ensurePromise('error')
8+
const value = stubbing.currentOutcome
9+
return new Promise((resolve, reject) => {
10+
callLater(() =>
11+
willResolve ? resolve(value) : reject(value)
12+
, [value], stubbing.options.defer, stubbing.options.delay)
13+
})
214
}

src/when/chain-stubbing.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import warnIfPromiseless from './warn-if-promiseless'
1+
import ensurePromise from '../log/ensure-promise'
22

33
export default function chainStubbing (double, completeStubbing) {
44
return {
@@ -19,12 +19,12 @@ export default function chainStubbing (double, completeStubbing) {
1919
return double.fake
2020
},
2121
thenResolve (...stubbedValues) {
22-
warnIfPromiseless()
22+
ensurePromise('warn')
2323
completeStubbing('thenResolve', stubbedValues)
2424
return double.fake
2525
},
2626
thenReject (...stubbedErrors) {
27-
warnIfPromiseless()
27+
ensurePromise('warn')
2828
completeStubbing('thenReject', stubbedErrors)
2929
return double.fake
3030
}

test/unit/log/ensure-promise.test.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
let config, log, subject
2+
module.exports = {
3+
beforeEach: () => {
4+
config = td.replace('../../../src/config').default
5+
log = td.replace('../../../src/log').default
6+
7+
subject = require('../../../src/log/ensure-promise').default
8+
},
9+
'config has no promise set': () => {
10+
td.when(config()).thenReturn({promiseConstructor: null})
11+
12+
subject('warn')
13+
14+
td.verify(log.warn('td.when', `\
15+
no promise constructor is set, so this \`thenResolve\` or \`thenReject\` stubbing
16+
will fail if it's satisfied by an invocation on the test double. You can tell
17+
testdouble.js which promise constructor to use with \`td.config\`, like so:
18+
19+
td.config({
20+
promiseConstructor: require('bluebird')
21+
})\
22+
`
23+
))
24+
},
25+
'config has a promise set': () => {
26+
td.when(config()).thenReturn({promiseConstructor: function () {}})
27+
28+
subject('warn')
29+
30+
assert.equal(td.explain(log.warn).callCount, 0)
31+
assert.equal(td.explain(log.error).callCount, 0)
32+
},
33+
'config has no promise set (error level)': () => {
34+
td.when(config()).thenReturn({promiseConstructor: null})
35+
36+
subject('error')
37+
38+
td.verify(log.error('td.when', `\
39+
no promise constructor is set, so this \`thenResolve\` or \`thenReject\` stubbing
40+
will fail if it's satisfied by an invocation on the test double. You can tell
41+
testdouble.js which promise constructor to use with \`td.config\`, like so:
42+
43+
td.config({
44+
promiseConstructor: require('bluebird')
45+
})\
46+
`
47+
))
48+
},
49+
50+
'config has a promise set (on error level)': () => {
51+
td.when(config()).thenReturn({promiseConstructor: function () {}})
52+
53+
subject('error')
54+
55+
assert.equal(td.explain(log.warn).callCount, 0)
56+
assert.equal(td.explain(log.error).callCount, 0)
57+
}
58+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import Stubbing from '../../../src/value/stubbing'
2+
3+
let ensurePromise, callLater, config, subject
4+
let fakePromise, resolver, rejecter, stubbing
5+
module.exports = {
6+
beforeEach: () => {
7+
ensurePromise = td.replace('../../../src/log/ensure-promise').default
8+
callLater = td.replace('../../../src/share/call-later').default
9+
config = td.replace('../../../src/config').default
10+
11+
subject = require('../../../src/share/create-promise').default
12+
},
13+
'resolve & reject': {
14+
beforeEach: () => {
15+
resolver = td.func('resolve')
16+
rejecter = td.func('reject')
17+
fakePromise = class FakePromise {
18+
constructor (handler) {
19+
handler(resolver, rejecter)
20+
}
21+
}
22+
td.when(config()).thenReturn({promiseConstructor: fakePromise})
23+
stubbing = new Stubbing(null, null, ['pants'], {
24+
defer: 'a defer',
25+
delay: 'a delay'
26+
})
27+
},
28+
'resolve': () => {
29+
const result = subject(stubbing, true)
30+
31+
assert(result instanceof fakePromise)
32+
td.verify(ensurePromise('error'))
33+
34+
// Phase 2: make sure call later invokes the resolver
35+
const captor = td.matchers.captor()
36+
td.verify(callLater(captor.capture(), ['pants'], 'a defer', 'a delay'))
37+
38+
captor.value()
39+
40+
td.verify(resolver('pants'))
41+
assert.equal(td.explain(rejecter).callCount, 0)
42+
},
43+
'reject': () => {
44+
const result = subject(stubbing, false)
45+
46+
assert(result instanceof fakePromise)
47+
td.verify(ensurePromise('error'))
48+
49+
// Phase 2: make sure call later invokes the rejecter
50+
const captor = td.matchers.captor()
51+
td.verify(callLater(captor.capture(), ['pants'], 'a defer', 'a delay'))
52+
53+
captor.value()
54+
55+
td.verify(rejecter('pants'))
56+
assert.equal(td.explain(resolver).callCount, 0)
57+
},
58+
}
59+
}

test/unit/when/chain-stubbing.test.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import Double from '../../../src/value/double'
22

3-
let warnIfPromiseless, subject
3+
let ensurePromise, subject
44
let double, type, outcomes, callback
55
module.exports = {
66
beforeEach: () => {
7-
warnIfPromiseless = td.replace('../../../src/when/warn-if-promiseless').default
7+
ensurePromise = td.replace('../../../src/log/ensure-promise').default
88

99
subject = require('../../../src/when/chain-stubbing').default
1010

@@ -49,7 +49,7 @@ module.exports = {
4949
'.thenResolve': () => {
5050
const result = subject(double, callback).thenResolve('pants')
5151

52-
td.verify(warnIfPromiseless())
52+
td.verify(ensurePromise('warn'))
5353
assert.equal(result, 'a fake')
5454
assert.equal(type, 'thenResolve')
5555
assert.deepEqual(outcomes, ['pants'])
@@ -59,7 +59,7 @@ module.exports = {
5959

6060
const result = subject(double, callback).thenReject(error)
6161

62-
td.verify(warnIfPromiseless())
62+
td.verify(ensurePromise('warn'))
6363
assert.equal(result, 'a fake')
6464
assert.equal(type, 'thenReject')
6565
assert.deepEqual(outcomes, [error])

test/unit/when/warn-if-promiseless.test.js

Lines changed: 0 additions & 32 deletions
This file was deleted.

0 commit comments

Comments
 (0)