Vue: Vue catches errors while running Jest tests

Created on 17 Nov 2018  ·  2Comments  ·  Source: vuejs/vue

Version

2.5.17

Reproduction link

https://github.com/chris-sorrells/vue-jest-console-error-bug

Relevant code added to scaffolding

Steps to reproduce

  • Scaffold a new Vue project using vue-cli. Use Jest for unit testing.
  • Create a mounted() lifecycle hook in the HelloWorld.vue component.
  • Within mounted(), directly manipulate the msg prop to cause Vue to generate an error.
  • Run the default example.spec.js test using npm run test:unit.

What is expected?

The test should fail due to the error generated when directly manipulating the msg prop.

What is actually happening?

Vue catches the error and uses console.error to display it. Because console.error does not fail Jest tests, the test pass despite the error thrown.

bug


The underlying problem is that Vue is trying to determine whether it is appropriate to catch and console.error an error or allow the error to remain uncaught based on if Vue believes it is in a browser. Unfortunately, because Jest emulates the browser environment, error handling does not function as intended and tests will succeed inappropriately.

A fix for this would be to also check whether Vue is in a Node environment before catching the error. This would allow Jest tests to operate as intended, and maintain the behavior of error handling in the browser.

Another fix would be to re-throw the error if process.env.NODE_ENV === "test".

Most helpful comment

It's also problematic for anyone relying on CICD, particularly if you have a large team with junior developers who don't have a full understanding of Vue design patterns and you need a safeguard against poorly written code.

I do have a work-around that uses spies if anyone who comes across this issue is interested:

const spies = {};

beforeEach(done => {
  function failIfError(error) {
    // You can also just immediately fail if you don't use console.error()
    if (error instanceof Error) {
      done.fail(error);
    }
  }

  spies.consoleError = jest
    .spyOn(console, "error")
    .mockImplementation(failIfError);

  done();
});

afterEach(() => {
  spies.consoleError.mockRestore();
});

All 2 comments

Having an error thrown in test while it's just logging in development would be problematic. It would break existing tests for people writing libraries with development warnings. The errors are still logged to the console so you can see them. You can use a spy in console error to check if an error was logged or not and make the test fail. I use this technique in libraries to check if I'm providing development hints

It's also problematic for anyone relying on CICD, particularly if you have a large team with junior developers who don't have a full understanding of Vue design patterns and you need a safeguard against poorly written code.

I do have a work-around that uses spies if anyone who comes across this issue is interested:

const spies = {};

beforeEach(done => {
  function failIfError(error) {
    // You can also just immediately fail if you don't use console.error()
    if (error instanceof Error) {
      done.fail(error);
    }
  }

  spies.consoleError = jest
    .spyOn(console, "error")
    .mockImplementation(failIfError);

  done();
});

afterEach(() => {
  spies.consoleError.mockRestore();
});
Was this page helpful?
0 / 5 - 0 ratings

Related issues

franciscolourenco picture franciscolourenco  ·  3Comments

loki0609 picture loki0609  ·  3Comments

fergaldoyle picture fergaldoyle  ·  3Comments

lmnsg picture lmnsg  ·  3Comments

robertleeplummerjr picture robertleeplummerjr  ·  3Comments