@@ -8,8 +8,10 @@ var isRegExp = require('is-regex');
8
8
var trim = require ( 'string.prototype.trim' ) ;
9
9
var bind = require ( 'function-bind' ) ;
10
10
var forEach = require ( 'for-each' ) ;
11
+ var inspect = require ( 'object-inspect' ) ;
11
12
var isEnumerable = bind . call ( Function . call , Object . prototype . propertyIsEnumerable ) ;
12
13
var toLowerCase = bind . call ( Function . call , String . prototype . toLowerCase ) ;
14
+ var isProto = bind . call ( Function . call , Object . prototype . isPrototypeOf ) ;
13
15
14
16
module . exports = Test ;
15
17
@@ -514,7 +516,7 @@ Test.prototype['throws'] = function (fn, expected, msg, extra) {
514
516
fn ( ) ;
515
517
} catch ( err ) {
516
518
caught = { error : err } ;
517
- if ( ( err != null ) && ( ! isEnumerable ( err , 'message' ) || ! has ( err , 'message' ) ) ) {
519
+ if ( err != null && ( ! isEnumerable ( err , 'message' ) || ! has ( err , 'message' ) ) ) {
518
520
var message = err . message ;
519
521
delete err . message ;
520
522
err . message = message ;
@@ -523,16 +525,42 @@ Test.prototype['throws'] = function (fn, expected, msg, extra) {
523
525
524
526
var passed = caught ;
525
527
526
- if ( isRegExp ( expected ) ) {
527
- passed = expected . test ( caught && caught . error ) ;
528
- expected = String ( expected ) ;
529
- }
530
-
531
- if ( typeof expected === 'function' && caught ) {
532
- passed = caught . error instanceof expected ;
528
+ if ( caught ) {
529
+ if ( typeof expected === 'string' && caught . error && caught . error . message === expected ) {
530
+ throw new TypeError ( 'The "error/message" argument is ambiguous. The error message ' + inspect ( expected ) + ' is identical to the message.' ) ;
531
+ }
532
+ if ( typeof expected === 'function' ) {
533
+ if ( typeof expected . prototype !== 'undefined' && caught . error instanceof expected ) {
534
+ passed = true ;
535
+ } else if ( isProto ( Error , expected ) ) {
536
+ passed = false ;
537
+ } else {
538
+ passed = expected . call ( { } , caught . error ) === true ;
539
+ }
540
+ } else if ( isRegExp ( expected ) ) {
541
+ passed = expected . test ( caught . error ) ;
542
+ expected = inspect ( expected ) ;
543
+ } else if ( expected && typeof expected === 'object' ) { // Handle validation objects.
544
+ var keys = Object . keys ( expected ) ;
545
+ // Special handle errors to make sure the name and the message are compared as well.
546
+ if ( expected instanceof Error ) {
547
+ keys . push ( 'name' , 'message' ) ;
548
+ } else if ( keys . length === 0 ) {
549
+ throw new TypeError ( '`throws` validation object must not be empty' ) ;
550
+ }
551
+ passed = keys . every ( function ( key ) {
552
+ if ( typeof caught . error [ key ] === 'string' && isRegExp ( expected [ key ] ) && expected [ key ] . test ( caught . error [ key ] ) ) {
553
+ return true ;
554
+ }
555
+ if ( key in caught . error && deepEqual ( caught . error [ key ] , expected [ key ] , { strict : true } ) ) {
556
+ return true ;
557
+ }
558
+ return false ;
559
+ } ) ;
560
+ }
533
561
}
534
562
535
- this . _assert ( typeof fn === 'function' && passed , {
563
+ this . _assert ( ! ! passed , {
536
564
message : defined ( msg , 'should throw' ) ,
537
565
operator : 'throws' ,
538
566
actual : caught && caught . error ,
0 commit comments