@@ -861,6 +861,348 @@ describe("issues", function () {
861861 assert . equals ( cb . firstCall . args , [ "Hello" ] ) ;
862862 } ) ;
863863
864+ describe ( "#2668 - callThrough" , function ( ) {
865+ describe ( "callThrough" , function ( ) {
866+ it ( "should clear throws(exception)" , function ( ) {
867+ const instance = {
868+ foo ( ) {
869+ return "ok" ;
870+ } ,
871+ } ;
872+
873+ const stub = sinon . stub ( instance , "foo" ) ;
874+ const expectedError = new Error ( "boom" ) ;
875+ stub . throws ( expectedError ) ;
876+
877+ assert . exception (
878+ ( ) => instance . foo ( ) ,
879+ ( err ) => err === expectedError ,
880+ ) ;
881+
882+ stub . callThrough ( ) ;
883+
884+ // Issue caused the stub to still apply.
885+ assert . equals ( instance . foo ( ) , "ok" ) ;
886+ } ) ;
887+
888+ it ( "should clear throws(exceptionFactory)" , function ( ) {
889+ const instance = {
890+ foo ( ) {
891+ return "ok" ;
892+ } ,
893+ } ;
894+
895+ const stub = sinon . stub ( instance , "foo" ) ;
896+ const expectedError = new Error ( "boom" ) ;
897+ stub . throws ( function ( ) {
898+ throw expectedError ;
899+ } ) ;
900+
901+ assert . exception (
902+ ( ) => instance . foo ( ) ,
903+ ( err ) => err === expectedError ,
904+ ) ;
905+
906+ stub . callThrough ( ) ;
907+
908+ // Issue caused the stub to still apply.
909+ assert . equals ( instance . foo ( ) , "ok" ) ;
910+ } ) ;
911+
912+ it ( "should clear throwsArg" , function ( ) {
913+ const instance = {
914+ foo ( ) {
915+ return "ok" ;
916+ } ,
917+ } ;
918+
919+ const stub = sinon . stub ( instance , "foo" ) ;
920+ stub . throwsArg ( 0 ) ;
921+
922+ const expectedError = new Error ( "boom" ) ;
923+ assert . exception (
924+ ( ) => instance . foo ( expectedError ) ,
925+ ( err ) => err === expectedError ,
926+ ) ;
927+
928+ stub . callThrough ( ) ;
929+
930+ // Issue caused the stub to still apply.
931+ assert . equals (
932+ instance . foo ( new Error ( "Should not be thrown" ) ) ,
933+ "ok" ,
934+ ) ;
935+ } ) ;
936+
937+ it ( "should clear returnsThis" , function ( ) {
938+ let called = false ;
939+ const instance = {
940+ foo ( ) {
941+ called = true ;
942+ return this ;
943+ } ,
944+ } ;
945+
946+ const stub = sinon . stub ( instance , "foo" ) ;
947+ stub . returnsThis ( ) ;
948+
949+ assert . equals ( instance . foo ( ) , instance ) ;
950+ assert . equals ( called , false ) ;
951+
952+ stub . callThrough ( ) ;
953+
954+ // Issue caused the stub to still apply.
955+ assert . same ( instance . foo ( ) , instance ) ;
956+ assert . equals ( called , true ) ;
957+ } ) ;
958+
959+ it ( "should clear resolves" , async function ( ) {
960+ const instance = {
961+ foo ( ) {
962+ return Promise . resolve ( "bar" ) ;
963+ } ,
964+ } ;
965+
966+ const stub = sinon . stub ( instance , "foo" ) ;
967+ stub . resolves ( "baz" ) ;
968+
969+ assert . equals ( await instance . foo ( ) , "baz" ) ;
970+
971+ stub . callThrough ( ) ;
972+
973+ // Issue caused the stub to still apply.
974+ assert . equals ( await instance . foo ( ) , "bar" ) ;
975+ } ) ;
976+
977+ it ( "should clear resolvesArg" , async function ( ) {
978+ const instance = {
979+ foo ( a ) {
980+ return Promise . resolve ( a ) ;
981+ } ,
982+ } ;
983+
984+ const stub = sinon . stub ( instance , "foo" ) ;
985+ stub . resolvesArg ( 1 ) ;
986+
987+ assert . equals ( await instance . foo ( "a" , "b" ) , "b" ) ;
988+
989+ stub . callThrough ( ) ;
990+
991+ // Issue caused the stub to still apply.
992+ assert . equals ( await instance . foo ( "a" , "b" ) , "a" ) ;
993+ } ) ;
994+
995+ it ( "should clear resolvesThis" , async function ( ) {
996+ const instance = {
997+ callCount : 0 ,
998+ foo ( ) {
999+ this . callCount += 1 ;
1000+ return Promise . resolve ( this ) ;
1001+ } ,
1002+ } ;
1003+
1004+ const stub = sinon . stub ( instance , "foo" ) ;
1005+ stub . resolvesThis ( ) ;
1006+
1007+ assert . same ( await instance . foo ( ) , instance ) ;
1008+ assert . equals ( instance . callCount , 0 ) ;
1009+
1010+ stub . callThrough ( ) ;
1011+
1012+ // Issue caused the stub to still apply.
1013+ assert . same ( await instance . foo ( ) , instance ) ;
1014+ assert . equals ( instance . callCount , 1 ) ;
1015+ } ) ;
1016+
1017+ it ( "should clear rejects" , async function ( ) {
1018+ const instance = {
1019+ foo ( ) {
1020+ return Promise . resolve ( "ok" ) ;
1021+ } ,
1022+ } ;
1023+
1024+ const stub = sinon . stub ( instance , "foo" ) ;
1025+ const error = new Error ( "nope" ) ;
1026+ stub . rejects ( error ) ;
1027+
1028+ await assert . rejects ( instance . foo ( ) , error ) ;
1029+
1030+ stub . callThrough ( ) ;
1031+
1032+ // Issue caused the stub to still apply.
1033+ assert . equals ( await instance . foo ( ) , "ok" ) ;
1034+ } ) ;
1035+
1036+ it ( "should clear returnsArg" , function ( ) {
1037+ const instance = {
1038+ foo ( a ) {
1039+ return `ok ${ a } ` ;
1040+ } ,
1041+ } ;
1042+
1043+ const stub = sinon . stub ( instance , "foo" ) ;
1044+ stub . returnsArg ( 0 ) ;
1045+
1046+ assert . equals ( instance . foo ( "x" ) , "x" ) ;
1047+
1048+ stub . callThrough ( ) ;
1049+
1050+ // Issue caused the stub to still apply.
1051+ assert . equals ( instance . foo ( "z" ) , "ok z" ) ;
1052+ } ) ;
1053+
1054+ it ( "should clear callsFake" , function ( ) {
1055+ const instance = {
1056+ foo ( ) {
1057+ return "orig" ;
1058+ } ,
1059+ } ;
1060+
1061+ const stub = sinon . stub ( instance , "foo" ) ;
1062+ stub . callsFake ( function ( ) {
1063+ return "fake" ;
1064+ } ) ;
1065+
1066+ assert . equals ( instance . foo ( ) , "fake" ) ;
1067+
1068+ stub . callThrough ( ) ;
1069+
1070+ // Issue caused the stub to still apply.
1071+ assert . equals ( instance . foo ( ) , "orig" ) ;
1072+ } ) ;
1073+
1074+ it ( "should clear callsArg/yield stuff" , function ( ) {
1075+ const instance = {
1076+ foo ( cbk ) {
1077+ cbk ( ) ;
1078+ return "original" ;
1079+ } ,
1080+ } ;
1081+
1082+ const stub = sinon . stub ( instance , "foo" ) ;
1083+ stub . callsArg ( 0 ) ;
1084+ stub . returns ( "fake" ) ;
1085+
1086+ const cbkStub = sinon . stub ( ) ;
1087+ assert . same ( instance . foo ( cbkStub ) , "fake" ) ;
1088+ assert . equals ( cbkStub . callCount , 1 ) ;
1089+
1090+ stub . callThrough ( ) ;
1091+
1092+ const cbkStub2 = sinon . stub ( ) ;
1093+ assert . same ( instance . foo ( cbkStub2 ) , "original" ) ;
1094+ // Issue was causing the callback to be called once by the function, and once by the stub.
1095+ assert . equals ( cbkStub2 . callCount , 1 ) ;
1096+ } ) ;
1097+ } ) ;
1098+
1099+ describe ( "callThroughWithNew" , function ( ) {
1100+ it ( "should clear throws(exception)" , function ( ) {
1101+ class OriginalClass {
1102+ constructor ( ) {
1103+ this . foo = "original" ;
1104+ }
1105+ }
1106+
1107+ const instance = { MyClass : OriginalClass } ;
1108+
1109+ const stub = sinon . stub ( instance , "MyClass" ) ;
1110+ const expectedError = new Error ( "boom" ) ;
1111+ stub . throws ( expectedError ) ;
1112+ assert . exception (
1113+ ( ) => new instance . MyClass ( ) ,
1114+ ( err ) => err === expectedError ,
1115+ ) ;
1116+
1117+ stub . callThroughWithNew ( ) ;
1118+
1119+ // Issue caused the stub to still apply.
1120+ const obj = new instance . MyClass ( ) ;
1121+ assert . equals ( obj . foo , "original" ) ;
1122+ } ) ;
1123+
1124+ it ( "should clear throws(exceptionFactory)" , function ( ) {
1125+ class OriginalClass {
1126+ constructor ( ) {
1127+ this . foo = "original" ;
1128+ }
1129+ }
1130+
1131+ const instance = { MyClass : OriginalClass } ;
1132+
1133+ const stub = sinon . stub ( instance , "MyClass" ) ;
1134+ const expectedError = new Error ( "boom" ) ;
1135+ stub . throws ( function ( ) {
1136+ throw expectedError ;
1137+ } ) ;
1138+ assert . exception (
1139+ ( ) => new instance . MyClass ( ) ,
1140+ ( err ) => err === expectedError ,
1141+ ) ;
1142+
1143+ stub . callThroughWithNew ( ) ;
1144+
1145+ // Issue caused the stub to still apply.
1146+ const obj = new instance . MyClass ( ) ;
1147+ assert . equals ( obj . foo , "original" ) ;
1148+ } ) ;
1149+
1150+ it ( "should clear throwsArg" , function ( ) {
1151+ class OriginalClass {
1152+ constructor ( ) {
1153+ this . foo = "original" ;
1154+ }
1155+ }
1156+
1157+ const instance = { MyClass : OriginalClass } ;
1158+
1159+ const stub = sinon . stub ( instance , "MyClass" ) ;
1160+ stub . throwsArg ( 0 ) ;
1161+ const expectedError = new Error ( "boom" ) ;
1162+ assert . exception (
1163+ ( ) => new instance . MyClass ( expectedError ) ,
1164+ ( err ) => err === expectedError ,
1165+ ) ;
1166+
1167+ stub . callThroughWithNew ( ) ;
1168+
1169+ // Issue caused the stub to still apply.
1170+ assert . equals (
1171+ new instance . MyClass ( new Error ( "Should not be thrown" ) ) . foo ,
1172+ "original" ,
1173+ ) ;
1174+ } ) ;
1175+
1176+ it ( "should clear callsArg/yield stuff" , function ( ) {
1177+ class OriginalClass {
1178+ constructor ( cbk ) {
1179+ this . foo = "original" ;
1180+ cbk ( ) ;
1181+ }
1182+ }
1183+
1184+ const instance = { MyClass : OriginalClass } ;
1185+
1186+ const stub = sinon . stub ( instance , "MyClass" ) ;
1187+
1188+ stub . callsArg ( 0 ) ;
1189+ const dummyInstance = { foo : "fake" } ;
1190+ stub . returns ( dummyInstance ) ;
1191+
1192+ const cbkStub = sinon . stub ( ) ;
1193+ assert . same ( new instance . MyClass ( cbkStub ) , dummyInstance ) ;
1194+ assert . equals ( cbkStub . callCount , 1 ) ;
1195+
1196+ stub . callThroughWithNew ( ) ;
1197+
1198+ const cbkStub2 = sinon . stub ( ) ;
1199+ assert . same ( new instance . MyClass ( cbkStub2 ) . foo , "original" ) ;
1200+ // Issue was causing the callback to be called once by the constructor, and once by the stub.
1201+ assert . equals ( cbkStub2 . callCount , 1 ) ;
1202+ } ) ;
1203+ } ) ;
1204+ } ) ;
1205+
8641206 it ( "#2702 - stub creation should ignore inherited non-writable Object prototype properties" , function ( ) {
8651207 const descriptor = Object . getOwnPropertyDescriptor (
8661208 Object . prototype ,
0 commit comments