Skip to content

[object Object] thrown when using mockRejectedValue() #7396

Closed
@foxbunny

Description

@foxbunny

🐛 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',
  ],
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions