@cuppet/core
Version:
Core testing framework components for Cuppet - BDD framework based on Cucumber and Puppeteer
309 lines (283 loc) • 12.6 kB
JavaScript
const assert = require('chai').assert;
const storage = require('./dataStorage');
const helper = require('./helperFunctions');
/**
* MQTT Functions Module
* Provides core MQTT testing operations following the same pattern as Puppeteer and Appium functions
*/
module.exports = {
/** @type {string} */
messageString: null,
/**
* Prepare topic by replacing variables
* @param {string} topic - Topic with potential variables
* @returns {Promise<string>} - Resolved topic
*/
prepareTopic: async function (topic) {
return await storage.checkForMultipleVariables(topic);
},
/**
* Prepare message by replacing variables
* @param {string} message - Message with potential variables
* @returns {Promise<string>} - Resolved message
*/
prepareMessage: async function (message, json = false) {
const resolvedMessage = await storage.checkForMultipleVariables(message);
if (json) {
try {
// Validate JSON (do not assign the value to the message object)
JSON.parse(resolvedMessage);
// Pass it as a string
this.messageString = resolvedMessage;
return this.messageString;
} catch (error) {
throw new Error(`Invalid JSON message: ${error.message}`);
}
}
return resolvedMessage;
},
/**
* Subscribe to a topic
* @param {object} mqttManager - MQTT manager instance
* @param {string} topic - Topic to subscribe to
* @param {number} qos - Quality of Service level (0, 1, or 2)
* @returns {Promise<void>}
*/
subscribeToTopic: async function (mqttManager, topic, qos = 0) {
const resolvedTopic = await this.prepareTopic(topic);
await mqttManager.subscribe(resolvedTopic, { qos });
},
/**
* Unsubscribe from a topic
* @param {object} mqttManager - MQTT manager instance
* @param {string} topic - Topic to unsubscribe from
* @returns {Promise<void>}
*/
unsubscribeFromTopic: async function (mqttManager, topic) {
const resolvedTopic = await this.prepareTopic(topic);
await mqttManager.unsubscribe(resolvedTopic);
},
/**
* Publish a message to a topic
* @param {object} mqttManager - MQTT manager instance
* @param {string} message - Message to publish
* @param {string} topic - Topic to publish to
* @param {number} qos - Quality of Service level (0, 1, or 2)
* @param {boolean} retain - Whether to retain the message
* @returns {Promise<void>}
*/
publishMessage: async function (mqttManager, message, topic, qos = 0, retain = false) {
const resolvedTopic = await this.prepareTopic(topic);
const resolvedMessage = await this.prepareMessage(message);
await mqttManager.publish(resolvedTopic, resolvedMessage, { qos, retain });
},
/**
* Publish a JSON message to a topic
* @param {object} mqttManager - MQTT manager instance
* @param {string} topic - Topic to publish to
* @param {string} jsonString - JSON string to publish
* @param {number} qos - Quality of Service level
* @param {boolean} retain - Whether to retain the message
* @returns {Promise<void>}
*/
publishJsonMessage: async function (mqttManager, topic, jsonString = null, qos = 0, retain = false) {
const resolvedTopic = await this.prepareTopic(topic);
const resolvedJson = jsonString ? await this.prepareMessage(jsonString, true) : this.messageString;
// Delete the message object before the message is published to avoid conflicts if the request fails.
delete this.messageString;
await mqttManager.publish(resolvedTopic, resolvedJson, { qos, retain });
},
/**
* Wait for a message on a specific topic
* @param {object} mqttManager - MQTT manager instance
* @param {string} topic - Topic to wait for message on
* @param {number} timeoutSeconds - Timeout in seconds
* @returns {Promise<Object>} - Message object
*/
waitForMessage: async function (mqttManager, topic, timeoutSeconds = 10) {
const resolvedTopic = await this.prepareTopic(topic);
return await mqttManager.waitForMessage(resolvedTopic, timeoutSeconds);
},
/**
* Wait for a specific message on a topic with timeout
* @param {object} mqttManager - MQTT manager instance
* @param {string} topic - Topic to wait for message on
* @param {string} message - Message to wait for
* @param {number} timeoutSeconds - Timeout in seconds
* @returns {Promise<Object>} - Message object
*/
waitForSpecificMessage: async function (mqttManager, topic, message, timeoutSeconds = 10) {
const resolvedTopic = await this.prepareTopic(topic);
const resolvedMessage = await this.prepareMessage(message);
return await mqttManager.waitForSpecificMessage(resolvedTopic, resolvedMessage, timeoutSeconds);
},
/**
* Get the latest message from a topic
* @param {object} mqttManager - MQTT manager instance
* @param {string} topic - Topic to get message from
* @returns {Promise<Object>} - Latest message object
*/
getLatestMessage: async function (mqttManager, topic) {
const resolvedTopic = await this.prepareTopic(topic);
const message = mqttManager.getLatestMessage(resolvedTopic);
if (!message) {
throw new Error(`No messages received on topic: ${resolvedTopic}`);
}
return message;
},
/**
* Parse message as JSON
* @param {Object} messageObj - Message object from buffer
* @returns {Object} - Parsed JSON object
*/
parseMessageAsJson: function (messageObj) {
try {
return JSON.parse(messageObj.message);
} catch (error) {
throw new Error(`Failed to parse message as JSON: ${error.message}`);
}
},
/**
* Validate that a message was received on a topic
* @param {object} mqttManager - MQTT manager instance
* @param {string} topic - Topic to check
* @param {number} timeoutSeconds - Timeout in seconds
* @returns {Promise<Object>} - Message object
*/
validateMessageReceived: async function (mqttManager, topic, timeoutSeconds = 10) {
const message = await this.waitForMessage(mqttManager, topic, timeoutSeconds);
assert.isDefined(message, `No message received on topic: ${topic}`);
return message;
},
/**
* Validate message content equals expected value
* @param {object} mqttManager - MQTT manager instance
* @param {string} topic - Topic to check message on
* @param {string} expectedContent - Expected message content
* @returns {Promise<void>}
*/
validateMessageContent: async function (mqttManager, topic, expectedContent) {
const resolvedExpected = await storage.checkForSavedVariable(expectedContent);
const message = await this.getLatestMessage(mqttManager, topic);
assert.strictEqual(
message.message,
resolvedExpected,
`Message content does not match. Expected: ${resolvedExpected}, Actual: ${message.message}`
);
},
/**
* Validate message contains a substring
* @param {object} mqttManager - MQTT manager instance
* @param {string} topic - Topic to check message on
* @param {string} substring - Substring to search for
* @returns {Promise<void>}
*/
validateMessageContains: async function (mqttManager, topic, substring) {
const resolvedSubstring = await storage.checkForSavedVariable(substring);
const message = await this.getLatestMessage(mqttManager, topic);
assert.include(
message.message,
resolvedSubstring,
`Message does not contain expected substring: ${resolvedSubstring}`
);
},
/**
* Validate JSON message property has expected value
* @param {object} mqttManager - MQTT manager instance
* @param {string} topic - Topic to get message from
* @param {string} property - Property path (e.g., "data.temperature")
* @param {string} expectedValue - Expected value
* @returns {Promise<void>}
*/
validateJsonProperty: async function (mqttManager, topic, property, expectedValue) {
let resolvedExpected = await storage.checkForSavedVariable(expectedValue);
resolvedExpected = helper.castPrimitiveType(resolvedExpected);
const message = await this.getLatestMessage(mqttManager, topic);
const jsonData = this.parseMessageAsJson(message);
const value = helper.getPropertyValue(jsonData, property);
assert.strictEqual(
value,
resolvedExpected,
`The value of the property "${property}" does not match: Expected: ${resolvedExpected}, Actual: ${value}`
);
},
/**
* Validate JSON message property type
* @param {object} mqttManager - MQTT manager instance
* @param {string} topic - Topic to get message from
* @param {string} property - Property path
* @param {string} type - Expected type (string, number, boolean, object, array)
* @returns {Promise<void>}
*/
validateJsonPropertyType: async function (mqttManager, topic, property, type) {
const message = await this.getLatestMessage(mqttManager, topic);
const jsonData = this.parseMessageAsJson(message);
const value = helper.getPropertyValue(jsonData, property);
assert.typeOf(value, type, `Property "${property}" is not of type ${type}`);
},
/**
* Remember a property value from JSON message
* @param {object} mqttManager - MQTT manager instance
* @param {string} topic - Topic to get message from
* @param {string} property - Property path
* @param {string} variableName - Variable name to store value
* @returns {Promise<void>}
*/
rememberJsonProperty: async function (mqttManager, topic, property, variableName) {
const message = await this.getLatestMessage(mqttManager, topic);
const jsonData = this.parseMessageAsJson(message);
const value = helper.getPropertyValue(jsonData, property);
await storage.iStoreVariableWithValueToTheJsonFile(value, variableName);
},
/**
* Remember the entire message content
* @param {object} mqttManager - MQTT manager instance
* @param {string} topic - Topic to get message from
* @param {string} variableName - Variable name to store message
* @returns {Promise<void>}
*/
rememberMessage: async function (mqttManager, topic, variableName) {
const message = await this.getLatestMessage(mqttManager, topic);
await storage.iStoreVariableWithValueToTheJsonFile(message.message, variableName);
},
/**
* Clear message buffer for a topic
* @param {object} mqttManager - MQTT manager instance
* @param {string} topic - Topic to clear buffer for (or null for all)
* @returns {Promise<void>}
*/
clearMessageBuffer: async function (mqttManager, topic = null) {
if (topic) {
const resolvedTopic = await this.prepareTopic(topic);
mqttManager.clearMessageBuffer(resolvedTopic);
} else {
mqttManager.clearMessageBuffer();
}
},
/**
* Get message count for a topic
* @param {object} mqttManager - MQTT manager instance
* @param {string} topic - Topic to get message count for
* @returns {Promise<number>} - Number of messages
*/
getMessageCount: async function (mqttManager, topic) {
const resolvedTopic = await this.prepareTopic(topic);
return (await mqttManager.getMessages(resolvedTopic)).length;
},
/**
* Validate message count on a topic
* @param {object} mqttManager - MQTT manager instance
* @param {string} topic - Topic to check
* @param {number} expectedCount - Expected number of messages
* @returns {Promise<void>}
*/
validateMessageCount: async function (mqttManager, topic, expectedCount) {
const resolvedTopic = await this.prepareTopic(topic);
const actualCount = await this.getMessageCount(mqttManager, resolvedTopic);
assert.strictEqual(
actualCount,
expectedCount,
`Expected ${expectedCount} messages on topic "${topic}", but found ${actualCount}`
);
},
};