Skip to content

Commit

Permalink
Merge branch 'main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
wswebcreation authored May 26, 2022
2 parents f8648f9 + c264bc4 commit c5f8b16
Show file tree
Hide file tree
Showing 17 changed files with 196 additions and 111 deletions.
56 changes: 51 additions & 5 deletions README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -113,18 +113,21 @@ The directory in which the report needs to be saved, relative from where the scr

### `staticFilePath`
- **Type:** `boolean`
- **Default:** `false`
- **Mandatory:** No

If true each feature will get a static filename for the html. Use this feature only if you are not running multiple instances of the same tests.

### `openReportInBrowser`
- **Type:** `boolean`
- **Default:** `false`
- **Mandatory:** No

If true the report will automatically be opened in the default browser of the operating system.

### `saveCollectedJSON`
- **Type:** `boolean`
- **Default:** `false`
- **Mandatory:** No

This module will first merge all the JSON-files to 1 file and then enrich it with data that is used for the report. If `saveCollectedJSON :true` the merged JSON **AND** the enriched JSON will be saved in the `reportPath`. They will be saved as:
Expand All @@ -134,8 +137,8 @@ This module will first merge all the JSON-files to 1 file and then enrich it wit

### `disableLog`
- **Type:** `boolean`
- **Mandatory:** No
- **Default:** `false`
- **Mandatory:** No

This will disable the log so will **NOT** see this.

Expand Down Expand Up @@ -165,8 +168,28 @@ You can change the report name to a name you want

You can customise Page Footer if required. You just need to provide a html string like `<div><p>A custom footer in html</p></div>`

### `plainDescription`
- **Type:** `boolean`
- **Default:** `false`
- **Mandatory:** No

The feature description is assumed to be a simple string and the library formats it accordingly, by copying it inside a
paragraph tag. Since the description can be any free text, it can also be as complex as a full `div`, e.g.:

```html
<div>
<p><strong>Test description </strong> : The test implements comparisons using all our datatypes</p>
<p><strong>Expected result </strong> : Device does not reset</p>
<p><strong>Feature type </strong> : Robustness</p>
<p><strong>Comments </strong> : Test covers comparison operators</p>
</div>
```

If the description already include formatting tags you can include it _as is_ by setting `plainDescription` to `true`.

### `displayDuration`
- **Type:** `boolean`
- **Default:** `false`
- **Mandatory:** No

If set to `true` the duration of steps, scenarios and features is displayed on the Features overview and single feature page in an easily readable format.
Expand Down Expand Up @@ -198,6 +221,7 @@ If set to `true` the date and time at which the JSON-files were generated, is di

### `useCDN`
- **Type:** `boolean`
- **Default:** `false`
- **Mandatory:** No

If you prefer, you can use CDN for assets.
Expand All @@ -206,14 +230,35 @@ If you prefer, you can use CDN for assets.
- **Type:** `path`
- **Mandatory:** No

If you need add some custom style to your report. Add it like this `customStyle: 'your-path-where/custom.css'`
If you need to add some custom style to your report. Add it like this `customStyle: 'your-path-where/custom.css'`
Customization is now possible also for the doughnut chart by using [CSS variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties).
The user can define colors for the chart by defining variables for the different categories as follows:
```css
:root {
--ambiguous-color:#AAAAAA;
--failed-color:#BBBBBB;
--not-defined-color:#CCCCCC;
--passed-color:#DDDDDD;
--pending-color:#EEEEEE;
--skipped-color:#FFFFFF;
}
```
Please note that these colors do _not_ affect the main colors CSS. To have homogeneous styling you can simply link those
colors to the variables, e.g.:

```css
.ambiguous-color {
color: var(--ambiguous-color) !important;
}
```
Please refer to the `test` directory and the `embedded-array` test report for a complete color customization example.

### `overrideStyle`
- **Type:** `path`
- **Mandatory:** No

If you need replace default style for your report. Add it like this `overrideStyle: 'your-path-where/custom.css'`

If you need to replace completely the default style for your report. Add it like this `overrideStyle: 'your-path-where/custom.css'`
Please refer to the `test` directory for an example.

### `metadata`
- **Type:** `JSON`
Expand Down Expand Up @@ -242,6 +287,7 @@ See [metadata](./README.MD#metadata-1) for more info

### `customMetadata`
- **Type:** `boolean`
- **Default:** `false`
- **Mandatory:** No

It is possible to provide custom metadata by setting this variable to `true`. Custom metadata will override the regular metadata completely and potentially have strange formatting bugs if too many (10+) variables are used.
Expand Down Expand Up @@ -420,7 +466,7 @@ You can attach screenshots at any time to a Cucumber JSON file. Just create a Cu
### How to attach Plain Text to HTML report
You can attach plain-text / data at any time to a Cucumber JSON file to help debug / review the results. You can add them during running or when a `scenario` failed.

> Check the framework you are using to attach plain text to the JSON file.
> Check the framework you are using to attach plain text to the JSON file. Please make sure to convert binary/non-readable data to a suitable textual representation, e.g. via Base64 encoding.
### How to attach pretty JSON to HTML report
You can attach JSON at any time to a Cucumber JSON file. You can add them during running or when a `scenario` failed.
Expand Down
6 changes: 2 additions & 4 deletions lib/collect-jsons.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ module.exports = function collectJSONS(options) {
json.metadata.reportTime = formatToLocalIso(json.metadata.reportTime)
}

// Only check the feature hooks if there are elements (fail safe)
// Only check the feature hooks if there are elements (fail-safe)
const {elements} = json;

if (elements) {
const scenarios = elements.map(scenario => {
json.elements = elements.map(scenario => {
const {before, after} = scenario;

if (before) {
Expand All @@ -74,8 +74,6 @@ module.exports = function collectJSONS(options) {

return scenario
})

json.elements = scenarios
}

jsonOutput.push(json)
Expand Down
86 changes: 30 additions & 56 deletions lib/generate-report.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,21 +49,22 @@ function generateReport(options) {

const customMetadata = options.customMetadata || false;
const customData = options.customData || null;
const plainDescription = !!options.plainDescription;
const style = options.overrideStyle || REPORT_STYLESHEET;
const customStyle = options.customStyle;
const disableLog = options.disableLog;
const openReportInBrowser = options.openReportInBrowser;
const disableLog = !!options.disableLog;
const openReportInBrowser = !!options.openReportInBrowser;
const reportName = options.reportName || DEFAULT_REPORT_NAME;
const reportPath = path.resolve(process.cwd(), options.reportPath);
const saveCollectedJSON = options.saveCollectedJSON;
const displayDuration = options.displayDuration || false;
const displayReportTime = options.displayReportTime || false;
const durationInMS = options.durationInMS || false;
const hideMetadata = options.hideMetadata || false;
const saveCollectedJSON = !!options.saveCollectedJSON;
const displayDuration = !!options.displayDuration;
const displayReportTime = !!options.displayReportTime;
const durationInMS = !!options.durationInMS;
const hideMetadata = !!options.hideMetadata;
const pageTitle = options.pageTitle || 'Multiple Cucumber HTML Reporter';
const pageFooter = options.pageFooter || false;
const useCDN = options.useCDN || false;
const staticFilePath = options.staticFilePath || false;
const pageFooter = !!options.pageFooter;
const useCDN = !!options.useCDN;
const staticFilePath = !!options.staticFilePath;

fs.ensureDirSync(reportPath);
fs.ensureDirSync(path.resolve(reportPath, FEATURE_FOLDER));
Expand Down Expand Up @@ -95,7 +96,7 @@ function generateReport(options) {
total: 0,
ambiguousPercentage: 0,
failedPercentage: 0,
notdefinedPercentage: 0,
notDefinedPercentage: 0,
pendingPercentage: 0,
skippedPercentage: 0,
passedPercentage: 0
Expand All @@ -118,7 +119,7 @@ function generateReport(options) {
// Percentages
suite.featureCount.ambiguousPercentage = _calculatePercentage(suite.featureCount.ambiguous, suite.featureCount.total);
suite.featureCount.failedPercentage = _calculatePercentage(suite.featureCount.failed, suite.featureCount.total);
suite.featureCount.notdefinedPercentage = _calculatePercentage(suite.featureCount.notDefined, suite.featureCount.total);
suite.featureCount.notDefinedPercentage = _calculatePercentage(suite.featureCount.notDefined, suite.featureCount.total);
suite.featureCount.pendingPercentage = _calculatePercentage(suite.featureCount.pending, suite.featureCount.total);
suite.featureCount.skippedPercentage = _calculatePercentage(suite.featureCount.skipped, suite.featureCount.total);
suite.featureCount.passedPercentage = _calculatePercentage(suite.featureCount.passed, suite.featureCount.total);
Expand Down Expand Up @@ -168,7 +169,7 @@ function generateReport(options) {
ambiguous: 0,
passedPercentage: 0,
failedPercentage: 0,
notdefinedPercentage: 0,
notDefinedPercentage: 0,
skippedPercentage: 0,
pendingPercentage: 0,
ambiguousPercentage: 0,
Expand All @@ -182,7 +183,7 @@ function generateReport(options) {
feature.isNotdefined = false;
feature.isPending = false;
suite.featureCount.total++;
var idPrefix = staticFilePath ? '' : `${ uuid() }.` ;
const idPrefix = staticFilePath ? '' : `${ uuid() }.` ;
feature.id = `${ idPrefix }${ feature.id }`.replace(/[^a-zA-Z0-9-_]/g, '-');
feature.app = 0;
feature.browser = 0;
Expand Down Expand Up @@ -225,13 +226,13 @@ function generateReport(options) {
// Percentages
feature.scenarios.ambiguousPercentage = _calculatePercentage(feature.scenarios.ambiguous, feature.scenarios.total);
feature.scenarios.failedPercentage = _calculatePercentage(feature.scenarios.failed, feature.scenarios.total);
feature.scenarios.notdefinedPercentage = _calculatePercentage(feature.scenarios.notDefined, feature.scenarios.total);
feature.scenarios.notDefinedPercentage = _calculatePercentage(feature.scenarios.notDefined, feature.scenarios.total);
feature.scenarios.passedPercentage = _calculatePercentage(feature.scenarios.passed, feature.scenarios.total);
feature.scenarios.pendingPercentage = _calculatePercentage(feature.scenarios.pending, feature.scenarios.total);
feature.scenarios.skippedPercentage = _calculatePercentage(feature.scenarios.skipped, feature.scenarios.total);
suite.scenarios.ambiguousPercentage = _calculatePercentage(suite.scenarios.ambiguous, suite.scenarios.total);
suite.scenarios.failedPercentage = _calculatePercentage(suite.scenarios.failed, suite.scenarios.total);
suite.scenarios.notdefinedPercentage = _calculatePercentage(suite.scenarios.notDefined, suite.scenarios.total);
suite.scenarios.notDefinedPercentage = _calculatePercentage(suite.scenarios.notDefined, suite.scenarios.total);
suite.scenarios.passedPercentage = _calculatePercentage(suite.scenarios.passed, suite.scenarios.total);
suite.scenarios.pendingPercentage = _calculatePercentage(suite.scenarios.pending, suite.scenarios.total);
suite.scenarios.skippedPercentage = _calculatePercentage(suite.scenarios.skipped, suite.scenarios.total);
Expand Down Expand Up @@ -332,45 +333,38 @@ function generateReport(options) {
function _parseSteps(scenario) {
scenario.steps.forEach(step => {
if (step.embeddings !== undefined) {
const Base64 = require('js-base64').Base64;

step.attachments = [];
step.embeddings.forEach((embedding, embeddingIndex) => {
/* istanbul ignore else */
if (embedding.mime_type === 'application/json' || embedding.media && embedding.media.type === 'application/json') {
step.json = (step.json ? step.json : []).concat([typeof embedding.data === 'string' ? JSON.parse(embedding.data) : embedding.data]);
} else if (embedding.mime_type === 'text/html' || (embedding.media && embedding.media.type === 'text/html')) {
step.html = (step.html ? step.html : []).concat([
_isBase64(embedding.data) ? Base64.decode(embedding.data) :
embedding.data
]);
step.html = (step.html ? step.html : []).concat([embedding.data]);
} else if (embedding.mime_type === 'text/plain' || (embedding.media && embedding.media.type === 'text/plain')) {
step.text = (step.text ? step.text : []).concat([
_isBase64(embedding.data) ? _escapeHtml(Base64.decode(embedding.data)) : _escapeHtml(embedding.data)
]);
step.text = (step.text ? step.text : []).concat([_escapeHtml(embedding.data)]);
} else if (embedding.mime_type === 'image/png' || (embedding.media && embedding.media.type === 'image/png')) {
step.image = (step.image ? step.image : []).concat([ 'data:image/png;base64,' + embedding.data ]);
step.embeddings[ embeddingIndex ] = {};
} else {
let embeddingtype = 'text/plain';
let embeddingType = 'text/plain';
if (embedding.mime_type) {
embeddingtype = embedding.mime_type;
embeddingType = embedding.mime_type;
} else if (embedding.media && embedding.media.type) {
embeddingtype = embedding.media.type;
embeddingType = embedding.media.type;
}
step.attachments.push({
data: 'data:' + embeddingtype + ';base64,' + embedding.data,
type: embeddingtype
data: 'data:' + embeddingType + ';base64,' + embedding.data,
type: embeddingType
});
step.embeddings[ embeddingIndex ] = {};
}
});
}

if (step.doc_string !== undefined) {
step.id = `${uuid()}.${scenario.id}.${step.name}`.replace(/[^a-zA-Z0-9-_]/g, '-');
step.restWireData = _escapeHtml(step.doc_string.value).replace(new RegExp('\r?\n', 'g'), '<br />');
}
if (step.doc_string !== undefined) {
step.id = `${uuid()}.${scenario.id}.${step.name}`.replace(/[^a-zA-Z0-9-_]/g, '-');
step.restWireData = _escapeHtml(step.doc_string.value).replace(new RegExp('\r?\n', 'g'), '<br />');
}

if (!step.result
// Don't log steps that don't have a text/hidden/images/attachments unless they are failed.
Expand Down Expand Up @@ -430,27 +424,6 @@ function generateReport(options) {
}
}

/**
* Check if the string a base64 string
* @param string
* @return {boolean}
* @private
*/
function _isBase64(string) {
const notBase64 = /[^A-Z0-9+\/=]/i;
const stringLength = string.length;

if (!stringLength || stringLength % 4 !== 0 || notBase64.test(string)) {
return false;
}

const firstPaddingChar = string.indexOf('=');

return firstPaddingChar === -1 ||
firstPaddingChar === stringLength - 1 ||
(firstPaddingChar === stringLength - 2 && string[ stringLength - 1 ] === '=');
}

/**
* Escape html in string
* @param string
Expand Down Expand Up @@ -553,9 +526,10 @@ function generateReport(options) {
pageTitle: pageTitle,
reportName: reportName,
pageFooter: pageFooter,
plainDescription: plainDescription
})
);
// Copy the assets, but first check if they don't exists and not useCDN
// Copy the assets, but first check if they don't exist and not useCDN
if (!fs.pathExistsSync(path.resolve(reportPath, 'assets')) && !suite.useCDN) {
fs.copySync(
path.resolve(path.dirname(require.resolve('../package.json')), 'templates/assets'),
Expand Down
5 changes: 0 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
"chalk": "^3.0.0",
"find": "^0.3.0",
"fs-extra": "^8.1.0",
"js-base64": "^2.5.1",
"jsonfile": "^5.0.0",
"lodash": "^4.17.19",
"moment": "^2.24.0",
Expand Down
16 changes: 16 additions & 0 deletions templates/assets/js/Chart.style.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
function getChartColors() {
const colorsMap = [
{colorVar: "--passed-color", defaultColor: "#26B99A"},
{colorVar: "--failed-color", defaultColor: "#E74C3C"},
{colorVar: "--pending-color", defaultColor: "#FFD119"},
{colorVar: "--skipped-color", defaultColor: "#3498DB"},
{colorVar: "--ambiguous-color", defaultColor: "#b73122"},
{colorVar: "--not-defined-color", defaultColor: "#F39C12"},
];
const colors = []
const style = window.getComputedStyle(document.body);
for (let i = 0; i < colorsMap.length; i++) {
colors.push(style.getPropertyValue(colorsMap[i].colorVar) || colorsMap[i].defaultColor)
}
return colors
}
2 changes: 1 addition & 1 deletion templates/components/features-overview.chart.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
Not Defined
</p>
</td>
<td class="percentage"><%= suite.featureCount.notdefinedPercentage %> %</td>
<td class="percentage"><%= suite.featureCount.notDefinedPercentage %> %</td>
</tr>
<%}%>
<%if(suite.featureCount.pending > 0){%>
Expand Down
2 changes: 1 addition & 1 deletion templates/components/scenarios-overview.chart.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
Not defined
</p>
</td>
<td class="percentage"><%= scenarios.notdefinedPercentage %> %</td>
<td class="percentage"><%= scenarios.notDefinedPercentage %> %</td>
</tr>
<% } %>
</tr>
Expand Down
Loading

0 comments on commit c5f8b16

Please sign in to comment.