Skip to content

Instantly share code, notes, and snippets.

@ngraf
Last active July 7, 2022 13:00
Show Gist options
  • Save ngraf/5a97520407bc3341c49584ce989e8f63 to your computer and use it in GitHub Desktop.
Save ngraf/5a97520407bc3341c49584ce989e8f63 to your computer and use it in GitHub Desktop.
A plugin for CodeceptJS to send data to Elasticsearch
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
}
},
}
}
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)
}
@ngraf
Copy link
Author

ngraf commented Jul 7, 2022

Usage:

  1. Create file ElasticReporter.js with content from Gist
  2. Add configuration for ElasticReporter plugin in your existing codecept.conf.js. You need to adjust some values.
  3. Run tests with npx codeceptjs run -p elastic to activate the plugin on demand.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment