How do I stub an event emitter with Sinon.js
Asked Answered
W

3

15

I am trying to stub the following:

on('complete', function(data){ });

I only want to call the callback if the first parameter is 'complete'.

The function I am testing also contains:

on('error', function(data){ });

So I can't just do yield cause that will fire both the complete and the error callback.

If I wouldn't use sinon I would fake it by writing the following.

var on = function(event, callback){
  if (event === 'complete'){
    callback('foobar');
  };
};
Warrigal answered 14/5, 2012 at 17:23 Comment(1)
Can you show a more full example of the function containing this?Unconsidered
A
9

You can narrow the circumstances under which a yield occurs by combining it with a withArgs like so...

on.withArgs('complete').yields(valueToPassToCompleteCallback);
on.withArgs('error').yields(valueToPassToErrorCallback);
Atwater answered 24/7, 2015 at 14:57 Comment(0)
B
0

Maybe you can use a spyCall:

var spy = sinon.spy(window, 'on');
on('error', function(data){ });
on('complete', function(data){ });
for(var i=0; i < spy.callCount; i++){
    var call = spy.getCall(i);
    if(call.args[0] === 'complete') call.args[1]('foobar');
}
Bathsheb answered 15/5, 2012 at 20:19 Comment(0)
O
0

Events

  • The best approach is to simply outsource your callback of your event into a own method that you can easily export it and write unit tests for this method.
    • Then you only write 1x unit tests which makes sure that the correct callback function is called.





Stub Service Event with Event Emitter

  • Stub the event in your service with an event emitter which you are emitting in your test. This is how you can trigger your callback in this case getNewPairsEventHandler()
    • getNewPairsEventHandler() in this case is a class method which can be easily stubbed or spyed with sinon if needed.

service.ts:

private getNewPairsEventHandler() {
    return async(event: pairEvent) => {
       //...
    }
}

// Listen for new pairs
public async getNewPairs() {
    const newPairsEvent = await this.uniswapPairCreatedFactory.events.PairCreated()

    newPairsEvent.on('data', this.getNewPairsEventHandler())

    newPairsEvent.on('error', (e: Error) => {
        throw new BaseError('Error fetching new pairs', e)
    })
}

test.ts:

  describe('[SUCCESS]', () => {
      let uniswapPairCreatedFactoryStub: sinon.SinonStub
      let eventHandlerFn: any
      let newPairsEvent: EventEmitter
      let uniswapPairCreatedFactoryStub: sinon.SinonStub

      const expectedEventArgs = {
            returnValues: { token0, token1, pair }
        }

      beforeEach(() => {
          eventHandlerFn = (<any>ethCoinManager.contract).getNewPairsEventHandler()

          newPairsEvent = new EventEmitter()

          uniswapPairCreatedFactoryStub = sinon.stub(
              ethCoinManager.contract.uniswapPairCreatedFactory.events, 'PairCreated'
          ).resolves(newPairsEvent)
      })    

      afterEach(() => {
          uniswapPairCreatedFactoryStub.restore()
      })
  
      it.only('should listen for new pair events and save them to the database', async() => {
          await getNewPairs()

          await new Promise(resolve => {
              newPairsEvent.once('data', () => {
                  resolve(true)
              })
        
              newPairsEvent.emit('data', expectedEventArgs)
          })

          expect(anythinghere)
      })
  })





Stub Service Event with Event Emitter and throw Error

  • Same idea like above Stub Service Event with Event Emitter
    • However, in this example we will trigger the error Event. It is just a callback with a catch of the error and then pass it to a custom error logger.

service.ts

// Listen for new pairs
public async getNewPairs() {
    const newPairsEvent = await this.uniswapPairCreatedFactory.events.PairCreated()

    newPairsEvent.on('data', this.getNewPairsEventHandler())

    newPairsEvent.on('error', (e: Error) => {
        throw new BaseError('Error fetching new pairs', e)
    })
}

test.js

describe('[newPairsEvent]', () => {
    let newPairsEvent: EventEmitter
    let uniswapPairCreatedFactoryStub: sinon.SinonStub

    const errorMessage = 'Test error'

    beforeEach(() => {
        newPairsEvent = new EventEmitter()

        uniswapPairCreatedFactoryStub = sinon.stub(
            ethCoinManager.contract.uniswapPairCreatedFactory.events, 'PairCreated'
        ).resolves(newPairsEvent)
    })    

    afterEach(() => {
        uniswapPairCreatedFactoryStub.restore()
    })

    it('should throw an error if there is an error fetching new pairs', async() => {
        await ethCoinManager.contract.getNewPairs()

        try {
            newPairsEvent.emit('error', new Error(errorMessage))
            expect(true).toBe(false)
        } catch (e: any) {
            expect(e.name).toBe('BaseError')
            expect(e.message).toBe('Error fetching new pairs')
            expect(e.httpStatus).toBe(500)
            expect(e.e.message).toBe(errorMessage)
        }
    })
})
Oceangoing answered 18/7 at 22:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.