diff --git a/index.d.ts b/index.d.ts index 5a74911..9034ecc 100644 --- a/index.d.ts +++ b/index.d.ts @@ -19,6 +19,9 @@ export { LogType } from "./lib/log-types"; export { INsCapabilities } from "./lib/interfaces/ns-capabilities"; export { INsCapabilitiesArgs } from "./lib/interfaces/ns-capabilities-args"; export { logInfo, logError, logWarn } from "./lib/utils"; +export { ITestReporter } from "./lib/interfaces/test-reporter"; +export { screencapture } from "./lib/helpers/screenshot-manager"; +export { LogImageType } from "./lib/enums/log-image-type"; export declare const nsCapabilities: INsCapabilities; export declare function startServer(port?: number, deviceManager?: IDeviceManager): Promise; export declare function stopServer(): Promise; diff --git a/index.ts b/index.ts index 07fae1c..f12d2eb 100644 --- a/index.ts +++ b/index.ts @@ -6,11 +6,12 @@ import * as frameComparerHelper from "./lib/frame-comparer"; import { FrameComparer } from "./lib/frame-comparer"; import { DeviceManager } from "./lib/device-manager"; import { DeviceController } from "mobile-devices-controller"; -import { logInfo, logError, logWarn } from "./lib/utils"; +import { logInfo, logError } from "./lib/utils"; import { INsCapabilities } from "./lib/interfaces/ns-capabilities"; import { INsCapabilitiesArgs } from "./lib/interfaces/ns-capabilities-args"; import * as parser from "./lib/parser" import { isWin } from "./lib/utils"; +import { LogImageType } from "./lib/enums/log-image-type"; export { AppiumDriver } from "./lib/appium-driver"; export { AppiumServer } from "./lib/appium-server"; @@ -28,6 +29,9 @@ export { LogType } from "./lib/log-types"; export { INsCapabilities } from "./lib/interfaces/ns-capabilities"; export { INsCapabilitiesArgs } from "./lib/interfaces/ns-capabilities-args"; export { logInfo, logError, logWarn } from "./lib/utils"; +export { ITestReporter } from "./lib/interfaces/test-reporter"; +export { screencapture } from "./lib/helpers/screenshot-manager"; +export { LogImageType } from "./lib/enums/log-image-type"; export const nsCapabilities: INsCapabilities = new NsCapabilities(parser); @@ -80,8 +84,9 @@ export async function createDriver(args?: INsCapabilitiesArgs) { if (args) { nsCapabilities.extend(args); } - const port = nsCapabilities.port || appiumServer.port; - + if (!nsCapabilities.port) { + nsCapabilities.port = appiumServer.port; + } if (nsCapabilities.attachToDebug) { if (!appiumDriver) { appiumDriver = await AppiumDriver.createAppiumDriver(nsCapabilities); diff --git a/lib/appium-driver.d.ts b/lib/appium-driver.d.ts index 043f5cc..fb76004 100644 --- a/lib/appium-driver.d.ts +++ b/lib/appium-driver.d.ts @@ -190,6 +190,7 @@ export declare class AppiumDriver { private compare; prepareImageToCompare(filePath: string, rect: IRectangle): Promise; takeScreenshot(fileName: string): Promise; + testReporterLog(log: any): any; logScreenshot(fileName: string): Promise; getlog(logType: LogType): Promise; logPageSource(fileName: string): Promise; diff --git a/lib/appium-driver.ts b/lib/appium-driver.ts index 68cbcc0..ee3e7b7 100644 --- a/lib/appium-driver.ts +++ b/lib/appium-driver.ts @@ -35,7 +35,9 @@ import { logInfo, prepareDevice, getStorage, - encodeImageToBase64 + encodeImageToBase64, + ensureReportsDirExists, + checkImageLogType } from "./utils"; import { INsCapabilities } from "./interfaces/ns-capabilities"; @@ -45,8 +47,10 @@ import { ImageHelper } from "./image-helper"; import { ImageOptions } from "./image-options" import { unlinkSync, writeFileSync, existsSync } from "fs"; import { DeviceManager } from "../lib/device-manager"; -import { extname, basename } from "path"; +import { extname, basename, join } from "path"; import { LogType } from "./log-types"; +import { screencapture } from "./helpers/screenshot-manager"; +import { LogImageType } from "./enums/log-image-type"; export class AppiumDriver { private static pngFileExt = '.png'; @@ -274,8 +278,17 @@ export class AppiumDriver { } if (hasStarted) { console.log("Appium driver has started successfully!"); + if (checkImageLogType(args.testReporter, LogImageType.screenshots)) { + args.testReporterLog(`appium_driver_started`); + args.testReporterLog(screencapture(`${getReportPath(args)}/appium_driver_started.png`)); + } } else { - logError("Appium driver is NOT started!") + logError("Appium driver is NOT started!"); + if (checkImageLogType(args.testReporter, LogImageType.screenshots)) { + ensureReportsDirExists(args); + args.testReporterLog(`appium_driver_boot_failure`); + args.testReporterLog(screencapture(`${getReportPath(args)}/appium_driver_boot_failure.png`)); + } } retries--; @@ -566,7 +579,6 @@ export class AppiumDriver { } private async compare(imageName: string, timeOutSeconds: number = 3, tolerance: number = 0.01, rect?: IRectangle, toleranceType?: ImageOptions) { - if (!this._logPath) { this._logPath = getReportPath(this._args); } @@ -588,6 +600,9 @@ export class AppiumDriver { copy(pathActualImage, pathActualImageToReportsFolder, false); console.log("Remove the 'actual' suffix to continue using the image as expected one ", pathExpectedImage); + this._args.testReporterLog(basename(pathActualImage)); + this._args.testReporterLog(join(this._logPath, basename(pathActualImage))); + return false; } @@ -609,8 +624,17 @@ export class AppiumDriver { await this.prepareImageToCompare(pathActualImage, rect); result = await this._imageHelper.compareImages(pathActualImage, pathExpectedImage, pathDiffImage, tolerance, toleranceType); + if (checkImageLogType(this._args.testReporter, LogImageType.everyImage)) { + this._args.testReporterLog("Actual image: "); + this._args.testReporterLog(join(this._logPath, basename(pathActualImage))); + } counter++; } + + if (!checkImageLogType(this._args.testReporter, LogImageType.everyImage)) { + this._args.testReporterLog("Actual image: "); + this._args.testReporterLog(join(this._logPath, basename(pathDiffImage))); + } } else { if (existsSync(pathDiffImage)) { unlinkSync(pathDiffImage); @@ -653,15 +677,30 @@ export class AppiumDriver { }); } + public testReporterLog(log: any): any { + if (this._args.testReporterLog) { + return this._args.testReporterLog(log); + } + return undefined; + } + public async logScreenshot(fileName: string) { if (!this._logPath) { this._logPath = getReportPath(this._args); } if (!fileName.endsWith(AppiumDriver.pngFileExt)) { - fileName = fileName.concat(AppiumDriver.pngFileExt); + fileName = fileName.concat(AppiumDriver.pngFileExt).replace(/\s+/ig, "_"); } - const imgPath = await this.takeScreenshot(resolvePath(this._logPath, fileName)); + if (Object.getOwnPropertyNames(this._args.testReporter).length > 0) { + this.testReporterLog(fileName.replace(/\.\w+/ig, "")); + fileName = join(this._logPath, fileName); + fileName = this.testReporterLog(fileName); + } + + fileName = resolvePath(this._logPath, fileName) + + const imgPath = await this.takeScreenshot(fileName); return imgPath; } @@ -741,6 +780,8 @@ export class AppiumDriver { */ public async backgroundApp(minutes: number) { logInfo("Sending the currently active app to the background ..."); + this._args.testReporterLog("Sending the currently active app to the background ..."); + await this._driver.backgroundApp(minutes); } @@ -750,7 +791,7 @@ export class AppiumDriver { public async hideDeviceKeyboard() { try { await this._driver.hideDeviceKeyboard(); - } catch (error) {} + } catch (error) { } } public async isKeyboardShown() { @@ -777,11 +818,19 @@ export class AppiumDriver { await this._driver.quit(); this._isAlive = false; console.log("Driver is dead!"); + if (checkImageLogType(this._args.testReporter, LogImageType.screenshots)) { + this._args.testReporterLog(`appium_driver_quit`); + this._args.testReporterLog(screencapture(`${getReportPath(this._args)}/appium_driver_quit.png`)); + } } else { //await this._webio.detach(); } } catch (error) { if (this._args.verbose) { + if (checkImageLogType(this._args.testReporter, LogImageType.screenshots)) { + this._args.testReporterLog(`appium_driver_quit_failure`); + this._args.testReporterLog(screencapture(`${getReportPath(this._args)}/appium_driver_quit_failure.png`)); + } console.dir(error); } } diff --git a/lib/appium-server.ts b/lib/appium-server.ts index 3cc93c6..f766689 100644 --- a/lib/appium-server.ts +++ b/lib/appium-server.ts @@ -1,4 +1,4 @@ -import { ChildProcess, spawn, execSync } from "child_process"; +import { ChildProcess, spawn } from "child_process"; import { log, resolvePath, @@ -10,13 +10,18 @@ import { logInfo, prepareApp, prepareDevice, - stopServerCommand + getReportPath, + ensureReportsDirExists, + logError, + checkImageLogType } from "./utils"; import { INsCapabilities } from "./interfaces/ns-capabilities"; import { IDeviceManager } from "./interfaces/device-manager"; import { DeviceManager } from "./device-manager"; import { existsSync } from "fs"; import { killAllProcessAndRelatedCommand } from "mobile-devices-controller"; +import { screencapture } from "./helpers/screenshot-manager"; +import { LogImageType } from "./enums/log-image-type"; export class AppiumServer { private _server: ChildProcess; @@ -98,6 +103,19 @@ export class AppiumServer { } this.hasStarted = response; + try { + ensureReportsDirExists(this._args); + if (checkImageLogType(this._args.testReporter, LogImageType.screenshots)) { + this._args.testReporterLog(`on_server_started`); + this._args.testReporterLog(screencapture(`${getReportPath(this._args)}/on_server_started.png`)); + } + } catch (error) { + logError(`Appium server is NOT started - ${error.message}`); + if (checkImageLogType(this._args.testReporter, LogImageType.screenshots)) { + this._args.testReporterLog(`on_start_server_failure`); + this._args.testReporterLog(screencapture(`${getReportPath(this._args)}/on_start_server_failure.png`)); + } + } return response; } else if (!this._args.attachToDebug) { return true; @@ -158,6 +176,12 @@ export class AppiumServer { this._server.kill("SIGKILL"); process.kill(this._server.pid, "SIGKILL"); shutdown(this._server, this._args.verbose); + try { + if (checkImageLogType(this._args.testReporter, LogImageType.screenshots)) { + this._args.testReporterLog(`on_server_stopped`); + this._args.testReporterLog(screencapture(`${getReportPath(this._args)}/on_server_stopped.png`)); + } + } catch (error) { } } } catch (error) { console.log(error); @@ -195,14 +219,15 @@ export class AppiumServer { logInfo("Using project-local Appium binary.", this._args.verbose); appium = projectAppiumBinary; } else { + // TODO: find faster and reliable way to check if appium is installed globally //const result = executeCommand("npm list -g"); - //if (result.includes("appium")) { + // if (result.includes("appium")) { logWarn("Using global Appium binary."); - console.log('Please, make sure it is installed globally.'); + // console.log('Please, make sure it is installed globally.'); //} else if (result.includes("appium")) { - // const msg = "Appium not found. Please install appium before runnig tests!"; - // log(msg, this._args.verbose); - // new Error(msg); + // const msg = "Appium not found. Please install appium before runnig tests!"; + // log(msg, this._args.verbose); + // new Error(msg); // } } diff --git a/lib/enums/log-image-type.d.ts b/lib/enums/log-image-type.d.ts new file mode 100644 index 0000000..c022605 --- /dev/null +++ b/lib/enums/log-image-type.d.ts @@ -0,0 +1,13 @@ +export declare enum LogImageType { + /** + * Setting this property to add each image + * during the image comparison into the report. + * If not set, it will be logged only the last image comparison. + */ + everyImage = "everyImage", + /** + * Setting this property to take screenshot on each hook + * and add the images into the report. + */ + screenshots = "screenshots" +} diff --git a/lib/enums/log-image-type.ts b/lib/enums/log-image-type.ts new file mode 100644 index 0000000..11c6111 --- /dev/null +++ b/lib/enums/log-image-type.ts @@ -0,0 +1,13 @@ +export enum LogImageType { + /** + * Setting this property to add each image + * during the image comparison into the report. + * If not set, it will be logged only the last image comparison. + */ + everyImage = "everyImage", + /** + * Setting this property to take screenshot on each hook + * and add the images into the report. + */ + screenshots = "screenshots" +} \ No newline at end of file diff --git a/lib/helpers/screenshot-manager.d.ts b/lib/helpers/screenshot-manager.d.ts new file mode 100644 index 0000000..85739e0 --- /dev/null +++ b/lib/helpers/screenshot-manager.d.ts @@ -0,0 +1 @@ +export declare const screencapture: (imageFullName: string) => string; diff --git a/lib/helpers/screenshot-manager.ts b/lib/helpers/screenshot-manager.ts new file mode 100644 index 0000000..ea63d7e --- /dev/null +++ b/lib/helpers/screenshot-manager.ts @@ -0,0 +1,31 @@ + + +import { isWin, isMac, isLinux } from "../utils"; +import { execSync } from "child_process"; + +export const screencapture = (imageFullName: string) => { + let command = "", result = ""; + + if (isWin()) { + command = ""; + } else if (isMac()) { + command = `screencapture -x -f '${imageFullName}'`; + } else if (isLinux()) { + command = `gnome-screenshot -f '${imageFullName}'`; + } else { + console.log("We could not capture the screen. Not supported OS!"); + } + + if (command) { + try { + execSync(command) + ""; + result = imageFullName; + } catch (error) { + result = "We could not capture the screen!"; + } + } else { + result = "No file name provided to catch the screen!"; + } + + return result; +} \ No newline at end of file diff --git a/lib/image-helper.ts b/lib/image-helper.ts index 6476917..0e721c7 100644 --- a/lib/image-helper.ts +++ b/lib/image-helper.ts @@ -3,6 +3,7 @@ import * as PngJsImage from "pngjs-image"; import { ImageOptions } from "./image-options"; import { INsCapabilities } from "./interfaces/ns-capabilities"; import { IRectangle } from "./interfaces/rectangle"; +import { LogImageType } from "./enums/log-image-type"; export class ImageHelper { @@ -57,12 +58,13 @@ export class ImageHelper { } private runDiff(diffOptions: BlinkDiff, diffImage: string) { + var that = this; return new Promise((resolve, reject) => { diffOptions.run(function (error, result) { if (error) { throw error; } else { - let message; + let message: string; let resultCode = diffOptions.hasPassed(result.code); if (resultCode) { message = "Screen compare passed!"; @@ -70,10 +72,12 @@ export class ImageHelper { console.log('Found ' + result.differences + ' differences.'); return resolve(true); } else { - message = "Screen compare failed!"; + message = `Screen compare failed! Found ${result.differences} differences.\n`; console.log(message); - console.log('Found ' + result.differences + ' differences.'); - console.log('Diff image: ' + diffImage); + if (Object.getOwnPropertyNames(that._args.testReporter).length > 0 && that._args.testReporter.logImageTypes && that._args.testReporter.logImageTypes.indexOf(LogImageType.everyImage) > -1) { + that._args.testReporterLog(message); + that._args.testReporterLog(diffImage); + } return resolve(false); } } diff --git a/lib/interfaces/ns-capabilities-args.d.ts b/lib/interfaces/ns-capabilities-args.d.ts index 35d5581..0a9101f 100644 --- a/lib/interfaces/ns-capabilities-args.d.ts +++ b/lib/interfaces/ns-capabilities-args.d.ts @@ -1,6 +1,8 @@ import { IDevice } from "mobile-devices-controller"; import { IDeviceManager } from "./device-manager"; import { AutomationName } from "../automation-name"; +import { ITestReporter } from "./test-reporter"; +import { LogImageType } from "../enums/log-image-type"; export interface INsCapabilitiesArgs { port?: number; wdaLocalPort?: number; @@ -39,4 +41,6 @@ export interface INsCapabilitiesArgs { startDeviceOptions?: string; deviceTypeOrPlatform?: string; driverConfig?: any; + testReporter?: ITestReporter; + logImageTypes?: Array; } diff --git a/lib/interfaces/ns-capabilities-args.ts b/lib/interfaces/ns-capabilities-args.ts index 9fd18e2..145a543 100644 --- a/lib/interfaces/ns-capabilities-args.ts +++ b/lib/interfaces/ns-capabilities-args.ts @@ -1,6 +1,8 @@ import { IDevice } from "mobile-devices-controller"; import { IDeviceManager } from "./device-manager"; import { AutomationName } from "../automation-name"; +import { ITestReporter } from "./test-reporter"; +import { LogImageType } from "../enums/log-image-type"; export interface INsCapabilitiesArgs { port?: number; @@ -40,4 +42,6 @@ export interface INsCapabilitiesArgs { startDeviceOptions?: string; deviceTypeOrPlatform?: string driverConfig?: any; + testReporter?: ITestReporter; + logImageTypes?: Array; } \ No newline at end of file diff --git a/lib/interfaces/ns-capabilities.d.ts b/lib/interfaces/ns-capabilities.d.ts index 792e41f..a41ff01 100644 --- a/lib/interfaces/ns-capabilities.d.ts +++ b/lib/interfaces/ns-capabilities.d.ts @@ -2,4 +2,5 @@ import { INsCapabilitiesArgs } from "./ns-capabilities-args"; export interface INsCapabilities extends INsCapabilitiesArgs { validateArgs?: () => {}; extend?: (args: INsCapabilitiesArgs) => {}; + testReporterLog?: (text: any) => any; } diff --git a/lib/interfaces/ns-capabilities.ts b/lib/interfaces/ns-capabilities.ts index cc729dc..301bd3d 100644 --- a/lib/interfaces/ns-capabilities.ts +++ b/lib/interfaces/ns-capabilities.ts @@ -3,5 +3,6 @@ import { INsCapabilitiesArgs } from "./ns-capabilities-args"; export interface INsCapabilities extends INsCapabilitiesArgs { validateArgs?: () => {}; extend?: (args: INsCapabilitiesArgs) => {}; + testReporterLog?: (text: any) => any; } diff --git a/lib/interfaces/test-reporter.d.ts b/lib/interfaces/test-reporter.d.ts new file mode 100644 index 0000000..0f53656 --- /dev/null +++ b/lib/interfaces/test-reporter.d.ts @@ -0,0 +1,28 @@ +import { LogImageType } from "../enums/log-image-type"; +/** + * Provide report context to nativescript-dev-appium plugin + * to add logs and images to the report + * Supported reports: mochawesome + */ +export interface ITestReporter { + /** + * The name of reporter as mochawesome + */ + name: string; + /** + * When we need to see all results from image comaprisson + */ + logImageTypes: Array; + /** + * Usually shouldbe set on each describe + */ + context: any; + /** + * Method for logging + */ + log: any; + /** + * Report drirecotry + */ + reportDir: string; +} diff --git a/lib/interfaces/test-reporter.ts b/lib/interfaces/test-reporter.ts new file mode 100644 index 0000000..9d91cb6 --- /dev/null +++ b/lib/interfaces/test-reporter.ts @@ -0,0 +1,29 @@ +import { LogImageType } from "../enums/log-image-type"; + +/** + * Provide report context to nativescript-dev-appium plugin + * to add logs and images to the report + * Supported reports: mochawesome + */ +export interface ITestReporter { + /** + * The name of reporter as mochawesome + */ + name: string; + /** + * When we need to see all results from image comaprisson + */ + logImageTypes: Array; + /** + * Usually shouldbe set on each describe + */ + context: any; + /** + * Method for logging + */ + log: any; + /** + * Report drirecotry + */ + reportDir: string; +} \ No newline at end of file diff --git a/lib/ns-capabilities.d.ts b/lib/ns-capabilities.d.ts index f0b94b2..cfecda9 100644 --- a/lib/ns-capabilities.d.ts +++ b/lib/ns-capabilities.d.ts @@ -3,9 +3,12 @@ import { INsCapabilitiesArgs } from "./interfaces/ns-capabilities-args"; import { AutomationName } from "./automation-name"; import { IDevice } from "mobile-devices-controller"; import { IDeviceManager } from "./interfaces/device-manager"; +import { ITestReporter } from "./interfaces/test-reporter"; +import { LogImageType } from "./enums/log-image-type"; export declare class NsCapabilities implements INsCapabilities { private _parser; private _automationName; + private _testReporter; projectDir: string; projectBinary: string; pluginRoot: string; @@ -40,11 +43,29 @@ export declare class NsCapabilities implements INsCapabilities { imagesPath: string; deviceTypeOrPlatform: string; driverConfig: any; + logImageTypes: Array; constructor(_parser: INsCapabilitiesArgs); readonly isAndroid: any; readonly isIOS: boolean; automationName: AutomationName; setAutomationNameFromString(automationName: String): void; + /** + * Set testRoprter + * @experimental + */ + /** + * Set testRoprter name like mochawesome + * Set testRoprter context usually this + * Set testRoprter log method like addContext in mochawesome + * @experimental + */ + testReporter: ITestReporter; + private _imagesReportDir; + /** + * @exprimental + * @param text to log in test report + */ + testReporterLog(text: any): any; extend(args: INsCapabilities): this; validateArgs(): Promise; private isAndroidPlatform; diff --git a/lib/ns-capabilities.ts b/lib/ns-capabilities.ts index 6036eb8..5e79d6f 100644 --- a/lib/ns-capabilities.ts +++ b/lib/ns-capabilities.ts @@ -5,11 +5,15 @@ import { resolveCapabilities } from "./capabilities-helper"; import { getAppPath, logInfo, logError, logWarn } from "./utils"; import { IDevice, Platform, Status, DeviceType } from "mobile-devices-controller"; import { IDeviceManager } from "./interfaces/device-manager"; -import { existsSync } from "fs"; +import { existsSync, mkdirSync } from "fs"; import { DeviceManager } from "./device-manager"; +import { ITestReporter } from "./interfaces/test-reporter"; +import { sep, basename } from "path"; +import { LogImageType } from "./enums/log-image-type"; export class NsCapabilities implements INsCapabilities { private _automationName: AutomationName; + private _testReporter: ITestReporter = {}; public projectDir: string; public projectBinary: string; @@ -45,6 +49,7 @@ export class NsCapabilities implements INsCapabilities { public imagesPath: string; public deviceTypeOrPlatform: string; public driverConfig: any; + public logImageTypes: Array; constructor(private _parser: INsCapabilitiesArgs) { this.projectDir = this._parser.projectDir; @@ -75,6 +80,7 @@ export class NsCapabilities implements INsCapabilities { this.deviceTypeOrPlatform = this._parser.deviceTypeOrPlatform; this.device = this._parser.device; this.driverConfig = this._parser.driverConfig; + this.logImageTypes = this._parser.logImageTypes; } get isAndroid() { return this.isAndroidPlatform(); } @@ -89,6 +95,58 @@ export class NsCapabilities implements INsCapabilities { this.automationName = AutomationName[key[0]]; } + /** + * Set testRoprter + * @experimental + */ + public get testReporter() { + return this._testReporter; + } + + /** + * Set testRoprter name like mochawesome + * Set testRoprter context usually this + * Set testRoprter log method like addContext in mochawesome + * @experimental + */ + public set testReporter(testReporter: ITestReporter) { + this._testReporter = testReporter; + if (this.logImageTypes && this.logImageTypes.length > 0) { + this._testReporter.logImageTypes = this.logImageTypes; + } + } + + private _imagesReportDir: string; + /** + * @exprimental + * @param text to log in test report + */ + public testReporterLog(text: any) { + if (this._testReporter && this._testReporter.name === "mochawesome") { + if (/\.\w{3,3}$/ig.test(text) && this._testReporter.reportDir) { + if (!this._imagesReportDir) { + if (!existsSync(this._testReporter.reportDir)) { + mkdirSync(this._testReporter.reportDir); + } + + const reportDir = this._testReporter.reportDir.replace(/^\.\//, "") + const reportDirs = reportDir.split("/"); + const reportDirsSeparated = reportDirs.slice(1, reportDirs.length); + this._imagesReportDir = reportDirsSeparated.length > 0 ? reportDirsSeparated.join(sep) : `.`; + } + + const imagesPath = `${this._imagesReportDir}${sep}${basename(text)}`.replace(/\/{2,9}/ig, "/"); + this._testReporter.log(this._testReporter.context, imagesPath); + return imagesPath; + } else { + this._testReporter.log(this._testReporter.context, text); + return text; + } + } + + return undefined; + } + public extend(args: INsCapabilities) { Object.keys(args).forEach(key => { if (args[key]) { @@ -110,7 +168,7 @@ export class NsCapabilities implements INsCapabilities { this.driverConfig.host = "localhost"; this.driverConfig.port = this.port; } - + if (this.deviceTypeOrPlatform || this.device) { let searchQuery = {}; if (this.deviceTypeOrPlatform) { diff --git a/lib/parser.d.ts b/lib/parser.d.ts index 2293fcf..f1be376 100644 --- a/lib/parser.d.ts +++ b/lib/parser.d.ts @@ -1 +1,2 @@ -export declare const projectDir: string, projectBinary: string, pluginRoot: string, pluginBinary: string, port: number, verbose: boolean, appiumCapsLocation: string, testFolder: string, runType: string, isSauceLab: boolean, appPath: string, storage: string, testReports: string, devMode: boolean, ignoreDeviceController: boolean, wdaLocalPort: number, path: string, relaxedSecurity: boolean, cleanApp: boolean, attachToDebug: boolean, sessionId: string, startSession: boolean, capabilitiesName: string, imagesPath: string, startDeviceOptions: string, deviceTypeOrPlatform: string, device: any, driverConfig: any; +import { LogImageType } from "./enums/log-image-type"; +export declare const projectDir: string, projectBinary: string, pluginRoot: string, pluginBinary: string, port: number, verbose: boolean, appiumCapsLocation: string, testFolder: string, runType: string, isSauceLab: boolean, appPath: string, storage: string, testReports: string, devMode: boolean, ignoreDeviceController: boolean, wdaLocalPort: number, path: string, relaxedSecurity: boolean, cleanApp: boolean, attachToDebug: boolean, sessionId: string, startSession: boolean, capabilitiesName: string, imagesPath: string, startDeviceOptions: string, deviceTypeOrPlatform: string, device: any, driverConfig: any, logImageTypes: LogImageType[]; diff --git a/lib/parser.ts b/lib/parser.ts index fe4e288..0a280b9 100644 --- a/lib/parser.ts +++ b/lib/parser.ts @@ -2,6 +2,7 @@ import * as yargs from "yargs"; import { join } from "path"; import { resolvePath, logError, logWarn } from "./utils"; import { INsCapabilitiesArgs } from "./interfaces/ns-capabilities-args"; +import { LogImageType } from "./enums/log-image-type"; const config = (() => { const options = yargs @@ -67,7 +68,7 @@ const config = (() => { .option("relaxedSecurity", { describe: "appium relaxedSecurity", default: false, type: "boolean" }) .option("appPath", { describe: "application path", type: "string" }) .option("storage", { describe: "Storage for images folder.", type: "string" }) - .option("testReports", { describe: "Test reporting folder", type: "string" }) + .option("testReports", { describe: "Override default test reporting storage", type: "string" }) .option("devMode", { alias: "dev-mode", @@ -85,6 +86,7 @@ const config = (() => { }) .option("cleanApp", { alias: "c", describe: "Clean app before and after run.", type: "boolean", default: false }) .option("imagesPath", { describe: "comparison images path relative to resources/images", type: "string" }) + .option("logImageTypes", { describe: "Applicable only if testReporter is set", type: 'array', default: [] }) .help() .argv; @@ -93,9 +95,9 @@ const config = (() => { appRootPath = require('app-root-path').toString(); } - if (appRootPath.includes("mocha")) { - appRootPath = join(appRootPath, "../../.."); - } + // if (appRootPath.includes("mocha")) { + // appRootPath = join(appRootPath, "../../.."); + // } if (options.startSession) { options.reuseDevice = true; @@ -178,7 +180,8 @@ const config = (() => { startDeviceOptions: options.startDeviceOptions || process.env.npm_config_startDeviceOptions, deviceTypeOrPlatform: deviceTypeOrPlatform, device: options.device || process.env.npm_config_device, - driverConfig: options.driverConfig + driverConfig: options.driverConfig, + logImageTypes: >options.logImageTypes }; return config; @@ -210,7 +213,8 @@ export const { capabilitiesName, imagesPath, startDeviceOptions, - deviceTypeOrPlatform: deviceTypeOrPlatform, - device: device, - driverConfig: driverConfig + deviceTypeOrPlatform, + device, + driverConfig, + logImageTypes }: INsCapabilitiesArgs = config; \ No newline at end of file diff --git a/lib/ui-element.ts b/lib/ui-element.ts index 16ab07d..dac4a2a 100644 --- a/lib/ui-element.ts +++ b/lib/ui-element.ts @@ -27,6 +27,7 @@ export class UIElement { public async tapCenter() { let action = new this._wd.TouchAction(this._driver); const rect = await this.getActualRectangle(); + this._args.testReporterLog(`Tap on center element ${ {"x": rect.x + rect.width / 2, "y": rect.y + rect.height / 2 }}`); action .tap({ x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 }); await action.perform(); @@ -181,7 +182,7 @@ export class UIElement { const displaySize = await this._driver.getWindowSize(); try { const elemCoordinates = await el.getLocation(); - + isDisplayed = isDisplayedWebDriver && elemCoordinates.x >= 0 && elemCoordinates.x < displaySize.width && elemCoordinates.y >= 0 && elemCoordinates.y < displaySize.height; } catch (error) { @@ -415,7 +416,9 @@ export class UIElement { } public async log() { - console.dir(await this.element()); + const el = await this.element(); + console.dir(el); + this._args.testReporterLog(el); } public async refetch() { diff --git a/lib/utils.d.ts b/lib/utils.d.ts index 393e5fb..764e2ca 100644 --- a/lib/utils.d.ts +++ b/lib/utils.d.ts @@ -2,6 +2,8 @@ import { INsCapabilities } from "./interfaces/ns-capabilities"; import { Point } from "./point"; import { Direction } from "./direction"; import { IDeviceManager } from "./interfaces/device-manager"; +import { LogImageType } from "./enums/log-image-type"; +import { ITestReporter } from "./interfaces/test-reporter"; export declare function resolvePath(mainPath: any, ...args: any[]): string; export declare function isDirectory(fullName: any): boolean; export declare function isFile(fullName: any): boolean; @@ -11,6 +13,8 @@ export declare function killPid(pid: any, verbose: any): void; export declare function waitForOutput(process: any, matcher: any, errorMatcher: any, timeout: any, verbose: any): Promise; export declare function executeCommand(args: any, cwd?: string): string; export declare function isWin(): boolean; +export declare function isMac(): boolean; +export declare function isLinux(): boolean; export declare function getStorageByDeviceName(args: INsCapabilities): string; export declare function getStorageByPlatform(args: INsCapabilities): string; export declare const getStorage: (args: INsCapabilities) => string; @@ -36,6 +40,8 @@ export declare function wait(milliseconds: any): void; export declare function getSessions(port: any, host?: string): Promise<{}>; export declare const prepareDevice: (args: INsCapabilities, deviceManager: IDeviceManager) => Promise; export declare const prepareApp: (args: INsCapabilities) => Promise; +export declare const ensureReportsDirExists: (nsCapabilities: any) => void; +export declare const checkImageLogType: (testReporter: ITestReporter, logImageType: LogImageType) => boolean; export declare const sessionIds: (port: any) => Promise; export declare function encodeImageToBase64(path: any): string; export declare const shouldUserMobileDevicesController: (args: INsCapabilities) => boolean; diff --git a/lib/utils.ts b/lib/utils.ts index 3940555..c8defec 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -23,6 +23,8 @@ import { isAbsolute, resolve } from "path"; +import { LogImageType } from "./enums/log-image-type"; +import { ITestReporter } from "./interfaces/test-reporter"; export function resolvePath(mainPath, ...args) { if (!isAbsolute(mainPath) && mainPath.startsWith('~')) { @@ -200,7 +202,15 @@ export function executeCommand(args, cwd = process.cwd()): string { } export function isWin() { - return /^win/.test(process.platform); + return /^win/i.test(process.platform); +} + +export function isMac() { + return /^darwin/i.test(process.platform); +} + +export function isLinux() { + return /^linux/i.test(process.platform); } const getDeviceName = (args) => { @@ -250,6 +260,9 @@ export const getStorage = (args: INsCapabilities) => { } export function getReportPath(args: INsCapabilities) { + if (Object.getOwnPropertyNames(args.testReporter).length > 0 && args.testReporter.reportDir) { + return args.testReporter.reportDir; + } let report = args.testReports; if (!report) { report = createStorageFolder(resolvePath(args.projectDir, args.testFolder), "reports"); @@ -580,6 +593,22 @@ export const prepareApp = async (args: INsCapabilities) => { return args; } +export const ensureReportsDirExists = (nsCapabilities) => { + if (nsCapabilities + && nsCapabilities.testReporter + && nsCapabilities.testReporter.reportDir + && !existsSync(nsCapabilities.testReporter.reportDir)) { + mkdirSync(nsCapabilities.testReporter.reportDir); + } +} + +export const checkImageLogType = (testReporter: ITestReporter, logImageType: LogImageType) => { + return testReporter + && Object.getOwnPropertyNames(testReporter).length > 0 + && testReporter.logImageTypes + && testReporter.logImageTypes.indexOf(logImageType) > -1; +} + export const sessionIds = async (port) => { const sessions = JSON.parse(((await getSessions(port)) || "{}") + ''); const ids = []; diff --git a/postinstall.js b/postinstall.js index f350a54..bc2e72d 100644 --- a/postinstall.js +++ b/postinstall.js @@ -18,6 +18,7 @@ const inquirer = require("inquirer"); const jasmine = "jasmine"; const mocha = "mocha"; +const mochawesome = "mochawesome"; const none = "none"; const js = "javascript"; const tsc = "typescript"; @@ -31,6 +32,8 @@ const testingFrameworks = `${mocha} | ${jasmine} | ${none}`; const packageJsonPath = resolve(appRootPath, "package.json"); const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8")); +const isWin = () => { return /^win/i.test(process.platform) }; + class Template { constructor(testingFramwork, projectType, storage, fileExt) { this._testingFramwork = testingFramwork; @@ -83,27 +86,36 @@ const copy = (src, dest) => { } const getDevDependencies = (frameworkType) => { - const testingFrameworkDeps = new Map(); - - testingFrameworkDeps.set(jasmine, [ - { name: "jasmine", version: "~3.3.1" }, - { name: "jasmine-core", version: "~3.3.0" }, - { name: "jasmine-spec-reporter", version: "~4.2.1" }, - { name: "@types/jasmine", version: "~3.3.4" }, - { name: "@types/node", version: "~10.12.18" }, - ]); - - testingFrameworkDeps.set(mocha, [ - { name: "mocha", version: "~5.2.0" }, - { name: "mocha-junit-reporter", version: "~1.18.0" }, - { name: "mocha-multi", version: "~1.0.1" }, - { name: "@types/mocha", version: "~5.2.5" }, - { name: "@types/chai", version: "~4.1.7" }, - { name: "@types/node", version: "~10.12.18" }, - ]); - - testingFrameworkDeps.set(js, []); - return testingFrameworkDeps.get(frameworkType); + if (frameworkType === jasmine) { + return [ + { name: "jasmine", version: "~3.3.1" }, + { name: "jasmine-core", version: "~3.3.0" }, + { name: "jasmine-spec-reporter", version: "~4.2.1" }, + { name: "@types/jasmine", version: "~3.3.4" }, + { name: "@types/node", version: "~10.12.18" }, + ] + } + + if (frameworkType === mocha) { + const mochaDeps = [ + { name: "mocha", version: "~5.2.0" }, + { name: "mochawesome", version: "~3.1.2" }, + { name: "@types/mocha", version: "~5.2.5" }, + { name: "@types/chai", version: "~4.1.7" }, + { name: "@types/node", version: "~10.12.18" }, + ] + + if (!isWin()) { + mochaDeps.push({ name: "mochawesome", version: "~3.1.2" }); + } else { + mochaDeps.push({ name: "mocha-junit-reporter", version: "~1.18.0" }); + mochaDeps.push({ name: "mocha-multi", version: "~1.0.1" }); + } + + return mochaDeps; + } + + return []; } const configureDevDependencies = (packageJson, frameworkType) => { @@ -274,12 +286,18 @@ const run = async () => { const samplesFilePostfix = "sample.e2e-spec"; - copy(resolve(e2eSamplesFolder, `${template.projectType}.${template.testingFramwork}.${samplesFilePostfix}.${template.fileExt}`), resolve(sampleTestsProjectFolderPath, `${samplesFilePostfix}.${template.fileExt}`)); - copy(resolve(e2eSamplesFolder, `${template.testingFramwork}.setup.${template.fileExt}`), resolve(sampleTestsProjectFolderPath, `setup.${template.fileExt}`)); + const includeMochawesomeReport = !isWin() && template.testingFramwork === mocha ? `${mochawesome}.` : ""; + copy(resolve(e2eSamplesFolder, `${template.projectType}.${template.testingFramwork}.${samplesFilePostfix}.${includeMochawesomeReport}${template.fileExt}`), resolve(sampleTestsProjectFolderPath, `${samplesFilePostfix}.${template.fileExt}`)); + copy(resolve(e2eSamplesFolder, `${template.testingFramwork}.setup.${includeMochawesomeReport}${template.fileExt}`), resolve(sampleTestsProjectFolderPath, `setup.${template.fileExt}`)); copy(resolve(basicSampleTestsPluginFolderPath, "config"), resolve(sampleTestsProjectFolderPath, "config")); - const settingsFile = template.testingFramwork === jasmine ? `${template.testingFramwork}.json` : `${template.testingFramwork}.opts`; - copy(resolve(basicSampleTestsPluginFolderPath, settingsFile), resolve(sampleTestsProjectFolderPath, "config", settingsFile)); + + if (isWin() && template.testingFramwork === mocha) { + copy(resolve(basicSampleTestsPluginFolderPath, "mocha.win.opts"), resolve(sampleTestsProjectFolderPath, "config", `${template.testingFramwork}.opts`)); + } else { + const settingsFile = template.testingFramwork === jasmine ? `${template.testingFramwork}.json` : `${template.testingFramwork}.opts`; + copy(resolve(basicSampleTestsPluginFolderPath, settingsFile), resolve(sampleTestsProjectFolderPath, "config", settingsFile)); + } } updatePackageJsonDependencies(packageJson, PROJECT_TYPE, TESTING_FRAMEWORK); diff --git a/samples/e2e-js/javascript.mocha.sample.e2e-spec.mochawesome.js b/samples/e2e-js/javascript.mocha.sample.e2e-spec.mochawesome.js new file mode 100644 index 0000000..fc37d33 --- /dev/null +++ b/samples/e2e-js/javascript.mocha.sample.e2e-spec.mochawesome.js @@ -0,0 +1,45 @@ +const nsAppium = require("nativescript-dev-appium"); +const assert = require("chai").assert; +const addContext = require('mochawesome/addContext'); + +describe("sample scenario", () => { + let driver; + + before(async function () { + nsAppium.nsCapabilities.testReporter.context = this; + driver = await nsAppium.createDriver(); + }); + + after(async function () { + await driver.quit(); + console.log("Quit driver!"); + }); + + afterEach(async function () { + if (this.currentTest.state === "failed") { + await driver.logTestArtifacts(this.currentTest.title); + } + }); + + it("should find an element by text", async function () { + const btnTap = await driver.findElementByAutomationText("TAP"); + await btnTap.click(); + + const message = " taps left"; + const lblMessage = await driver.findElementByText(message, nsAppium.SearchOptions.contains); + assert.equal(await lblMessage.text(), "41" + message); + + // Image verification + // const screen = await driver.compareScreen("hello-world-41"); + // assert.isTrue(screen); + }); + + it("should find an element by type", async function () { + const btnTap = await driver.findElementByClassName(driver.locators.button); + await btnTap.click(); + + const message = " taps left"; + const lblMessage = await driver.findElementByText(message, nsAppium.SearchOptions.contains); + assert.equal(await lblMessage.text(), "40" + message); + }); +}); \ No newline at end of file diff --git a/samples/e2e-js/mocha.setup.mochawesome.js b/samples/e2e-js/mocha.setup.mochawesome.js new file mode 100644 index 0000000..644d087 --- /dev/null +++ b/samples/e2e-js/mocha.setup.mochawesome.js @@ -0,0 +1,25 @@ +const nsAppium = require("nativescript-dev-appium"); +const addContext = require('mochawesome/addContext'); + +const testReporterContext = {}; +testReporterContext.name = "mochawesome"; + +/** + * This folder should be the one provided in mocha.opts. + * If omitted the default one is "mochawesome-report". + * This is necessary because we need the logged images to be relatively + * positioned according to mochawesome.html in the same folder + */ +testReporterContext.reportDir = "mochawesome-report"; +testReporterContext.log = addContext; +testReporterContext.logImageTypes = [nsAppium.LogImageType.screenshots]; +nsAppium.nsCapabilities.testReporter = testReporterContext; + +before("start server", async function () { + nsAppium.nsCapabilities.testReporter.context = this; + await nsAppium.startServer(); +}); + +after("stop appium server", async function () { + await nsAppium.stopServer(); +}); diff --git a/samples/e2e-js/vue.mocha.sample.e2e-spec.mochawesome.js b/samples/e2e-js/vue.mocha.sample.e2e-spec.mochawesome.js new file mode 100644 index 0000000..481ac39 --- /dev/null +++ b/samples/e2e-js/vue.mocha.sample.e2e-spec.mochawesome.js @@ -0,0 +1,28 @@ +const nsAppium = require("nativescript-dev-appium"); +const assert = require("chai").assert; +const addContext = require('mochawesome/addContext'); + +describe("sample scenario", () => { + let driver; + + before(async function() { + nsAppium.nsCapabilities.testReporter.context = this; + driver = await nsAppium.createDriver(); + }); + + after(async function () { + await driver.quit(); + console.log("Quit driver!"); + }); + + afterEach(async function () { + if (this.currentTest.state === "failed") { + await driver.logTestArtifacts(this.currentTest.title); + } + }); + + it("should find an element by text", async function () { + const label = await driver.findElementByText("Welcome", "contains"); + assert.isTrue(await label.isDisplayed()); + }); +}); \ No newline at end of file diff --git a/samples/e2e-ts/mocha.setup.mochawesome.ts b/samples/e2e-ts/mocha.setup.mochawesome.ts new file mode 100644 index 0000000..9093007 --- /dev/null +++ b/samples/e2e-ts/mocha.setup.mochawesome.ts @@ -0,0 +1,24 @@ +import { startServer, stopServer, ITestReporter, nsCapabilities, LogImageType } from "nativescript-dev-appium"; +const addContext = require('mochawesome/addContext'); + +const testReporterContext = {}; +testReporterContext.name = "mochawesome"; +/** + * This folder should be the one provided in mocha.opts. + * If omitted the default one is "mochawesome-report". + * This is necessary because we need the logged images to be relatively + * positioned according to mochawesome.html in the same folder + */ +testReporterContext.reportDir = "mochawesome-report"; +testReporterContext.log = addContext; +testReporterContext.logImageTypes = [LogImageType.screenshots]; +nsCapabilities.testReporter = testReporterContext; + +before("start server", async function () { + nsCapabilities.testReporter.context = this; + await startServer(); +}); + +after("stop server", async function () { + await stopServer(); +}); diff --git a/samples/e2e-ts/typescript.mocha.sample.e2e-spec.mochawesome.ts b/samples/e2e-ts/typescript.mocha.sample.e2e-spec.mochawesome.ts new file mode 100644 index 0000000..0d1a2ac --- /dev/null +++ b/samples/e2e-ts/typescript.mocha.sample.e2e-spec.mochawesome.ts @@ -0,0 +1,45 @@ +import { AppiumDriver, createDriver, SearchOptions, nsCapabilities } from "nativescript-dev-appium"; +import { assert } from "chai"; +const addContext = require('mochawesome/addContext'); + +describe("sample scenario", () => { + let driver: AppiumDriver; + + before(async function(){ + nsCapabilities.testReporter.context = this; + driver = await createDriver(); + }); + + after(async function () { + await driver.quit(); + console.log("Quit driver!"); + }); + + afterEach(async function () { + if (this.currentTest.state === "failed") { + await driver.logTestArtifacts(this.currentTest.title); + } + }); + + it("should find an element by text", async function () { + const btnTap = await driver.findElementByAutomationText("TAP"); + await btnTap.click(); + + const message = " taps left"; + const lblMessage = await driver.findElementByText(message, SearchOptions.contains); + assert.equal(await lblMessage.text(), "41" + message); + + // Image verification + // const screen = await driver.compareScreen("hello-world-41"); + // assert.isTrue(screen); + }); + + it("should find an element by type", async function () { + const btnTap = await driver.findElementByClassName(driver.locators.button); + await btnTap.click(); + + const message = " taps left"; + const lblMessage = await driver.findElementByText(message, SearchOptions.contains); + assert.equal(await lblMessage.text(), "40" + message); + }); +}); \ No newline at end of file diff --git a/samples/mocha.opts b/samples/mocha.opts index 26304a7..c21dcca 100644 --- a/samples/mocha.opts +++ b/samples/mocha.opts @@ -1,5 +1,5 @@ --timeout 999999 --recursive e2e ---reporter mocha-multi ---reporter-options spec=-,mocha-junit-reporter=test-results.xml +--reporter mochawesome +--reporter-options quiet=true,html=true,inline=true,autoOpen=true --exit \ No newline at end of file diff --git a/samples/mocha.win.opts b/samples/mocha.win.opts new file mode 100644 index 0000000..26304a7 --- /dev/null +++ b/samples/mocha.win.opts @@ -0,0 +1,5 @@ +--timeout 999999 +--recursive e2e +--reporter mocha-multi +--reporter-options spec=-,mocha-junit-reporter=test-results.xml +--exit \ No newline at end of file diff --git a/test-app/package.json b/test-app/package.json deleted file mode 100644 index 3d2abc7..0000000 --- a/test-app/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "description": "NativeScript Application", - "license": "SEE LICENSE IN ", - "readme": "NativeScript Application", - "repository": "", - "devDependencies": { - "typescript": "~3.3.3", - "@types/chai": "~4.1.7", - "@types/mocha": "~5.2.5", - "@types/node": "~10.12.18", - "mocha": "~5.2.0", - "mocha-junit-reporter": "~1.18.0", - "mocha-multi": "~1.0.1" - } -} diff --git a/test-app/tsconfig.json b/test-app/tsconfig.json deleted file mode 100644 index 18b6c43..0000000 --- a/test-app/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es6", - "experimentalDecorators": true, - "emitDecoratorMetadata": true, - "importHelpers": false, - "types": [ - "node", - "mocha", - "chai" - ], - "lib": [ - "es6", - "dom" - ] - } -} \ No newline at end of file diff --git a/test/device-manager.spec.ts b/test/device-manager.spec.ts index f950d44..a44153e 100644 --- a/test/device-manager.spec.ts +++ b/test/device-manager.spec.ts @@ -15,11 +15,33 @@ import { AppiumDriver } from "../lib/appium-driver"; import { resolveCapabilities } from "../lib/capabilities-helper"; import { INsCapabilities } from "lib/interfaces/ns-capabilities"; import { INsCapabilitiesArgs } from "lib/interfaces/ns-capabilities-args"; +import { existsSync, mkdirSync, copyFileSync } from "fs"; +import { execSync } from "child_process"; -const androidApp = `${process.cwd()}/test/out/template-hello-world-ts-release.apk`; -const iosApp = `${process.cwd()}/test/out/template-hello-world-ts.app`; +const outDir = `${process.cwd()}/test/out`; +const androidApp = `${outDir}/template-hello-world-ts-release.apk`; +const iosApp = `${outDir}/template-hello-world-ts.app`; +const remoteStorage = "/tns-dist"; -describe("android devices", () => { +// For local run +// if (!existsSync(outDir)) { +// mkdirSync(outDir); +// } + +// if (!existsSync(`${outDir}/template-hello-world-ts-release.apk`)) { +// execSync(`cp ${remoteStorage}/TestApps/Stable/Android/template-hello-world-ts-release.apk ${outDir}`); +// } + +// if (!existsSync(`${outDir}/vue-cli-template-simple-release.apk`)) { +// execSync(`cp ${remoteStorage}/TestApps/Stable/Android/vue-cli-template-simple-release.apk ${outDir}`); +// } + +// if (!existsSync(`${outDir}/template-hello-world-ts.app`)) { +// execSync(`cp ${remoteStorage}/TestApps/Stable/iOS/template-hello-world-ts.tgz ${outDir}`); +// execSync("tar xf template-hello-world-ts.tgz", { cwd: outDir }); +// } + +describe("android-devices", () => { let deviceManager: DeviceManager; const appiumArgs: INsCapabilities = nsCapabilities; @@ -53,7 +75,7 @@ describe("android devices", () => { }); }); -describe("ios devices", () => { +describe("ios-devices", () => { let deviceManager: DeviceManager; let appiumArgs: NsCapabilities; @@ -68,7 +90,7 @@ describe("ios devices", () => { DeviceController.killAll(DeviceType.SIMULATOR); }) - it("Start simulator fullReset: false", async () => { + it("Start simulator fullReset: false, should not kill device", async () => { const device = await deviceManager.startDevice(appiumArgs); let foundBootedDevices = await DeviceController.getDevices({ platform: Platform.IOS, status: Status.BOOTED }); assert.isTrue(foundBootedDevices.some(d => d.token === device.token)); @@ -77,7 +99,7 @@ describe("ios devices", () => { assert.isTrue(foundBootedDevices.some(d => d.token === device.token)); }); - it("Start simulator fullReset", async () => { + it("Start simulator fullReset: true, should kill device", async () => { appiumArgs.extend({ appiumCaps: { platformName: Platform.IOS, fullReset: true, deviceName: /iPhone X/ } }); appiumArgs.shouldSetFullResetOption(); const device = await deviceManager.startDevice(appiumArgs); @@ -89,12 +111,12 @@ describe("ios devices", () => { }); }); -describe("find capabilities", async () => { +describe("find-capabilities", async () => { const caps: any = resolveCapabilities("../samples", "android23", ".", "appium.capabilities.json"); assert.isTrue(caps.deviceName === "Emulator-Api23-Default"); }) -describe("start Appium server android", async () => { +describe("start-appium-server-android", async () => { before("Init capabilities", () => { }); @@ -124,6 +146,7 @@ describe("start Appium server android", async () => { it("Start appium driver", async () => { const nsCaps = new NsCapabilities({ appPath: androidApp, + testReports: `${process.cwd()}/test`, port: 9900, appiumCaps: { platformName: Platform.ANDROID, @@ -134,9 +157,12 @@ describe("start Appium server android", async () => { await server.start(nsCaps.port); assert.isTrue(server.hasStarted); const driver = await AppiumDriver.createAppiumDriver(nsCaps); - const currentWindowName = AndroidController.getCurrentFocusedScreen(nsCaps.device); + let currentWindowName = AndroidController.getCurrentFocusedScreen(nsCaps.device); const startTime = Date.now(); - while (!currentWindowName.includes("com.tns.NativeScriptActivity") && Date.now() - startTime < 5000) { } + while (!currentWindowName.includes("com.tns.NativeScriptActivity") && Date.now() - startTime < 5000) { + console.log(currentWindowName); + currentWindowName = AndroidController.getCurrentFocusedScreen(nsCaps.device); + } assert.isTrue(currentWindowName.includes("com.tns.NativeScriptActivity"), `Focused screen doesn't include activity ${currentWindowName}!`); await driver.quit(); @@ -145,7 +171,7 @@ describe("start Appium server android", async () => { }); -describe("start Appium server ios", async () => { +describe("start-appium-server-ios", async () => { before("Init capabilities", () => { }); @@ -195,7 +221,7 @@ describe("start Appium server ios", async () => { }); }); -describe("Start device by apiLevel", async () => { +describe("start-device-by-apiLevel", async () => { it("test-start-emulator-apiLevel-6.0", async () => { const nsCaps = new NsCapabilities({ port: 8799,