cucumber-html-report-generator
Version:
Generate beautiful cucumberjs html reports for multiple instances (browsers / devices)
147 lines (132 loc) • 7.49 kB
text/typescript
import * as CommonFunctions from '../../common-functions/common-functions';
import * as Models from '../../models/models';
import type * as messages from '@cucumber/messages';
import { ScenarioFormatter } from './scenario-formatter';
export class FeatureFormatter {
private readonly gherkinFeature: messages.Feature | null | undefined;
private jsonFeature: Models.Feature;
private readonly scenarioFormatter: ScenarioFormatter;
private readonly scenarioOutlines: Models.ScenarioOutline[];
public constructor( gherkinFeature: messages.Feature | null | undefined, jsonFeature: Models.Feature ) {
this.gherkinFeature = gherkinFeature;
this.jsonFeature = jsonFeature;
this.scenarioFormatter = new ScenarioFormatter( this.gherkinFeature );
this.scenarioOutlines = this.getOutlineScenarios();
}
public parseFeature (): Models.Feature {
this.initializeFeature();
if ( this.jsonFeature.elements?.length ) {
this.joinOutlineScenarios();
for ( let index = 0; index < this.jsonFeature.elements.length; index++ ) {
const jsonScenario = this.scenarioFormatter.parseScenario( this.jsonFeature.elements[ index ], this.jsonFeature.name );
if ( jsonScenario !== null && typeof jsonScenario !== 'undefined' ) {
this.jsonFeature.elements[ index ] = jsonScenario;
this.updateFeatureStatistics( this.jsonFeature.elements[ index ]?.results );
const gherkinScenario = this.gherkinFeature?.children.filter(
scenario => scenario.scenario?.name === jsonScenario.name )[ 0 ]?.scenario;
if ( this.isLastScenarioOutlineWithFeature( jsonScenario, index ) && gherkinScenario ) {
const scenarios = this.addFirstScenarioOutline( this.jsonFeature.elements, jsonScenario, index, gherkinScenario );
this.jsonFeature.elements = scenarios;
index++;
}
}
}
this.jsonFeature.results.overview.durationHHMMSS =
CommonFunctions.convertTimeFromNanoSecondsToHHMMSS( this.jsonFeature.results.overview.duration );
this.jsonFeature.elements = this.jsonFeature.elements.filter( scenario => Object.keys( scenario ).length && scenario.steps?.length );
}
return this.jsonFeature;
}
private addFirstScenarioOutline ( scenarios: Models.Scenario[], jsonScenario: Models.Scenario, index: number, gherkinScenario: messages.Scenario ): Models.Scenario[] {
const scenarioName = jsonScenario.name;
const scenarioOutlineLengthWithoutHeaders = this.scenarioOutlines.filter( scenario => scenario.name === scenarioName ).length - 1;
const scenarioOutline = this.scenarioFormatter.createNewFirstScenarioOutline( jsonScenario, gherkinScenario, scenarios, index - scenarioOutlineLengthWithoutHeaders );
scenarios.splice( index - scenarioOutlineLengthWithoutHeaders, 0, scenarioOutline );
return scenarios;
}
private updateFeatureStatistics ( scenarioResults: Models.ScenarioResults ): void {
this.jsonFeature.results.scenarios.undefined += scenarioResults.steps.undefined ? 1 : 0;
this.jsonFeature.results.scenarios.failed += !scenarioResults.steps.undefined && scenarioResults.steps.failed ? 1 : 0;
this.jsonFeature.results.scenarios.ambiguous += scenarioResults.steps.ambiguous &&
!scenarioResults.steps.undefined &&
!scenarioResults.steps.failed ? 1 : 0;
this.jsonFeature.results.scenarios.pending += scenarioResults.steps.pending &&
!scenarioResults.steps.failed &&
!scenarioResults.steps.ambiguous &&
!scenarioResults.steps.undefined ? 1 : 0;
this.jsonFeature.results.scenarios.skipped += scenarioResults.steps.skipped &&
!scenarioResults.steps.failed &&
!scenarioResults.steps.ambiguous &&
!scenarioResults.steps.pending &&
!scenarioResults.steps.undefined ? 1 : 0;
this.jsonFeature.results.scenarios.passed +=
scenarioResults.steps.passed &&
!scenarioResults.steps.failed &&
!scenarioResults.steps.skipped &&
!scenarioResults.steps.pending &&
!scenarioResults.steps.ambiguous &&
!scenarioResults.steps.undefined ? 1 : 0;
this.jsonFeature.results.scenarios.total =
this.jsonFeature.results.scenarios.passed +
this.jsonFeature.results.scenarios.skipped +
this.jsonFeature.results.scenarios.pending +
this.jsonFeature.results.scenarios.undefined +
this.jsonFeature.results.scenarios.ambiguous +
this.jsonFeature.results.scenarios.failed;
this.jsonFeature.results.scenarios = CommonFunctions.updatePercentages( this.jsonFeature.results.scenarios );
this.jsonFeature.results.steps = CommonFunctions.updateResultsAndPercentages( this.jsonFeature.results.steps, scenarioResults.steps );
this.jsonFeature.results.overview.result = CommonFunctions.updateStatus( this.jsonFeature.results );
this.jsonFeature.results.overview.duration += scenarioResults.overview.duration;
}
private initializeFeature (): void {
this.jsonFeature.description = typeof this.jsonFeature.description === 'undefined' ? '' : this.jsonFeature.description;
this.jsonFeature.elements = this.jsonFeature.elements === null || typeof this.jsonFeature.elements === 'undefined' ? [] : this.jsonFeature.elements;
this.jsonFeature.results = Models.featureResultsInitializer();
this.jsonFeature.tags = typeof this.jsonFeature.tags === 'undefined' ? [] : this.jsonFeature.tags;
this.jsonFeature.metadataTitle = this.jsonFeature.metadataTitle ?? 'Custom Data';
this.jsonFeature.metadata = CommonFunctions.isMetadata( this.jsonFeature.metadata ) ? this.jsonFeature.metadata : [];
this.jsonFeature.line = this.jsonFeature.line ?? 0;
this.joinOutlineScenarios();
}
private joinOutlineScenarios (): void {
const scenarioOutlines: {
index: number;
name: string;
}[] = [];
this.jsonFeature.elements?.forEach( scenario => {
if ( this.scenarioFormatter.isOutlineScenario( scenario ) ) {
scenarioOutlines.push( {
index: parseInt( `${( this.jsonFeature.elements! ).indexOf( scenario )}`, 10 ),
name: `${scenario.name}`
} );
}
} );
const scenarioOutlineNames = [ ...new Set( scenarioOutlines.map( item => item.name ) ) ];
scenarioOutlineNames.forEach( name => {
const scenarioOutlineElements = scenarioOutlines.filter( scenario => scenario.name === name );
const firstScenarioIndex = scenarioOutlineElements[ 0 ].index;
scenarioOutlineElements.forEach( ( scenarioOutlineElement, index ) => {
CommonFunctions.moveArray( this.jsonFeature.elements!, scenarioOutlineElement.index, firstScenarioIndex + index );
} );
} );
}
private isLastScenarioOutlineWithFeature ( scenario: Models.Scenario, index: number ): boolean {
const occurrences = this.scenarioOutlines.filter( scenarioElement => scenarioElement.name === scenario.name );
if ( occurrences[ occurrences.length - 1 ]?.index === index ) {
return true;
}
return false;
}
private getOutlineScenarios (): Models.ScenarioOutline[] {
const scenarioOutlines: Models.ScenarioOutline[] = [];
this.jsonFeature.elements?.forEach( scenario => {
if ( this.scenarioFormatter.isOutlineScenario( scenario ) ) {
scenarioOutlines.push( {
index: parseInt( `${( this.jsonFeature.elements! ).indexOf( scenario )}`, 10 ),
name: `${scenario.name}`
} );
}
} );
return scenarioOutlines;
}
}