-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[jest-mock] Track thrown errors in MockFunctionState #5764
Changes from 3 commits
f160a65
7e41bda
de2b0de
e2b012d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,6 +25,7 @@ type MockFunctionState = { | |
instances: Array<any>, | ||
calls: Array<Array<any>>, | ||
returnValues: Array<any>, | ||
thrownErrors: Array<any>, | ||
timestamps: Array<number>, | ||
}; | ||
|
||
|
@@ -282,6 +283,7 @@ class ModuleMockerClass { | |
calls: [], | ||
instances: [], | ||
returnValues: [], | ||
thrownErrors: [], | ||
timestamps: [], | ||
}; | ||
} | ||
|
@@ -319,67 +321,85 @@ class ModuleMockerClass { | |
mockState.calls.push(Array.prototype.slice.call(arguments)); | ||
mockState.timestamps.push(Date.now()); | ||
|
||
// The bulk of the implementation is wrapped in an immediately executed | ||
// arrow function so the return value of the mock function can | ||
// be easily captured and recorded, despite the many separate return | ||
// points within the logic. | ||
const finalReturnValue = (() => { | ||
if (this instanceof f) { | ||
// This is probably being called as a constructor | ||
prototypeSlots.forEach(slot => { | ||
// Copy prototype methods to the instance to make | ||
// it easier to interact with mock instance call and | ||
// return values | ||
if (prototype[slot].type === 'function') { | ||
const protoImpl = this[slot]; | ||
this[slot] = mocker.generateFromMetadata(prototype[slot]); | ||
this[slot]._protoImpl = protoImpl; | ||
} | ||
}); | ||
|
||
// Run the mock constructor implementation | ||
const mockImpl = mockConfig.specificMockImpls.length | ||
? mockConfig.specificMockImpls.shift() | ||
: mockConfig.mockImpl; | ||
return mockImpl && mockImpl.apply(this, arguments); | ||
} | ||
|
||
const returnValue = mockConfig.defaultReturnValue; | ||
// If return value is last set, either specific or default, i.e. | ||
// mockReturnValueOnce()/mockReturnValue() is called and no | ||
// mockImplementationOnce()/mockImplementation() is called after that. | ||
// use the set return value. | ||
if (mockConfig.specificReturnValues.length) { | ||
return mockConfig.specificReturnValues.shift(); | ||
} | ||
// Will be set to the return value of the mock if an error is not thrown | ||
let finalReturnValue; | ||
// Will be set to the error that is thrown by the mock (if it throws) | ||
let thrownError; | ||
|
||
try { | ||
// The bulk of the implementation is wrapped in an immediately | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Everything in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Append a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the tip. Would be nicer if this option was exposed in the UI. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can recommend refined github: https://github.com/sindresorhus/refined-github |
||
// executed arrow function so the return value of the mock function | ||
// can be easily captured and recorded, despite the many separate | ||
// return points within the logic. | ||
finalReturnValue = (() => { | ||
if (this instanceof f) { | ||
// This is probably being called as a constructor | ||
prototypeSlots.forEach(slot => { | ||
// Copy prototype methods to the instance to make | ||
// it easier to interact with mock instance call and | ||
// return values | ||
if (prototype[slot].type === 'function') { | ||
const protoImpl = this[slot]; | ||
this[slot] = mocker.generateFromMetadata(prototype[slot]); | ||
this[slot]._protoImpl = protoImpl; | ||
} | ||
}); | ||
|
||
// Run the mock constructor implementation | ||
const mockImpl = mockConfig.specificMockImpls.length | ||
? mockConfig.specificMockImpls.shift() | ||
: mockConfig.mockImpl; | ||
return mockImpl && mockImpl.apply(this, arguments); | ||
} | ||
|
||
if (mockConfig.isReturnValueLastSet) { | ||
return mockConfig.defaultReturnValue; | ||
} | ||
const returnValue = mockConfig.defaultReturnValue; | ||
// If return value is last set, either specific or default, i.e. | ||
// mockReturnValueOnce()/mockReturnValue() is called and no | ||
// mockImplementationOnce()/mockImplementation() is called after | ||
// that. | ||
// use the set return value. | ||
if (mockConfig.specificReturnValues.length) { | ||
return mockConfig.specificReturnValues.shift(); | ||
} | ||
|
||
// If mockImplementationOnce()/mockImplementation() is last set, | ||
// or specific return values are used up, use the mock implementation. | ||
let specificMockImpl; | ||
if (returnValue === undefined) { | ||
specificMockImpl = mockConfig.specificMockImpls.shift(); | ||
if (specificMockImpl === undefined) { | ||
specificMockImpl = mockConfig.mockImpl; | ||
if (mockConfig.isReturnValueLastSet) { | ||
return mockConfig.defaultReturnValue; | ||
} | ||
if (specificMockImpl) { | ||
return specificMockImpl.apply(this, arguments); | ||
|
||
// If mockImplementationOnce()/mockImplementation() is last set, | ||
// or specific return values are used up, use the mock | ||
// implementation. | ||
let specificMockImpl; | ||
if (returnValue === undefined) { | ||
specificMockImpl = mockConfig.specificMockImpls.shift(); | ||
if (specificMockImpl === undefined) { | ||
specificMockImpl = mockConfig.mockImpl; | ||
} | ||
if (specificMockImpl) { | ||
return specificMockImpl.apply(this, arguments); | ||
} | ||
} | ||
} | ||
|
||
// Otherwise use prototype implementation | ||
if (returnValue === undefined && f._protoImpl) { | ||
return f._protoImpl.apply(this, arguments); | ||
} | ||
// Otherwise use prototype implementation | ||
if (returnValue === undefined && f._protoImpl) { | ||
return f._protoImpl.apply(this, arguments); | ||
} | ||
|
||
return returnValue; | ||
})(); | ||
return returnValue; | ||
})(); | ||
} catch (error) { | ||
// Store the thrown error so we can record it, then re-throw it. | ||
thrownError = error; | ||
throw error; | ||
} finally { | ||
// Record the return value of the mock function. | ||
// If the mock threw an error, then the value will be undefined. | ||
mockState.returnValues.push(finalReturnValue); | ||
// Record the error thrown by the mock function. | ||
// If no error was thrown, then the value will be udnefiend. | ||
mockState.thrownErrors.push(thrownError); | ||
} | ||
|
||
// Record the return value of the mock function before returning it. | ||
mockState.returnValues.push(finalReturnValue); | ||
return finalReturnValue; | ||
}, metadata.length || 0); | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could consider including this in the example rather than a note:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated the documentation.