47

I have the following test:

it.only('validation should fail', function(done) {
    var body = {
        title: "dffdasfsdfsdafddfsadsa",
        description: "Postman Description",
        beginDate: now.add(3, 'd').format(),
        endDate: now.add(4, 'd').format()
    }


    var rules = eventsValidation.eventCreationRules();
    var valMessages = eventsValidation.eventCreationMessages();

    indicative
        .validateAll(rules, body, valMessages)
        .then(function(data) {
            console.log("SHOULD NOT GET HERE");
            should.fail("should not get here");
            done();

        })
        .catch(function(error) {
            console.log("SHOULD GET HERE");
            console.log(error);
        });
    done();
});

The test execution path is correct. When I have validating data, it goes to "SHOULD NOT GET HERE". The test is really to make sure it doesn't. And when I put in non validating data the code does go to "SHOULD GET HERE". So the validation rules work.

What I'm trying to do is make sure the test fails when when I have bad validation data and it validates. However when I run it as it is with good data it validates, runs the fail, but mocha still marks it as the passing. I want it to fail if the execution gets to "SHOULD NOT GET HERE".

I've tried throw new Error("fail"); as well with no luck. In both cases it actually seems to run the code in the .catch block as well.

Any suggestions? I found solutions for this in a similar question. This question is written because those solutions don't seem to be working for me.

Alexis Tyler
  • 1,394
  • 6
  • 30
  • 48
Pompey Magnus
  • 2,191
  • 5
  • 27
  • 40
  • possible duplicate of [Force Mocha test to fail?](http://stackoverflow.com/questions/14879181/force-mocha-test-to-fail) – aug Jun 16 '15 at 17:52
  • call the done callback only in the 'then' function remove the outer done function, because when it will come to the catch function there will be no done callback so it will automatically show timeout error as of now since you are just consoling the outer done is passing all the test – Mukesh Agarwal Jun 16 '15 at 18:20

4 Answers4

74

You can call assert.fail:

it("should return empty set of tags", function()
{
    assert.fail("actual", "expected", "Error message");
});

Also, Mocha considers the test has failed if you call the done() function with a parameter.

For example:

it("should return empty set of tags", function(done)
{
    done(new Error("Some error message here"));
});

Though the first one looks clearer to me.

Daniel
  • 21,933
  • 14
  • 72
  • 101
  • There's absolutely no reason to solve the OP's problem by doing this rather than using the accepted answer. – Louis Nov 11 '16 at 02:13
  • 28
    @Louis Are you talking about the accepted answer that recommends adding chai as another dependency? Limiting dependencies seems like a valid reason. – qxn Nov 16 '16 at 17:45
  • 1
    @ken The OP uses promises. So the solution should take advantage of the fact that Mocha understands promises. Half of the questions asked in [tag:mocha] these days are due to problems caused by some insistence to use `done` when it all could be simplified by just using the promises already generated by the tested code. Because, see, while it is *possible* to use `done` with promises, it comes with some *significant gotchas* that the answer here *omits*. As for dependencies, as soon as you go beyond toy code, having a dependency on `chai-as-promised` is not a big deal. – Louis Nov 16 '16 at 18:02
  • @Louis Can you expand on the gotchas? – Daniel Kobe Apr 25 '17 at 05:41
  • @DanielKobe I've improved my answer a bit now that I know other ways of causing the test to fail. – Daniel Apr 25 '17 at 18:23
  • You can also use `assert.throws(() => fnToTest(param))` to assert that the function will throw *something* (the second parameter; Error by default). Note that `throws()` accepts a function itself, instead of expecting you to return a function *call*, so if you need to provide any parameters to the function to test, wrap that call in another function. – iono Mar 20 '19 at 07:13
  • unfortunately this is not working, the test still pass – Matteo May 19 '20 at 03:26
21

In the ES2017 async/await world chai-as-promised is not needed as much. Although simple rejections are one place chai-as-promised remains a little neater to use.

A catch is required if you want to test the error in more detail.

it.only('validation should fail', async function(){
    let body = { ... }
    let rules = eventsValidation.eventCreationRules()
    let valMessages = eventsValidation.eventCreationMessages()

    try {
        await indicative.validateAll(rules, body, valMessages)
    } catch (error) {
        expect(error).to.be.instanceOf(Error)
        expect(error.message).to.match(/Oh no!/)
        return
    }
    expect.fail(null, null, 'validateAll did not reject with an error')
    // or throw new Error('validateAll did not reject with an error')
})

async/await requires Node.js 7.6+ or a compiler like Babel

Matt
  • 68,711
  • 7
  • 155
  • 158
18

Use chai-as-promised, with native Mocha promise handlers.

var chai = require('chai').use(require('chai-as-promised'));
var should = chai.should(); // This will enable .should for promise assertions

You no longer need done, simply return the promise.

// Remove `done` from the line below
it.only('validation should fail', function(/* done */) {
    var body = {
        title: "dffdasfsdfsdafddfsadsa",
        description: "Postman Description",
        beginDate: now.add(3, 'd').format(),
        endDate: now.add(4, 'd').format()
    }

    var rules = eventsValidation.eventCreationRules();
    var valMessages = eventsValidation.eventCreationMessages();

    // Return the promise
    return indicative
        .validateAll(rules, body, valMessages)
        .should.be.rejected; // The test will pass only if the promise is rejected

    // Remove done, we no longer need it
    // done();
});
Zayn Ali
  • 4,765
  • 1
  • 30
  • 40
Yuri Zarubin
  • 11,439
  • 4
  • 30
  • 33
8

This simple throw is working for me

describe('Lead', () => {
  it('should create a new lead', async () => {
     throw 'not implemented'
  })
})
Alex Smirnov
  • 97
  • 1
  • 2