UNPKG

6.68 kBJavaScriptView Raw
1/// Module test
2//
3// Represents a single test.
4//
5//
6// Copyright (c) 2013 Quildreen Motta
7//
8// Permission is hereby granted, free of charge, to any person
9// obtaining a copy of this software and associated documentation files
10// (the "Software"), to deal in the Software without restriction,
11// including without limitation the rights to use, copy, modify, merge,
12// publish, distribute, sublicense, and/or sell copies of the Software,
13// and to permit persons to whom the Software is furnished to do so,
14// subject to the following conditions:
15//
16// The above copyright notice and this permission notice shall be
17// included in all copies or substantial portions of the Software.
18//
19// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26//
27
28//// -- Dependencies ---------------------------------------------------
29var boo = require('boo')
30var pinky = require('pinky')
31var timeout = require('./utils').timeout
32
33
34//// -- Interfaces -----------------------------------------------------
35
36///// type Verdict
37// The verdict of running a test.
38//
39// :: String ('success' | 'failure' | 'ignored')
40
41
42///// type Result
43// The result of running a test.
44//
45// :: verdict :: Verdict --^ The verdict about the test
46// .. started :: Date --^ When it started
47// .. finished :: Date --^ When it finished
48// .. exception :: Error --^ The exception thrown (if any)
49// .. slow :: Boolean --^ Was it slower than the threshold?
50// .. test :: Test --^ The test that we ran
51
52
53///// type TestMeta
54// Meta information about a Test.
55//
56// :: title :: String --^ The name of the test
57// .. test :: () -> Promise a --^ The test code
58// .. timeout :: Number --^ How long to wait for async (ms)
59// .. slow :: Number --^ What to consider slow (ms)
60// .. enabled :: Test -> Boolean --^ Should we run this at all?
61
62
63///// type Test
64// Represents a single test.
65//
66// :: Test -: TestMeta
67// .. -- | Yields all the components of the Test's title.
68// .. full-title :: @TestMeta => () -> [String]
69
70
71///// type Runnable a
72// The type of all the things we can run.
73//
74// :: run :: Reporter, Report -> Promise a
75
76
77//// -- Results --------------------------------------------------------
78
79///// λ isSlow
80// :internal:
81// Checks if a test should be considered slow.
82//
83// :: Test, Date, Date -> Boolean
84function isSlow(test, started, finished) {
85 return (finished - started) >= test.slow
86}
87
88///// λ makeResult
89// :internal:
90// Constructs an object of the Result type.
91//
92// :: Test, Date, Date -> Result
93function makeResult(test, started, finished) {
94 return { started : started
95 , finished : finished
96 , slow : isSlow(test, started, finished)
97 , test : test
98 }
99}
100
101///// λ success
102// :internal:
103// Constructs a Result for successful tests.
104//
105// :: Test, Date, Date -> Result
106function success(test, started, finished) {
107 return boo.merge( makeResult(test, started, finished)
108 , { verdict: 'success' })
109
110}
111
112///// λ fail
113// :internal:
114// Constructs a Result for failed tests.
115//
116// :: Test, Date, Date, Error -> Result
117function fail(test, started, finished, error) {
118 return boo.merge( makeResult(test, started, finished)
119 , { verdict : 'failure'
120 , exception : error })
121}
122
123///// λ ignore
124// :internal:
125// Constructs a Result for a test that didn't ran.
126//
127// :: Test -> Result
128function ignore(test) {
129 return boo.merge( makeResult(test, new Date, new Date)
130 , { verdict: 'ignored' })
131}
132
133//// -- Base test class ------------------------------------------------
134
135///// {} Test
136//
137// Represents a single test.
138//
139// :: boo.Base <| Test -: ((Runnable Result) + Test)
140var Test = boo.Base.derive({
141
142 ///// -- Interface: TestMeta -----------------------------------------
143
144 ////// data slow
145 // The slow threshold for this test.
146 // :: Number
147 slow: 500
148
149 ////// data timeout
150 // The timeout threshold for this test.
151 // :: Number
152, timeout : 2000
153
154 ////// λ enabled
155 // Should we run this test at all?
156 // :: Test -> Bool
157, enabled:
158 function _enabled() {
159 return true
160 }
161
162 ///// -- Interface: Instantiable -------------------------------------
163
164 ////// λ init
165 // Initialises a instance of Test.
166 //
167 // :: @Test => Suite, String, (() -> Promise a), TestOptions -> ()
168, init:
169 function _init(suite, title, fn, options) {
170 this.parent = suite
171 this.title = title
172 this.test = fn
173
174 boo.extend(this, options || {})
175 if (suite) suite.add(this)
176 }
177
178 ///// -- Interface: Test ---------------------------------------------
179
180 ////// λ fullTitle
181 // Returns all the components of the fully qualified title for this
182 // test.
183 //
184 // :: () -> [String]
185, fullTitle:
186 function _fullTitle() {
187 var parentTitle = this.parent? this.fullTitle.call(this.parent)
188 : /* otherwise */ []
189
190 return parentTitle.concat(this.title).filter(Boolean)
191 }
192
193 ////// λ setEnabled
194 // Sets the enabled property of this test.
195 //
196 // :: @Test => (Test -> Bool) -> Test
197, setEnabled:
198 function _setEnabled(f) {
199 this.enabled = f
200 return this
201 }
202
203 ////// λ setTimeout
204 // Defines the timeout of this test.
205 //
206 // :: @Test => Number -> Test
207, setTimeout:
208 function _setTimeout(n) {
209 this.timeout = n
210 return this
211 }
212
213 ////// λ setSlow
214 // Defines the slow threshold for this test.
215 //
216 // :: @Test => Number -> Test
217, setSlow:
218 function _setSlow(n) {
219 this.slow = n
220 return this
221 }
222
223
224 ///// -- Interface: Runnable -----------------------------------------
225
226 ////// λ run
227 // Runs the test.
228 //
229 // :: Reporter, Report -> Promise Result
230, run:
231 function _run() {
232 if (!this.enabled()) return pinky(ignore(this))
233
234 var test = this
235 var start = new Date
236 var p = pinky(undefined)
237 var fn = this.test.bind(null, p.fulfill)
238
239 return timeout(this.timeout, p.then(fn))
240 .then(ok, failure)
241
242 function ok() { return success(test, start, new Date) }
243 function failure(e) { return fail(test, start, new Date, e) }
244 }
245})
246
247//// -- Exports --------------------------------------------------------
248module.exports = { Test: Test }
\No newline at end of file