@mojaloop/ml-testing-toolkit-client-lib 1.8.0-snapshot.1 → 1.8.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/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ## [1.8.0](https://github.com/mojaloop/ml-testing-toolkit-client-lib/compare/v1.7.0...v1.8.0) (2025-03-17)
6
+
7
+
8
+ ### Features
9
+
10
+ * **csi-1309:** added notifications for failed tests only ([#21](https://github.com/mojaloop/ml-testing-toolkit-client-lib/issues/21)) ([6bf47f7](https://github.com/mojaloop/ml-testing-toolkit-client-lib/commit/6bf47f7e39ab76d954b0dc818e53dd7aaeb0b9f7))
11
+
5
12
  ## [1.7.0](https://github.com/mojaloop/ml-testing-toolkit-client-lib/compare/v1.6.1...v1.7.0) (2025-03-13)
6
13
 
7
14
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mojaloop/ml-testing-toolkit-client-lib",
3
3
  "description": "Testing Toolkit Client Library",
4
- "version": "1.8.0-snapshot.1",
4
+ "version": "1.8.0",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Vijaya Kumar Guthi, ModusBox Inc. ",
7
7
  "contributors": [
@@ -38,6 +38,10 @@ const millisecondsToTime = (milliseconds) => {
38
38
  return `${String(hours).padStart(2, '0')}:${String(minutes % 60).padStart(2, '0')}:${String(seconds % 60).padStart(2, '0')}`
39
39
  }
40
40
 
41
+ /**
42
+ * @param {FinalReport} progress
43
+ * @param {string} reportURL - URL of the report
44
+ */
41
45
  const generateSlackBlocks = (progress, reportURL) => {
42
46
  const slackBlocks = []
43
47
  let totalAssertionsCount = 0
@@ -88,10 +92,10 @@ const generateSlackBlocks = (progress, reportURL) => {
88
92
  text: [
89
93
  `${totalAssertionsCount === totalPassedAssertionsCount ? '🟢' : '🔴'}`,
90
94
  reportURL ? `<${reportURL}|${config.briefSummaryPrefix}>` : `${config.briefSummaryPrefix}`,
95
+ `tests: \`${progress.test_cases.length}\`,`,
96
+ `requests: \`${totalRequestsCount}\`,`,
91
97
  `failed: \`${totalAssertionsCount - totalPassedAssertionsCount}/${totalAssertionsCount}`,
92
98
  `(${(100 * ((totalAssertionsCount - totalPassedAssertionsCount) / totalAssertionsCount)).toFixed(2)}%)\`,`,
93
- `requests: \`${totalRequestsCount}\`,`,
94
- `tests: \`${progress.test_cases.length}\`,`,
95
99
  `duration: \`${millisecondsToTime(progress.runtimeInformation.runDurationMs)}\``,
96
100
  top5FailedTestCases.length > 0 && '\nTop 5 failed test cases:\n',
97
101
  top5FailedTestCases.length > 0 && top5FailedTestCases.map(tc => `• ${tc.name}: \`${tc.failedAssertions}\``).join('\n')
@@ -170,53 +174,52 @@ const generateSlackBlocks = (progress, reportURL) => {
170
174
  return slackBlocks
171
175
  }
172
176
 
177
+ /**
178
+ * @param {FinalReport} progress
179
+ * @param {string} reportURL - URL of the report
180
+ */
173
181
  const sendSlackNotification = async (progress, reportURL = 'http://localhost/') => {
174
- console.log('runtimeInformation: ', progress.runtimeInformation)
175
-
176
- let blocks
177
- if (config.slackWebhookUrl) {
178
- const url = config.slackWebhookUrl
179
- const webhook = new IncomingWebhook(url)
180
- blocks = generateSlackBlocks(progress, reportURL)
181
-
182
- try {
183
- // console.log(JSON.stringify(slackBlocks, null, 2))
184
- await webhook.send({
185
- text: 'Test Report',
186
- blocks
187
- })
188
- console.log('Slack notification sent.')
189
- } catch (err) {
190
- console.log('ERROR: Sending slack notification failed. ', err.message)
191
- }
182
+ const { slackWebhookUrl, slackWebhookUrlForFailed } = config
183
+
184
+ if (!slackWebhookUrl && !needToNotifyFailed(slackWebhookUrlForFailed, progress)) {
185
+ console.log('No Slack webhook URLs configured.')
186
+ return
192
187
  }
188
+ const blocks = generateSlackBlocks(progress, reportURL)
193
189
 
194
- if (needToNotifyFailed(config, progress)) {
195
- const url = config.slackWebhookUrlForFailed
196
- const webhook = new IncomingWebhook(url)
190
+ if (slackWebhookUrl) {
191
+ await sendWebhook(slackWebhookUrl, 'Test Report', blocks)
192
+ }
197
193
 
198
- if (!blocks) blocks = generateSlackBlocks(progress, reportURL)
194
+ if (needToNotifyFailed(slackWebhookUrlForFailed, progress)) {
195
+ await sendWebhook(slackWebhookUrlForFailed, 'Failed Tests Report', blocks)
196
+ }
197
+ }
199
198
 
200
- try {
201
- // console.log(JSON.stringify(slackBlocks, null, 2))
202
- await webhook.send({
203
- text: 'Failed Tests Report',
204
- blocks
205
- })
206
- console.log('Slack notification sent.')
207
- } catch (err) {
208
- console.log('ERROR: Sending slack notification failed. ', err.message)
209
- }
199
+ const sendWebhook = async (url, text, blocks) => {
200
+ const webhook = new IncomingWebhook(url)
201
+ try {
202
+ await webhook.send({ text, blocks })
203
+ console.log('Slack notification sent.')
204
+ } catch (err) {
205
+ console.log('ERROR: Sending Slack notification failed. ', err.message)
210
206
  }
211
207
  }
212
208
 
213
- const needToNotifyFailed = (conf, totalResult) => {
214
- return conf.slackWebhookUrlForFailed && (!totalResult?.runtimeInformation?.totalAssertions
209
+ /**
210
+ * Determines if a notification for failed tests needs to be sent.
211
+ * @param {string | undefined} webhookUrl
212
+ * @param {FinalReport} progress
213
+ * @returns {boolean}
214
+ */
215
+ const needToNotifyFailed = (webhookUrl, progress) => {
216
+ return webhookUrl && (!progress?.runtimeInformation?.totalAssertions
215
217
  ? true
216
- : totalResult.runtimeInformation.totalPassedAssertions !== totalResult.runtimeInformation.totalAssertions)
218
+ : progress.runtimeInformation.totalPassedAssertions !== progress.runtimeInformation.totalAssertions)
217
219
  }
218
220
 
219
221
  module.exports = {
220
222
  sendSlackNotification,
223
+ sendWebhook,
221
224
  needToNotifyFailed
222
225
  }
@@ -180,6 +180,36 @@ const sendTemplate = async (sessionId) => {
180
180
  }
181
181
  }
182
182
 
183
+ /**
184
+ * Consolidated final report, created by generateFinalReport function (ml-testing-toolkit repo).
185
+ * @typedef {Object} FinalReport
186
+ * @property {RuntimeInformation} runtimeInformation - Provides metadata about the runtime environment or execution context.
187
+ * @property {Array<Object>} test_cases - An array of objects where each object represents a test case and its results.
188
+ * @property {string} status
189
+ * @property {Object} totalResult
190
+ * @property {Object} saveReportStatus
191
+ * @property {unknown} [otherFields] - see ml-testing-toolkit repo.
192
+ */
193
+
194
+ /**
195
+ * @typedef {Object} RuntimeInformation
196
+ * @property {string} testReportId - Test report ID
197
+ * @property {string} completedTimeISO - Completed time in ISO format
198
+ * @property {string} startedTime - Started time in readable format
199
+ * @property {string} completedTime - Completed time in readable format
200
+ * @property {string} completedTimeUTC - Completed time in UTC format
201
+ * @property {number} startedTS - Started timestamp
202
+ * @property {number} completedTS - Completed timestamp
203
+ * @property {number} runDurationMs - Run duration in milliseconds
204
+ * @property {number} totalAssertions - Total number of assertions
205
+ * @property {number} totalPassedAssertions - Total number of passed assertions
206
+ */
207
+
208
+ /**
209
+ * Handles incoming progress updates and processes them as needed.
210
+ * @param {FinalReport} progress
211
+ * @returns {Promise<void>}
212
+ */
183
213
  const handleIncomingProgress = async (progress) => {
184
214
  const config = objectStore.get('config')
185
215
  if (progress.status === 'FINISHED') {
@@ -135,59 +135,31 @@ describe('Cli client', () => {
135
135
  })
136
136
  })
137
137
 
138
- describe.skip('needToNotify Tests -->', () => {
139
- it('should not notify if slackWebhookUrl is not set', () => {
140
- expect(slackBroadCast.needToNotify({})).toBeFalsy()
138
+ describe('needToNotifyFailed Tests -->', () => {
139
+ it('should not notify if slackWebhookUrlForFailed is not configured', () => {
140
+ expect(slackBroadCast.needToNotifyFailed(undefined, {})).toBeFalsy()
141
141
  })
142
142
 
143
- it('should notify if slackWebhookUrl is set and slackOnlyFailed not', () => {
144
- const conf = { slackWebhookUrl: 'url' }
145
- expect(slackBroadCast.needToNotify(conf)).toBe(true)
143
+ it('should notify if webhookUrl is set, but no progress.runtimeInformation info', () => {
144
+ expect(slackBroadCast.needToNotifyFailed('url', {})).toBe(true)
146
145
  })
147
146
 
148
- it('should notify if slackWebhookUrl is set and slackOnlyFailed is false', () => {
149
- const conf = {
150
- slackWebhookUrl: 'url',
151
- slackOnlyFailed: false
152
- }
153
- expect(slackBroadCast.needToNotify(conf)).toBe(true)
154
- })
155
-
156
- it('should notify if slackOnlyFailed=true, and tests failed', () => {
157
- const conf = {
158
- slackWebhookUrl: 'url',
159
- slackOnlyFailed: true
160
- }
161
- const totalResult = {
147
+ it('should NOT notify success tests', () => {
148
+ expect(slackBroadCast.needToNotifyFailed('url', {
162
149
  runtimeInformation: {
163
- totalPassedAssertions: 0,
164
- totalAssertion: 1
150
+ totalAssertions: 1,
151
+ totalPassedAssertions: 1
165
152
  }
166
- }
167
- expect(slackBroadCast.needToNotify(conf, totalResult)).toBe(true)
153
+ })).toBe(false)
168
154
  })
169
155
 
170
- it('should notify if slackOnlyFailed=true, and tests passed', () => {
171
- const conf = {
172
- slackWebhookUrl: 'url',
173
- slackOnlyFailed: true
174
- }
175
- const totalResult = {
156
+ it('should notify in case failed tests', () => {
157
+ expect(slackBroadCast.needToNotifyFailed('url', {
176
158
  runtimeInformation: {
177
- totalPassedAssertions: 1,
178
- totalAssertion: 1
159
+ totalAssertions: 1,
160
+ totalPassedAssertions: 0
179
161
  }
180
- }
181
- expect(slackBroadCast.needToNotify(conf, totalResult)).toBe(false)
182
- })
183
-
184
- it('should notify if slackOnlyFailed=true, but no totalResult.runtimeInformation', () => {
185
- const conf = {
186
- slackWebhookUrl: 'url',
187
- slackOnlyFailed: true
188
- }
189
- const totalResult = {}
190
- expect(slackBroadCast.needToNotify(conf, totalResult)).toBe(true)
162
+ })).toBe(true)
191
163
  })
192
164
  })
193
165
  })
@@ -30,12 +30,10 @@
30
30
 
31
31
  const spyExit = jest.spyOn(process, 'exit')
32
32
  const { cli } = require('../../src/router')
33
- // const objectStore = require('../../src/objectStore')
34
33
 
35
34
  jest.mock('../../src/utils/listeners')
36
35
  jest.mock('../../src/modes/outbound')
37
36
  jest.mock('../../src/modes/testcaseDefinitionReport')
38
- // jest.mock('../../src/objectStore')
39
37
 
40
38
  describe('Cli client', () => {
41
39
  describe('running router', () => {
@@ -113,14 +111,5 @@ describe('Cli client', () => {
113
111
  cli(config)
114
112
  }).not.toThrowError();
115
113
  })
116
- // it('should have default slackOnlyFailed value', async () => {
117
- // spyExit.mockImplementationOnce(jest.fn())
118
- // cli({
119
- // mode: 'outbound',
120
- // inputFiles: 'test',
121
- // environmentFile: 'test'
122
- // })
123
- // expect(objectStore.set.mock.lastCall[1].slackOnlyFailed).toBe(false)
124
- // })
125
114
  })
126
115
  })