Jonatan Kłosko
Jonatan Kłosko

Reputation: 205

Javascript specs: promises chains and omitted expectations

Consider the following spec:

describe('User', () => {
  it('requires username', done => {
    factory.build('user', { username: '' })
      .then(user => user.validate())
      .catch(error => expect(error.errors.messages.username).toMatch('is required'))
      .then(done);
  });
});

In this case if the creation succeeds, then the catch callback is not invoked and we are done. So basically spec succeeds whereas it should fail. This is just an example of a general problem: when we place expectation inside then/catch then we cannot be sure that they'll be called.

How would you write this?

For this concrete example I can think of such solution (but I don't like mixing callbacks with promises this way):

describe('User', () => {
  it('requires username', done => {
    factory.build('user', { username: '' })
      .then(user => user.validate(error =>
        expect(error.errors.messages.username).toMatch('is required')))
      .then(done);
  });
});

Upvotes: 0

Views: 42

Answers (1)

Bergi
Bergi

Reputation: 665316

You would throw an error in the case that you don't expect:

return factory.build('user', { username: '' })
  .then(user => user.validate())
  .then(result => { throw new Error("expected rejection but got fulfilled promise"); },
        error => expect(error.errors.messages.username).toMatch('is required'))

Alternatively you can transform both cases into a result value on which you match, either manually or by using a promise method such as reflect:

  .then(result => null,
        error => error)
  .then(val => expect(val.errors.messages.username).toMatch('is required'))

If you know that the result is never an error-like object you can omit the first onFulfilled callback or just use catch.

Upvotes: 2

Related Questions