Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot test testdoubles inside .then function. #409

Closed
3 tasks
chakradhari opened this issue Mar 14, 2019 · 3 comments
Closed
3 tasks

Cannot test testdoubles inside .then function. #409

chakradhari opened this issue Mar 14, 2019 · 3 comments

Comments

@chakradhari
Copy link

Description

I am trying to work on a closure where I pass a testdouble(const next = td.func()) to inner function.
Inside inner function I create a testdouble which returns a promise.
when handling the promise i.e., inside .then block I call the testdouble that I passed to inner function.

Issue

When I try to check the testdouble the pass down to innerfunction and invoked inside .then block it says I din't invoke the testdouble.

Environment

  • node -v output: 10.5.0
  • npm -v (or yarn --version) output: 6.1.0
  • npm ls testdouble (or yarn list testdouble) version: 3.11.0

Code-fenced Examples

const td = require('testdouble');

describe('Mock function testing', () => {
  it(' unable to check next function is invoked even once', () => {
    
    const mockFunc = td.function('mockFunc');
    
    td.when(mockFunc()).thenResolve('abcdef');
    
    const next = td.function();

    const validateCustomer = () => {
      return (next) => {
        mockFunc().then((response) => {
          return next(); // Stuck how to test whether this next was called;
        });
      }
    }

    validateCustomer()(next);
    td.verify(mockFunc(), {times:1}) // passes
    td.verify(next(), {times: 1}) // This is where the test fails says next was not invoked even once
  })
})
@searls
Copy link
Member

searls commented Mar 14, 2019

Yes, this is to be expected, because even though mockFunc is made to immediately resolve, the promise spec specifies that any resolutions (i.e. your then callback) be deferred to a subsequent tick. However, the verification is being run synchronously in the same tick, so it's running before the callback executes and next() is called.

@searls searls closed this as completed Mar 14, 2019
@chakradhari
Copy link
Author

chakradhari commented Mar 15, 2019

What would be the best alternative for testing whether next() is called is this scenario.

@searls
Copy link
Member

searls commented Mar 15, 2019

Here is a way to make what you're doing work

const td = require('testdouble');

describe('Mock function testing', () => {
  it(' unable to check next function is invoked even once', (done) => { // <- done callback
    
    const mockFunc = td.function('mockFunc');
    
    td.when(mockFunc()).thenResolve('abcdef');
    
    const next = td.function();

    const validateCustomer = () => {
      return (next) => {
        return mockFunc().then((response) => {  //<-- return a promise
          return next(); 
        });
      }
    }

    validateCustomer()(next).then(() => { // <-- chain off that promise
      td.verify(mockFunc(), {times:1}) 
      td.verify(next(), {times: 1}) 
      done() //  <-- signal to your test runner that it's done so it waits
    });
  })
})

However, a (IMO) better code design is almost always to return values and assert those values than verify something was called, because the latter is specifying a side-effect, which (as you have seen) are harder to observe than simply returning something, even via a promise.

Something like this:

const td = require('testdouble');
const assert = require('assert');

describe('Mock function testing', () => {
  it(' unable to check next function is invoked even once', (done) => {
    
    const mockFunc = td.function('mockFunc');
    
    td.when(mockFunc()).thenResolve('abcdef');
    
    const next = td.when(td.func('abcdef')).thenResolve('foo');

    const validateCustomer = () => {
      return (next) => {
        return mockFunc().then((response) => {
          return next(response); 
        });
      }
    }

    validateCustomer()(next).then((result) => {
      assert.equal(result, 'foo')
      done()
    });
  })
})

These examples weren't runnable so I just edited them inline, but in broad strokes they should work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants