@@ -24,6 +24,7 @@ export type MockFunctionMetadata = {
2424type MockFunctionState = {
2525 instances : Array < any > ,
2626 calls : Array < Array < any >> ,
27+ returnValues : Array < any > ,
2728 timestamps : Array < number > ,
2829} ;
2930
@@ -280,6 +281,7 @@ class ModuleMockerClass {
280281 return {
281282 calls : [ ] ,
282283 instances : [ ] ,
284+ returnValues : [ ] ,
283285 timestamps : [ ] ,
284286 } ;
285287 }
@@ -316,58 +318,69 @@ class ModuleMockerClass {
316318 mockState . instances . push ( this ) ;
317319 mockState . calls . push ( Array . prototype . slice . call ( arguments ) ) ;
318320 mockState . timestamps . push ( Date . now ( ) ) ;
319- if ( this instanceof f ) {
320- // This is probably being called as a constructor
321- prototypeSlots . forEach ( slot => {
322- // Copy prototype methods to the instance to make
323- // it easier to interact with mock instance call and
324- // return values
325- if ( prototype [ slot ] . type === 'function' ) {
326- const protoImpl = this [ slot ] ;
327- this [ slot ] = mocker . generateFromMetadata ( prototype [ slot ] ) ;
328- this [ slot ] . _protoImpl = protoImpl ;
329- }
330- } ) ;
331321
332- // Run the mock constructor implementation
333- const mockImpl = mockConfig . specificMockImpls . length
334- ? mockConfig . specificMockImpls . shift ( )
335- : mockConfig . mockImpl ;
336- return mockImpl && mockImpl . apply ( this , arguments ) ;
337- }
322+ // The bulk of the implementation is wrapped in an immediately executed
323+ // arrow function so the return value of the mock function can
324+ // be easily captured and recorded, despite the many separate return
325+ // points within the logic.
326+ const finalReturnValue = ( ( ) => {
327+ if ( this instanceof f ) {
328+ // This is probably being called as a constructor
329+ prototypeSlots . forEach ( slot => {
330+ // Copy prototype methods to the instance to make
331+ // it easier to interact with mock instance call and
332+ // return values
333+ if ( prototype [ slot ] . type === 'function' ) {
334+ const protoImpl = this [ slot ] ;
335+ this [ slot ] = mocker . generateFromMetadata ( prototype [ slot ] ) ;
336+ this [ slot ] . _protoImpl = protoImpl ;
337+ }
338+ } ) ;
338339
339- const returnValue = mockConfig . defaultReturnValue ;
340- // If return value is last set, either specific or default, i.e.
341- // mockReturnValueOnce()/mockReturnValue() is called and no
342- // mockImplementationOnce()/mockImplementation() is called after that.
343- // use the set return value.
344- if ( mockConfig . specificReturnValues . length ) {
345- return mockConfig . specificReturnValues . shift ( ) ;
346- }
340+ // Run the mock constructor implementation
341+ const mockImpl = mockConfig . specificMockImpls . length
342+ ? mockConfig . specificMockImpls . shift ( )
343+ : mockConfig . mockImpl ;
344+ return mockImpl && mockImpl . apply ( this , arguments ) ;
345+ }
347346
348- if ( mockConfig . isReturnValueLastSet ) {
349- return mockConfig . defaultReturnValue ;
350- }
347+ const returnValue = mockConfig . defaultReturnValue ;
348+ // If return value is last set, either specific or default, i.e.
349+ // mockReturnValueOnce()/mockReturnValue() is called and no
350+ // mockImplementationOnce()/mockImplementation() is called after that.
351+ // use the set return value.
352+ if ( mockConfig . specificReturnValues . length ) {
353+ return mockConfig . specificReturnValues . shift ( ) ;
354+ }
351355
352- // If mockImplementationOnce()/mockImplementation() is last set,
353- // or specific return values are used up, use the mock implementation.
354- let specificMockImpl ;
355- if ( returnValue === undefined ) {
356- specificMockImpl = mockConfig . specificMockImpls . shift ( ) ;
357- if ( specificMockImpl === undefined ) {
358- specificMockImpl = mockConfig . mockImpl ;
356+ if ( mockConfig . isReturnValueLastSet ) {
357+ return mockConfig . defaultReturnValue ;
359358 }
360- if ( specificMockImpl ) {
361- return specificMockImpl . apply ( this , arguments ) ;
359+
360+ // If mockImplementationOnce()/mockImplementation() is last set,
361+ // or specific return values are used up, use the mock implementation.
362+ let specificMockImpl ;
363+ if ( returnValue === undefined ) {
364+ specificMockImpl = mockConfig . specificMockImpls . shift ( ) ;
365+ if ( specificMockImpl === undefined ) {
366+ specificMockImpl = mockConfig . mockImpl ;
367+ }
368+ if ( specificMockImpl ) {
369+ return specificMockImpl . apply ( this , arguments ) ;
370+ }
362371 }
363- }
364372
365- // Otherwise use prototype implementation
366- if ( returnValue === undefined && f . _protoImpl ) {
367- return f . _protoImpl . apply ( this , arguments ) ;
368- }
373+ // Otherwise use prototype implementation
374+ if ( returnValue === undefined && f . _protoImpl ) {
375+ return f . _protoImpl . apply ( this , arguments ) ;
376+ }
377+
378+ return returnValue ;
379+ } ) ( ) ;
369380
370- return returnValue ;
381+ // Record the return value of the mock function before returning it.
382+ mockState . returnValues . push ( finalReturnValue ) ;
383+ return finalReturnValue ;
371384 } , metadata . length || 0 ) ;
372385
373386 f = this . _createMockFunction ( metadata , mockConstructor ) ;
0 commit comments