Skip to content

Commit

Permalink
major code refactor upgraded to work with cucumber v8
Browse files Browse the repository at this point in the history
  • Loading branch information
larryg01 committed Feb 28, 2023
1 parent 8dafe54 commit 762a72d
Show file tree
Hide file tree
Showing 24 changed files with 1,760 additions and 1,310 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,9 @@
test/report/*.html
test/report/*.json
*.log
.DS_Store
/samples/.DS_Store
templates/.DS_Store
templates/_common/.DS_Store
test/.DS_Store
test/features/.DS_Store
50 changes: 50 additions & 0 deletions coding-Standards/eslint/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"env": {
"browser": true,
"commonjs": true,
"es6": true,
"node": true
},
"parserOptions": {
"ecmaVersion":2017,
"ecmaFeatures": {
"jsx": true
},
"sourceType": "module"
},
"plugins": ["import", "prettier"],
"extends": [
"eslint:recommended",
"plugin:import/errors",
"plugin:import/warnings"
],
"rules": {
"prettier/prettier": [
"warn",
{
"singleQuote": true,
"printWidth": 120
}
],
"no-const-assign": "warn",
"no-this-before-super": "warn",
"no-undef": "warn",
"no-unreachable": "warn",
"no-unused-vars": "warn",
"constructor-super": "warn",
"valid-typeof": "warn",
"linebreak-style": [ "error", "unix" ],
"no-console": [ 0, "error" ],
"indent": [ "error", 2 ],
"semi": [ "error", "always" ],
"quotes":["error", "single"]
},
"globals": {
"noImplicitAny": "readonly",
"noImplicitThis": "readonly",
"strictNullChecks": "readonly",
"strictFunctionTypes": "readonly",
"noEmit": "readonly",
"forceConsistentCasingInFileNames": "readonly"
}
}
6 changes: 3 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@

'use strict';

var reporter = require('./lib/reporter');
const reporter = require('./lib/reporter');

function generateReport(options, callback) {
return reporter.generate(options, callback);
return reporter.generate(options, callback);
}

module.exports = {
generate: generateReport
generate: generateReport,
};
170 changes: 83 additions & 87 deletions lib/hierarchyReporter.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
'use strict';

var _ = require('lodash');
var path = require('path');
// const _ = require('lodash');
const path = require('path');

/**
* hierarchyReporter.js
Expand All @@ -11,119 +9,117 @@ var path = require('path');
* but they will be harmlessly ignored by other report types
*/

/**
* Review each feature in the suite, and find the common baseDir that is shared by all of them.
* We will later use this as the basis from which to construct the feature hierarchy--
* the basedir prefix needs to be removed since it is not important.
*/
var getBaseDir = function (suite) {
var baseDir = [];
module.exports = {
/**
* Review each feature in the suite, and find the common baseDir that is shared by all of them.
* We will later use this as the basis from which to construct the feature hierarchy--
* the basedir prefix needs to be removed since it is not important.
*/
getBaseDir: function (suite) {
let baseDir = [];
suite.features.forEach(function (feature) {
var uriParts = feature.uri.split(path.sep);
if (!baseDir.length) {
baseDir = uriParts;
} else {
for (var i = uriParts.length; i > 0; i--) {
if ((baseDir.length > i) && (baseDir[i] !== uriParts[i])) {
baseDir.length = i;
}
}
}
baseDir = feature.uri.split(path.sep);
// let uriParts = feature.uri.split(path.sep);
// if (!baseDir?.length) {
// baseDir = uriParts;
// // console.log('this is the result 1 ===> ', suite);
// } else {
// for (let i = uriParts.length; i > 0; i--) {
// // for (let i = 0, l = uriParts.length; i < l; i++) {
// if ((baseDir.length > i) && (baseDir[i] !== uriParts[i])) {
// baseDir.length = i;
// // console.log('this is the result ===> ', baseDir.length = i)
// }
// }
// }
});
return baseDir.join(path.sep);
};
},

/**
* Given a feature, remove the basedir prefix and the feature name suffix from its URI
* and return the remaining folders (if any) in an array. If the feature is at the top-level,
* it will return []
* For example:
* @param featureUri: '/home/cstrong/myproj/test/features/authentication/login/guestLogin.feature'
* @param baseDir: '/home/cstrong/myproj/test/features'
* @returns [ 'authentication', 'login' ]
*/
var getFeatureHierarchy = function (featureUri, baseDir) {
var noBaseDir = featureUri.slice(baseDir.length + 1);
var noBadChars = noBaseDir.split('=').join('_');
var featureDirs = noBadChars.split(path.sep);
/**
* Given a feature, remove the basedir prefix and the feature name suffix from its URI
* and return the remaining folders (if any) in an array. If the feature is at the top-level,
* it will return []
* For example:
* @param featureUri: '/home/cstrong/myproj/test/features/authentication/login/guestLogin.feature'
* @param baseDir: '/home/cstrong/myproj/test/features'
* @returns [ 'authentication', 'login' ]
*/
getFeatureHierarchy: function (featureUri, baseDir) {
let noBaseDir = featureUri.slice(baseDir.length + 1);
let noBadChars = noBaseDir.split('=').join('_');
let featureDirs = noBadChars.split(path.sep);

// remove the feature name itself
featureDirs.length = featureDirs.length - 1;

return featureDirs;
};
},

/**
* Given the top-level suite and the hierarchy to build, recursively create the hierarchy
* of sub-suites (if needed) and return the lowest level sub-suite.
*
* @param suite
* @param hierarchy e.g. [ 'authentication', 'login' ]
* @returns suite object or null if there is no hierarchy
*/
var findOrCreateSubSuite = function (suite, hierarchy) {

/*
/**
* Given the top-level suite and the hierarchy to build, recursively create the hierarchy
* of sub-suites (if needed) and return the lowest level sub-suite.
*
* @param suite
* @param hierarchy e.g. [ 'authentication', 'login' ]
* @returns suite object or null if there is no hierarchy
*/
findOrCreateSubSuite: function (suite, hierarchy) {
/**
Create a new sub-suite correspond to a folder name. The suite will contain the features that are defined
within that folder, and/or sub-suites corresponding to any sub-folders that themselves may contain features.
A sub-suite has a reference to its parent suite, so that we can easily aggregate statistics of passed and failed
tests up the hierarchy.
*/
function newSubSuite(name, parent) {
return {
name: {
plain: name,
sanitized: name
},
passed: 0,
failed: 0,
ambiguous: 0,
skipped: 0,
parent: parent,
features: [],
suites: []
};
return {
name: {
plain: name,
sanitized: name,
},
passed: 0,
failed: 0,
ambiguous: 0,
skipped: 0,
parent: parent,
features: [],
suites: [],
};
}

if (hierarchy.length < 1) {
return null;
return null;
}
var subSuiteName = hierarchy[0];
let subSuiteName = hierarchy[0];
if (!suite.suites) {
suite.suites = [];
suite.suites = [];
}
var subSuite = suite.suites.find(function (s) {
return s.name.plain === subSuiteName;
let subSuite = suite.suites.find(function (s) {
return s.name.plain === subSuiteName;
});
if (!subSuite) {
subSuite = newSubSuite(subSuiteName, suite);
suite.suites.push(subSuite);
let subSuite = newSubSuite(subSuiteName, suite);
suite.suites.push(subSuite);
}
if (hierarchy.length === 1) {
return subSuite;
return subSuite;
} else {
return findOrCreateSubSuite(subSuite, hierarchy.slice(1));
return this.findOrCreateSubSuite(subSuite, hierarchy.slice(1));
}
};
},

/**
* Increment stat such as failed, ambiguous or passed for the current suite
* and follow the parent attribute (if any) recursively up the tree, incrementing all.
* That way the top level suite accumulates all results from child and grandchild suites
*
* @param subSuite
* @param attrName ('passed', 'failed', 'ambiguous', or 'skipped')
*/
var recursivelyIncrementStat = function (subSuite, attrName) {
/**
* Increment stat such as failed, ambiguous or passed for the current suite
* and follow the parent attribute (if any) recursively up the tree, incrementing all.
* That way the top level suite accumulates all results from child and grandchild suites
*
* @param subSuite
* @param attrName ('passed', 'failed', 'ambiguous', or 'skipped')
*/
recursivelyIncrementStat: function (subSuite, attrName) {
subSuite[attrName] = subSuite[attrName] + 1;
if (subSuite.parent) {
recursivelyIncrementStat(subSuite.parent, attrName);
this.recursivelyIncrementStat(subSuite.parent, attrName);
}
};

module.exports = {
getBaseDir: getBaseDir,
getFeatureHierarchy: getFeatureHierarchy,
findOrCreateSubSuite: findOrCreateSubSuite,
recursivelyIncrementStat: recursivelyIncrementStat
},
};
45 changes: 35 additions & 10 deletions lib/jsonDir.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
'use strict';
// 'use strict';
const jsonFile = require('jsonfile');
const find = require('find');
const path = require('path');

var jsonFile = require('jsonfile');
var find = require('find');

var collectJSONS = function (options) {
var jsonOutput = [];
var files;
const collectJSONS = function (options) {
const jsonOutput = [];
const featureCollection = new Map();
let files;

try {
files = find.fileSync(/\.json$/, options.jsonDir);
Expand All @@ -16,10 +17,30 @@ var collectJSONS = function (options) {
if (files.length === 0) throw new Error('No JSON files found under \'options.jsonDir\': ' + options.jsonDir);

function mergeJSONS(file) {
var cucumberJson = jsonFile.readFileSync(file);
let cucumberJson = jsonFile.readFileSync(file);

function trackScenarioRetries(scenarios) {
// HACK: Very brittle. Will track if cucumber json file name is not in format command.1.1.log.json
let basename = path.basename(file, ".log.json");
let retried = basename.split(".")[2] ?? "0";
retried = parseInt(retried);
scenarios.forEach( (scenario) => {
scenario["retried"] = retried;
});
}

function collect(json) {
jsonOutput.push(json);
trackScenarioRetries(json["elements"] ?? []);
let featureKey = json["uri"] ?? "Feature: URI Not Present";
if (featureCollection.has(featureKey)) {
const featureItem = featureCollection.get(featureKey);
const elements = featureItem["elements"] ?? [];
elements.push(...(json["elements"] ?? []));
featureItem["elements"] = elements;
featureCollection.set(featureKey, featureItem);
} else {
featureCollection.set(featureKey, json);
}
}

if ((!cucumberJson || typeof cucumberJson[0] === 'undefined') && !options.ignoreBadJsonFile) {
Expand All @@ -38,7 +59,7 @@ var collectJSONS = function (options) {
featureItem["elements"][0]["steps"][0]["output"] && featureItem["elements"][0]["steps"][0]["output"][0]) {

if (typeof featureItem["elements"][0]["steps"][0]["output"][0] !== 'undefined') {
var timestamp = featureItem["elements"][0]["steps"][0]["output"][0];
const timestamp = featureItem["elements"][0]["steps"][0]["output"][0];
featureItem["timestamp"] = Date.parse(timestamp.match(/[0-9]{4}-.+:[0-9]{2}/g));
}
}
Expand All @@ -47,6 +68,10 @@ var collectJSONS = function (options) {

files.map(mergeJSONS);

featureCollection.forEach( (feature, _) => {
jsonOutput.push(feature);
});

jsonOutput.map(addTimestamp);
if (!jsonOutput.filter(f => !f.timestamp).length) {
jsonOutput.sort(function (feature, nextFeature) {
Expand Down
Loading

0 comments on commit 762a72d

Please sign in to comment.