Just a heads up: I want to clarify that my knowledge of TypeScript and the inner workings of your application is limited, so the solutions provided below may not be plug-and-play. However, they can serve as inspiration for implementing similar tests.
I've abstracted the client code that needs testing:
// mqtt-module.js
const mqtt = require('mqtt');
const messageReceivedCallBack = require('./callbacks');
// Instead of a class, I opted for a simple function to mimic your current setup.
module.exports = {
setup() {
let client = mqtt.connect();
client.on('message', (topic, message) => {
// This section is what we aim to test.
messageReceivedCallBack.onMessageReceived(message);
});
}
}
In your existing code, it's unclear where messageReceivedCallBack
originates from. To make it accessible by Sinon, ensure it's within an importable module (though this relies on imports being cached like with require()
, which TypeScript may or may not do).
Here's a basic mock example used:
// callbacks.js
module.exports = {
onMessageReceived(message) {}
};
Now onto the actual test, which involves several steps:
- Create an
EventEmitter
subclass to substitute the original MqttClient
- Stub various functions and callbacks
- Configure the testing environment
The following snippet outlines these actions:
// test.js
const mqtt = require('mqtt');
// The aforementioned modules.
const mqttModule = require('./mqtt-module');
const messageReceivedCallBack = require('./callbacks');
// Set up Sinon and Chai
const sinon = require('sinon');
const chai = require('chai');
let expect = chai.expect;
chai.use(require('sinon-chai'));
// Create a mock client for testing purposes.
const EventEmitter = require('events').EventEmitter;
class Client extends EventEmitter {}
// Begin the test case.
describe('my test case', () => {
var mockClient;
beforeEach(() => {
mockClient = new Client();
// Stub `mqtt.connect()` to return a fake client instance facilitating event emission.
sinon.stub(mqtt, 'connect').returns(mockClient);
// Invoke the setup function of our MQTT class after stubbing `mqtt.connect()`.
mqttModule.setup();
});
afterEach(() => {
// Revert to the original function.
mqtt.connect.restore();
});
it('should invoke messageReceivedCallBack.onMessageReceived', () => {
// Define the message to pass during testing.
let message = 'this is a test message';
// Stub `messageReceivedCallBack.onMessageReceived()`.
sinon.stub(messageReceivedCallBack, 'onMessageReceived');
// Emit a `message` event on the mock client to trigger `client.on('message', ...)` in your MQTT class.
mockClient.emit('message', 'topic', message);
// Confirm that the stub was invoked with the correct argument.
expect(messageReceivedCallBack.onMessageReceived).to.be.calledWith(message);
// Restore the original function.
messageReceivedCallBack.onMessageReceived.restore();
});
});