Skip to content

Commit 7fcece6

Browse files
feat: add support for mochawesome reporter (#216)
* feat: add support for mochawesome reporter
1 parent e4e4949 commit 7fcece6

34 files changed

+624
-107
lines changed

index.d.ts

+3
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ export { LogType } from "./lib/log-types";
1919
export { INsCapabilities } from "./lib/interfaces/ns-capabilities";
2020
export { INsCapabilitiesArgs } from "./lib/interfaces/ns-capabilities-args";
2121
export { logInfo, logError, logWarn } from "./lib/utils";
22+
export { ITestReporter } from "./lib/interfaces/test-reporter";
23+
export { screencapture } from "./lib/helpers/screenshot-manager";
24+
export { LogImageType } from "./lib/enums/log-image-type";
2225
export declare const nsCapabilities: INsCapabilities;
2326
export declare function startServer(port?: number, deviceManager?: IDeviceManager): Promise<AppiumServer>;
2427
export declare function stopServer(): Promise<void>;

index.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ import * as frameComparerHelper from "./lib/frame-comparer";
66
import { FrameComparer } from "./lib/frame-comparer";
77
import { DeviceManager } from "./lib/device-manager";
88
import { DeviceController } from "mobile-devices-controller";
9-
import { logInfo, logError, logWarn } from "./lib/utils";
9+
import { logInfo, logError } from "./lib/utils";
1010
import { INsCapabilities } from "./lib/interfaces/ns-capabilities";
1111
import { INsCapabilitiesArgs } from "./lib/interfaces/ns-capabilities-args";
1212
import * as parser from "./lib/parser"
1313
import { isWin } from "./lib/utils";
14+
import { LogImageType } from "./lib/enums/log-image-type";
1415

1516
export { AppiumDriver } from "./lib/appium-driver";
1617
export { AppiumServer } from "./lib/appium-server";
@@ -28,6 +29,9 @@ export { LogType } from "./lib/log-types";
2829
export { INsCapabilities } from "./lib/interfaces/ns-capabilities";
2930
export { INsCapabilitiesArgs } from "./lib/interfaces/ns-capabilities-args";
3031
export { logInfo, logError, logWarn } from "./lib/utils";
32+
export { ITestReporter } from "./lib/interfaces/test-reporter";
33+
export { screencapture } from "./lib/helpers/screenshot-manager";
34+
export { LogImageType } from "./lib/enums/log-image-type";
3135

3236
export const nsCapabilities: INsCapabilities = new NsCapabilities(parser);
3337

@@ -80,8 +84,9 @@ export async function createDriver(args?: INsCapabilitiesArgs) {
8084
if (args) {
8185
nsCapabilities.extend(args);
8286
}
83-
const port = nsCapabilities.port || appiumServer.port;
84-
87+
if (!nsCapabilities.port) {
88+
nsCapabilities.port = appiumServer.port;
89+
}
8590
if (nsCapabilities.attachToDebug) {
8691
if (!appiumDriver) {
8792
appiumDriver = await AppiumDriver.createAppiumDriver(nsCapabilities);

lib/appium-driver.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ export declare class AppiumDriver {
190190
private compare;
191191
prepareImageToCompare(filePath: string, rect: IRectangle): Promise<void>;
192192
takeScreenshot(fileName: string): Promise<string>;
193+
testReporterLog(log: any): any;
193194
logScreenshot(fileName: string): Promise<string>;
194195
getlog(logType: LogType): Promise<any>;
195196
logPageSource(fileName: string): Promise<void>;

lib/appium-driver.ts

+56-7
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@ import {
3535
logInfo,
3636
prepareDevice,
3737
getStorage,
38-
encodeImageToBase64
38+
encodeImageToBase64,
39+
ensureReportsDirExists,
40+
checkImageLogType
3941
} from "./utils";
4042

4143
import { INsCapabilities } from "./interfaces/ns-capabilities";
@@ -45,8 +47,10 @@ import { ImageHelper } from "./image-helper";
4547
import { ImageOptions } from "./image-options"
4648
import { unlinkSync, writeFileSync, existsSync } from "fs";
4749
import { DeviceManager } from "../lib/device-manager";
48-
import { extname, basename } from "path";
50+
import { extname, basename, join } from "path";
4951
import { LogType } from "./log-types";
52+
import { screencapture } from "./helpers/screenshot-manager";
53+
import { LogImageType } from "./enums/log-image-type";
5054

5155
export class AppiumDriver {
5256
private static pngFileExt = '.png';
@@ -274,8 +278,17 @@ export class AppiumDriver {
274278
}
275279
if (hasStarted) {
276280
console.log("Appium driver has started successfully!");
281+
if (checkImageLogType(args.testReporter, LogImageType.screenshots)) {
282+
args.testReporterLog(`appium_driver_started`);
283+
args.testReporterLog(screencapture(`${getReportPath(args)}/appium_driver_started.png`));
284+
}
277285
} else {
278-
logError("Appium driver is NOT started!")
286+
logError("Appium driver is NOT started!");
287+
if (checkImageLogType(args.testReporter, LogImageType.screenshots)) {
288+
ensureReportsDirExists(args);
289+
args.testReporterLog(`appium_driver_boot_failure`);
290+
args.testReporterLog(screencapture(`${getReportPath(args)}/appium_driver_boot_failure.png`));
291+
}
279292
}
280293

281294
retries--;
@@ -566,7 +579,6 @@ export class AppiumDriver {
566579
}
567580

568581
private async compare(imageName: string, timeOutSeconds: number = 3, tolerance: number = 0.01, rect?: IRectangle, toleranceType?: ImageOptions) {
569-
570582
if (!this._logPath) {
571583
this._logPath = getReportPath(this._args);
572584
}
@@ -588,6 +600,9 @@ export class AppiumDriver {
588600
copy(pathActualImage, pathActualImageToReportsFolder, false);
589601

590602
console.log("Remove the 'actual' suffix to continue using the image as expected one ", pathExpectedImage);
603+
this._args.testReporterLog(basename(pathActualImage));
604+
this._args.testReporterLog(join(this._logPath, basename(pathActualImage)));
605+
591606
return false;
592607
}
593608

@@ -609,8 +624,17 @@ export class AppiumDriver {
609624

610625
await this.prepareImageToCompare(pathActualImage, rect);
611626
result = await this._imageHelper.compareImages(pathActualImage, pathExpectedImage, pathDiffImage, tolerance, toleranceType);
627+
if (checkImageLogType(this._args.testReporter, LogImageType.everyImage)) {
628+
this._args.testReporterLog("Actual image: ");
629+
this._args.testReporterLog(join(this._logPath, basename(pathActualImage)));
630+
}
612631
counter++;
613632
}
633+
634+
if (!checkImageLogType(this._args.testReporter, LogImageType.everyImage)) {
635+
this._args.testReporterLog("Actual image: ");
636+
this._args.testReporterLog(join(this._logPath, basename(pathDiffImage)));
637+
}
614638
} else {
615639
if (existsSync(pathDiffImage)) {
616640
unlinkSync(pathDiffImage);
@@ -653,15 +677,30 @@ export class AppiumDriver {
653677
});
654678
}
655679

680+
public testReporterLog(log: any): any {
681+
if (this._args.testReporterLog) {
682+
return this._args.testReporterLog(log);
683+
}
684+
return undefined;
685+
}
686+
656687
public async logScreenshot(fileName: string) {
657688
if (!this._logPath) {
658689
this._logPath = getReportPath(this._args);
659690
}
660691
if (!fileName.endsWith(AppiumDriver.pngFileExt)) {
661-
fileName = fileName.concat(AppiumDriver.pngFileExt);
692+
fileName = fileName.concat(AppiumDriver.pngFileExt).replace(/\s+/ig, "_");
662693
}
663694

664-
const imgPath = await this.takeScreenshot(resolvePath(this._logPath, fileName));
695+
if (Object.getOwnPropertyNames(this._args.testReporter).length > 0) {
696+
this.testReporterLog(fileName.replace(/\.\w+/ig, ""));
697+
fileName = join(this._logPath, fileName);
698+
fileName = this.testReporterLog(fileName);
699+
}
700+
701+
fileName = resolvePath(this._logPath, fileName)
702+
703+
const imgPath = await this.takeScreenshot(fileName);
665704
return imgPath;
666705
}
667706

@@ -741,6 +780,8 @@ export class AppiumDriver {
741780
*/
742781
public async backgroundApp(minutes: number) {
743782
logInfo("Sending the currently active app to the background ...");
783+
this._args.testReporterLog("Sending the currently active app to the background ...");
784+
744785
await this._driver.backgroundApp(minutes);
745786
}
746787

@@ -750,7 +791,7 @@ export class AppiumDriver {
750791
public async hideDeviceKeyboard() {
751792
try {
752793
await this._driver.hideDeviceKeyboard();
753-
} catch (error) {}
794+
} catch (error) { }
754795
}
755796

756797
public async isKeyboardShown() {
@@ -777,11 +818,19 @@ export class AppiumDriver {
777818
await this._driver.quit();
778819
this._isAlive = false;
779820
console.log("Driver is dead!");
821+
if (checkImageLogType(this._args.testReporter, LogImageType.screenshots)) {
822+
this._args.testReporterLog(`appium_driver_quit`);
823+
this._args.testReporterLog(screencapture(`${getReportPath(this._args)}/appium_driver_quit.png`));
824+
}
780825
} else {
781826
//await this._webio.detach();
782827
}
783828
} catch (error) {
784829
if (this._args.verbose) {
830+
if (checkImageLogType(this._args.testReporter, LogImageType.screenshots)) {
831+
this._args.testReporterLog(`appium_driver_quit_failure`);
832+
this._args.testReporterLog(screencapture(`${getReportPath(this._args)}/appium_driver_quit_failure.png`));
833+
}
785834
console.dir(error);
786835
}
787836
}

lib/appium-server.ts

+32-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ChildProcess, spawn, execSync } from "child_process";
1+
import { ChildProcess, spawn } from "child_process";
22
import {
33
log,
44
resolvePath,
@@ -10,13 +10,18 @@ import {
1010
logInfo,
1111
prepareApp,
1212
prepareDevice,
13-
stopServerCommand
13+
getReportPath,
14+
ensureReportsDirExists,
15+
logError,
16+
checkImageLogType
1417
} from "./utils";
1518
import { INsCapabilities } from "./interfaces/ns-capabilities";
1619
import { IDeviceManager } from "./interfaces/device-manager";
1720
import { DeviceManager } from "./device-manager";
1821
import { existsSync } from "fs";
1922
import { killAllProcessAndRelatedCommand } from "mobile-devices-controller";
23+
import { screencapture } from "./helpers/screenshot-manager";
24+
import { LogImageType } from "./enums/log-image-type";
2025

2126
export class AppiumServer {
2227
private _server: ChildProcess;
@@ -98,6 +103,19 @@ export class AppiumServer {
98103
}
99104

100105
this.hasStarted = response;
106+
try {
107+
ensureReportsDirExists(this._args);
108+
if (checkImageLogType(this._args.testReporter, LogImageType.screenshots)) {
109+
this._args.testReporterLog(`on_server_started`);
110+
this._args.testReporterLog(screencapture(`${getReportPath(this._args)}/on_server_started.png`));
111+
}
112+
} catch (error) {
113+
logError(`Appium server is NOT started - ${error.message}`);
114+
if (checkImageLogType(this._args.testReporter, LogImageType.screenshots)) {
115+
this._args.testReporterLog(`on_start_server_failure`);
116+
this._args.testReporterLog(screencapture(`${getReportPath(this._args)}/on_start_server_failure.png`));
117+
}
118+
}
101119
return response;
102120
} else if (!this._args.attachToDebug) {
103121
return true;
@@ -158,6 +176,12 @@ export class AppiumServer {
158176
this._server.kill("SIGKILL");
159177
process.kill(this._server.pid, "SIGKILL");
160178
shutdown(this._server, this._args.verbose);
179+
try {
180+
if (checkImageLogType(this._args.testReporter, LogImageType.screenshots)) {
181+
this._args.testReporterLog(`on_server_stopped`);
182+
this._args.testReporterLog(screencapture(`${getReportPath(this._args)}/on_server_stopped.png`));
183+
}
184+
} catch (error) { }
161185
}
162186
} catch (error) {
163187
console.log(error);
@@ -195,14 +219,15 @@ export class AppiumServer {
195219
logInfo("Using project-local Appium binary.", this._args.verbose);
196220
appium = projectAppiumBinary;
197221
} else {
222+
// TODO: find faster and reliable way to check if appium is installed globally
198223
//const result = executeCommand("npm list -g");
199-
//if (result.includes("appium")) {
224+
// if (result.includes("appium")) {
200225
logWarn("Using global Appium binary.");
201-
console.log('Please, make sure it is installed globally.');
226+
// console.log('Please, make sure it is installed globally.');
202227
//} else if (result.includes("appium")) {
203-
// const msg = "Appium not found. Please install appium before runnig tests!";
204-
// log(msg, this._args.verbose);
205-
// new Error(msg);
228+
// const msg = "Appium not found. Please install appium before runnig tests!";
229+
// log(msg, this._args.verbose);
230+
// new Error(msg);
206231
// }
207232
}
208233

lib/enums/log-image-type.d.ts

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export declare enum LogImageType {
2+
/**
3+
* Setting this property to add each image
4+
* during the image comparison into the report.
5+
* If not set, it will be logged only the last image comparison.
6+
*/
7+
everyImage = "everyImage",
8+
/**
9+
* Setting this property to take screenshot on each hook
10+
* and add the images into the report.
11+
*/
12+
screenshots = "screenshots"
13+
}

lib/enums/log-image-type.ts

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export enum LogImageType {
2+
/**
3+
* Setting this property to add each image
4+
* during the image comparison into the report.
5+
* If not set, it will be logged only the last image comparison.
6+
*/
7+
everyImage = "everyImage",
8+
/**
9+
* Setting this property to take screenshot on each hook
10+
* and add the images into the report.
11+
*/
12+
screenshots = "screenshots"
13+
}

lib/helpers/screenshot-manager.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export declare const screencapture: (imageFullName: string) => string;

lib/helpers/screenshot-manager.ts

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
3+
import { isWin, isMac, isLinux } from "../utils";
4+
import { execSync } from "child_process";
5+
6+
export const screencapture = (imageFullName: string) => {
7+
let command = "", result = "";
8+
9+
if (isWin()) {
10+
command = "";
11+
} else if (isMac()) {
12+
command = `screencapture -x -f '${imageFullName}'`;
13+
} else if (isLinux()) {
14+
command = `gnome-screenshot -f '${imageFullName}'`;
15+
} else {
16+
console.log("We could not capture the screen. Not supported OS!");
17+
}
18+
19+
if (command) {
20+
try {
21+
execSync(command) + "";
22+
result = imageFullName;
23+
} catch (error) {
24+
result = "We could not capture the screen!";
25+
}
26+
} else {
27+
result = "No file name provided to catch the screen!";
28+
}
29+
30+
return result;
31+
}

lib/image-helper.ts

+8-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as PngJsImage from "pngjs-image";
33
import { ImageOptions } from "./image-options";
44
import { INsCapabilities } from "./interfaces/ns-capabilities";
55
import { IRectangle } from "./interfaces/rectangle";
6+
import { LogImageType } from "./enums/log-image-type";
67

78
export class ImageHelper {
89

@@ -57,23 +58,26 @@ export class ImageHelper {
5758
}
5859

5960
private runDiff(diffOptions: BlinkDiff, diffImage: string) {
61+
var that = this;
6062
return new Promise<boolean>((resolve, reject) => {
6163
diffOptions.run(function (error, result) {
6264
if (error) {
6365
throw error;
6466
} else {
65-
let message;
67+
let message: string;
6668
let resultCode = diffOptions.hasPassed(result.code);
6769
if (resultCode) {
6870
message = "Screen compare passed!";
6971
console.log(message);
7072
console.log('Found ' + result.differences + ' differences.');
7173
return resolve(true);
7274
} else {
73-
message = "Screen compare failed!";
75+
message = `Screen compare failed! Found ${result.differences} differences.\n`;
7476
console.log(message);
75-
console.log('Found ' + result.differences + ' differences.');
76-
console.log('Diff image: ' + diffImage);
77+
if (Object.getOwnPropertyNames(that._args.testReporter).length > 0 && that._args.testReporter.logImageTypes && that._args.testReporter.logImageTypes.indexOf(LogImageType.everyImage) > -1) {
78+
that._args.testReporterLog(message);
79+
that._args.testReporterLog(diffImage);
80+
}
7781
return resolve(false);
7882
}
7983
}

0 commit comments

Comments
 (0)