@cuppet/core 1.2.5 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/features/app/hooks.js +16 -4
- package/features/app/managers/index.js +7 -0
- package/features/app/managers/kafkaManager.js +180 -0
- package/features/app/stepDefinitions/kafkaSteps.js +71 -0
- package/features/app/stepDefinitions/mqttSteps.js +1 -1
- package/features/tests/example-kafka.feature +16 -0
- package/index.js +4 -3
- package/package.json +4 -2
- package/src/kafkaFunctions.js +170 -0
- /package/features/app/{appiumManager.js → managers/appiumManager.js} +0 -0
- /package/features/app/{browserManager.js → managers/browserManager.js} +0 -0
- /package/features/app/{mqttManager.js → managers/mqttManager.js} +0 -0
- /package/features/tests/{mqttExample.feature → example-mqtt.feature} +0 -0
package/features/app/hooks.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
const { BeforeAll, AfterAll, Before, After, AfterStep, Status } = require('@cucumber/cucumber');
|
|
2
|
-
const BrowserManager = require('./
|
|
3
|
-
const AppiumManager = require('./appiumManager');
|
|
4
|
-
const MqttManager = require('./mqttManager');
|
|
2
|
+
const { BrowserManager, AppiumManager, MqttManager, KafkaManager } = require('./managers');
|
|
5
3
|
const fs = require('fs');
|
|
6
4
|
const config = require('config');
|
|
7
5
|
const dataStore = require('../../src/dataStorage');
|
|
@@ -68,6 +66,7 @@ Before(async function (testCase) {
|
|
|
68
66
|
const appiumTag = arrayTags.find((item) => item.name === '@appium');
|
|
69
67
|
const mqttTag = arrayTags.find((item) => item.name === '@mqtt');
|
|
70
68
|
const apiTag = arrayTags.find((item) => item.name === '@api');
|
|
69
|
+
const kafkaTag = arrayTags.find((item) => item.name === '@kafka');
|
|
71
70
|
|
|
72
71
|
// Initialize MQTT Manager if @mqtt tag is present
|
|
73
72
|
if (mqttTag) {
|
|
@@ -76,8 +75,15 @@ Before(async function (testCase) {
|
|
|
76
75
|
this.mqttManager = mqttManager;
|
|
77
76
|
}
|
|
78
77
|
|
|
78
|
+
// Initialize Kafka Manager if @kafka tag is present
|
|
79
|
+
if (kafkaTag) {
|
|
80
|
+
const kafkaManager = new KafkaManager();
|
|
81
|
+
await kafkaManager.initialize();
|
|
82
|
+
this.kafkaManager = kafkaManager;
|
|
83
|
+
}
|
|
84
|
+
|
|
79
85
|
// Initialize browser unless it's API-only or MQTT-only test
|
|
80
|
-
if (!appiumTag && !apiTag && !mqttTag) {
|
|
86
|
+
if (!appiumTag && !apiTag && !mqttTag && !kafkaTag) {
|
|
81
87
|
const browserManager = new BrowserManager(browserViewport, browserArgs, credentials);
|
|
82
88
|
await browserManager.initialize();
|
|
83
89
|
|
|
@@ -112,4 +118,10 @@ After(async function (testCase) {
|
|
|
112
118
|
} else if (this.appiumDriver) {
|
|
113
119
|
await this.appiumManager.stop();
|
|
114
120
|
}
|
|
121
|
+
|
|
122
|
+
// Cleanup Kafka connection if present
|
|
123
|
+
if (this.kafkaManager) {
|
|
124
|
+
await this.kafkaManager.stop();
|
|
125
|
+
this.kafkaManager = null;
|
|
126
|
+
}
|
|
115
127
|
});
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
const { Kafka, logLevel } = require('kafkajs');
|
|
2
|
+
const config = require('config');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* KafkaManager class for managing Kafka client lifecycle
|
|
6
|
+
* Follows the same pattern as MqttManager and BrowserManager
|
|
7
|
+
*/
|
|
8
|
+
class KafkaManager {
|
|
9
|
+
constructor(customOptions = {}) {
|
|
10
|
+
this.kafka = null;
|
|
11
|
+
this.producer = null;
|
|
12
|
+
this.consumer = null;
|
|
13
|
+
this.options = this.prepareOptions(customOptions);
|
|
14
|
+
this.isInitialized = false;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Prepare Kafka connection options from config or provided options
|
|
19
|
+
* @param {Object} customOptions - Custom options to override config
|
|
20
|
+
* @returns {Object} - Kafka connection options
|
|
21
|
+
*/
|
|
22
|
+
prepareOptions(customOptions) {
|
|
23
|
+
const defaultOptions = {
|
|
24
|
+
clientId: config.has('kafka.clientId')
|
|
25
|
+
? config.get('kafka.clientId')
|
|
26
|
+
: `cuppet-test-${Math.random().toString(16).slice(2, 8)}`,
|
|
27
|
+
brokers: config.has('kafka.brokers') ? config.get('kafka.brokers') : ['localhost:9092'],
|
|
28
|
+
connectionTimeout: config.has('kafka.connectionTimeout') ? config.get('kafka.connectionTimeout') : 5000,
|
|
29
|
+
requestTimeout: config.has('kafka.requestTimeout') ? config.get('kafka.requestTimeout') : 30000,
|
|
30
|
+
logLevel: config.has('kafka.logLevel') ? Number(config.get('kafka.logLevel')) : logLevel.ERROR,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// Add SASL authentication if provided in config
|
|
34
|
+
if (config.has('kafka.sasl')) {
|
|
35
|
+
defaultOptions.sasl = config.get('kafka.sasl');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Add SSL configuration if provided
|
|
39
|
+
if (config.has('kafka.ssl')) {
|
|
40
|
+
defaultOptions.ssl = config.get('kafka.ssl');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Merge with custom options (custom options take precedence)
|
|
44
|
+
return { ...defaultOptions, ...customOptions };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Initialize Kafka client and test connection
|
|
49
|
+
* @returns {Promise<void>}
|
|
50
|
+
*/
|
|
51
|
+
async initialize() {
|
|
52
|
+
try {
|
|
53
|
+
// Create Kafka instance
|
|
54
|
+
this.kafka = new Kafka(this.options);
|
|
55
|
+
console.log(`Successfully connected to Kafka`);
|
|
56
|
+
this.isInitialized = true;
|
|
57
|
+
} catch (error) {
|
|
58
|
+
throw new Error(`Failed to initialize Kafka client: ${error.message}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Create and connect a producer
|
|
64
|
+
* @param {Object} producerOptions - Producer configuration options
|
|
65
|
+
* @returns {Promise<Object>} - Connected producer instance
|
|
66
|
+
*/
|
|
67
|
+
async createProducer(producerOptions = {}) {
|
|
68
|
+
if (!this.isInitialized) {
|
|
69
|
+
throw new Error('Kafka client not initialized. Call initialize() first.');
|
|
70
|
+
}
|
|
71
|
+
this.producer = this.kafka.producer(producerOptions);
|
|
72
|
+
await this.producer.connect();
|
|
73
|
+
return this.producer;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Create and connect a consumer
|
|
78
|
+
* @param {Object} consumerOptions - Consumer configuration options (must include groupId)
|
|
79
|
+
* @returns {Promise<Object>} - Connected consumer instance
|
|
80
|
+
*/
|
|
81
|
+
async createConsumer(consumerOptions = {}) {
|
|
82
|
+
if (!this.isInitialized) {
|
|
83
|
+
throw new Error('Kafka client not initialized. Call initialize() first.');
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (!consumerOptions.groupId) {
|
|
87
|
+
consumerOptions.groupId = `cuppet-test-${Math.random().toString(16).slice(2, 8)}`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
this.consumer = this.kafka.consumer(consumerOptions);
|
|
91
|
+
await this.consumer.connect();
|
|
92
|
+
return this.consumer;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Check if Kafka client is initialized
|
|
97
|
+
* @returns {boolean}
|
|
98
|
+
*/
|
|
99
|
+
isReady() {
|
|
100
|
+
return this.isInitialized;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Send a message to a topic (currently only supports one message at a time)
|
|
104
|
+
* @param {string} topic - Topic to send message to
|
|
105
|
+
* @param {Object} message - Message to send. An object with key and value properties.
|
|
106
|
+
* @returns {Promise<void>}
|
|
107
|
+
*/
|
|
108
|
+
async sendMessage(topic, message = {}) {
|
|
109
|
+
if (!this.producer) {
|
|
110
|
+
await this.createProducer();
|
|
111
|
+
}
|
|
112
|
+
await this.producer.send({
|
|
113
|
+
topic,
|
|
114
|
+
messages: [message],
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Subscribe to a topic
|
|
119
|
+
* @param {Array} topics - Array of topics to subscribe to
|
|
120
|
+
* @returns {Promise<Object>} - Object with topic, partition, and message properties
|
|
121
|
+
*/
|
|
122
|
+
async subscribeToTopics(topics = []) {
|
|
123
|
+
if (!this.consumer) {
|
|
124
|
+
await this.createConsumer();
|
|
125
|
+
}
|
|
126
|
+
await this.consumer.subscribe({
|
|
127
|
+
topics: topics,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Consume a message from a topic
|
|
132
|
+
* @returns {Promise<Object>} - Object with topic, partition, and message properties
|
|
133
|
+
*/
|
|
134
|
+
async consumeMessage() {
|
|
135
|
+
return new Promise((resolve) => {
|
|
136
|
+
this.consumer.run({
|
|
137
|
+
eachMessage: async ({ topic, partition, message }) => {
|
|
138
|
+
resolve({ topic, partition, message });
|
|
139
|
+
},
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** Disconnect from all topics
|
|
145
|
+
* @returns {Promise<void>}
|
|
146
|
+
*/
|
|
147
|
+
async disconnect() {
|
|
148
|
+
await this.consumer.stop();
|
|
149
|
+
await this.consumer.disconnect();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Stop all Kafka connections and cleanup
|
|
154
|
+
* @returns {Promise<void>}
|
|
155
|
+
*/
|
|
156
|
+
async stop() {
|
|
157
|
+
const disconnectPromises = [];
|
|
158
|
+
try {
|
|
159
|
+
if (this.producer) {
|
|
160
|
+
disconnectPromises.push(this.producer.disconnect());
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (this.consumer) {
|
|
164
|
+
disconnectPromises.push(this.consumer.disconnect());
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
await Promise.all(disconnectPromises);
|
|
168
|
+
console.log('Kafka client stopped successfully');
|
|
169
|
+
} catch (error) {
|
|
170
|
+
throw new Error(`Error during Kafka client cleanup: ${error.message}`);
|
|
171
|
+
} finally {
|
|
172
|
+
this.producer = null;
|
|
173
|
+
this.consumer = null;
|
|
174
|
+
this.kafka = null;
|
|
175
|
+
this.isInitialized = false;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
module.exports = KafkaManager;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
const { Given, When, Then } = require('@cucumber/cucumber');
|
|
2
|
+
const kafkaFunctions = require('../../../src/kafkaFunctions');
|
|
3
|
+
|
|
4
|
+
Given('I subscribe to Kafka topic/topics {string}', async function (topics) {
|
|
5
|
+
await kafkaFunctions.subscribeToTopics(this.kafkaManager, topics);
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
Given('I listen for a kafka message on the subscribed topics', async function () {
|
|
9
|
+
await kafkaFunctions.listenForMessage(this.kafkaManager);
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
Given('I unsubscribe from all Kafka topics', async function () {
|
|
13
|
+
await kafkaFunctions.unsubscribeFromAllTopics(this.kafkaManager);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
Then('I should receive a kafka message with key {string} and value {string}', async function (key, value) {
|
|
17
|
+
await kafkaFunctions.validateSimpleMessage(value, key);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
Then('I should receive a kafka message with value {string}', async function (value) {
|
|
21
|
+
await kafkaFunctions.validateSimpleMessage(value);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
Then('I should receive a kafka message with property {string} and value {string}', async function (property, value) {
|
|
25
|
+
await kafkaFunctions.validateJsonMessageContains(property, value);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
Then(
|
|
29
|
+
'I should receive a kafka message with property {string} and value {string} and key {string}',
|
|
30
|
+
async function (property, value, key) {
|
|
31
|
+
await kafkaFunctions.validateJsonMessageContains(property, value, true, key);
|
|
32
|
+
}
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
Then(
|
|
36
|
+
'I should receive a kafka message with property {string} and key {string} which value does not match {string}',
|
|
37
|
+
async function (property, key, value) {
|
|
38
|
+
await kafkaFunctions.validateJsonMessageContains(property, value, false, key);
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
Then(
|
|
43
|
+
'I should receive a kafka message with property {string} which value does not match {string}',
|
|
44
|
+
async function (property, value) {
|
|
45
|
+
await kafkaFunctions.validateJsonMessageContains(property, value, false);
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
When('I send a kafka message to topic {string} with value {string}', async function (topic, message) {
|
|
50
|
+
await kafkaFunctions.sendMessage(this.kafkaManager, topic, message);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
When(
|
|
54
|
+
'I send a kafka message to topic {string} with value {string} and key {string}',
|
|
55
|
+
async function (topic, message, key) {
|
|
56
|
+
await kafkaFunctions.sendMessage(this.kafkaManager, topic, message, key);
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
When(
|
|
61
|
+
'I send a kafka message to topic {string} with key {string} and JSON value',
|
|
62
|
+
async function (topic, key, docString) {
|
|
63
|
+
const message = JSON.stringify(docString);
|
|
64
|
+
await kafkaFunctions.sendMessage(this.kafkaManager, topic, message, key);
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
When('I send a kafka message to topic {string} with JSON value', async function (topic, docString) {
|
|
69
|
+
const message = JSON.stringify(docString);
|
|
70
|
+
await kafkaFunctions.sendMessage(this.kafkaManager, topic, message);
|
|
71
|
+
});
|
|
@@ -168,7 +168,7 @@ Then('I should have received {int} messages on MQTT topic {string}', async funct
|
|
|
168
168
|
* These are not needed if using the @mqtt tag (connection is automatic)
|
|
169
169
|
*/
|
|
170
170
|
Given('I connect to MQTT broker {string}', async function (brokerUrl) {
|
|
171
|
-
const MqttManager = require('../
|
|
171
|
+
const { MqttManager } = require('../managers');
|
|
172
172
|
const mqttManager = new MqttManager(brokerUrl);
|
|
173
173
|
await mqttManager.initialize();
|
|
174
174
|
this.mqttManager = mqttManager;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
@kafka
|
|
2
|
+
Feature: Kafka Testing Examples
|
|
3
|
+
Test Kafka messaging functionality using Cucumber and kafka.js
|
|
4
|
+
|
|
5
|
+
Scenario: Simple message publish and receive
|
|
6
|
+
Given I subscribe to Kafka topic "testTopic"
|
|
7
|
+
Then I listen for a kafka message on the subscribed topics
|
|
8
|
+
Then I should receive a kafka message with property "message" and value "test"
|
|
9
|
+
And I unsubscribe from all Kafka topics
|
|
10
|
+
When I send a kafka message to topic "testTopic" with JSON value
|
|
11
|
+
"""
|
|
12
|
+
{
|
|
13
|
+
"message": "test3"
|
|
14
|
+
}
|
|
15
|
+
"""
|
|
16
|
+
|
package/index.js
CHANGED
|
@@ -12,11 +12,10 @@ const appiumTesting = require('./src/appiumTesting');
|
|
|
12
12
|
const accessibilityTesting = require('./src/accessibilityTesting');
|
|
13
13
|
const lighthouse = require('./src/lighthouse');
|
|
14
14
|
const visualRegression = require('./src/visualRegression');
|
|
15
|
+
const kafkaFunctions = require('./src/kafkaFunctions');
|
|
15
16
|
|
|
16
17
|
// Export managers
|
|
17
|
-
const BrowserManager = require('./features/app/
|
|
18
|
-
const AppiumManager = require('./features/app/appiumManager');
|
|
19
|
-
const MqttManager = require('./features/app/mqttManager');
|
|
18
|
+
const { BrowserManager, AppiumManager, MqttManager, KafkaManager } = require('./features/app/managers');
|
|
20
19
|
|
|
21
20
|
// Export step definitions
|
|
22
21
|
const stepDefinitions = require('./stepDefinitions');
|
|
@@ -29,6 +28,7 @@ module.exports = {
|
|
|
29
28
|
helperFunctions,
|
|
30
29
|
apiFunctions,
|
|
31
30
|
mqttFunctions,
|
|
31
|
+
kafkaFunctions,
|
|
32
32
|
appiumTesting,
|
|
33
33
|
accessibilityTesting,
|
|
34
34
|
lighthouse,
|
|
@@ -38,6 +38,7 @@ module.exports = {
|
|
|
38
38
|
BrowserManager,
|
|
39
39
|
AppiumManager,
|
|
40
40
|
MqttManager,
|
|
41
|
+
KafkaManager,
|
|
41
42
|
|
|
42
43
|
// Step definitions
|
|
43
44
|
stepDefinitions,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cuppet/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Core testing framework components for Cuppet - BDD framework based on Cucumber and Puppeteer",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"axios": "^1.11.0",
|
|
37
37
|
"backstopjs": "^6.3.25",
|
|
38
38
|
"chai": "6.0.1",
|
|
39
|
+
"kafkajs": "^2.2.4",
|
|
39
40
|
"lighthouse": "^12.8.0",
|
|
40
41
|
"mime": "^3.0.0",
|
|
41
42
|
"mime-types": "^3.0.1",
|
|
@@ -65,10 +66,11 @@
|
|
|
65
66
|
},
|
|
66
67
|
"scripts": {
|
|
67
68
|
"test": "cucumber-js features/tests/example.feature",
|
|
69
|
+
"run:kafka": "cucumber-js features/tests/example-kafka.feature",
|
|
68
70
|
"run:visual": "cucumber-js features/tests/example-visual-test.feature",
|
|
69
71
|
"run:pa11y": "cucumber-js features/tests/example-pa11y.feature",
|
|
70
72
|
"run:lighthouse": "cucumber-js features/tests/example-lighthouse.feature",
|
|
71
|
-
"run:mqtt": "cucumber-js features/tests/
|
|
73
|
+
"run:mqtt": "cucumber-js features/tests/example-mqtt.feature",
|
|
72
74
|
"run:mobile": "cucumber-js features/tests/example-mobile.feature",
|
|
73
75
|
"run:accessibility": "cucumber-js features/tests/example-accessibility.feature",
|
|
74
76
|
"run:performance": "cucumber-js features/tests/example-performance.feature",
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
const storage = require('./dataStorage');
|
|
2
|
+
const assert = require('chai').assert;
|
|
3
|
+
const helperFunctions = require('./helperFunctions');
|
|
4
|
+
|
|
5
|
+
module.exports = {
|
|
6
|
+
/** @type {Object} */
|
|
7
|
+
messageObject: null,
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Subscribe to a topic
|
|
11
|
+
* @param {object} kafkaManager - Kafka manager instance
|
|
12
|
+
* @param {string} topics - String, comma separated list of topics to subscribe to
|
|
13
|
+
* @returns {Promise<void>}
|
|
14
|
+
*/
|
|
15
|
+
subscribeToTopics: async function (kafkaManager, topics) {
|
|
16
|
+
const resolvedTopics = await this.prepareTopics(topics);
|
|
17
|
+
const topicsArray = resolvedTopics.split(',');
|
|
18
|
+
await kafkaManager.subscribeToTopics(topicsArray);
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Listen for a message on the subscribed topics
|
|
23
|
+
* @param {object} kafkaManager - Kafka manager instance
|
|
24
|
+
* @returns {Promise<void>}
|
|
25
|
+
*/
|
|
26
|
+
listenForMessage: async function (kafkaManager) {
|
|
27
|
+
this.messageObject = await kafkaManager.consumeMessage();
|
|
28
|
+
return this.messageObject;
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Disconnect from all topics
|
|
33
|
+
* @param {object} kafkaManager - Kafka manager instance
|
|
34
|
+
* @returns {Promise<void>}
|
|
35
|
+
*/
|
|
36
|
+
unsubscribeFromAllTopics: async function (kafkaManager) {
|
|
37
|
+
await kafkaManager.disconnect();
|
|
38
|
+
delete this.messageObject;
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Prepare topic by replacing variables
|
|
43
|
+
* @param {string} topic - Topic with potential variables
|
|
44
|
+
* @returns {Promise<string>} - Resolved topic
|
|
45
|
+
*/
|
|
46
|
+
prepareTopics: async function (topics) {
|
|
47
|
+
return await storage.checkForMultipleVariables(topics);
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Prepare message by replacing variables
|
|
52
|
+
* @param {string} message - Message with potential variables
|
|
53
|
+
* @returns {Promise<Object>} - Resolved message as JSON object
|
|
54
|
+
*/
|
|
55
|
+
prepareMessage: async function (message) {
|
|
56
|
+
const resolvedMessage = await storage.checkForMultipleVariables(message);
|
|
57
|
+
try {
|
|
58
|
+
const jsonObject = JSON.parse(resolvedMessage);
|
|
59
|
+
return jsonObject;
|
|
60
|
+
} catch {
|
|
61
|
+
// If the message is not a valid JSON object, return it as a string
|
|
62
|
+
return resolvedMessage;
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Validate that the message key equals the expected value
|
|
68
|
+
* @param {string} key - Key to validate
|
|
69
|
+
* @returns {Promise<void>}
|
|
70
|
+
*/
|
|
71
|
+
validateMessageKeyEquals: async function (key) {
|
|
72
|
+
const resolvedKey = await storage.checkForSavedVariable(key);
|
|
73
|
+
const messageKey = this.messageObject?.key?.toString();
|
|
74
|
+
if (!messageKey) {
|
|
75
|
+
throw new Error(`Message key is not present in the message object`);
|
|
76
|
+
}
|
|
77
|
+
assert.strictEqual(
|
|
78
|
+
messageKey,
|
|
79
|
+
resolvedKey,
|
|
80
|
+
`Message key does not match. Expected: ${resolvedKey}, Actual: ${messageKey}`
|
|
81
|
+
);
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Validate that the message object has a value property containing the actual message
|
|
86
|
+
* @returns {Promise<string>} - Message value
|
|
87
|
+
*/
|
|
88
|
+
validateMessageHasValue: function () {
|
|
89
|
+
const messageValue = this.messageObject?.message?.value?.toString();
|
|
90
|
+
if (!messageValue) {
|
|
91
|
+
throw new Error(`Message value is not present in the message object`);
|
|
92
|
+
}
|
|
93
|
+
return messageValue;
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Read the message from the message object
|
|
98
|
+
* @param {string} key - Key to validate
|
|
99
|
+
* @param {string} value - Value to validate
|
|
100
|
+
* @returns {Promise<void>}
|
|
101
|
+
*/
|
|
102
|
+
validateSimpleMessage: async function (value, key = null) {
|
|
103
|
+
if (key) {
|
|
104
|
+
await this.validateMessageKeyEquals(key);
|
|
105
|
+
}
|
|
106
|
+
const resolvedValue = await storage.checkForMultipleVariables(value);
|
|
107
|
+
const messageValue = this.validateMessageHasValue();
|
|
108
|
+
assert.strictEqual(
|
|
109
|
+
messageValue,
|
|
110
|
+
resolvedValue,
|
|
111
|
+
`Message does not match. Expected: ${resolvedValue}, Actual: ${messageValue}`
|
|
112
|
+
);
|
|
113
|
+
},
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Validate that a JSON message contains a property with a specific value
|
|
117
|
+
* @param {string} property - Property path to validate (e.g., "eventType" or "payload.metadata.userId")
|
|
118
|
+
* @param {string} value - Expected value (or null to just check property exists)
|
|
119
|
+
* @param {boolean} contains - Whether the property should match (true) or NOT match (false) the value
|
|
120
|
+
* @param {string} key - Key to validate (optional)
|
|
121
|
+
* @returns {Promise<void>}
|
|
122
|
+
*/
|
|
123
|
+
validateJsonMessageContains: async function (property, value, contains = true, key = null) {
|
|
124
|
+
if (key) {
|
|
125
|
+
await this.validateMessageKeyEquals(key);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const messageValue = this.validateMessageHasValue();
|
|
129
|
+
// Parse the message value to a JSON object
|
|
130
|
+
let jsonData;
|
|
131
|
+
try {
|
|
132
|
+
jsonData = JSON.parse(messageValue);
|
|
133
|
+
} catch (error) {
|
|
134
|
+
throw new Error(`The message value is not a valid JSON object: ${error.message}`);
|
|
135
|
+
}
|
|
136
|
+
// Get the property value using helperFunctions (handles nested properties)
|
|
137
|
+
const actualValue = helperFunctions.getPropertyValue(jsonData, property);
|
|
138
|
+
const resolvedValue = await storage.checkForMultipleVariables(value);
|
|
139
|
+
|
|
140
|
+
if (contains) {
|
|
141
|
+
assert.strictEqual(
|
|
142
|
+
actualValue?.toString(),
|
|
143
|
+
resolvedValue,
|
|
144
|
+
`Value of property "${property}" does not match. Expected: ${resolvedValue}, Actual: ${actualValue}`
|
|
145
|
+
);
|
|
146
|
+
} else {
|
|
147
|
+
assert.notStrictEqual(
|
|
148
|
+
actualValue?.toString(),
|
|
149
|
+
resolvedValue,
|
|
150
|
+
`Value of property "${property}" should NOT match but it does. Value: ${resolvedValue}`
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Send a message to a topic
|
|
157
|
+
* @param {object} kafkaManager - Kafka manager instance
|
|
158
|
+
* @param {string} topic - Topic to send message to
|
|
159
|
+
* @param {object|string} message - Message to send. Can be a JSON object or a string.
|
|
160
|
+
* @returns {Promise<void>}
|
|
161
|
+
*/
|
|
162
|
+
sendMessage: async function (kafkaManager, topic, message, key = null) {
|
|
163
|
+
const resolvedMessage = await this.prepareMessage(message);
|
|
164
|
+
const messageObject = {
|
|
165
|
+
...(key && { key: await storage.checkForSavedVariable(key) }),
|
|
166
|
+
value: typeof resolvedMessage === 'object' ? JSON.stringify(resolvedMessage) : resolvedMessage,
|
|
167
|
+
};
|
|
168
|
+
await kafkaManager.sendMessage(topic, messageObject);
|
|
169
|
+
},
|
|
170
|
+
};
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|