Description
🐛 Bug Report
In some cases (I was not able to determine when and why), jest will fail a test with a message that looks like this:
[object Object] thrown
In one of the tests, I was able to make it pass by changing the location of the mock:
it('should show an error message on failure', async () => {
// <-- from here
const vm = createDialog({ list, close: jest.fn() })
const action = createActionInterface(vm)
action.enterText('input', 'Bar')
await nextTick()
data.renameList.mockRejectedValue({ status: 500 }) // <--- to here
action.submitForm('form')
await nextTick()
expect(vm.$options.propsData.close).not.toHaveBeenCalled()
expect(vm.$el.querySelector('.Message')).toMatchSnapshot()
})
In the above example (using Vue), action.submitForm('form')
will force the submit event on a form and that triggers a call to data.renameList()
which is mocked here.
In another test, I ran into the same issue:
it('should show an error message on server error', async () => {
const { vm, action } = bootstrap(PasswordChange)
vm.$mount()
action.enterText('[name="current"]', 'my old pw 123')
action.leaveField('[name="current"]')
await nextTick()
action.enterText('[name="password"]', 'my new pw 123')
action.leaveField('[name="password"]')
await nextTick()
action.enterText('[name="repeat"]', 'my new pw 123')
action.leaveField('[name="repeat"]')
await nextTick()
data.changePassword.mockRejectedValue({ status: 500 })
action.submitForm('form')
await nextTick() // <-- throws around here but cannot be caught
expect(vm.$el).toMatchSnapshot()
})
Moving the mock to the line just above form submission does not work in this case. I've marked the line that I suspect leads to the exception based on what wallaby's coverage reports say. The exception cannot be trapped in any way from either the test code or the application code (I've tried putting try catch
around the whole test to no avail.
The await nextTick()
is function that wraps setTimeout()
in a Promise
to allow Vue to re-render the interface after state change.
Point of failure (according to wallaby) depends on where the mockRejectedValue()
is called:
it('should show an error message on server error', async () => {
data.changePassword.mockRejectedValue({ status: 500 }) // <-- at the top
const { vm, action } = bootstrap(PasswordChange)
vm.$mount()
action.enterText('[name="current"]', 'my old pw 123')
action.leaveField('[name="current"]') // <-- fails here
await nextTick()
action.enterText('[name="password"]', 'my new pw 123')
action.leaveField('[name="password"]')
await nextTick()
action.enterText('[name="repeat"]', 'my new pw 123')
action.leaveField('[name="repeat"]')
await nextTick()
action.submitForm('form')
await nextTick()
expect(vm.$el).toMatchSnapshot()
})
In the second case, the code that is invoked as a result of action.leaveField()
is completely unrelated to the mocked function.
In all cases, there are multiple calls to mockResolvedValue()
in at least one of the previous tests, and there is a call to mockClear()
made before each test.
To Reproduce
Steps to reproduce the behavior: n/a
Expected behavior
I expect that, regardless of where the mockRejectedValue()
is called, the test would always succeed.
Link to repl or repo (highly encouraged)
I was not able to create a small test case for this as even in this project, mockRejectedValue()
works as expected in most cases.
Run npx envinfo --preset jest
Cannot install envinfo
OS: Windows 10 64bit
NodeJS: v8.11.1
NPM: v5.6.0
package.json deps:
"babel-core": "^6.26.0",
"babel-jest": "^22.4.3",
"babel-loader": "^7.1.4",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-plugin-dynamic-import-webpack": "^1.0.2",
"babel-plugin-ramda": "^1.6.1",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-plugin-transform-react-jsx": "^6.24.1",
"babel-preset-env": "^1.6.0",
"babel-preset-jest": "^21.0.2",
"jest": "^22.4.3",
babelrc:
{
"presets": [
[
"env",
{
"targets": {
"browsers": [
"last 2 major versions",
"ie >= 11"
]
},
"useBuiltins": true
}
]
],
"plugins": [
"ramda",
"syntax-dynamic-import",
"dynamic-import-webpack",
"transform-decorators-legacy",
"transform-object-rest-spread",
"transform-class-properties",
[
"transform-react-jsx",
{
"pragma": "h"
}
]
]
}
jest.config.js:
module.exports = {
verbose: true,
testURL: 'http://localhost/',
transform: {
'\\.js': 'babel-jest',
},
testRegex: '\\.test\\.(js|ts|tsx)$',
modulePaths: [
'<rootDir>',
'<rootDir>/src/',
'<rootDir>/node_modules/',
],
moduleFileExtensions: [
'js',
],
moduleNameMapper: {
'(\\.scss|\\.webfont)': 'identity-obj-proxy',
'(\\.handlebars)': '<rootDir>/src/__mocks__/hbs.js',
'\\.(jpg|png|gif|ttf|woff|eot|svg|html)': '<rootDir>/src/__mocks__/file-mock.js',
},
setupFiles: [
'./src/__testing__/setup.js',
],
}