3

I've recently picked up the JS unit test libraries Mocha, Chai and Chai-As-Promise. However, I'm running into a situation where I'm not sure if it's a default behaviour or it's something I've missed.

when I assert an error message rejected from a promise, it seems that as long as the expected error message is a substring of the actual error message, it assertion will pass. and below is an example:

var chai = require('chai');
var expect = chai.expect;
var chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);

var q = require('q');

describe('demo test', function(){

    // a mock up promise function for demo purpose
    function test(input){
        var d = q.defer();

        setTimeout(function() {
            if(input){
                d.resolve('12345');
            }else{
                // throw a new Error after half a sec here
                d.reject(new Error('abcde fghij'));
            }
        }, (500));

        return d.promise;
    }

    // assertion starts here

    it('should pass if input is true', ()=>{
        return expect(test(true)).to.eventually.equal('12345');
    });

    it('this passes when matching the first half', ()=>{
        return expect(test(false)).to.be.rejectedWith('abcde');
    });

    it('this also passes when matching the second half', ()=>{
        return expect(test(false)).to.be.rejectedWith('fghij');
    });

    it('this again passes when even only matching the middle', ()=>{
        return expect(test(false)).to.be.rejectedWith('de fg');
    });

    it('this fails when the expected string is not a substring of the actual string', ()=>{
        return expect(test(false)).to.be.rejectedWith('abcdefghij');
    });
});

Is this the default behaviour? If it is, is there an option to force an exact match of the error message?

mocha@3.4.2 chai@4.0.2 chai-as-promised@7.1.1 q@1.5.0

Many Thanks.

Louis
  • 146,715
  • 28
  • 274
  • 320
SunnyHoHoHo
  • 328
  • 3
  • 8

2 Answers2

2

Is this the default behaviour?

Yes, it is. Chai-as-promised is mirroring what Chai does. When you use expect(fn).to.throw("foo"), Chai is looking for a substring foo in the error message. It would be confusing if Chai-as-promised worked differently.

If it is, is there an option to force an exact match of the error message?

There's no option to set. However, you can pass a regular expression instead of a string. If you test with /^abcde$/ the error message will have to be exactly "abcde" to pass.

Louis
  • 146,715
  • 28
  • 274
  • 320
  • Thanks, I couldn't relate "rejectedWith" to "throw" at first so I couldn't find the correct info. But now it makes sense :) and in case anyone stops by with the same wonder, here's the link to the documentation: [http://chaijs.com/api/assert/#method_throws] note: a friend of mine showed me an alternative which also works: `expect(fn).to.eventually.be.rejected.and.has.property('message', 'foo');` – SunnyHoHoHo Jul 21 '17 at 23:36
  • Ah, yes that works too. I often use regular expressions anyway so I've managed with `rejectedWith` and I've not sought another way to do it. You could submit that as another answer. – Louis Jul 21 '17 at 23:39
0

To provide an alternative to using regex, one can do this to enforce an exact match:

it('should fail with an error message "foo".', ()=>{
    return expect(fn).to.eventually.be.rejected.and.has.property('messa‌​ge', 'foo');
});

which is to check that the rejected object has a property message "foo".

please note: this is for asserting the error rejected/throw from a Promise, so eventually is required here, otherwise it will not run properly.

SunnyHoHoHo
  • 328
  • 3
  • 8
  • Please also note, that "return" or "await" before expect is required here, otherwise it will always pass. – meerkat Jul 23 '21 at 12:54