Skip to content

Commit 3f5318c

Browse files
reuse appium sessions (#131)
* include: get session and attachToDebug options * feature: include bin * feat: add logging * feat: startSession option * fix: don' keep activities * feature: include colored console logging * update change log * chore: rename processToExitFrom to processToAttach
1 parent 1cca1e8 commit 3f5318c

22 files changed

+477
-133
lines changed

Diff for: CHANGELOG.md

+35
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,38 @@
1+
<a name="4.0.0"></a>
2+
# [4.0.0]() (2018-07-02)
3+
4+
### Bug Fixes
5+
6+
* fix sauce lab compatibility (#118) ([48946fd](https://github.com/NativeScript/nativescript-dev-appium/commit/48946fd)), closes [#118](https://github.com/NativeScript/nativescript-dev-appium/issues/118)
7+
* fix exiting appium server process
8+
* **android:** setDontKeepActivities should work for all api levels
9+
10+
### Features
11+
12+
* optins "--cleanApp" to uninstall application after finishing tests (#128) ([6447403](https://github.com/NativeScript/nativescript-dev-appium/commit/6447403)), closes [#128](https://github.com/NativeScript/nativescript-dev-appium/issues/128)
13+
* attach to session option "--attachToDebug"
14+
* create session "--createSession"
15+
* option "--sessionId" to provide specific session
16+
* get device log
17+
* **android:** provide option "--relaxedSecurity" to enable relaxed security and execute shell commands using appium android driver (#126) ([ce780bf](https://github.com/NativeScript/nativescript-dev-appium/commit/ce780bf)), closes [#126](https://github.com/NativeScript/nativescript-dev-appium/issues/126)
18+
19+
+### BREAKING CHANGES
20+
21+
* **android:** change default automation name if not specified in appium config (#122) ([3ba0a1c](https://github.com/NativeScript/nativescript-dev-appium/commit/3ba0a1c)), closes [#122](https://github.com/NativeScript/nativescript-dev-appium/issues/122).
22+
23+
Before:
24+
```
25+
Default automation was 'Appium' for all api levels.
26+
```
27+
After:
28+
```
29+
For all api levels higer or equal than api23 (including) default automator name is 'UiAutomator2'
30+
For all api levels lower than api23 default automator is still 'Appium'
31+
```
32+
* rename DeviceController to DeviceManager - In general this should not affect any user except those that are using DeviceManager explicity
33+
* bump version of mocha to ~5.1.0 which requires flag --exit to be set in mocha config file when the tests are run ot Travis
34+
```
35+
136
<a name="3.3.0"></a>
237
# [3.3.0](https://github.com/NativeScript/nativescript-dev-appium/compare/v3.2.0...v3.3.0) (2018-04-21)
338

Diff for: README.md

+39-8
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ my-plugin
211211
```
212212
Thus, the same configuration can be used by both apps without duplication of files.
213213

214-
If you wish to use another location of the capapabilities file instead default ones, you can specify it with `--capsLocation` option. Remember that the path provided has to be relative to the root directory.
214+
If you wish to use another location of the capapabilities file instead default ones, you can specify it with `--appiumCapsLocation` option. Remember that the path provided has to be relative to the root directory.
215215

216216
Notice that once custom capabilities are provided you will be able to pick any of them using the `--runType` option (e.g. `--runType android25`). See sample content of `appium.capabilities.json` file below. For more details regarding the Appium Capabilities read [Appium documentation about Desired Capabilities](https://appium.io/docs/en/writing-running-appium/caps/):
217217

@@ -250,6 +250,8 @@ As you can see, the `app` property can be left an empty string which will force
250250

251251
**It is important to build your app in advance as explained in [Usage](#usage) section, because the runner expects to provide app package to it or such to exists in the search location.**
252252

253+
**For faster testsing when working on an app with livesync it would be better to use --devMode option or start a new session using --startSession option and run tests using --attachToSession option and specify appium --port.**
254+
253255
## Options
254256

255257
|Option| Description | Value |
@@ -259,15 +261,48 @@ As you can see, the `app` property can be left an empty string which will force
259261
| reuseDevice | Reuse the device specified in the `runType` capabilities. If the emulator/simulator is not running, it will launch, execute tests and remain running. The next execution of `npm run e2e` with the `reuseDevice` option will attach to the already running emulator/simulator, execute tests and keep it running. | e.g. --reuseDevice |
260262
| devMode | `devMode` capabilities. Skipping application instalation and will automatically reuse device. | e.g. --devMode |
261263
|sauceLab| Enable tests execution in [Sauce Labs](https://saucelabs.com/). As a prerequisite you will have to define `SAUCE_USER` and `SAUCE_KEY` as [environment variable](https://wiki.saucelabs.com/display/DOCS/Best+Practice%3A+Use+Environment+Variables+for+Authentication+Credentials)| e.g. --sauceLab|
262-
|capsLocation| Change the location where `appium.capabilities.json` config file can be. It should be relative to the root directory | e.g. --capsLocation /e2e-tests|
264+
|appiumCapsLocation| Change the location where `appium.capabilities.json` config file can be. It should be relative to the root directory | e.g. --appiumCapsLocation /e2e-tests|
263265
|port| Appium server port|
264266
|storage| Specify remote image storage |
265267
|ignoreDeviceController| Setting this option you will use default appium device controller which is recommended when tests are executed on cloud based solutions |
268+
|sessionId| In oreder to attach to already started session|Option --port is mendatory in this case. It will automatically set --devMode to true. Provides ability nativescript-dev-appium to be used with [appium desktop client](https://github.com/appium/appium-desktop/releases)|
269+
|attachToDebug| Same as sessionId but no need to porvide session id.|Option --port is mendatory in this case. It will automatically resolve --sessionId. Provides ability nativescript-dev-appium to be used with [appium desktop client](https://github.com/appium/appium-desktop/releases)|
270+
|startSession|Start new appium server and initialize appium driver.|
271+
|cleanApp| Remove application from device on server quit.|
266272

267273
Examples:
268274

275+
Let say that we have a script in package.json like this
276+
277+
```
278+
"scripts": {
279+
"e2e": "tsc -p e2e && mocha --opts ./config/mocha.opts --recursive e2e --appiumCapsLocation ./config/appium.capabilities.json"
280+
}
281+
282+
```
283+
284+
Run tests in sauceLab
285+
```
286+
$ npm run e2e -- --runType android25 --sauceLab --appPath demo.apk
287+
```
288+
289+
Run tests locally
290+
```
291+
$ npm run e2e -- --runType android25
292+
```
293+
294+
Starting new session will console log appium server port and session id
295+
```
296+
$ node ./node_modules/.bin/ns-appium -- --runType android23 --startSession
297+
```
298+
299+
Run tests with already started session. Specify session id and server port. Default value for server port is 8300
269300
```
270-
$ npm run e2e -- --runType android25 --sauceLab --appLocation demo.apk --capsLocation "/e2e-tests/config"
301+
$ npm run e2e -- --runType android23 --sessionId e72daf17-8db6-4500-a0cf-59a66effd6b9 --port 8300
302+
```
303+
or simply use --attachToDebug which will attached to first available session. This is not recommended when more than one session is available.
304+
```
305+
$ npm run e2e -- --runType android23 --attachToDebug --port 8300
271306
```
272307

273308
## Troubleshooting
@@ -282,11 +317,7 @@ $ npm run e2e -- --runType android25 --verbose
282317

283318
1. Missing installed appium
284319
2. Misleading appPath or capabilities location. Please make sure that the path to the app or capabilities location is correct.
285-
286-
287-
## Missing Features
288-
289-
1. Faster developer turnaround when working on an app. Find a way to use livesync and kick off Appium tests for the app that's on the device already.
320+
3. Misleading detials for device specified in appium config
290321

291322
## Contribute
292323
We love PRs! Check out the [contributing guidelines](CONTRIBUTING.md). If you want to contribute, but you are not sure where to start - look for [issues labeled `help wanted`](https://github.com/NativeScript/nativescript-dev-appium/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22).

Diff for: bin/nativescript-dev-appium

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/usr/bin/env node
2+
3+
"use strict";
4+
require("../index.js");

Diff for: bin/nativescript-dev-appium.cmd

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@node %~dp0\nativescript-dev-appium %*

Diff for: index.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export { DeviceManager } from "./lib/device-manager";
1212
export { FrameComparer } from "./lib/frame-comparer";
1313
export { IRectangle } from "./lib/interfaces/rectangle";
1414
export { IDeviceManager } from "./lib/interfaces/device-manager";
15+
export { LogType } from "./lib/log-types";
1516
export declare function startServer(port?: number, deviceManager?: IDeviceManager): Promise<void>;
1617
export declare function stopServer(): Promise<void>;
1718
export declare function createDriver(): Promise<any>;

Diff for: index.ts

+36-7
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import { AppiumServer } from "./lib/appium-server";
22
import { AppiumDriver } from "./lib/appium-driver";
3-
import { ElementHelper } from "./lib/element-helper";
43
import { NsCapabilities } from "./lib/ns-capabilities";
54
import { IDeviceManager } from "./lib/interfaces/device-manager";
6-
import { shutdown, findFreePort } from "./lib/utils";
75
import * as frameComparerHelper from "./lib/frame-comparer";
86
import { FrameComparer } from "./lib/frame-comparer";
97
import { DeviceManager } from "./lib/device-manager";
108
import { DeviceController } from "mobile-devices-controller";
9+
import { logInfo, logError } from "./lib/utils";
1110

1211
export { AppiumDriver } from "./lib/appium-driver";
1312
export { AppiumServer } from "./lib/appium-server";
@@ -21,25 +20,51 @@ export { DeviceManager } from "./lib/device-manager";
2120
export { FrameComparer } from "./lib/frame-comparer";
2221
export { IRectangle } from "./lib/interfaces/rectangle";
2322
export { IDeviceManager } from "./lib/interfaces/device-manager";
23+
export { LogType } from "./lib/log-types";
2424

2525
const nsCapabilities = new NsCapabilities();
2626
const appiumServer = new AppiumServer(nsCapabilities);
2727
let frameComparer: FrameComparer;
2828
let appiumDriver = null;
2929

30-
const attachToExitProcessHoockup = (processToExitFrom, processName) => {
30+
const attachToExitProcessHoockup = (processToAttach, processName) => {
3131
const signals = ['SIGHUP', 'SIGINT', 'SIGQUIT', 'SIGILL', 'SIGTRAP', 'SIGABRT',
3232
'SIGBUS', 'SIGFPE', 'SIGUSR1', 'SIGSEGV', 'SIGUSR2', 'SIGTERM'];
33+
if (!processToAttach) {
34+
return;
35+
}
3336
signals.forEach(function (sig) {
34-
processToExitFrom.once(sig, async function () {
37+
processToAttach.once(sig, async function () {
3538
await killProcesses(sig);
3639
console.log(`Exited from ${processName}`);
37-
processToExitFrom.removeListener(sig, killProcesses);
40+
processToAttach.removeListener(sig, killProcesses);
41+
});
42+
});
43+
}
44+
45+
if (nsCapabilities.startSession) {
46+
startServer(nsCapabilities.port).then(s => {
47+
createDriver().then((d: AppiumDriver) => {
48+
logInfo("Session has started successfully!");
49+
d.sessionId().then(session => {
50+
logInfo(`Session id: ${session}`);
51+
logInfo(`Appium server port: ${appiumServer.port}`);
52+
}).catch(error => {
53+
logError('Something went wrong startig appium driver! Check appium config file!');
54+
logError(error);
55+
});
56+
}).catch(error => {
57+
logError('Something went wrong startig appium driver! Check appium config file!');
58+
logError(error);
3859
});
60+
}).catch(error => {
61+
logError('Something went wrong startig appium server! Check appium config file!');
62+
logError(error);
3963
});
4064
}
65+
4166
export async function startServer(port?: number, deviceManager?: IDeviceManager) {
42-
await appiumServer.start(port || 8300, deviceManager);
67+
await appiumServer.start(port || nsCapabilities.port, deviceManager);
4368
await attachToExitProcessHoockup(appiumServer.server, "appium");
4469
}
4570

@@ -57,6 +82,10 @@ export async function stopServer() {
5782
};
5883

5984
export async function createDriver() {
85+
if (nsCapabilities.attachToDebug) {
86+
appiumDriver = await AppiumDriver.createAppiumDriver(appiumServer.port, nsCapabilities);
87+
return appiumDriver;
88+
}
6089
if (!appiumServer.server) {
6190
throw new Error("Server is not available!");
6291
}
@@ -77,7 +106,7 @@ export async function createDriver() {
77106

78107
// Make sure to turn off "Don't keep activities"
79108
// in case of previous execution failure.
80-
await DeviceManager.setDontKeepActivities(nsCapabilities, appiumDriver, false);
109+
await DeviceManager.setDontKeepActivities(nsCapabilities, appiumDriver.driver, false);
81110

82111
return appiumDriver;
83112
}

Diff for: lib/appium-driver.d.ts

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { IRectangle } from "./interfaces/rectangle";
99
import { Point } from "./point";
1010
import { ImageHelper } from "./image-helper";
1111
import { ImageOptions } from "./image-options";
12+
import { LogType } from "./log-types";
1213
export declare class AppiumDriver {
1314
private _driver;
1415
private _wd;
@@ -54,6 +55,7 @@ export declare class AppiumDriver {
5455
* Get the storage where images are captured. It will be resources/app nam/device name
5556
*/
5657
readonly storageByDeviceName: string;
58+
getlog(logType: LogType): Promise<any>;
5759
static createAppiumDriver(port: number, args: INsCapabilities): Promise<AppiumDriver>;
5860
/**
5961
*

Diff for: lib/appium-driver.ts

+48-5
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ import {
3232
scroll,
3333
findFreePort,
3434
wait,
35-
copy
35+
copy,
36+
getSessions,
37+
logError
3638
} from "./utils";
3739

3840
import { INsCapabilities } from "./interfaces/ns-capabilities";
@@ -44,6 +46,7 @@ import { unlinkSync, writeFileSync } from "fs";
4446
import * as webdriverio from "webdriverio";
4547
import { DeviceManager } from "../lib/device-manager";
4648
import { extname, basename } from "path";
49+
import { LogType } from "./log-types";
4750

4851
export class AppiumDriver {
4952
private static pngFileExt = '.png';
@@ -155,6 +158,20 @@ export class AppiumDriver {
155158
return this._storageByDeviceName;
156159
}
157160

161+
public async getlog(logType: LogType) {
162+
const logs = await this._driver.log(logType);
163+
return logs;
164+
}
165+
166+
// Still not supported in wd
167+
// public async getPerformanceDataTypes() {
168+
// return await this._driver.getSupportedPerformanceDataTypes;
169+
// }
170+
171+
// public async getPerformanceData(type, timeout: number = 5) {
172+
// return await this._driver.getPerformanceData(this._args.appiumCaps.appPackage, type, timeout);
173+
// }
174+
158175
public static async createAppiumDriver(port: number, args: INsCapabilities) {
159176
let driverConfig: any = {
160177
host: "localhost",
@@ -188,7 +205,29 @@ export class AppiumDriver {
188205
let retries = 10;
189206
while (retries > 0 && !hasStarted) {
190207
try {
191-
const sessionIfno = await driver.init(args.appiumCaps);
208+
let sessionIfno;
209+
210+
try {
211+
if (args.sessionId || args.attachToDebug) {
212+
if (!args.sessionId) {
213+
sessionIfno = await getSessions(args.port) + '';
214+
if (sessionIfno) {
215+
const info = JSON.parse(sessionIfno);
216+
args.sessionId = info.value[0].id;
217+
}
218+
if (!args.sessionId || args.sessionId.includes("undefined")) {
219+
logError("Please provide session id!");
220+
process.exit(1);
221+
}
222+
}
223+
await driver.attach(args.sessionId);
224+
} else {
225+
sessionIfno = await driver.init(args.appiumCaps);
226+
}
227+
228+
} catch (error) {
229+
230+
}
192231
log(sessionIfno, args.verbose);
193232
await DeviceManager.applyDeviceAdditionsSettings(driver, args, sessionIfno);
194233

@@ -204,6 +243,8 @@ export class AppiumDriver {
204243
}
205244
if (hasStarted) {
206245
console.log("Appium driver has started successfully!");
246+
}else{
247+
logError("Appium driver is NOT started!")
207248
}
208249

209250
retries--;
@@ -572,9 +613,11 @@ export class AppiumDriver {
572613
this._recordVideoInfo['videoRecoringProcess'].kill("SIGINT");
573614
}
574615
try {
575-
await this._driver.quit();
576-
await this._driver.quit();
577-
await this._webio.quit();
616+
if (!this._args.attachToDebug) {
617+
await this._driver.quit();
618+
await this._driver.quit();
619+
await this._webio.quit();
620+
}
578621
} catch (error) {
579622
}
580623
this._isAlive = false;

0 commit comments

Comments
 (0)