/
utils-p-spec.coffee
179 lines (154 loc) · 6.12 KB
/
utils-p-spec.coffee
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
require "promise-matchers"
describe "Promise Utility Functions",->
Promise = require("promise")
utils = require('../src/utils-p')
describe "The ifP()-Function", ->
expect42 = (done)->
(result)->
expect(result).toEqual(42)
done()
it "promises the result of calling the second argument if the first argument is truthy", (done)->
utils.ifP(true, -> 42).then expect42(done)
it "promises the result of calling third argument if the fist argument is falsy", (done)->
utils.ifP(false, undefined,-> 42).then expect42(done)
it "transparently unwrapps the first argument if it is a promise", (done)->
utils.ifP(Promise.from(false),undefined,->42).then expect42(done)
it "also allows the callbacks to return promises", (done)->
utils.ifP(Promise.from(false),undefined,->Promise.from(42)).then expect42(done)
it "passes the condition value when calling the callbacks", (done)->
utils.ifP(Promise.from(21), (c)->2*c).then expect42(done)
describe "The mapP()-Function", ->
double=(x)->2*x
expect246 =(done)->
(result)->
expect(result).toEqual([2,4,6])
done()
it "does what Array.prototype.map() does, but returns a Promise", (done)->
utils.mapP([1,2,3],double).then expect246(done)
it "transparently unwraps the first argument if it is a Promise", (done) ->
utils.mapP(Promise.from([1,2,3]),double).then expect246(done)
it "transparently unwraps array elements if they are Promises", (done) ->
utils.mapP(Promise.from([1,Promise.from(2),3]),double).then expect246(done)
it "transparently unwraps the second argument if it is a Promise", (done) ->
utils.mapP([1,2,3],Promise.from(double)).then expect246(done)
describe "The composeP()-Function",->
it "composes functions, creating a function that returns a promise", (done)->
h = (x)-> x+"h"
g = (x)-> x+"g"
f = (x)-> x+"f"
fgh=utils.composeP([f,g,h])
fgh("").then (result)->
expect(result).toEqual("hgf")
done()
it "transparently unwrapps promised values", (done)->
h = (x)-> x+"h"
g = (x)-> Promise.from(x+"g")
f = (x)-> x+"f"
fgh=utils.composeP([f,g,h])
fgh(Promise.from("")).then (result)->
expect(result).toEqual("hgf")
done()
describe "The pipeP()-Function",->
it "pipes a value through a sequence of functions, yielding a promise", (done)->
h = (x)-> x+"h"
g = (x)-> x+"g"
f = (x)-> x+"f"
utils.pipeP("",[f,g,h]).then (result)->
expect(result).toEqual("fgh")
done()
it "transparently unwrapps promised values", (done)->
h = (x)-> x+"h"
g = (x)-> Promise.from(x+"g")
f = (x)-> x+"f"
utils.pipeP(Promise.from(""),[f,g,h]).then (result)->
expect(result).toEqual("fgh")
done()
describe "The eachP-Function",->
it "like mapP but in strict sequencial order", (done)->
trace=[]
delay =(millis)->
new Promise (resolve)->
setTimeout resolve,millis
f=(x)->
trace.push("s"+x)
delay(x).then ()->
trace.push("r"+x)
x*x
expect(utils.eachP([200,50,0],f)).toHaveBeenResolvedWith done, (result)->
expect(trace).toEqual(["s200","r200","s50","r50","s0","r0"])
expect(result).toEqual([40000,2500,0])
it "resolves the returned promise with an array containing the return values",(done)->
f=(x)->x*x
utils.eachP([1,2,3],f).then (r)->
expect(r).toEqual([1,4,9])
done()
it "also works if the first argument is a promise yielding an array",(done)->
delay =(millis)->
new Promise (resolve)->
setTimeout resolve,millis
r=[]
f=(x)->
delay(x)
r.push(x)
utils.eachP(Promise.from([200,50,0]),f).then (result)->
expect(r).toEqual([200,50,0])
done()
it "keeps calm and easy even if the array contains promises",(done)->
delay =(millis)->
new Promise (resolve)->
setTimeout resolve,millis
r=[]
f=(x)->
delay(x)
r.push(x)
utils.eachP(Promise.from([200,Promise.from(50),0]),f).then (result)->
expect(r).toEqual([200,50,0])
done()
describe "The reduceP-Function",(done)->
it "works like Array.prototype.reduceP", (done)->
trace=[]
sum = (prev,cur) ->
trace.push "#{prev}+#{cur}"
prev+cur
expect(utils.reduceP [1,2,3], sum).toHaveBeenResolvedWith done, (r)->
expect(r).toBe(6)
expect(trace).toEqual [
"1+2",
"3+3"
]
it "can take an extra start value", (done)->
trace=[]
sum = (prev,cur) ->
trace.push "#{prev}+#{cur}"
prev+cur
expect(utils.reduceP [1,2,3], sum,4).toHaveBeenResolvedWith done, (r)->
expect(r).toBe(10)
expect(trace).toEqual [
"4+1",
"5+2",
"7+3"
]
it "transparently unwrapps promise elements in the array", (done)->
sum = (a,b)->a+b
expect(utils.reduceP [1,Promise.from(2),3], sum).toHaveBeenResolvedWith done, (r)->
expect(r).toBe(6)
it "deals with promises returned from the aggregator function", (done)->
sum = (a,b)-> Promise.from(a+b)
expect(utils.reduceP [1,2,3], sum).toHaveBeenResolvedWith done, (r)->
expect(r).toBe(6)
describe "The whileP-Function",->
it "executes statement while guard evaluates to something truthy", (done)->
negative = createSpy("guard").andCallFake (i)->i<0
increment = createSpy("statement").andCallFake (i)->i+1
p = utils.whileP negative,increment,-3
expect(p).toHaveBeenResolvedWith done,(i)->
expect(i).toBe 0
expect(negative.calls.length).toBe 4
expect(increment.calls.length).toBe 3
describe "The waitForP-Function",->
start = undefined
condition = ()-> Promise.from(Date.now() - start > 120)
beforeEach ()-> start=Date.now()
it "polls condition, resolving if it evaluates to true", (done)->
p = utils.waitForP condition, 200
expect(p).toHaveBeenResolved done