jest: Programatically fail a test

In the jest docs it mentions an example in the async tutorial

// Or try-catch.
it('tests error with async/await', async () => {
  try {
    await user.getUserName(2);
  } catch (object) {
    expect(object.error).toEqual('User with 2 not found.');
  }
});

I think that this code should be written like this:

// Or try-catch.
it('tests error with async/await', async () => {
  try {
    await user.getUserName(2);
    fail();
  } catch (object) {
    expect(object.error).toEqual('User with 2 not found.');
  }
});

The fail() will prevent the test from passing if getUserName() does not throw an error.

However, I see no mention of the fail() command anywhere in the docs, is this a supported API?

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 32
  • Comments: 20 (6 by maintainers)

Most upvoted comments

Somehow this is not documented, but since Jest uses Jasmin this is possible:

test('How to manually fail tests', done => {
  done.fail(new Error('I want my test to fail'))
})

The problem with your method is that if the promise resolves then the test will pass even though you expect it to reject.

The test should fail if the promise resolves. It should only pass if it rejects with the exact error that you expected.

it('tests error with async/await', async () => {
  try {
    await user.getUserName(2);  //If this resolves then the test will pass
  } catch (object) {
    expect(object.error).toEqual('User with 2 not found.');
  }
});

You can also call done.fail() after done() has been called. This is important if you want to fail conditionally when a specific thing happens.

For example I wanted any call to console.error to trigger an exception and fail the test in question:

// console.error should fail the test
beforeEach(done => {
  jest.spyOn(global.console, 'error').mockImplementation(e => {
    done.fail(e);
  });
  done(); // it is important to call this here or every test will timeout
});

In case anyone else comes across this, the global function fail works. I believe it’s a feature of Jasmine.

it('should not fail', () => {
  try {
    myFunctionThatWillNotError()
  } catch (e) {
    fail('should not have thrown an error')
  }
})

In case anyone else comes across this, the global function fail works. I believe it’s a feature of Jasmine.

That will stop working at some point - it’s not part of Jest’s documented API.


Also, any reason why you aren’t using this?

test('the fetch fails with an error', async () => {
  expect.assertions(1);
  await expect(fetchData()).rejects.toMatch('error');
});

This is the idiomatic example from the docs:

test('the fetch fails with an error', async () => {
  expect.assertions(1);
  try {
    await fetchData();
  } catch (e) {
    expect(e).toMatch('error');
  }
});

So related to this, I’m currently trying to force my Jest tests to fail if console.error or console.warn is called. Unfortunately, the only reliable way I’ve found to do so is to use fail():


console.error = function(message) {
  error.apply(console, arguments); // keep default behaviour
  fail(message);
};

const warn = console.warn;

console.warn = function(message) {
  warn.apply(console, arguments); // keep default behaviour
  fail(message);
};

Raising an error does not work reliably when dealing with asynchronous React code, unfortunately. Does anyone have any thoughts on how this could be made to work without resort to fail()?

It does look like using expect.assertions(Infinity) works, but that certainly seems like an abuse of the intent of expect.assertions.

I’m not sure if it’s possible to do with async/await syntax, I didn’t play with it much to be honest.

But maybe we could introduce a new matcher e.g. .toBeRejected(object | string)?

Then you could test the case like this:

it('rejects on username 2', () => {
  const object = {error: 'User with 2 not found'};
  expect(user.getUserName(2)).toBeRejected(object);
})

I’m not sure if we want to have a function like this. fail() as you proposed here will also prevent the test from passing if getUserName() doesn’t throw and returns instantly.

Instead you could test if getUserName function throws with e.g. .toThrow() method: http://facebook.github.io/jest/docs/api.html#tothrow

If you want to test Promise rejection, you can still go on with something like this:

it('tests if getUserName rejects promise', () => {
  user.getUserName(2)
    .then(() => {}, error => {
      expect(error).toBe('My rejected Promise')
    })
});

There are plenty of ways, I just don’t see the reason to add another one.

Won’t this pass if fetchData() doesn’t throw as the test is expecting?

No, expect.assertions(1); will fail the test if no assertion is run

This feature is also useful in case you are programmatically generating test/it blocks based on async code. For example reading a text file -avoiding readSync- to assert something for each line.

As the describe doesn’t allow the callback to return a promise (#2235), you cannot generate many its. So the solution is to use a beforeAll for the async code. Then you can only have a single it/test for the whole file. So, if an expect fails, the error won’t be verbose enough to understand the error (which line failed) It is then cool to have a way to make it fail with a custom message.

Here is my example. done.fail() worked but an out-of-the-box fail() would get rid of the done(). Also having a custom message for expect() could have done it.

    describe('examples from file', () => {
        let lines;

        beforeAll(() => new Promise(resolve => {
          lines = []
          // asynchronously read each line into lines
        }))

        it('should accept all lines in samples.txt', done => {
          lines.forEach(line => {
            if (!someBooleanChecking(line)) {
              done.fail(new Error(`"${line}" was NOT accepted !`))
            } else {
              done()
            }
          })
        })
      })