|
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); |
|
|
|
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); |
|
} |
One example of a dashboard in Kibana based on the data pushed to the Elasticsearch index: