How to get a sinon stub to call another function on nth call
Asked Answered
S

1

0

I want to use a sinon stub to asynchronously test an event emitter. I want the stub to call a callback after it is called.

I thought stub.yields was what I want but not. Is there a neat way to do this?

    it('asynchronously emits finish after logging is complete', function(done){
        const EE = require('events');
        const testEmitter = new EE();

        var cb = sinon.stub();
        cb.calls(completed);    // no such method but this is what I need

        testEmitter.on('finish', cb.bind(null));

        testEmitter.emit('finish');

        function completed() {

            expect(cb).to.have.been.calledOnce;
            expect(cb).to.have.been.calledOn(null);
            expect(cb).to.have.exactArgs();

            done()
        }

    });

Currently, I'm doing something like this...

        it('asynchronously emits finish', function(done) {
            const EE = require('events');
            const testEmitter = new EE();
            var count = 1;

            process.nextTick(() => testEmitter.emit('finish'));

            function cb(e) {
                var self = this;
                expect(e).to.be.an('undefined');
                expect(self).to.equal(testEmitter);
                if(!count--)
                    done()
            }

            testEmitter.on('finish', cb);

            process.nextTick(() => testEmitter.emit('finish'));

        });

And it works fine but, I need to generalise it and I thought I could do it more efficiently with sinon. But I can't figure out how to do it from the sinon docs . Am I missing something?


Thanks to Robert Klep, here is the solution...

it('asynchronously emits finish after logging is complete', function(done){
    const EE = require('events');
    const testEmitter = new EE();

    var cb = sinon.spy(completed);

    process.nextTick(() => testEmitter.emit('finish'));

    testEmitter.on('finish', cb.bind(null));

    process.nextTick(() => testEmitter.emit('finish'));

    function completed() {

        if(cb.callCount < 2)
            return;

        expect(cb).to.have.been.calledTwice;
        expect(cb).to.have.been.calledOn(null);
        expect(cb).to.have.been.calledWithExactly();

        done()
    }

});
Splenitis answered 10/8, 2016 at 13:49 Comment(0)
D
2

You can use a spy, because spies will call the function they are spying on:

var cb = sinon.spy(completed);

If, however, for some reason the event handler never gets called, the test will fail by timing out.

Declivous answered 10/8, 2016 at 14:46 Comment(5)
Perfect, thanks! I'll update my question with that implemented.Splenitis
how to get it to call back on the second call?Splenitis
@CoolBlue you can't do that with spies, only stubs (but with stubs, you can't easily call completed, so that's a bit of a catch-22 situation), although you could check cb.callCount inside completed.Declivous
Perfect, thanks. I updated my answer again. Looks very clean.Splenitis
Perfect. Thank for taking your time to write about how to capture callbacks.Accustom

© 2022 - 2024 — McMap. All rights reserved.