Testing Promises with multiple thens using testdoublejs
Asked Answered
B

2

11

I am using testdouble for stubbing calls within my node.js project. This particular function is wrapping a promise and has multiple then calls within the function itself.

function getUser (rethink, username) {
  return new Promise((resolve, reject) => {
  let r = database.connect();
  r.then(conn => database.table(tablename).filter({username}))
   .then(data => resolve(data))
   .error(err => reject(err));
 });
}

So I am wanting to determine if the resolve and reject are handled correctly based on error conditions. Assume there is some custom logic in there that I need to validate.

For my test

import getUser from './user';
import td from 'testdouble';
test(t => {
  const db = td.object();
  const connect = td.function();
  td.when(connect('options')).thenResolve();
  const result = getUser(db, 'testuser');
  t.verify(result);
}

The issue is that the result of connect needs to be a promise, so I use then resolve with a value which needs to be another promise that resolves or rejects.

The line it is relating to is the result of database.connect() is not a promise.

TypeError: Cannot read property 'then' of undefined

Anyone have success with stubbing this type of call with Test Double?

Banna answered 21/3, 2017 at 18:55 Comment(7)
Can you provide the error that you get?Menstruation
@Banna Mind showing us the error and/or a stacktrace?Voodoo
i added the error to the question about essentially it is stating the result of database.connect is not a promise.Banna
What is database.connect()? If it accepts a callback you can do your logic in the callback and resolve or reject it there.Coronado
the result of database.connection is a promise, so i am thinking that I need to then resolve another object that has a then function on it.Banna
Have you tried not assigning it to r and trying database.connect().then(...)...? Also, does databae.connet() accept any parameters?Coronado
so stubbing a promises like this seems to satisfy the stub. td.when(database.connect()).thenResolve({then: (resolve) => resolve('ok')});Banna
B
1

So figured out the resolution. There are a few things to note in the solution and that we encountered. In short the resolution ended up being this...

td.when(database.connect()).thenResolve({then: (resolve) => resolve('ok')});

This resolves a thenable that is returned when test double sees database connect. Then subsequent calls can also be added.

There is also a part to note if you send in an object to database.connect() you have to be aware that it is doing === equality checking and you will need to have a reference to that object for it to correctly use td.when.

Banna answered 12/4, 2017 at 18:34 Comment(0)
E
0

Test double provides stubs for unit testing. And in your case 'db' is the object we need to mock. Creating the mocking db through

td.object(Database) // Database is the class or constructor of your db

will be the right choice, but to simply mock those methods you need in this case, I wouldn't pick that way.

Here's the tested module, 'some.js':

function getUser (database, username) {
  return new Promise((resolve, reject) => {
    let r = database.connect();
    r.then(conn => database.table('table').filter({username:username}))
      .then(data => resolve(data))
      .catch(err => reject(err));
  });
}

module.exports = getUser;

And the test file, using mocha and chai.expect, which is could also be any other unit test module here:

let td = require('testdouble');
let expect = require('chai').expect;

const getUser = require('./some');

describe('some.js',()=>{
  it('getUser',()=>{
    const db = {};
    const name = 'name';
    db.connect = td.function();
    db.table = td.function('table');
    db.filter = td.function('filter');
    td.when(db.connect()).thenResolve(db);
    td.when(db.table('table')).thenReturn(db);
    td.when(db.filter({username: name})).thenResolve('some user data');
    return getUser(db, name)
      .then(user=>{
        expect(user).to.equal('some user data')
      })
      .catch(e=>assert(e))
  })
})

So please let me know if any of these confuse you.

Emlin answered 29/3, 2017 at 15:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.