如何让Mocha等待SSE协议Web服务返回数据后再完成测试(基于Mocha+Chai+Node.js+Express)
The issue you're seeing is because Mocha treats your test case as synchronous by default. Your test function finishes executing right after creating the EventSource instance, so Mocha marks it as passed immediately—before the onmessage callback ever runs. That's why even your obviously failing assertion (expect(false).to.equal(true)) doesn't affect the test result.
To fix this, you need to tell Mocha to wait for the asynchronous SSE message to arrive. There are two standard ways to handle async tests in Mocha: using the done callback, or returning a Promise.
Solution 1: Use the done Callback
Add the done parameter to your test function. Mocha will wait until you call done() (to signal success) or done(error) (to signal failure) before marking the test as complete.
import { expect } from 'chai'; var EventSource = require('eventsource'); describe('Connection tests', () => { it('checks for connection', (done) => { // Extend timeout if needed (Mocha defaults to 2000ms) this.timeout(5000); const source = new EventSource('http://localhost:3000/api/v1/prenotazione?subscribe=300'); // Handle incoming messages source.onmessage = (e: any) => { try { // Replace this with your actual assertion expect(e.data).to.be.a('string').and.not.be.empty; // Clean up the connection and signal test success source.close(); done(); } catch (err) { // If assertion fails, close connection and pass error to Mocha source.close(); done(err); } }; // Handle connection errors to avoid hanging tests source.onerror = (err: any) => { source.close(); done(new Error(`SSE connection failed: ${err}`)); }; }); });
Solution 2: Return a Promise
Wrap your EventSource logic in a Promise. Mocha will automatically wait for the Promise to resolve (success) or reject (failure).
import { expect } from 'chai'; var EventSource = require('eventsource'); describe('Connection tests', () => { it('checks for connection', () => { return new Promise((resolve, reject) => { const source = new EventSource('http://localhost:3000/api/v1/prenotazione?subscribe=300'); source.onmessage = (e: any) => { try { // Your actual assertion here expect(e.data).to.contain('expected-content'); source.close(); resolve(); } catch (err) { source.close(); reject(err); } }; source.onerror = (err: any) => { source.close(); reject(new Error(`SSE connection error: ${err}`)); }; // Optional: Add a timeout to prevent infinite hanging setTimeout(() => { source.close(); reject(new Error('Test timed out waiting for SSE message')); }, 5000); }); }); });
Key Notes
- Always clean up: Call
source.close()after handling the message or error to avoid leaving open connections. - Handle timeouts: If your SSE endpoint might take longer than Mocha's default 2-second timeout, use
this.timeout(ms)(with thedoneapproach) or asetTimeout(with the Promise approach) to prevent false failures. - Catch assertion errors: When using
done, wrap your assertions in atry/catchblock—otherwise, a failed assertion will throw an error that Mocha won't catch, and the test will hang indefinitely.
内容的提问来源于stack exchange,提问作者Lucio Crusca

