Me enfrento a un problema de detección de excepciones cuando el contexto es async .
Aquí está mi código reproducible mínimo
const { EventEmitter } = require('events'); const delaySync = function(ttd) { return new Promise((resolve) => { setTimeout(() => resolve(0), ttd); }); }; const myEvent = new EventEmitter(); myEvent.on('something', async () => { console.log('Event triggered'); // Just delay for 100ms and then throw await delaySync(100); throw new Error('Something happened'); }); describe('Events', () => { it('should catch error', async () => { await expect(myEvent.emit('something')).rejects.toThrow('Something happened'); }); }); Básicamente, tengo un emisor de eventos. Tiene una devolución de llamada adjunta en el evento 'algo' que es asíncrono. Hay algunos trabajos asíncronos dentro y después de 100ms de retraso arroja un error.
Normalmente detectaría tales errores en broma usando await expect(fn).rejects.toThrow(...) sin embargo, este caso es diferente porque expect fn espera una promesa y myEvent.emit('something') es un contexto normal sin promesa .
En este caso, estoy recibiendo un error.
● Events › should catch error expect(received).rejects.toThrow() Matcher error: received value must be a promise or a function returning a promise Received has type: boolean Received has value: true ... (node:20242) UnhandledPromiseRejectionWarning: Error: Something happenedLo probé con el bloque try-catch también, pero no funcionó (no pude atrapar en absoluto);
try { myEvent.emit('something'); await delaySync(250); } catch (e) { expect(e.message).toBe('Something happened'); }He intentado
// Not throwing because exception is not happening right away expect(() => myEvent.emit('something')).toThrow('Something happened');También esto
expect(async () => { // Will thow after 100ms myEvent.emit('something'); await delaySync(250); }).toThrow('Something happened');Pero no hubo suerte con ninguno de ellos. 😕
¿Alguna idea sobre cómo puedo detectar el error en este caso? o alguna solución?
El Eventemitter está completamente sync y no hay solución para ello. Lo que puede hacer es usar el módulo eventemitter2 para reemplazar la clase Eventemitter original. Es totalmente compatible con Eventemitter y le permite usar acciones async .
var EventEmitter = require('eventemitter2'); const delaySync = function (ttd) { return new Promise((resolve) => { setTimeout(() => resolve(0), ttd); }); }; const myEvent = new EventEmitter(); myEvent.on('something', async () => { console.log('Event triggered'); // Just delay for 100ms and then throw await delaySync(100); throw new Error('Something happened'); // for async emitters pass promisify true. }, { promisify: true }); describe('Events', () => { it('should catch error', async () => { await expect(myEvent.emit('something')).rejects.toThrow('Something happened'); }); }