UNPKG

4.79 kBtext/coffeescriptView Raw
1{util, deferred, parallel} = require 'also'
2{AssertionError} = require 'assert'
3facto = require 'facto'
4Loader = require './loader'
5colors = require 'colors'
6Does = require 'does'
7does = Does does: mode: 'spec'
8should = require 'should'
9
10config =
11
12 #
13 # **ipso should be run in repo root**
14 #
15
16 dir: process.cwd()
17 modules: {}
18
19{loadModules, loadModulesSync} = Loader.create config
20
21#
22# `ipso( testFunction )` - Decorates a test function
23# --------------------------------------------------
24#
25# * All ipso tests are asynchronous - done is called in the background on the nextTick
26# if the testFunction signature itself did not contain 'done' at argument1
27#
28
29module.exports = ipso = (actualTestFunction) ->
30
31 return testFunctionForMocha = (done) ->
32
33 fnArgsArray = util.argsOf actualTestFunction
34
35 argsToInjectIntoTest = []
36
37 unless done?
38
39 #
40 # ### Injecting into describe() or context()
41 #
42
43 if fnArgsArray[0] is 'done' or fnArgsArray[0] is 'facto'
44
45 console.log 'ipso cannot inject done into describe() or context()'.red
46 return
47
48 does.activate context: @, mode: 'spec', spec: null, resolver: null
49 argsToInjectIntoTest.push Module for Module in loadModulesSync( fnArgsArray, does )
50 actualTestFunction.apply @, argsToInjectIntoTest
51 return
52
53
54
55
56 #
57 # ### Injecting into hook or it()
58 #
59
60 does.activate context: @, mode: 'spec', spec: @test, resolver: done
61
62
63 #
64 # * testResolver wraps mocha's done into a proxy that call it via
65 # does.asset(... for function expectations that mocha is not aware of.
66 #
67
68 testResolver = (metadata) ->
69
70 does.assert( done ).then(
71
72 (result) ->
73
74 #
75 # * does.assert(... does not call done if nothing failed
76 #
77
78 if fnArgsArray[0] is 'facto' then facto metadata
79 done()
80
81
82 (error) ->
83
84 #
85 # * does.assert(... already called done - to fail the mocha test
86 #
87
88 if fnArgsArray[0] is 'facto' then facto metadata
89
90 (notify) ->
91
92 #
93 # * later...
94 #
95
96 )
97
98 #
99 # * testResolver is only injected if arg1 is done or facto
100 #
101
102 if fnArgsArray[0] is 'done' or fnArgsArray[0] is 'facto'
103
104 argsToInjectIntoTest.push testResolver
105 arg1 = fnArgsArray.shift()
106
107 loadModules( fnArgsArray, does ).then(
108
109 #
110 # * loader resolved with list of Modules refs to inject
111 #
112
113 (Modules) =>
114
115 argsToInjectIntoTest.push Module for Module in Modules
116
117 try promise = actualTestFunction.apply @, argsToInjectIntoTest
118 catch error
119
120 does.reset()
121 done error
122 return
123
124 if arg1 isnt 'done' and arg1 isnt 'facto'
125
126 #
127 # * test did not "request" done or facto (ie. synchronous)
128 # but this test wrapper got a done from mocha, it needs
129 # to be called.
130 #
131
132 testResolver()
133
134 #
135 # * redirect AssertionError being raised in a promise chain
136 # back into mocha's test resolver
137 #
138
139 if promise.then? then promise.then (->), done
140
141 #
142 # * loader rejection into done() - error loading module
143 #
144
145 done
146
147 )
148
149
150ipso.modules = (list) ->
151
152 for tag of list
153 unless list[tag].require?
154 throw new Error 'ipso.module expects { tagName: { require: "path/or/name" } }'
155 config.modules[tag] = list[tag]
156 return ipso
157
158#
159# convenience {ipso, mock, tag} = require 'ipso'
160#
161
162ipso.ipso = ipso
163ipso.mock = (name) ->
164
165 object =
166 title: name
167 is: (mock) ->
168 if typeof mock is 'object' then return object.should.equal mock
169 name.should.equal mock
170
171 #
172 # TODO: tagged?
173 #
174
175 return does.spectateSync name: name, tagged: true, object
176
177
178
179
180ipso.tag = deferred (action, list) ->
181
182 parallel( for tag of list
183
184 do (tag) -> -> does.spectate
185
186 name: tag
187 tagged: true
188 list[tag]
189
190 ).then action.resolve, action.reject, action.notify
191
192
193
194module.exports.once = (fn) -> do (done = false) -> ->
195
196 return if done
197 done = true
198 fn.apply @, arguments
199
200