Skip to content

Commit

Permalink
Add support for multiple JSON outputs
Browse files Browse the repository at this point in the history
  • Loading branch information
alextiley committed Jun 10, 2018
1 parent f6f3425 commit 45c5744
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 34 deletions.
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ I have adapted and added missing properties to the JSON report. It's quite rough
outputDir: 'some/output/dir',
cucumberJsonReporter: {
silent: true, // true|false - supresses message notifying of report output
baseDir: __dirname // Should be your project's root directory, used to determine where your feature files are stored
baseDir: __dirname, // Should be your project's root directory, used to determine where your feature files are stored
deviceName: 'Local test environment' // Meta data for multiple-cucumber-html-reporter
}
}
}
Expand All @@ -31,3 +32,13 @@ I have adapted and added missing properties to the JSON report. It's quite rough
## Bug reporting ##

Feel free to raise a pull request, or throw me a ticket via the issues section.

## Known issues / missing features ##

* Add support for screenshots via cucumber attachments/"embeddings"
* Add browser name to feature metadata
* Add metadata for test start time, end time and total duration
* Add metadata for feature count, scenario/scenario outline counts and step counts
* Add metadata for failing test count
* Step duration and line number is experimental - It's nigh on impossible to fetch the correct step data if the step contains a variable
* Svme report file names based on browser name and timestamp
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "wdio-json-cucumber-reporter",
"version": "1.0.5",
"version": "1.1.0",
"description": "JSON Cucumber reporter",
"main": "lib/reporter.js",
"directories": {
Expand Down
96 changes: 81 additions & 15 deletions src/JSONBuilder.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
import os from 'os';

class JSONBuilder {
constructor() {
this.features = [];
this.reports = {};
}

initialiseReport(cid) {
if (typeof this.reports[cid] === 'undefined') {
this.reports[cid] = {};
this.reports[cid].features = [];
}
return this.reports[cid];
}

addFeature(options) {
this.features.push({
const report = this.initialiseReport(options.cid);

report.features.push({
keyword: options.keyword,
type: options.type,
name: options.name,
Expand All @@ -19,8 +31,10 @@ class JSONBuilder {


addScenario(options) {
const featureIndex = this.features.findIndex(feature => feature.id === options.parentId);
const scenarioIndex = this.features[featureIndex].elements
const report = this.initialiseReport(options.cid);

const featureIndex = report.features.findIndex(feature => feature.id === options.parentId);
const scenarioIndex = report.features[featureIndex].elements
.findIndex(scenario => scenario.id === options.id);

const scenarioData = {
Expand All @@ -36,19 +50,21 @@ class JSONBuilder {
};

if (scenarioIndex === -1) {
this.features[featureIndex].elements.push(scenarioData);
report.features[featureIndex].elements.push(scenarioData);
}
}

addStep(options) {
const featureIndex = this.features
const report = this.initialiseReport(options.cid);

const featureIndex = report.features
.findIndex(feature => feature.elements.find(scenario => scenario.id === options.parentId));

const scenarioIndex = this
const scenarioIndex = report
.features[featureIndex]
.elements.findIndex(scenario => scenario.id === options.parentId);

const stepIndex = this
const stepIndex = report
.features[featureIndex]
.elements[scenarioIndex]
.steps.findIndex(step => step.id === options.id);
Expand All @@ -61,21 +77,28 @@ class JSONBuilder {
tags: options.tags,
uri: options.uri,
result: options.result,
embeddings: options.embeddings,
embeddings: options.embeddings.map(embedding => ({
data: embedding.data,
media: {
type: embedding.mimeType,
},
})),
};

if (stepIndex === -1) {
this.features[featureIndex].elements[scenarioIndex].steps.push(stepData);
report.features[featureIndex].elements[scenarioIndex].steps.push(stepData);
} else {
this.features[featureIndex].elements[scenarioIndex].steps[stepIndex] = stepData;
report.features[featureIndex].elements[scenarioIndex].steps[stepIndex] = stepData;
}
}

addHook(options) {
const featureIndex = this.features
const report = this.initialiseReport(options.cid);

const featureIndex = report.features
.findIndex(feature => feature.elements.find(scenario => scenario.id === options.parentId));

const scenarioIndex = this
const scenarioIndex = report
.features[featureIndex]
.elements.findIndex(scenario => scenario.id === options.parentId);

Expand All @@ -95,11 +118,54 @@ class JSONBuilder {
})),
};

this.features[featureIndex].elements[scenarioIndex].steps.push(stepData);
report.features[featureIndex].elements[scenarioIndex].steps.push(stepData);
}

/**
* @todo add further meta data
* test execution start/end/total
* feature|scenario|scenariooverview|step counts
* failing test count
* passing test count
* @see https://github.com/evrycollin/wdio-allure-addons-reporter/issues/1 for an idea of how to get more data
*/
addMeta(options) {
const report = this.initialiseReport(options.cid);
const platformId = this.getPlatformId();

report.features.forEach((feature) => {
feature.metadata = {
browser: {
name: options.browser,
// @todo - check if it's possible to get the browser version from wdio events
version: options.browser.charAt(0).toUpperCase() + options.browser.slice(1),
},
device: options.deviceName,
platform: {
name: platformId,
version: `${os.type()} ${os.release()}`,
},
};
})
}

clearEmptyFeatures() {
this.features = this.features.filter(feature => feature.elements.length > 0);
Object.keys(this.reports).forEach((key) => {
this.reports[key].features = this.reports[key].features.filter(
feature => feature.elements.length > 0
);
});
}

/**
* Grabs meta data about the OS for the report output
*/
getPlatformId() {
switch (process.platform) {
case 'darwin': return 'osx';
case 'win32': return 'windows';
default: return 'linux';
}
}
}

Expand Down
52 changes: 35 additions & 17 deletions src/reporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,8 @@ class CucumberJSONReporter extends EventEmitter {
this.reportIdentifier = 0;
this.jsonBuilder = new JSONBuilder();

// this.on('suite:end', (suite) => {
// This is a feature, not a scenario
// if (suite.parent === null) {
// console.log('suite:end');
// console.log(suite);
// }
// });

/**
* @todo Collect unique reports for each browsing session or 'capability'
* At the moment this hook is only called once. Rewrite to collect multiple JSON's and use suite:end
* Once all tests completed, iterate over reports and generate multiple JSON reports
*/
this.on('end', () => {

Expand All @@ -50,29 +41,49 @@ class CucumberJSONReporter extends EventEmitter {

try {
const dir = path.resolve(this.options.outputDir);
const filename = (this.reportIdentifier === 0 ? 'report' : `report_${this.reportIdentifier}`) + '.json';
const filepath = path.join(dir, filename);

mkdirp.sync(dir);

this.jsonBuilder.clearEmptyFeatures();

fs.writeFileSync(filepath, JSON.stringify(this.jsonBuilder.features));
Object.keys(this.jsonBuilder.reports).forEach((cid) => {
const report = this.jsonBuilder.reports[cid];
const filename = (this.reportIdentifier === 0 ? 'report' : `report_${this.reportIdentifier}`) + '.json';
const filepath = path.join(dir, filename);

if (this.options.cucumberJsonReporter.silent !== true) {
console.log(`Wrote json report to [${this.options.outputDir}].`);
}
this.reportIdentifier += 1;
fs.writeFileSync(filepath, JSON.stringify(report.features));

if (this.options.cucumberJsonReporter.silent !== true) {
console.log(`Wrote json report '${filename}' to [${this.options.outputDir}].`);
}
this.reportIdentifier += 1;
});
} catch (e) {
console.log(`Failed to write json report to [${this.options.outputDir}]. Error: ${e}`);
}
});

/**
* Decorate features with meta data whenever a feature finishes
*/
this.on('suite:end', (suite) => {
if (suite.parent === null) {
this.jsonBuilder.addMeta({
cid: suite.cid,
browser: suite.runner[suite.cid].browserName,
deviceName: this.options.cucumberJsonReporter.deviceName
? this.options.cucumberJsonReporter.deviceName
: 'Local test environment'
});
}
});

this.on('suite:start', (test) => {
if (test.parent) {
const scenario = this.getScenario(test.file, test.title);

this.jsonBuilder.addScenario({
cid: test.cid,
type: 'scenario',
keyword: scenario.keyword,
description: scenario.description,
Expand All @@ -87,6 +98,7 @@ class CucumberJSONReporter extends EventEmitter {
const feature = this.getFeature(test.file);

this.jsonBuilder.addFeature({
cid: test.cid,
type: 'feature',
keyword: feature.keyword,
name: feature.name,
Expand All @@ -104,6 +116,7 @@ class CucumberJSONReporter extends EventEmitter {
const step = this.getStep(test.file, test.title);

const stepData = {
cid: test.cid,
type: 'step',
name: test.title,
id: test.uid,
Expand All @@ -116,6 +129,7 @@ class CucumberJSONReporter extends EventEmitter {
status: 'passed',
duration: test.duration * 1000000,
},
embeddings: []
};

if (stepData.keyword === 'After' || stepData.keyword === 'Before') {
Expand All @@ -129,6 +143,7 @@ class CucumberJSONReporter extends EventEmitter {
const step = this.getStep(test.file, test.title);

const stepData = {
cid: test.cid,
type: 'step',
name: test.title,
id: test.uid,
Expand All @@ -141,6 +156,7 @@ class CucumberJSONReporter extends EventEmitter {
status: 'failed',
duration: test.duration * 1000000,
},
embeddings: [],
};

if (test.err.stack) {
Expand All @@ -160,6 +176,7 @@ class CucumberJSONReporter extends EventEmitter {
const step = this.getStep(test.file, test.title);

const stepData = {
cid: test.cid,
type: 'step',
name: test.title,
id: test.uid,
Expand All @@ -172,6 +189,7 @@ class CucumberJSONReporter extends EventEmitter {
status: 'skipped',
duration: test.duration * 1000000,
},
embeddings: [],
};

if (stepData.keyword === 'After' || stepData.keyword === 'Before') {
Expand Down

0 comments on commit 45c5744

Please sign in to comment.