@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 +7 -0
- package/package.json +1 -1
- package/src/extras/slack-broadcast.js +40 -37
- package/src/modes/outbound.js +30 -0
- package/test/unit/extras/slack-broadcast.test.js +15 -43
- package/test/unit/router.test.js +0 -11
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
|
@@ -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
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
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 (
|
|
195
|
-
|
|
196
|
-
|
|
190
|
+
if (slackWebhookUrl) {
|
|
191
|
+
await sendWebhook(slackWebhookUrl, 'Test Report', blocks)
|
|
192
|
+
}
|
|
197
193
|
|
|
198
|
-
|
|
194
|
+
if (needToNotifyFailed(slackWebhookUrlForFailed, progress)) {
|
|
195
|
+
await sendWebhook(slackWebhookUrlForFailed, 'Failed Tests Report', blocks)
|
|
196
|
+
}
|
|
197
|
+
}
|
|
199
198
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
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
|
-
|
|
214
|
-
|
|
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
|
-
:
|
|
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
|
}
|
package/src/modes/outbound.js
CHANGED
|
@@ -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
|
|
139
|
-
it('should not notify if
|
|
140
|
-
expect(slackBroadCast.
|
|
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
|
|
144
|
-
|
|
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
|
|
149
|
-
|
|
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
|
-
|
|
164
|
-
|
|
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
|
|
171
|
-
|
|
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
|
-
|
|
178
|
-
|
|
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
|
})
|
package/test/unit/router.test.js
CHANGED
|
@@ -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
|
})
|