From b9e7b84db1819baf2b5bc7199fe635b322f44ebc Mon Sep 17 00:00:00 2001 From: SvetoslavTsenov Date: Fri, 1 Mar 2019 14:15:45 +0200 Subject: [PATCH 1/7] feat: start session command. This a very usefull if you need to keep server and driver running. --- bin/start-session | 4 +++ bin/start-session.cmd | 1 + lib/appium-driver.ts | 22 +++++++++------- lib/helpers/start-session.d.ts | 2 ++ lib/helpers/start-session.ts | 46 ++++++++++++++++++++++++++++++++++ package.json | 3 ++- 6 files changed, 68 insertions(+), 10 deletions(-) create mode 100755 bin/start-session create mode 100644 bin/start-session.cmd create mode 100644 lib/helpers/start-session.d.ts create mode 100644 lib/helpers/start-session.ts diff --git a/bin/start-session b/bin/start-session new file mode 100755 index 0000000..f00a36a --- /dev/null +++ b/bin/start-session @@ -0,0 +1,4 @@ +#!/usr/bin/env node + +"use strict"; +require("../lib/helpers/start-session.js"); \ No newline at end of file diff --git a/bin/start-session.cmd b/bin/start-session.cmd new file mode 100644 index 0000000..6d70619 --- /dev/null +++ b/bin/start-session.cmd @@ -0,0 +1 @@ +@node %~dp0\start-session %* \ No newline at end of file diff --git a/lib/appium-driver.ts b/lib/appium-driver.ts index 34c3fc7..3334802 100644 --- a/lib/appium-driver.ts +++ b/lib/appium-driver.ts @@ -188,7 +188,7 @@ export class AppiumDriver { } log("Creating driver!", args.verbose); - + if (!args.attachToDebug && !args.sessionId) { if (!args.device) { args.deviceManager = args.deviceManager || new DeviceManager(); @@ -730,7 +730,7 @@ export class AppiumDriver { * @param time in minutes */ public async backgroundApp(minutes: number) { - console.log("Sending the currently active app to the background ..."); + logInfo("Sending the currently active app to the background ..."); await this._driver.backgroundApp(minutes); } @@ -745,20 +745,21 @@ export class AppiumDriver { } public async quit() { - console.log("Killing driver"); if (this._recordVideoInfo && this._recordVideoInfo['videoRecordingProcess']) { this._recordVideoInfo['videoRecordingProcess'].kill("SIGINT"); } try { if (!this._args.attachToDebug) { + console.log("Killing driver..."); await this._driver.quit(); + this._isAlive = false; + console.log("Driver is dead!"); } else { - await this._webio.detach(); + //await this._webio.detach(); } } catch (error) { + console.dir(error) } - this._isAlive = false; - console.log("Driver is dead"); } private static async applyAdditionalSettings(args) { @@ -808,11 +809,14 @@ export class AppiumDriver { driver.on("status", function (info) { log(info.cyan, verbose); }); + driver.on("quit", function (info) { + console.log("QUIT: ",info); + }); driver.on("command", function (meth, path, data) { - log(" > " + meth.yellow + path.grey + " " + (data || ""), verbose); + log(" > " + meth + " " + path + " " + (data || ""), verbose); }); driver.on("http", function (meth, path, data) { - log(" > " + meth.magenta + path + " " + (data || "").grey, verbose); + log(" > " + meth + " " + path + " " + (data || ""), verbose); }); }; @@ -934,4 +938,4 @@ export class AppiumDriver { return new UIElement(searchResult, this._driver, this._wd, this._webio, this._args, "elementByImage", imageAsBase64); } -} +} \ No newline at end of file diff --git a/lib/helpers/start-session.d.ts b/lib/helpers/start-session.d.ts new file mode 100644 index 0000000..4652015 --- /dev/null +++ b/lib/helpers/start-session.d.ts @@ -0,0 +1,2 @@ +import { INsCapabilities } from "../interfaces/ns-capabilities"; +export declare const nsCapabilities: INsCapabilities; diff --git a/lib/helpers/start-session.ts b/lib/helpers/start-session.ts new file mode 100644 index 0000000..58e9d04 --- /dev/null +++ b/lib/helpers/start-session.ts @@ -0,0 +1,46 @@ +import { execSync } from "child_process"; +import { NsCapabilities } from "../ns-capabilities"; +import { AppiumServer } from "../appium-server"; +import { AppiumDriver } from "../appium-driver"; +import { isWin, logInfo, logError } from "../utils"; +import * as parser from "../parser" +import { INsCapabilities } from "../interfaces/ns-capabilities"; + +export const nsCapabilities: INsCapabilities = new NsCapabilities(parser); +let server: AppiumServer; + +const stopServerCommand = (port) => { + return `lsof -i tcp:${port} | grep -v grep | grep -v PID | awk '{print $2}' | xargs kill -9 || true`; +} + +const startSession = async () => { + if (!isWin()) { + execSync(stopServerCommand(nsCapabilities.port)); + console.log(stopServerCommand(nsCapabilities.port)); + } + + nsCapabilities.appiumCaps = nsCapabilities.appiumCaps || {}; + nsCapabilities.appiumCaps["newCommandTimeout"] = 300; + server = new AppiumServer(nsCapabilities); + await server.start(nsCapabilities.port); + const driver = await AppiumDriver.createAppiumDriver(nsCapabilities); + const session = await driver.sessionId(); + logInfo(`port: ${nsCapabilities.port}`); + logInfo(`session id: ${session}`); +} + +startSession().then(s => { + logInfo("session started") +}); + +process.on("uncaughtException", async () => { + logError(`uncaughtException!`) +}) + +process.on("SIGINT", async () => { + if (!isWin()) { + console.log(`stop server!`) + execSync(stopServerCommand(nsCapabilities.port)); + } + await server.stop(); +}) \ No newline at end of file diff --git a/package.json b/package.json index d19584e..b8e3248 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,8 @@ "bin": { "nativescript-dev-appium": "./bin/nativescript-dev-appium", "ns-dev-appium": "./bin/nativescript-dev-appium", - "ns-appium": "./bin/nativescript-dev-appium" + "ns-appium": "./bin/nativescript-dev-appium", + "ns-start-session": "./bin/start-session" }, "dependencies": { "app-root-path": "~2.1.0", From 4634ba06b6bb5e4c67080e13724857b623f42627 Mon Sep 17 00:00:00 2001 From: SvetoslavTsenov Date: Tue, 5 Mar 2019 12:38:42 +0200 Subject: [PATCH 2/7] chore: include log --- lib/parser.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/parser.ts b/lib/parser.ts index c5d3b9d..fe4e288 100644 --- a/lib/parser.ts +++ b/lib/parser.ts @@ -1,6 +1,6 @@ import * as yargs from "yargs"; import { join } from "path"; -import { resolvePath, logError } from "./utils"; +import { resolvePath, logError, logWarn } from "./utils"; import { INsCapabilitiesArgs } from "./interfaces/ns-capabilities-args"; const config = (() => { @@ -105,8 +105,8 @@ const config = (() => { options.devMode = true; console.log(`Option attachToDebug is set to true. Option --devMode is set true as well !`) if (!options.port) { - logError("Provide appium server port started from desktop application!") - process.exit(1); + logWarn(`Default appium server port 4732!`); + logWarn(`In order to change it use --port option!`); } } From 1f09c87283dfd3b4a2c6c6bf2113faccc3870dc3 Mon Sep 17 00:00:00 2001 From: SvetoslavTsenov Date: Wed, 6 Mar 2019 16:07:20 +0200 Subject: [PATCH 3/7] chore: update kill server --- lib/appium-driver.ts | 2 +- lib/appium-server.ts | 6 ++++-- lib/helpers/start-session.ts | 12 ++++-------- lib/utils.d.ts | 1 + lib/utils.ts | 3 +++ 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/lib/appium-driver.ts b/lib/appium-driver.ts index 492fd9e..752010e 100644 --- a/lib/appium-driver.ts +++ b/lib/appium-driver.ts @@ -903,7 +903,7 @@ export class AppiumDriver { public async findElementByAccessibilityIdIfExists(id: string, waitForElement: number = this.defaultWaitTime) { let element = undefined; try { - element = await this._driver.elementByAccessibilityIdIfExists(id, waitForElement); + element = await this._driver.waitForElementByAccessibilityIdIfExists(id, waitForElement); } catch (error) { } if (element) { diff --git a/lib/appium-server.ts b/lib/appium-server.ts index aaa5792..f35e972 100644 --- a/lib/appium-server.ts +++ b/lib/appium-server.ts @@ -1,4 +1,4 @@ -import { ChildProcess, spawn } from "child_process"; +import { ChildProcess, spawn, execSync } from "child_process"; import { log, resolvePath, @@ -9,7 +9,8 @@ import { logWarn, logInfo, prepareApp, - prepareDevice + prepareDevice, + stopServerCommand } from "./utils"; import { INsCapabilities } from "./interfaces/ns-capabilities"; import { IDeviceManager } from "./interfaces/device-manager"; @@ -157,6 +158,7 @@ export class AppiumServer { this._server.kill("SIGKILL"); process.kill(this._server.pid, "SIGKILL"); shutdown(this._server, this._args.verbose); + execSync(stopServerCommand(this._args.port)); } } catch (error) { console.log(error); diff --git a/lib/helpers/start-session.ts b/lib/helpers/start-session.ts index 58e9d04..6d52db6 100644 --- a/lib/helpers/start-session.ts +++ b/lib/helpers/start-session.ts @@ -2,23 +2,19 @@ import { execSync } from "child_process"; import { NsCapabilities } from "../ns-capabilities"; import { AppiumServer } from "../appium-server"; import { AppiumDriver } from "../appium-driver"; -import { isWin, logInfo, logError } from "../utils"; +import { isWin, logInfo, logError, stopServerCommand } from "../utils"; import * as parser from "../parser" import { INsCapabilities } from "../interfaces/ns-capabilities"; export const nsCapabilities: INsCapabilities = new NsCapabilities(parser); let server: AppiumServer; - -const stopServerCommand = (port) => { - return `lsof -i tcp:${port} | grep -v grep | grep -v PID | awk '{print $2}' | xargs kill -9 || true`; -} - const startSession = async () => { if (!isWin()) { execSync(stopServerCommand(nsCapabilities.port)); console.log(stopServerCommand(nsCapabilities.port)); } + nsCapabilities.validateArgs(); nsCapabilities.appiumCaps = nsCapabilities.appiumCaps || {}; nsCapabilities.appiumCaps["newCommandTimeout"] = 300; server = new AppiumServer(nsCapabilities); @@ -33,11 +29,11 @@ startSession().then(s => { logInfo("session started") }); -process.on("uncaughtException", async () => { +process.once("uncaughtException", async () => { logError(`uncaughtException!`) }) -process.on("SIGINT", async () => { +process.once("SIGINT", async () => { if (!isWin()) { console.log(`stop server!`) execSync(stopServerCommand(nsCapabilities.port)); diff --git a/lib/utils.d.ts b/lib/utils.d.ts index 22ddb23..393e5fb 100644 --- a/lib/utils.d.ts +++ b/lib/utils.d.ts @@ -39,6 +39,7 @@ export declare const prepareApp: (args: INsCapabilities) => Promise Promise; export declare function encodeImageToBase64(path: any): string; export declare const shouldUserMobileDevicesController: (args: INsCapabilities) => boolean; +export declare const stopServerCommand: (port: any) => string; export declare function logInfo(info: any, obj?: any): void; export declare function logWarn(info: any, obj?: any): void; export declare function logError(info: any, obj?: any): void; diff --git a/lib/utils.ts b/lib/utils.ts index 0c987cd..bb2f531 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -606,6 +606,9 @@ export const shouldUserMobileDevicesController = (args: INsCapabilities) => { return !args.isSauceLab && (new RegExp(`${useDsCS}`).test(`true`) || new RegExp(`${useMDsCS}`).test(`true`)); } +export const stopServerCommand = (port) => { + return `lsof -i tcp:${port} | grep -v grep | grep -v PID | awk '{print $2}' | xargs kill -9 || true`; +} export function logInfo(info, obj = undefined) { info += " " + convertObjToString(obj); From 49b8908e37e246f7fed1c5359cd7a7c75f2cc5ec Mon Sep 17 00:00:00 2001 From: SvetoslavTsenov Date: Thu, 7 Mar 2019 00:33:23 +0200 Subject: [PATCH 4/7] chore: fix tests --- lib/appium-driver.ts | 8 +++++--- lib/parser.d.ts | 2 +- test/device-manager.spec.ts | 14 ++++++++++---- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/lib/appium-driver.ts b/lib/appium-driver.ts index 752010e..13b86de 100644 --- a/lib/appium-driver.ts +++ b/lib/appium-driver.ts @@ -188,7 +188,7 @@ export class AppiumDriver { } log("Creating driver!", args.verbose); - + if (!args.attachToDebug && !args.sessionId) { if (!args.device) { args.deviceManager = args.deviceManager || new DeviceManager(); @@ -769,7 +769,9 @@ export class AppiumDriver { //await this._webio.detach(); } } catch (error) { - console.dir(error) + if (this._args.verbose) { + console.dir(error); + } } } @@ -821,7 +823,7 @@ export class AppiumDriver { log(info.cyan, verbose); }); driver.on("quit", function (info) { - console.log("QUIT: ",info); + console.log("QUIT: ", info); }); driver.on("command", function (meth, path, data) { log(" > " + meth + " " + path + " " + (data || ""), verbose); diff --git a/lib/parser.d.ts b/lib/parser.d.ts index 2293fcf..c30215c 100644 --- a/lib/parser.d.ts +++ b/lib/parser.d.ts @@ -1 +1 @@ -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; +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: import("mobile-devices-controller/lib/device").IDevice, driverConfig: any; diff --git a/test/device-manager.spec.ts b/test/device-manager.spec.ts index f0f0e95..47a5188 100644 --- a/test/device-manager.spec.ts +++ b/test/device-manager.spec.ts @@ -17,7 +17,7 @@ import { INsCapabilities } from "lib/interfaces/ns-capabilities"; import { INsCapabilitiesArgs } from "lib/interfaces/ns-capabilities-args"; const androidApp = `${process.cwd()}/test/out/template-hello-world-ts-release.apk`; -const iosApp = `${process.cwd()}/test/out/template-hello-world-ts.app`; +const iosApp = `${process.cwd()}/test/out/template-hello-world.app`; describe("android devices", () => { let deviceManager: DeviceManager; @@ -245,6 +245,7 @@ describe("Start device by apiLevel", async () => { describe("dev-mode-options", async () => { let appiumServer: AppiumServer; + const port = 8399; before("start devices", async () => { await DeviceController.startDevice({ platform: Platform.ANDROID, apiLevel: "23" }); @@ -263,6 +264,8 @@ describe("dev-mode-options", async () => { const nsCaps = new NsCapabilities({ deviceTypeOrPlatform: Platform.IOS, appPath: iosApp, + port: port, + verbose: true }); const appiumDriver = await AppiumDriver.createAppiumDriver(nsCaps); @@ -273,7 +276,8 @@ describe("dev-mode-options", async () => { it("test android", async () => { const nsCaps = new NsCapabilities({ deviceTypeOrPlatform: Platform.ANDROID, - appPath: androidApp + appPath: androidApp, + port: port, }); const appiumDriver = await AppiumDriver.createAppiumDriver(nsCaps); @@ -284,7 +288,8 @@ describe("dev-mode-options", async () => { it("test --device.platform=android", async () => { const nsCaps = new NsCapabilities({ device: { platform: Platform.ANDROID }, - appPath: androidApp + appPath: androidApp, + port: port }); const appiumDriver = await AppiumDriver.createAppiumDriver(nsCaps); @@ -295,7 +300,8 @@ describe("dev-mode-options", async () => { it("test --device.platform=ios", async () => { const nsCaps = new NsCapabilities({ device: { platform: Platform.IOS }, - appPath: iosApp + appPath: iosApp, + port: port }); const appiumDriver = await AppiumDriver.createAppiumDriver(nsCaps); From 98979e54e885c64bf79f163ab5ac02847baab3c6 Mon Sep 17 00:00:00 2001 From: SvetoslavTsenov Date: Thu, 7 Mar 2019 11:19:24 +0200 Subject: [PATCH 5/7] refactor: stop server --- lib/appium-server.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/appium-server.ts b/lib/appium-server.ts index f35e972..3cc93c6 100644 --- a/lib/appium-server.ts +++ b/lib/appium-server.ts @@ -158,7 +158,6 @@ export class AppiumServer { this._server.kill("SIGKILL"); process.kill(this._server.pid, "SIGKILL"); shutdown(this._server, this._args.verbose); - execSync(stopServerCommand(this._args.port)); } } catch (error) { console.log(error); From 22fd352b2a5a4d1ac12b99e379f422f24bb32588 Mon Sep 17 00:00:00 2001 From: SvetoslavTsenov Date: Thu, 7 Mar 2019 11:19:37 +0200 Subject: [PATCH 6/7] feat: findElementByAutomationTextIfExists --- lib/appium-driver.d.ts | 8 +++++++- lib/appium-driver.ts | 20 ++++++++++++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/lib/appium-driver.d.ts b/lib/appium-driver.d.ts index cdd3d95..0d76742 100644 --- a/lib/appium-driver.d.ts +++ b/lib/appium-driver.d.ts @@ -85,7 +85,13 @@ export declare class AppiumDriver { * @param text * @param waitForElement */ - findElementByAutomationText(automationText: string, waitForElement?: number): Promise; + findElementByAutomationText(automationText: string, waitForElement?: number): Promise; + /** + * Search for element by given automationText. Searches only for exact string. + * @param text + * @param waitForElement + */ + findElementByAutomationTextIfExists(automationText: string, waitForElement?: number): Promise; /** * Search for element by given automationText and waits until the element is displayed. * @param text diff --git a/lib/appium-driver.ts b/lib/appium-driver.ts index 13b86de..3032e18 100644 --- a/lib/appium-driver.ts +++ b/lib/appium-driver.ts @@ -320,6 +320,18 @@ export class AppiumDriver { * @param waitForElement */ public async findElementByAutomationText(automationText: string, waitForElement: number = this.defaultWaitTime) { + if (this.isIOS) { + return await this.findElementByAccessibilityId(`${automationText}`, waitForElement); + } + return await this.findElementByXPath(this._elementHelper.getXPathByText(automationText, true), waitForElement); + } + + /** + * Search for element by given automationText. Searches only for exact string. + * @param text + * @param waitForElement + */ + public async findElementByAutomationTextIfExists(automationText: string, waitForElement: number = this.defaultWaitTime) { if (this.isIOS) { return await this.findElementByAccessibilityIdIfExists(`${automationText}`, waitForElement); } @@ -334,12 +346,12 @@ export class AppiumDriver { public async waitForElement(automationText: string, waitInMilliseconds: number = this.defaultWaitTime): Promise { let element; try { - element = await this.findElementByAutomationText(automationText, 100); + element = await this.findElementByAutomationTextIfExists(automationText, 100); } catch (error) { } const startTime = Date.now(); while ((!element || !(await element.isDisplayed())) && Date.now() - startTime <= waitInMilliseconds) { try { - element = await this.findElementByAutomationText(automationText, 100); + element = await this.findElementByAutomationTextIfExists(automationText, 100); } catch (error) { } } @@ -820,7 +832,7 @@ export class AppiumDriver { private static configureLogging(driver, verbose) { driver.on("status", function (info) { - log(info.cyan, verbose); + log(info, verbose); }); driver.on("quit", function (info) { console.log("QUIT: ", info); @@ -905,7 +917,7 @@ export class AppiumDriver { public async findElementByAccessibilityIdIfExists(id: string, waitForElement: number = this.defaultWaitTime) { let element = undefined; try { - element = await this._driver.waitForElementByAccessibilityIdIfExists(id, waitForElement); + element = await this._driver.elementByAccessibilityIdIfExists(id, waitForElement); } catch (error) { } if (element) { From 0461c61fd309d0e8f55b8a67b872d1d7534b6573 Mon Sep 17 00:00:00 2001 From: SvetoslavTsenov Date: Thu, 7 Mar 2019 11:30:14 +0200 Subject: [PATCH 7/7] chore: test app for ios --- test/device-manager.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/device-manager.spec.ts b/test/device-manager.spec.ts index 47a5188..f950d44 100644 --- a/test/device-manager.spec.ts +++ b/test/device-manager.spec.ts @@ -17,7 +17,7 @@ import { INsCapabilities } from "lib/interfaces/ns-capabilities"; import { INsCapabilitiesArgs } from "lib/interfaces/ns-capabilities-args"; const androidApp = `${process.cwd()}/test/out/template-hello-world-ts-release.apk`; -const iosApp = `${process.cwd()}/test/out/template-hello-world.app`; +const iosApp = `${process.cwd()}/test/out/template-hello-world-ts.app`; describe("android devices", () => { let deviceManager: DeviceManager;