Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save Phenomite/038c57cdaf95b8b8383a0fd522919662 to your computer and use it in GitHub Desktop.
Save Phenomite/038c57cdaf95b8b8383a0fd522919662 to your computer and use it in GitHub Desktop.
Cucumber Report JSON Generator - Subfolder recurse for screenshots (fix for Issue#1)
function addScreenshots() {
/* Credits: https://gist.github.com/kethinov/6658166#gistcomment-3178557 */
/* Prepend the given path segment */
const prependPathSegment = pathSegment => location => path.join(pathSegment, location);
/* fs.readdir but with relative paths */
const readdirPreserveRelativePath = location => fs.readdirSync(location).map(prependPathSegment(location));
/* Recursive fs.readdir but with relative paths */
const readdirRecursive = location => readdirPreserveRelativePath(location)
.reduce((result, currentValue) => fs.statSync(currentValue).isDirectory()
? result.concat(readdirRecursive(currentValue))
: result.concat(currentValue), []);
const screenshots = readdirRecursive(path.resolve(screenshotsDir)).filter(file => {
return file.indexOf('.png') > -1
});
/* This is an awful hack to allow matching with the cucumberReportMap */
const featuresList = screenshots.map(x => x.split(/(?:\\|\/)+/).slice(-2)[0])
.filter((value, index, self) => self.indexOf(value) === index);
console.log("\nProcessing features:");
console.dir(featuresList);
console.log("\nProcessing screenshots:");
console.dir(screenshots);
/** Edit: We have already recursed and have the paths to all screenshots
* Thus we jump right into the inner loop
**/
featuresList.forEach(feature => {
screenshots.forEach(screenshot => {
// regex to parse 'I can use scenario outlines with examples' from either of these:
// - Getting Started -- I can use scenario outlines with examples (example #1) (failed).png
// - Getting Started -- I can use scenario outlines with examples (failed).png
// Now includes ability to process cucumber statement with the word "screenshot":
// - Getting Started -- I can use scenario outlines with examples.png
const regex = /(?<=--\ ).+?((?=\ \(example\ #\d+\))|(?=\ \(failed\))|(?=\.\w{3}))/g;
const [scenarioName] = screenshot.match(regex);
console.info(chalk.blue('\n Adding screenshot to cucumber-json report for'));
console.info(chalk.blue(` '${scenarioName}'`));
// Find all scenarios matching the scenario name of the screenshot.
// This is important when using the scenario outline mechanism
const myScenarios = cucumberReportMap[feature][0].elements.filter(
e => scenarioName.includes(e.name)
);
if (!myScenarios) { return; }
myScenarios.forEach(myScenario => {
let myStep;
if (screenshot.includes('(failed)')) {
myStep = myScenario.steps.find(
step => step.result.status === 'failed'
);
} else {
myStep = myScenario.steps.find(
step => step.name.includes('screenshot')
);
}
if (!myStep) {
console.info(chalk.blue("Not adding data!"));
return
}
const data = fs.readFileSync(
path.resolve(screenshot) // Since we now already have full location!
//path.join(screenshotsDir, feature, screenshot)
);
if (data) {
const base64Image = Buffer.from(data, 'binary').toString('base64')
if (!myStep.embeddings) {
myStep.embeddings = []
} else {
//remove existing screenshot
myStep.embeddings.pop();
}
myStep.embeddings.push({ data: base64Image, mime_type: 'image/png' });
}
});
//Write JSON with screenshot back to report file.
console.log(path.join(cucumberJsonDir, cucumberReportFileMap[feature]));
fs.writeFileSync(
path.join(cucumberJsonDir, cucumberReportFileMap[feature]),
JSON.stringify(cucumberReportMap[feature], null, jsonIndentLevel)
);
});
});
}
@Phenomite
Copy link
Author

Hey, thanks for the post. I am using this method and getting this below error. Any idea what is causing the issue?

Try webnexusmobile's edit that this gist contributed to:

  // Extract feature list from screenshot list
  const featuresList = Array.from(new Set(screenshots.map(x => x.match(/[\w-_.]+\.feature/g)[0])))

https://github.com/webnexusmobile/cypress-cucumber-getting-started/blob/master/cypress/reporting/report.js

@hari49951
Copy link

Thanks for the info. I am usingwebnexusmobile's code to generate reports. I am able to generate reports using the code. If there are any failures in any scenarios and when I run node ./cypress/reporting/report.js to generate reports with screenshots getting that error. Here is the code

#!/usr/bin/env node
/**

const report = require('multiple-cucumber-html-reporter')
const fs = require('fs-extra')
const path = require('path')
const chalk = require('chalk')

const cucumberJsonDir = './cypress/test-results/cucumber-json'
const cucumberReportFileMap = {}
const cucumberReportMap = {}
const jsonIndentLevel = 2
const htmlReportDir = './cypress/test-results/html'
const screenshotsDir = './cypress/screenshots'
// const snapshotDir = './cypress/snapshots'

getCucumberReportMaps()
addScreenshots()
// addSnapshots()
generateReport()

function getCucumberReportMaps() {
const files = fs.readdirSync(cucumberJsonDir).filter(file => {
return file.indexOf('.json') > -1
})
files.forEach(file => {
const json = JSON.parse(
fs.readFileSync(path.join(cucumberJsonDir, file))
)
if (!json[0]) { return }
const [feature] = json[0].uri.split('/').reverse()
cucumberReportFileMap[feature] = file
cucumberReportMap[feature] = json
})
}

function addScreenshots() {
/* Credits:
https://gist.github.com/kethinov/6658166#gistcomment-3178557
https://gist.github.com/Phenomite/038c57cdaf95b8b8383a0fd522919662
*/
// Prepend the given path segment
const prependPathSegment = pathSegment => location => path.join(pathSegment, location)
// fs.readdir but with relative paths
const readdirPreserveRelativePath = location => fs.readdirSync(location).map(prependPathSegment(location))
// Recursive fs.readdir but with relative paths
const readdirRecursive = location => readdirPreserveRelativePath(location)
.reduce((result, currentValue) => fs.statSync(currentValue).isDirectory()
? result.concat(readdirRecursive(currentValue))
: result.concat(currentValue), [])
const screenshots = readdirRecursive(path.resolve(screenshotsDir)).filter(file => {
return file.indexOf('.png') > -1
})
// Extract feature list from screenshot list
const featuresList = Array.from(new Set(screenshots.map(x => x.match(/[\w-_.]+.feature/g)[0])))
featuresList.forEach(feature => {
screenshots.forEach(screenshot => {
// regex to parse 'I can use scenario outlines with examples' from either of these:
// - Getting Started -- I can use scenario outlines with examples (example #1) (failed).png
// - Getting Started -- I can use scenario outlines with examples (failed).png
// - Getting Started -- I can use scenario outlines with examples.png
const regex = /(?<=--\ ).+?((?=\ (example\ #\d+))|(?=\ (failed))|(?=.\w{3}))/g
const [scenarioName] = screenshot.match(regex)
console.info(chalk.blue('\n Adding screenshot to cucumber-json report for'))
console.info(chalk.blue( '${scenarioName}'))
// Find all scenarios matching the scenario name of the screenshot.
// This is important when using the scenario outline mechanism
const myScenarios = cucumberReportMap[feature][0].elements.filter(
e => scenarioName.includes(e.name)
)
if (!myScenarios) { return }
let foundFailedStep = false
myScenarios.forEach(myScenario => {
if (foundFailedStep) {
return
}
let myStep
if (screenshot.includes('(failed)')) {
myStep = myScenario.steps.find(
step => step.result.status === 'failed'
)
} else {
myStep = myScenario.steps.find(
step => step.name.includes('screenshot')
)
}
if (!myStep) {
return
}
const data = fs.readFileSync(
path.resolve(screenshot)
)
if (data) {
const base64Image = Buffer.from(data, 'binary').toString('base64')
if (!myStep.embeddings) {
myStep.embeddings = []
myStep.embeddings.push({ data: base64Image, mime_type: 'image/png' })
foundFailedStep = true
}
}
})
//Write JSON with screenshot back to report file.
fs.writeFileSync(
path.join(cucumberJsonDir, cucumberReportFileMap[feature]),
JSON.stringify(cucumberReportMap[feature], null, jsonIndentLevel)
)
})
})
}

function generateReport() {
if (!fs.existsSync(cucumberJsonDir)) {
console.warn(chalk.yellow(WARNING: Folder './${cucumberJsonDir}' not found. REPORT CANNOT BE CREATED!))
} else {
report.generate({
jsonDir: cucumberJsonDir,
reportPath: htmlReportDir,
displayDuration: true,
pageTitle: 'System-Test Report',
reportName: System-Test Report - ${new Date().toLocaleString()},
metadata: {
browser: {
name: 'chrome'
},
device: 'VM',
platform: {
name: 'linux'
}
}
})
}
}

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