Adding a custom reporter to Detox

Search for a command to run...

No comments yet. Be the first to comment.
When performing end to end journey test automation on an eccommerce style website, it’s common for security reasons for the credit card fields to be loaded in an iframe to allow payment forms from a payment service provider to added to a website in a...

After 20 years of working with test automation, I like to think I've become quite good at it. Recently, I was advocating for a change in approach at a company I had just joined. I knew it was crucial to clearly explain my method for writing maintaina...

At Glofox, we regularly perform whole-team exploratory testing sessions. These are very effective at discovering problems that are not found when testing around acceptance criteria, as we get multiple different perspectives, and it gives developers t...

Lighthouse has a new user-flow API that allows lab testing at any point within a page's lifespan. There is support for generating a lighthouse report from a puppeteer script, but I wanted to explore using WebdriverIO to do the same! Why would you wan...

Much has been written about flaky tests, the perils of ignoring the signal they may be giving you and how to deal with them from a tools perspective, and here but I've never really read anything about how to stop flaky tests getting added in the firs...

Detox is a popular automation library for mobile apps, usually those built with React Native. I recently upgraded our implementation of Detox to use Jest Circus following this as the test runner instead of Mocha, as recommended.
One of the things mentioned in the guide is the use of a CustomDetoxEnvironment, is that there is no guide for writing custom detox listeners, and indeed there isn't! So I'll take you through how we added one for Allure
To understand what was going on I looked at the code inside DetoxCircusEnvironment, and specifically lines L52-L86
Within this file we can see the following code:
for (const listener of this.testEventListeners) {
if (typeof listener[name] === 'function') {
try {
await this._timer.run(() => listener[name](event, state));
} catch (listenerError) {
this._logger.error(`${listenerError}`);
}
}
}
so if we implemented functions that matched the names of events that we are interested in listed here then it would handle the events as part of the Jest Circus lifecycle for us.
const Allure = require('allure-js-commons'); // version "1.3.2",
const fs = require('fs');
const stripAnsi = require('strip-ansi');
class AllureReporterCircus {
constructor({ detox }) {
this.allure = new Allure();
this.detox = detox;
}
run_describe_start(event) {
if (event.describeBlock.parent !== undefined) {
this.allure.startSuite(event.describeBlock.name);
}
}
run_describe_finish(event) {
if (event.describeBlock.parent !== undefined) {
this.allure.endSuite();
}
}
test_start(event) {
const { test } = event;
this.allure.startCase(test.name)
}
async test_done(event) {
if (event.test.errors.length > 0) {
const { test } = event;
const screenshotPath = await this.detox.device.takeScreenshot(`${test.startedAt}-failed`);
const buffer = fs.readFileSync(`${screenshotPath}`);
this.allure.addAttachment('Screenshot test failue', Buffer.from(buffer, 'base64'), 'image/png');
const err = test.errors[0][0];
err.message = stripAnsi(err.message);
err.stack = stripAnsi(err.stack);
this.allure.endCase('failed', err);
}
else {
this.allure.endCase('passed')
}
}
test_skip(event) {
const { test } = event;
this.allure.startCase(test.name);
this.allure.pendingCase(test.name);
}
}
module.exports = AllureReporterCircus;
The final step is to add the reporter as a listener with the CustomDetoxEnvironment
const {
DetoxCircusEnvironment,
SpecReporter,
WorkerAssignReporter,
} = require('detox/runners/jest-circus');
const AllureReporter = require('./reporters/AllureReporterCircus')
class CustomDetoxEnvironment extends DetoxCircusEnvironment {
constructor(config, context) {
super(config, context);
this.initTimeout = 300000;
this.registerListeners({
SpecReporter,
AllureReporter,
WorkerAssignReporter,
});
}
}
module.exports = CustomDetoxEnvironment;