Skip to content
Permalink
Browse files
feat(serenity-bdd): AssertionErrors are reported together with a diff…
… of actual/expected
  • Loading branch information
jan-molak committed Nov 24, 2019
1 parent 689937d commit 6b7a55e28e727c5c43da4d811bf833bef7cefad6
@@ -31,6 +31,7 @@
},
"dependencies": {
"cuid": "2.1.1",
"diff": "^4.0.1",
"error-stack-parser": "2.0.2",
"filenamify": "^4.1.0",
"graceful-fs": "4.1.11",
@@ -42,6 +43,7 @@
"devDependencies": {
"@documentation/esdoc-template": "2.0.1-alpha.85",
"@types/cuid": "1.3.0",
"@types/diff": "^4.0.2",
"@types/filenamify": "^2.0.2",
"@types/mkdirp": "0.5.2",
"@types/mocha": "^5.2.6",
@@ -0,0 +1,38 @@
import { Change, diffLines } from 'diff';

export class AssertionReportDiffer {
constructor(private readonly mappers: AssertionReportDiffMappers) {
}

diff(expectedValue: string, actualValue: string): string {
const changes = diffLines(actualValue, expectedValue)
.map(change => this.markChanges(change));

return [
`Difference (${ this.mappers.expected('expected') }, ${ this.mappers.actual('actual') }):`,
'',
changes.length === 2
? changes.join('\n')
: changes.join(''),
].join('\n');
}

private markChanges(change: Change): string {

return !! change.added
? this.eachLineOf(change.value, this.mappers.expected)
: change.removed
? this.eachLineOf(change.value, this.mappers.actual)
: this.eachLineOf(change.value, this.mappers.matching);
}

private eachLineOf(lines: string, mapper: (line: string) => string): string {
return lines.split('\n').map(line => !! line.trim() ? mapper(line) : line).join('\n');
}
}

export interface AssertionReportDiffMappers {
expected: (line: string) => string;
actual: (line: string) => string;
matching: (line: string) => string;
}
@@ -1,3 +1,4 @@
export * from './AssertionReportDiffer';
export * from './ErrorSerialiser';
export * from './ErrorStackParser';
export * from './FileSystem';
@@ -8,6 +8,7 @@ import {
SceneTagged,
TestRunnerDetected,
} from '@serenity-js/core/lib/events';
import { AssertionReportDiffer } from '@serenity-js/core/lib/io';
import { Artifact, ArtifactType, AssertionReport, HTTPRequestResponse, JSONData, LogEntry, Photo, ScenarioDetails, TextData } from '@serenity-js/core/lib/model';
import { match } from 'tiny-types';
import { SceneReport } from '../reports';
@@ -17,6 +18,12 @@ import { SceneReport } from '../reports';
*/
export abstract class SceneReportingStrategy {

private static readonly differ = new AssertionReportDiffer({
expected: line => `+ ${ line }`,
actual: line => `- ${ line }`,
matching: line => ` ${ line }`,
});

constructor(protected readonly scenario: ScenarioDetails) {
}

@@ -34,7 +41,9 @@ export abstract class SceneReportingStrategy {
.when(TextData, _ => report.arbitraryDataCaptured(e.name, e.artifact.map(artifactContents => artifactContents.data)))
.when(LogEntry, _ => report.arbitraryDataCaptured(e.name, e.artifact.map(artifactContents => artifactContents.data)))
.when(AssertionReport, _ =>
report.arbitraryDataCaptured(e.name, e.artifact.map(artifactContents => `expected: ${ artifactContents.expected }\n\nactual: ${artifactContents.actual}`)),
report.arbitraryDataCaptured(e.name, e.artifact.map(artifactContents =>
SceneReportingStrategy.differ.diff(artifactContents.expected, artifactContents.actual),
)),
)
.when(JSONData, _ => report.arbitraryDataCaptured(e.name, e.artifact.map(artifactContents => JSON.stringify(artifactContents, null, 4))))
.else(_ => report))

0 comments on commit 6b7a55e

Please sign in to comment.