My setup uses chai, sinon, chai-sinon, chai-as-promised, babel and es6 syntax.
I have the following (reduced) code
// example.js
'use strict';
import EventEmitter from 'events';
class Dispatcher extends EventEmitter {
send(x) {
doSomethingAsync() // promise is NOT returned
.then(() => {
this.emit('sent');
})
.catch((err) => {
this.emit('error', err);
});
}
}
Note: the promise from doSomethingAsync is NOT returned. (And never will be)
Here's my (reduced) test file
let dispatcher;
let onSent;
let onError;
beforeEach(() => {
dispatcher = new Dispatcher();
onSent = sinon.stub();
onError= sinon.stub();
dispatcher.on('sent', onSent);
dispatcher.on('error', onError);
});
describe('send', () => {
it('should emit "error" on sendFn error instead of "sent"', () => {
... set up state for failure ...
dispatcher.send(...);
... What do I do here or how do I wrap the following? ...
expect(onSent).not.to.have.been.called;
expect(onError).to.have.been.called;
});
});
I know how to do this if I could return the promise from doSomethingAsync as the result of send, but that's not the case here. All I have is the knowledge that either the 'sent' or 'error' event will be emitted eventually.
My ideal syntax would look like:
expect(onError).to.eventually.have
But, that doesn't work. I CAN get a non-erroring version to work as follows simply by wrapping the expect in a new promise. But I have no idea why this works.
// This one works for some unknown reason!
it('should emit "send" on send success', () => {
... set up state for success ...
dispatcher.send(...);
return Promise.resolve().then(() => {
expect(onSent).to.have.been.called;
expect(onError).not.to.have.been.called;
});
});
If I could refactor the code in such a way as to expose the inner promise, then this would be trivial to solve. I have done so countless times in other circumstances. My question here however is very specifically how to solve this exact pattern; i.e. how to test the side-effects of an inaccessible promise or async code, particularly around event emitters when I cannot refactor the code to expose the promise.
I have tried at least the following just to see if I could trigger the desired send function to complete all its inner callbacks/promises before the test calls the expectations * wrapping the expectations in a promise * controlling time using sinon.useFakeTimers * wrapping the expectations in a timeout * wrapping both send call and expectations in various async/await patterns
Thanks in advance! You're really helping me out.
Aucun commentaire:
Enregistrer un commentaire