substantial / sinon-stub-promise

Synchronous Promise stubbing for Sinon.JS
MIT License
85 stars 11 forks source link

Using sinon-stub-promise on an existing promise object #17

Open Kannaj opened 8 years ago

Kannaj commented 8 years ago

Hello,

I have a promise object which i'm trying to force/resolve to a particular value. But i'm getting a timeout from mocha no matter how long i set the timeout duration.

I probably am stubbing the promise object incorrectly . Please let me know what else i can try.

import sinonStubPromise from 'sinon-stub-promise';
sinonStubPromise(sinon)

  it('should return a valid user if id_token is valid',function(){
    sinon.stub(jwt,'verify').returns({account_id:1,username:'Kannaj'});
    const stub = sinon.stub(db,'one').returnsPromise().resolves({username:'Kannaj'})
    id_token = ' {"hello":"you got another thing coming" }'
    return expect(getInitialState(id_token)).to.eventually.be.true
  })

i'm getting the below error form mocha

  1) GetInitialState should return a valid user if id_token is valid:
     Error: timeout of 2000ms exceeded. Ensure the done() callback is being called in this test.
rhagigi commented 8 years ago

Can you please post the code for getInitialState?

Kannaj commented 8 years ago
const getInitialState = (id_token) => {
  let initialState;
  return new Promise((resolve,reject) => {
    if(id_token == null){
      initialState = {userDetails:{username: 'Anonymous',isAuthenticated: false}}
      resolve(initialState)
    }else{
        var decoded = jwt.verify(JSON.parse(id_token),'rush2112')
        // console.log(decoded)
        db.one('SELECT  * FROM account WHERE account_id = $1',decoded.account_id)
          .then(function(result){
            console.log('result is : ',result)
            initialState = {userDetails:{username:result.username,isAuthenticated:true}}
            resolve(initialState)
          })
          .catch(function(err){
            console.log('There was something wrong with the token',e)
            reject('There was an error parsing the token')
          })
    }
  })
}

The function i'm testing is itself another promise object for which im using chaiasPromised

rhagigi commented 8 years ago

Wouldn't you expect it to eventually be: {userDetails:{username: 'Kannaj', isAuthenticated:true}}, not true? --- Also: Is it logging where you have console.log('result is : ',result)? If so it's not this library...

Kannaj commented 8 years ago

Yes for the first one .. no for the second .. it seems to be stuck in the db.one call and not resolving the promise :(

amay commented 8 years ago

I agree with @rhagigi that your expectation is wrong, but that doesn't explain the timeout.

I'm having a hard time replicating the issue with some test code that essentially replicates what you are trying to do. Both of the tests below pass:

var db;

function doAsyncThing() {
  return new Promise(function(resolve, reject) {
    db.one().then(function(value) {
      resolve({ foo: value });
    });
  });
}

beforeEach(() => {
  db = {
    one: function () {
      console.log('this is stubbed')
    }
  }
})

it('works with .then & done', function(done) {
  sinon.stub(db, 'one').returnsPromise().resolves('foo');
  doAsyncThing().then(function(value) {
    expect(value).to.eql({ foo: 'foo' });
    done();
  })
})

it('works with chai-as-promised', function() {
  sinon.stub(db, 'one').returnsPromise().resolves('foo');
  return expect(doAsyncThing()).to.eventually.eql({ foo: 'foo' })
})

One detail missing from your post is how you are going about accessing the same db and jwt variables in the implementation and your test code, so maybe it is some interplay there?

Also of note: if you are already using chai-as-promised and you are testing code that returns a promise (which getInitialState does), it is simpler to just return a promise from your stubbed db.one call like this:

it('works with Promise.resolve', function() {
  sinon.stub(db, 'one').returns(Promise.resolve('foo'))
  return expect(doAsyncThing()).to.eventually.eql({ foo: 'foo' })
})

sinon-stub-promise is only meant to be used when you are stubbing something that returns a promise and you don't want to deal with the asynchronous behavior inherent in "real" promises. In this case, you are testing a function that returns a real promise so you might as well go about testing it using mocha's asynchronous testing behavior.

Kannaj commented 8 years ago

Thanks for the detailed response - regarding how i'm accessing the db and jwt variables .. in the test file and the function file .. i import them directly from node_modules .. is this wrong?