Last active
July 7, 2022 13:00
-
-
Save ngraf/5a97520407bc3341c49584ce989e8f63 to your computer and use it in GitHub Desktop.
A plugin for CodeceptJS to send data to Elasticsearch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
exports.config = { | |
plugins: { | |
elastic: { | |
require: './ElasticReporter.js', | |
enabled: false, | |
protocol: 'https', | |
server: 'elasticsearch-example.domain.com', | |
port: 9200, | |
index : 'qa-e2etests-checkout', | |
customFields : { | |
url: 'https://my.domain.com', // URL of test environment | |
environment : process.env.ENVIRONMENT, | |
testrun : 'Run-' + new Date(new Date().getTime() - (new Date().getTimezoneOffset() * 60000)).toISOString().slice(0, -5), | |
division: 'Checkout', | |
subdivision: 'Checkout for beauty products', | |
jenkinsJob: process.env.JOB_NAME | |
} | |
}, | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { event } = require('codeceptjs'); | |
let httpOrHttps | |
// Trigger report to Elasticsearch when hook "event.test.after" is fired | |
module.exports = (config) => { | |
checkConfig(config) | |
httpOrHttps = config.protocol === 'https' ? require('https') : require('http') | |
event.dispatcher.on(event.test.after, async (test) => { | |
try { | |
await reportToElastic(config, test) | |
} catch (err) { | |
console.error(`[ERROR] (ElasticReporter) Report to Elasticsearch failed for ${test.title} with error: ` + err) | |
} | |
}); | |
} | |
function checkConfig (config) { | |
const properties = ['server', 'protocol', 'index'] | |
properties.forEach((property) => { | |
if ( ! config[property]) { | |
throw new Error(`[ERROR] (ElasticReporter) Configuration missing or empty for "${property}".`) | |
} | |
}) | |
} | |
/** | |
* Sends test result of a test scenario to Elasticsearch. | |
* | |
* @param config | |
* @param test | |
* @return {Promise<unknown>} | |
*/ | |
async function reportToElastic(config, test) { | |
// If number of retries is > 0 and this test is not the last try and it did not pass, then don't report it. We wait for last try. | |
if (parseInt(test._retries) > 0 && test._currentRetry < parseInt(test._retries) && test.state !== 'passed') { | |
return Promise.resolve(); | |
} | |
// Create JSON data out of test object | |
const jsonData = createJSON(test, config.customFields) | |
// console.log('TEST', test) | |
const options = { | |
hostname : config.server, | |
port: config.port, | |
rejectUnauthorized: false, | |
path : `/${config.index}/_doc/`, | |
method: 'POST', | |
headers: { | |
'Content-Type' : 'application/json', | |
'Content-Length': jsonData.length | |
} | |
} | |
return new Promise(function (resolve, reject) { | |
const req = httpOrHttps.request(options,function (res) { | |
if (res.statusCode === 201) { | |
resolve(res.statusCode); | |
} else { | |
reject(`ERROR: Unexpected status code ${res.statusCode} from Elasticsearch with message "${res.statusMessage}"`) | |
} | |
res.on('data', d => { | |
// process.stdout.write(d) | |
}) | |
}); | |
req.on('error', (e) => { | |
reject('ERROR during request:' + e); | |
}); | |
req.write(jsonData) | |
req.end(); | |
}); | |
} | |
/** | |
* Creates JSON structure out of test scenario result together with custom fields. | |
* | |
* @param test | |
* @param customFields | |
* @return {string} | |
*/ | |
function createJSON(test, customFields) { | |
const currentTimestampISO = new Date().toISOString() | |
const commonFields = { | |
'@timestamp' : currentTimestampISO, | |
'feature': test.parent ? test.parent.title : 'unknown' , | |
'scenario' : test.title, | |
'file' : test.file, | |
'state' : test.state, | |
'duration' : test.duration, | |
'retries' : test._currentRetry, | |
'error' : test.state === 'passed' ? '' : (test.err && test.err.message ? test.err.message : 'unknown'), | |
'failed' : test.state === 'failed' ? 1 : 0 | |
} | |
const allFields = Object.assign({}, commonFields, customFields) | |
return JSON.stringify( allFields) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage:
ElasticReporter.js
with content from Gistcodecept.conf.js
. You need to adjust some values.npx codeceptjs run -p elastic
to activate the plugin on demand.