aboutsummaryrefslogtreecommitdiffstats
path: root/test/runner/reporter.js
blob: c70c6d80c17be4cb03827cd94548d33ebb92971f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import chalk from "chalk";
import { getBrowserString } from "./lib/getBrowserString.js";
import { prettyMs } from "./lib/prettyMs.js";
import * as Diff from "diff";

export function reportTest( test, reportId, { browser, headless } ) {
	if ( test.status === "passed" ) {

		// Write to console without newlines
		process.stdout.write( "." );
		return;
	}

	let message = `${ chalk.bold( `${ test.suiteName }: ${ test.name }` ) }`;
	message += `\nTest ${ test.status } on ${ chalk.yellow(
		getBrowserString( browser, headless )
	) } (${ chalk.bold( reportId ) }).`;

	// test.assertions only contains passed assertions;
	// test.errors contains all failed asssertions
	if ( test.errors.length ) {
		for ( const error of test.errors ) {
			message += "\n";
			if ( error.message ) {
				message += `\n${ error.message }`;
			}
			message += `\n${ chalk.gray( error.stack ) }`;
			if ( "expected" in error && "actual" in error ) {
				message += `\nexpected: ${ JSON.stringify( error.expected ) }`;
				message += `\nactual: ${ JSON.stringify( error.actual ) }`;
				let diff;

				if (
					Array.isArray( error.expected ) &&
					Array.isArray( error.actual )
				) {

					// Diff arrays
					diff = Diff.diffArrays( error.expected, error.actual );
				} else if (
					typeof error.expected === "object" &&
					typeof error.actual === "object"
				) {

					// Diff objects
					diff = Diff.diffJson( error.expected, error.actual );
				} else if (
					typeof error.expected === "number" &&
					typeof error.expected === "number"
				) {

					// Diff numbers directly
					const value = error.actual - error.expected;
					if ( value > 0 ) {
						diff = [ { added: true, value: `+${ value }` } ];
					} else {
						diff = [ { removed: true, value: `${ value }` } ];
					}
				} else if (
					typeof error.expected === "boolean" &&
					typeof error.actual === "boolean"
				) {

					// Show the actual boolean in red
					diff = [ { removed: true, value: `${ error.actual }` } ];
				} else {

					// Diff everything else as characters
					diff = Diff.diffChars( `${ error.expected }`, `${ error.actual }` );
				}

				message += "\n";
				message += diff
					.map( ( part ) => {
						if ( part.added ) {
							return chalk.green( part.value );
						}
						if ( part.removed ) {
							return chalk.red( part.value );
						}
						return chalk.gray( part.value );
					} )
					.join( "" );
			}
		}
	}

	console.log( `\n\n${ message }` );

	// Only return failed messages
	if ( test.status === "failed" ) {
		return message;
	}
}

export function reportEnd( result, reportId, { browser, headless, modules } ) {
	console.log(
		`\n\nTests for ${ chalk.yellow( modules.join( ", " ) ) } on ${ chalk.yellow(
			getBrowserString( browser, headless )
		) } finished in ${ prettyMs( result.runtime ) } (${ chalk.bold( reportId ) }).`
	);
	console.log(
		( result.status !== "passed" ?
			`${ chalk.red( result.testCounts.failed ) } failed. ` :
			"" ) +
			`${ chalk.green( result.testCounts.total ) } passed. ` +
			`${ chalk.gray( result.testCounts.skipped ) } skipped.`
	);
	return result.testCounts;
}