Test if a promise is resolved or rejected with Jasmine in Nodejs

45,979

Solution 1

To test asynchronous code with jasmine you should use its async syntax, e.g.:

describe('test promise with jasmine', function(done) {
    var promise = getRejectedPromise();

    promise.then(function() {
      // Promise is resolved
      done(new Error('Promise should not be resolved'));
    }, function(reason) {
      // Promise is rejected
      // You could check rejection reason if you want to
      done(); // Success
    });
});

Solution 2

you can now use expectAsync()

Expecting success:

it('expect result', async () => {
   ...
   await expectAsync(someAsyncFunction(goodInput)).toBeResolved(expectedResponse)
})

Expecting failure:

it('expect result', async () => {
   ...
   await expectAsync(someAsyncFunction(badInput)).toBeRejectedWith(expectedResponse)
})

Solution 3

jasmine 2.7 onwards supports returning promises, and would have its fulfilled state tested.

To test for rejection:

it('test promise with jasmine', async () => {
    try {
        await getRejectedPromise();
    } catch (err) {
        return;
    }

    throw new Error('Promise should not be resolved');
});

or yet:

it('test promise with jasmine', async () => {
    await getRejectedPromise()
        .then(
            () => Promise.reject(new Error('Promise should not be resolved')), 
            () => {});
});

To verify the actual message, besides the usual instanceof/toBe(), place inside the catch:

expect(() => { throw err }).toThrow(new MyCustomError('Custom error message'));

The benefit from this approach is to have a nicer fail message on the test output.

Expected function to throw MyCustomError: Custom error message, but it threw Another error message.

Somewhat better than the usual output.

To test for resolved (can't be simpler):

it('test promise with jasmine', async () => {
    await getRejectedPromise();
});

Solution 4

You can use finally block to test promise state:

it('should resolve if auth succeed', (done)=>{
    var p = server.login('user', 'password');
    p.finally(()=>{
        expect(p.isFulfilled()).toBeTruthy();
        done();
    });
});

You can use isFulfilled to check if promise was fulfilled and value method to check the fulfillment value. Corresponding methods for rejection are isRejected and reason.

Share:
45,979
chepukha
Author by

chepukha

Updated on April 24, 2020

Comments

  • chepukha
    chepukha about 4 years

    I know how to do it in Mocha but want to know how to do it with Jasmine. I tried this

    describe('test promise with jasmine', function() {
        it('expects a rejected promise', function() {
            var promise = getRejectedPromise();
    
            // return expect(promise).toBe('rejected');
            return expect(promise.inspect().state).toBe('rejected');
        });
    });
    

    However, the state is always pending and, of course, the test fails. I couldn't find any example online that I could make it work.

    Can someone please help me with this?

    Thanks.

  • Cmag
    Cmag about 9 years
    Great! What if you wanted to check the contents of the error being rejected? For some reason I keep getting either Error: Actual is not a function or Expected { _subscribers : [ ], _state : 0, _detail : { } } to throw error of type Function. Thanks!
  • Cmag
    Cmag about 9 years
    great! yep, thats what im doing... but if i do expect(reason).toEqual('someerrorstring'); i get the errors i mentioned...
  • Leonid Beschastny
    Leonid Beschastny about 9 years
    @Cmag I would recommend to inspect rejection reason manually at first, to make sure that it's really what you're expecting it to be. Just use console.log or something like that.
  • Cmag
    Cmag about 9 years
    console.log shows it as [Error blahblah: blah], but if i match it with toEqual(''), it borks..
  • Leonid Beschastny
    Leonid Beschastny about 9 years
    @Cmag It's because you're matching Error object with a string.
  • Cmag
    Cmag about 9 years
    yep, got that ... how should i match the error object :)
  • Leonid Beschastny
    Leonid Beschastny about 9 years
    @Cmag I would suggest checking that it's an instance of Error class and that it contains msg property with expected error message.
  • sl3dg3
    sl3dg3 over 8 years
    Instead of done(new Error('Promise should not be resolved'));, I'd rather write throw new Error('Promise should not be resolved');
  • Leonid Beschastny
    Leonid Beschastny over 8 years
    @sl3dg3 in this case we should also return resulting promise and ensure that jasmine can handle promise rejections correctly. Jasmine had no build-in promise support when I used it for the last time. I switched to mocha a couple of years ago and never used jasmine since, so I'm not aware of the current situation there. If jasmine support promises now, then your proposal is indeed the better alternative to my answer.
  • jjalonso
    jjalonso almost 8 years
    But if the promise is already rejected, the the ''callbacks" success and failures never are gonna be called no? On my code is not working because im returning a rejected promise return $q.reject('reason')
  • Leonid Beschastny
    Leonid Beschastny almost 8 years
    @jjalonso you are wrong, A+ promise standard demands that appropriate .then(onresolve, onreject) callback should be called even if the promise is already resolved/rejected.
  • Rui Marques
    Rui Marques over 7 years
    With this method, how to you check if the promise was rejected, and check the rejection message?
  • SET001
    SET001 over 7 years
    @RuiMarques you can use isRejected and reason methods. I updated my answer.
  • nogridbag
    nogridbag about 7 years
    I'm maintaining an older library using jasmine 2.0.3 and done(new Error('Promise should not be resolved')); does not cause the test case to fail. I've replaced it with expect('Promise should not be resolved').toBeUndefined(); followed by done() but it doesn't seem elegant.
  • André Werlang
    André Werlang over 6 years
    finally(), isFulfilled() aren't standard (as of 2017). Please edit your answer to specify external requirements.
  • André Werlang
    André Werlang over 6 years
    Agreed. I've withdrawn my upvote because the ugly catch clause. Someone else downvoted probably because this note was missing and thought it wouldn't work.
  • André Werlang
    André Werlang over 6 years
    Starting from jasmine 2.7, I suggest to use the async/await style (see my answer below.
  • Alexander Mills
    Alexander Mills over 6 years
    The catch clause is necessary for it to work correctly, it's the normal API for Promises, I don't think it's ugly...would you code something incorrectly just to make it more beautiful? Lol idk
  • André Werlang
    André Werlang over 6 years
    The test() is for an error thrown a couple lines above, it's ugly and lazy coding. See my answer.
  • Alexander Mills
    Alexander Mills over 6 years
    @AndréWerlang eh, sometimes you have test for error messages, sometimes it's necessary to use catch blocks, perhaps not in this case, but I think mine is more generic, if you need to add more promises to the chain later down the road.
  • Alexander Mills
    Alexander Mills over 6 years
    try/catch is the ugliest coding construct in almost every programming language, imo
  • André Werlang
    André Werlang over 6 years
    @AlexanderMills I know you're kidding, but I' switched from plain promises/then to async/await long ago. Ofc I use the "old way" when it makes sense.
  • Alexander Mills
    Alexander Mills over 6 years
    If you add a promise above getRejectedPromise() this code will swallow errors, because there is no check for what type of error occurs in the error handler.
  • Alexander Mills
    Alexander Mills over 6 years
    Therefore this code is not really for general use, it's "pretty" shorthand.
  • malmike21
    malmike21 over 5 years
    As of jasmine ^2.3, I can not pass parameters into the done function. It would be better to use done.fail(new Error('error message')). Reference to documentation
  • malmike21
    malmike21 over 5 years
    If you are using jasmine 3 and above, you can pass an error parameter in the done function. Reference to documentation
  • isnot2bad
    isnot2bad over 4 years
    Additional note: It is crucial to always use await (await expectAsync(...)) - otherwise the test will always succeed, no matter if the promise is rejected or not, and no matter if the test expects it to be rejected or resolved!
  • isnot2bad
    isnot2bad over 4 years
    This answer is wrong in several ways: (1) isFulfilled() is not an official method of Promise according to the ECMAScript standard. (2) Even if it were, it would always return true inside finally, as fulfilled means the promise is either rejected or resolved, which is always true when finally is called.
  • Jack Fuchs
    Jack Fuchs over 4 years
    Actually not true. It can also just be returned from within the spec. return expectAsync(pi).toBeResolvedTo(3.14);
  • Coderer
    Coderer over 3 years
    This is the most idiomatic answer and should be accepted. (The current accepted answer was good when it was given, but your solution is objectively better now.)
  • Coderer
    Coderer over 3 years
    This used to be a good answer but at this point I'd expect everybody to be on a new enough version to use expectAsync, which allows you to write tests that "look like Jasmine".