@@ -11,336 +11,320 @@ var https = require('https');
11
11
var assert = require ( 'assert' ) ;
12
12
var Request = request . Request ;
13
13
14
- /**
15
- * Expose `Test`.
16
- */
17
-
18
- module . exports = Test ;
19
-
20
- /**
21
- * Initialize a new `Test` with the given `app`,
22
- * request `method` and `path`.
23
- *
24
- * @param {Server } app
25
- * @param {String } method
26
- * @param {String } path
27
- * @api public
28
- */
29
-
30
- function Test ( app , method , path ) {
31
- Request . call ( this , method . toUpperCase ( ) , path ) ;
32
- this . redirects ( 0 ) ;
33
- this . buffer ( ) ;
34
- this . app = app ;
35
- this . _asserts = [ ] ;
36
- this . url = typeof app === 'string'
37
- ? app + path
38
- : this . serverAddress ( app , path ) ;
39
- }
40
-
41
- /**
42
- * Inherits from `Request.prototype`.
43
- */
44
-
45
- Object . setPrototypeOf ( Test . prototype , Request . prototype ) ;
46
-
47
- /**
48
- * Returns a URL, extracted from a server.
49
- *
50
- * @param {Server } app
51
- * @param {String } path
52
- * @returns {String } URL address
53
- * @api private
54
- */
55
-
56
- Test . prototype . serverAddress = function ( app , path ) {
57
- var addr = app . address ( ) ;
58
- var port ;
59
- var protocol ;
60
-
61
- if ( ! addr ) this . _server = app . listen ( 0 ) ;
62
- port = app . address ( ) . port ;
63
- protocol = app instanceof https . Server ? 'https' : 'http' ;
64
- return protocol + '://127.0.0.1:' + port + path ;
65
- } ;
66
-
67
- /**
68
- * Wraps an assert function into another.
69
- * The wrapper function edit the stack trace of any assertion error, prepending a more useful stack to it.
70
- *
71
- * @param {Function } assertFn
72
- * @returns {Function } wrapped assert function
73
- */
14
+ class Test extends Request {
15
+ /**
16
+ * Initialize a new `Test` with the given `app`,
17
+ * request `method` and `path`.
18
+ *
19
+ * @param {Server } app
20
+ * @param {String } method
21
+ * @param {String } path
22
+ * @api public
23
+ */
24
+ constructor ( app , method , path ) {
25
+ super ( method . toUpperCase ( ) , path ) ;
26
+
27
+ this . redirects ( 0 ) ;
28
+ this . buffer ( ) ;
29
+ this . app = app ;
30
+ this . _asserts = [ ] ;
31
+ this . url = typeof app === 'string'
32
+ ? app + path
33
+ : this . serverAddress ( app , path ) ;
34
+ }
74
35
75
- function wrapAssertFn ( assertFn ) {
76
- var savedStack = new Error ( ) . stack . split ( '\n' ) . slice ( 3 ) ;
36
+ /**
37
+ * Returns a URL, extracted from a server.
38
+ *
39
+ * @param {Server } app
40
+ * @param {String } path
41
+ * @returns {String } URL address
42
+ * @api private
43
+ */
44
+ serverAddress ( app , path ) {
45
+ var addr = app . address ( ) ;
46
+ var port ;
47
+ var protocol ;
48
+
49
+ if ( ! addr ) this . _server = app . listen ( 0 ) ;
50
+ port = app . address ( ) . port ;
51
+ protocol = app instanceof https . Server ? 'https' : 'http' ;
52
+ return protocol + '://127.0.0.1:' + port + path ;
53
+ }
77
54
78
- return function ( res ) {
79
- var badStack ;
80
- var err = assertFn ( res ) ;
81
- if ( err instanceof Error && err . stack ) {
82
- badStack = err . stack . replace ( err . message , '' ) . split ( '\n' ) . slice ( 1 ) ;
83
- err . stack = [ err . toString ( ) ]
84
- . concat ( savedStack )
85
- . concat ( '----' )
86
- . concat ( badStack )
87
- . join ( '\n' ) ;
55
+ /**
56
+ * Expectations:
57
+ *
58
+ * .expect(200)
59
+ * .expect(200, fn)
60
+ * .expect(200, body)
61
+ * .expect('Some body')
62
+ * .expect('Some body', fn)
63
+ * .expect(['json array body', { key: 'val' }])
64
+ * .expect('Content-Type', 'application/json')
65
+ * .expect('Content-Type', 'application/json', fn)
66
+ * .expect(fn)
67
+ * .expect([200, 404])
68
+ *
69
+ * @return {Test }
70
+ * @api public
71
+ */
72
+ expect ( a , b , c ) {
73
+ // callback
74
+ if ( typeof a === 'function' ) {
75
+ this . _asserts . push ( wrapAssertFn ( a ) ) ;
76
+ return this ;
77
+ }
78
+ if ( typeof b === 'function' ) this . end ( b ) ;
79
+ if ( typeof c === 'function' ) this . end ( c ) ;
80
+
81
+ // status
82
+ if ( typeof a === 'number' ) {
83
+ this . _asserts . push ( wrapAssertFn ( this . _assertStatus . bind ( this , a ) ) ) ;
84
+ // body
85
+ if ( typeof b !== 'function' && arguments . length > 1 ) {
86
+ this . _asserts . push ( wrapAssertFn ( this . _assertBody . bind ( this , b ) ) ) ;
87
+ }
88
+ return this ;
88
89
}
89
- return err ;
90
- } ;
91
- }
92
90
93
- /**
94
- * Expectations:
95
- *
96
- * .expect(200)
97
- * .expect(200, fn)
98
- * .expect(200, body)
99
- * .expect('Some body')
100
- * .expect('Some body', fn)
101
- * .expect(['json array body', { key: 'val' }])
102
- * .expect('Content-Type', 'application/json')
103
- * .expect('Content-Type', 'application/json', fn)
104
- * .expect(fn)
105
- * .expect([200, 404])
106
- *
107
- * @return {Test }
108
- * @api public
109
- */
91
+ // multiple statuses
92
+ if ( Array . isArray ( a ) && a . length > 0 && a . every ( val => typeof val === 'number' ) ) {
93
+ this . _asserts . push ( wrapAssertFn ( this . _assertStatusArray . bind ( this , a ) ) ) ;
94
+ return this ;
95
+ }
110
96
111
- Test . prototype . expect = function ( a , b , c ) {
112
- // callback
113
- if ( typeof a === 'function' ) {
114
- this . _asserts . push ( wrapAssertFn ( a ) ) ;
115
- return this ;
116
- }
117
- if ( typeof b === 'function' ) this . end ( b ) ;
118
- if ( typeof c === 'function' ) this . end ( c ) ;
97
+ // header field
98
+ if ( typeof b === 'string' || typeof b === 'number' || b instanceof RegExp ) {
99
+ this . _asserts . push ( wrapAssertFn ( this . _assertHeader . bind ( this , { name : '' + a , value : b } ) ) ) ;
100
+ return this ;
101
+ }
119
102
120
- // status
121
- if ( typeof a === 'number' ) {
122
- this . _asserts . push ( wrapAssertFn ( this . _assertStatus . bind ( this , a ) ) ) ;
123
103
// body
124
- if ( typeof b !== 'function' && arguments . length > 1 ) {
125
- this . _asserts . push ( wrapAssertFn ( this . _assertBody . bind ( this , b ) ) ) ;
126
- }
127
- return this ;
128
- }
104
+ this . _asserts . push ( wrapAssertFn ( this . _assertBody . bind ( this , a ) ) ) ;
129
105
130
- // multiple statuses
131
- if ( Array . isArray ( a ) && a . length > 0 && a . every ( val => typeof val === 'number' ) ) {
132
- this . _asserts . push ( wrapAssertFn ( this . _assertStatusArray . bind ( this , a ) ) ) ;
133
106
return this ;
134
107
}
135
108
136
- // header field
137
- if ( typeof b === 'string' || typeof b === 'number' || b instanceof RegExp ) {
138
- this . _asserts . push ( wrapAssertFn ( this . _assertHeader . bind ( this , { name : '' + a , value : b } ) ) ) ;
109
+ /**
110
+ * Defer invoking superagent's `.end()` until
111
+ * the server is listening.
112
+ *
113
+ * @param {Function } fn
114
+ * @api public
115
+ */
116
+ end ( fn ) {
117
+ var self = this ;
118
+ var server = this . _server ;
119
+ var end = Request . prototype . end ;
120
+
121
+ end . call ( this , function ( err , res ) {
122
+ if ( server && server . _handle ) return server . close ( localAssert ) ;
123
+
124
+ localAssert ( ) ;
125
+
126
+ function localAssert ( ) {
127
+ self . assert ( err , res , fn ) ;
128
+ }
129
+ } ) ;
130
+
139
131
return this ;
140
132
}
141
133
142
- // body
143
- this . _asserts . push ( wrapAssertFn ( this . _assertBody . bind ( this , a ) ) ) ;
144
-
145
- return this ;
146
- } ;
147
-
148
- /**
149
- * Defer invoking superagent's `.end()` until
150
- * the server is listening.
151
- *
152
- * @param {Function } fn
153
- * @api public
154
- */
155
-
156
- Test . prototype . end = function ( fn ) {
157
- var self = this ;
158
- var server = this . _server ;
159
- var end = Request . prototype . end ;
160
-
161
- end . call ( this , function ( err , res ) {
162
- if ( server && server . _handle ) return server . close ( localAssert ) ;
163
-
164
- localAssert ( ) ;
165
-
166
- function localAssert ( ) {
167
- self . assert ( err , res , fn ) ;
134
+ /**
135
+ * Perform assertions and invoke `fn(err, res)`.
136
+ *
137
+ * @param {?Error } resError
138
+ * @param {Response } res
139
+ * @param {Function } fn
140
+ * @api private
141
+ */
142
+ assert ( resError , res , fn ) {
143
+ var errorObj ;
144
+ var i ;
145
+
146
+ // check for unexpected network errors or server not running/reachable errors
147
+ // when there is no response and superagent sends back a System Error
148
+ // do not check further for other asserts, if any, in such case
149
+ // https://nodejs.org/api/errors.html#errors_common_system_errors
150
+ var sysErrors = {
151
+ ECONNREFUSED : 'Connection refused' ,
152
+ ECONNRESET : 'Connection reset by peer' ,
153
+ EPIPE : 'Broken pipe' ,
154
+ ETIMEDOUT : 'Operation timed out'
155
+ } ;
156
+
157
+ if ( ! res && resError ) {
158
+ if ( resError instanceof Error && resError . syscall === 'connect'
159
+ && Object . getOwnPropertyNames ( sysErrors ) . indexOf ( resError . code ) >= 0 ) {
160
+ errorObj = new Error ( resError . code + ': ' + sysErrors [ resError . code ] ) ;
161
+ } else {
162
+ errorObj = resError ;
163
+ }
168
164
}
169
- } ) ;
170
165
171
- return this ;
172
- } ;
173
-
174
- /**
175
- * Perform assertions and invoke `fn(err, res)`.
176
- *
177
- * @param {?Error } resError
178
- * @param {Response } res
179
- * @param {Function } fn
180
- * @api private
181
- */
182
-
183
- Test . prototype . assert = function ( resError , res , fn ) {
184
- var errorObj ;
185
- var i ;
186
-
187
- // check for unexpected network errors or server not running/reachable errors
188
- // when there is no response and superagent sends back a System Error
189
- // do not check further for other asserts, if any, in such case
190
- // https://nodejs.org/api/errors.html#errors_common_system_errors
191
- var sysErrors = {
192
- ECONNREFUSED : 'Connection refused' ,
193
- ECONNRESET : 'Connection reset by peer' ,
194
- EPIPE : 'Broken pipe' ,
195
- ETIMEDOUT : 'Operation timed out'
196
- } ;
166
+ // asserts
167
+ for ( i = 0 ; i < this . _asserts . length && ! errorObj ; i += 1 ) {
168
+ errorObj = this . _assertFunction ( this . _asserts [ i ] , res ) ;
169
+ }
197
170
198
- if ( ! res && resError ) {
199
- if ( resError instanceof Error && resError . syscall === 'connect'
200
- && Object . getOwnPropertyNames ( sysErrors ) . indexOf ( resError . code ) >= 0 ) {
201
- errorObj = new Error ( resError . code + ': ' + sysErrors [ resError . code ] ) ;
202
- } else {
171
+ // set unexpected superagent error if no other error has occurred.
172
+ if ( ! errorObj && resError instanceof Error && ( ! res || resError . status !== res . status ) ) {
203
173
errorObj = resError ;
204
174
}
205
- }
206
175
207
- // asserts
208
- for ( i = 0 ; i < this . _asserts . length && ! errorObj ; i += 1 ) {
209
- errorObj = this . _assertFunction ( this . _asserts [ i ] , res ) ;
176
+ fn . call ( this , errorObj || null , res ) ;
210
177
}
211
178
212
- // set unexpected superagent error if no other error has occurred.
213
- if ( ! errorObj && resError instanceof Error && ( ! res || resError . status !== res . status ) ) {
214
- errorObj = resError ;
179
+ /**
180
+ * Perform assertions on a response body and return an Error upon failure.
181
+ *
182
+ * @param {Mixed } body
183
+ * @param {Response } res
184
+ * @return {?Error }
185
+ * @api private
186
+ */ // eslint-disable-next-line class-methods-use-this
187
+ _assertBody ( body , res ) {
188
+ var isregexp = body instanceof RegExp ;
189
+ var a ;
190
+ var b ;
191
+
192
+ // parsed
193
+ if ( typeof body === 'object' && ! isregexp ) {
194
+ try {
195
+ assert . deepStrictEqual ( body , res . body ) ;
196
+ } catch ( err ) {
197
+ a = util . inspect ( body ) ;
198
+ b = util . inspect ( res . body ) ;
199
+ return error ( 'expected ' + a + ' response body, got ' + b , body , res . body ) ;
200
+ }
201
+ } else if ( body !== res . text ) {
202
+ // string
203
+ a = util . inspect ( body ) ;
204
+ b = util . inspect ( res . text ) ;
205
+
206
+ // regexp
207
+ if ( isregexp ) {
208
+ if ( ! body . test ( res . text ) ) {
209
+ return error ( 'expected body ' + b + ' to match ' + body , body , res . body ) ;
210
+ }
211
+ } else {
212
+ return error ( 'expected ' + a + ' response body, got ' + b , body , res . body ) ;
213
+ }
214
+ }
215
215
}
216
216
217
- fn . call ( this , errorObj || null , res ) ;
218
- } ;
219
-
220
- /**
221
- * Perform assertions on a response body and return an Error upon failure.
222
- *
223
- * @param {Mixed } body
224
- * @param {Response } res
225
- * @return {?Error }
226
- * @api private
227
- */
228
-
229
- Test . prototype . _assertBody = function ( body , res ) {
230
- var isregexp = body instanceof RegExp ;
231
- var a ;
232
- var b ;
233
-
234
- // parsed
235
- if ( typeof body === 'object' && ! isregexp ) {
236
- try {
237
- assert . deepStrictEqual ( body , res . body ) ;
238
- } catch ( err ) {
239
- a = util . inspect ( body ) ;
240
- b = util . inspect ( res . body ) ;
241
- return error ( 'expected ' + a + ' response body, got ' + b , body , res . body ) ;
217
+ /**
218
+ * Perform assertions on a response header and return an Error upon failure.
219
+ *
220
+ * @param {Object } header
221
+ * @param {Response } res
222
+ * @return {?Error }
223
+ * @api private
224
+ */ // eslint-disable-next-line class-methods-use-this
225
+ _assertHeader ( header , res ) {
226
+ var field = header . name ;
227
+ var actual = res . header [ field . toLowerCase ( ) ] ;
228
+ var fieldExpected = header . value ;
229
+
230
+ if ( typeof actual === 'undefined' ) return new Error ( 'expected "' + field + '" header field' ) ;
231
+ // This check handles header values that may be a String or single element Array
232
+ if ( ( Array . isArray ( actual ) && actual . toString ( ) === fieldExpected )
233
+ || fieldExpected === actual ) {
234
+ return ;
242
235
}
243
- } else if ( body !== res . text ) {
244
- // string
245
- a = util . inspect ( body ) ;
246
- b = util . inspect ( res . text ) ;
247
-
248
- // regexp
249
- if ( isregexp ) {
250
- if ( ! body . test ( res . text ) ) {
251
- return error ( 'expected body ' + b + ' to match ' + body , body , res . body ) ;
236
+ if ( fieldExpected instanceof RegExp ) {
237
+ if ( ! fieldExpected . test ( actual ) ) {
238
+ return new Error ( 'expected "' + field + '" matching '
239
+ + fieldExpected + ', got "' + actual + '"' ) ;
252
240
}
253
241
} else {
254
- return error ( 'expected ' + a + ' response body , got ' + b , body , res . body ) ;
242
+ return new Error ( 'expected " ' + field + '" of "' + fieldExpected + '" , got " ' + actual + '"' ) ;
255
243
}
256
244
}
257
- } ;
258
-
259
- /**
260
- * Perform assertions on a response header and return an Error upon failure.
261
- *
262
- * @param {Object } header
263
- * @param {Response } res
264
- * @return {?Error }
265
- * @api private
266
- */
267
-
268
- Test . prototype . _assertHeader = function ( header , res ) {
269
- var field = header . name ;
270
- var actual = res . header [ field . toLowerCase ( ) ] ;
271
- var fieldExpected = header . value ;
272
245
273
- if ( typeof actual === 'undefined' ) return new Error ( 'expected "' + field + '" header field' ) ;
274
- // This check handles header values that may be a String or single element Array
275
- if ( ( Array . isArray ( actual ) && actual . toString ( ) === fieldExpected )
276
- || fieldExpected === actual ) {
277
- return ;
278
- }
279
- if ( fieldExpected instanceof RegExp ) {
280
- if ( ! fieldExpected . test ( actual ) ) {
281
- return new Error ( 'expected "' + field + '" matching '
282
- + fieldExpected + ', got "' + actual + '"' ) ;
246
+ /**
247
+ * Perform assertions on the response status and return an Error upon failure.
248
+ *
249
+ * @param {Number } status
250
+ * @param {Response } res
251
+ * @return {?Error }
252
+ * @api private
253
+ */ // eslint-disable-next-line class-methods-use-this
254
+ _assertStatus ( status , res ) {
255
+ var a ;
256
+ var b ;
257
+ if ( res . status !== status ) {
258
+ a = http . STATUS_CODES [ status ] ;
259
+ b = http . STATUS_CODES [ res . status ] ;
260
+ return new Error ( 'expected ' + status + ' "' + a + '", got ' + res . status + ' "' + b + '"' ) ;
283
261
}
284
- } else {
285
- return new Error ( 'expected "' + field + '" of "' + fieldExpected + '", got "' + actual + '"' ) ;
286
262
}
287
- } ;
288
263
289
- /**
290
- * Perform assertions on the response status and return an Error upon failure.
291
- *
292
- * @param {Number } status
293
- * @param {Response } res
294
- * @return {?Error }
295
- * @api private
296
- */
264
+ /**
265
+ * Perform assertions on the response status and return an Error upon failure.
266
+ *
267
+ * @param {Array<Number> } statusArray
268
+ * @param {Response } res
269
+ * @return {?Error }
270
+ * @api private
271
+ */ // eslint-disable-next-line class-methods-use-this
272
+ _assertStatusArray ( statusArray , res ) {
273
+ var b ;
274
+ var expectedList ;
275
+ if ( ! statusArray . includes ( res . status ) ) {
276
+ b = http . STATUS_CODES [ res . status ] ;
277
+ expectedList = statusArray . join ( ', ' ) ;
278
+ return new Error (
279
+ 'expected one of "' + expectedList + '", got ' + res . status + ' "' + b + '"'
280
+ ) ;
281
+ }
282
+ }
297
283
298
- Test . prototype . _assertStatus = function ( status , res ) {
299
- var a ;
300
- var b ;
301
- if ( res . status !== status ) {
302
- a = http . STATUS_CODES [ status ] ;
303
- b = http . STATUS_CODES [ res . status ] ;
304
- return new Error ( 'expected ' + status + ' "' + a + '", got ' + res . status + ' "' + b + '"' ) ;
284
+ /**
285
+ * Performs an assertion by calling a function and return an Error upon failure.
286
+ *
287
+ * @param {Function } fn
288
+ * @param {Response } res
289
+ * @return {?Error }
290
+ * @api private
291
+ */ // eslint-disable-next-line class-methods-use-this
292
+ _assertFunction ( fn , res ) {
293
+ var err ;
294
+ try {
295
+ err = fn ( res ) ;
296
+ } catch ( e ) {
297
+ err = e ;
298
+ }
299
+ if ( err instanceof Error ) return err ;
305
300
}
306
- } ;
301
+ }
307
302
308
303
/**
309
- * Perform assertions on the response status and return an Error upon failure.
304
+ * Wraps an assert function into another.
305
+ * The wrapper function edit the stack trace of any assertion error, prepending a more useful stack to it.
310
306
*
311
- * @param {Array<Number> } statusArray
312
- * @param {Response } res
313
- * @return {?Error }
314
- * @api private
307
+ * @param {Function } assertFn
308
+ * @returns {Function } wrapped assert function
315
309
*/
316
310
317
- Test . prototype . _assertStatusArray = function ( statusArray , res ) {
318
- var b ;
319
- var expectedList ;
320
- if ( ! statusArray . includes ( res . status ) ) {
321
- b = http . STATUS_CODES [ res . status ] ;
322
- expectedList = statusArray . join ( ', ' ) ;
323
- return new Error ( 'expected one of "' + expectedList + '", got ' + res . status + ' "' + b + '"' ) ;
324
- }
325
- } ;
311
+ function wrapAssertFn ( assertFn ) {
312
+ var savedStack = new Error ( ) . stack . split ( '\n' ) . slice ( 3 ) ;
326
313
327
- /**
328
- * Performs an assertion by calling a function and return an Error upon failure.
329
- *
330
- * @param {Function } fn
331
- * @param {Response } res
332
- * @return {?Error }
333
- * @api private
334
- */
335
- Test . prototype . _assertFunction = function ( fn , res ) {
336
- var err ;
337
- try {
338
- err = fn ( res ) ;
339
- } catch ( e ) {
340
- err = e ;
341
- }
342
- if ( err instanceof Error ) return err ;
343
- } ;
314
+ return function ( res ) {
315
+ var badStack ;
316
+ var err = assertFn ( res ) ;
317
+ if ( err instanceof Error && err . stack ) {
318
+ badStack = err . stack . replace ( err . message , '' ) . split ( '\n' ) . slice ( 1 ) ;
319
+ err . stack = [ err . toString ( ) ]
320
+ . concat ( savedStack )
321
+ . concat ( '----' )
322
+ . concat ( badStack )
323
+ . join ( '\n' ) ;
324
+ }
325
+ return err ;
326
+ } ;
327
+ }
344
328
345
329
/**
346
330
* Return an `Error` with `msg` and results properties.
@@ -359,3 +343,9 @@ function error(msg, expected, actual) {
359
343
err . showDiff = true ;
360
344
return err ;
361
345
}
346
+
347
+ /**
348
+ * Expose `Test`.
349
+ */
350
+
351
+ module . exports = Test ;
0 commit comments