Skip to content

Commit e1bb8cf

Browse files
refactor: device-manager (#188)
* refactor: device-manager
1 parent 6ca2eec commit e1bb8cf

15 files changed

+468
-234
lines changed

index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export { LogType } from "./lib/log-types";
2828
export { INsCapabilities } from "./lib/interfaces/ns-capabilities";
2929
export { INsCapabilitiesArgs } from "./lib/interfaces/ns-capabilities-args";
3030
export { logInfo, logError, logWarn } from "./lib/utils";
31+
3132
export const nsCapabilities: INsCapabilities = new NsCapabilities(parser);
3233

3334
const appiumServer = new AppiumServer(nsCapabilities);

lib/appium-server.ts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,13 @@ export class AppiumServer {
9292
response = await waitForOutput(this._server, /listener started/, /Error: listen/, 60000, true);
9393
}
9494

95+
this.hasStarted = response;
9596
return response;
9697
} else if (!this._args.attachToDebug) {
9798
return true;
9899
}
99100

100101
return false;
101-
102102
}
103103

104104
private startAppiumServer(logLevel: string, isSauceLab: boolean) {
@@ -116,25 +116,30 @@ export class AppiumServer {
116116
}
117117

118118
public async stop() {
119-
await this._args.deviceManager.stopDevice(this._args);
119+
const onServerKilled = (server, signal, code, verbose) => {
120+
log(`Appium terminated due signal: ${signal} and code: ${code}`, verbose);
121+
server && server.removeAllListeners();
122+
}
123+
124+
await this._args.deviceManager.stopDevice(this._args.device, this._args);
120125
return new Promise((resolve, reject) => {
121-
this._server.on("close", (code, signal) => {
122-
log(`Appium terminated due signal: ${signal} and code: ${code}`, this._args.verbose);
126+
this._server.once("close", (code, signal) => {
127+
onServerKilled(this._server, signal,code, this._args.verbose);
123128
resolve();
124129
});
125130

126-
this._server.on("exit", (code, signal) => {
127-
log(`Appium terminated due signal: ${signal} and code: ${code}`, this._args.verbose);
131+
this._server.once("exit", (code, signal) => {
132+
onServerKilled(this._server, signal,code, this._args.verbose);
128133
resolve();
129134
});
130135

131-
this._server.on("error", (code, signal) => {
132-
log(`Appium terminated due signal: ${signal} and code: ${code}`, this._args.verbose);
136+
this._server.once("error", (code, signal) => {
137+
onServerKilled(this._server, signal,code, this._args.verbose);
133138
resolve();
134139
});
135140

136-
this._server.on("disconnect", (code, signal) => {
137-
log(`Appium terminated due signal: ${signal} and code: ${code}`, this._args.verbose);
141+
this._server.once("disconnect", (code, signal) => {
142+
onServerKilled(this._server, signal,code, this._args.verbose);
138143
resolve();
139144
});
140145

@@ -149,6 +154,7 @@ export class AppiumServer {
149154
this._server.kill("SIGINT");
150155
this._server.kill("SIGINT");
151156
this._server.kill("SIGKILL");
157+
process.kill(this._server.pid, "SIGKILL");
152158
shutdown(this._server, this._args.verbose);
153159
}
154160
} catch (error) {

lib/device-controller.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export declare class DeviceManger implements IDeviceManager {
55
private static _emulators;
66
constructor();
77
startDevice(args: INsCapabilities): Promise<IDevice>;
8-
stopDevice(args: INsCapabilities): Promise<any>;
8+
stopDevice(device: IDevice, args: INsCapabilities): Promise<any>;
99
installApp(args: INsCapabilities): Promise<any>;
1010
uninstallApp(args: INsCapabilities): Promise<any>;
1111
static kill(device: IDevice): Promise<void>;

lib/device-manager.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ export declare class DeviceManager implements IDeviceManager {
55
private static _emulators;
66
constructor();
77
startDevice(args: INsCapabilities): Promise<IDevice>;
8-
stopDevice(args: INsCapabilities): Promise<any>;
8+
stopDevice(device: IDevice, args: INsCapabilities): Promise<any>;
99
installApp(args: INsCapabilities): Promise<any>;
1010
uninstallApp(args: INsCapabilities): Promise<any>;
1111
static kill(device: IDevice): Promise<void>;
12-
static getDefaultDevice(args: INsCapabilities, deviceName?: string, token?: string, type?: DeviceType, platformVersion?: number): any;
12+
static getDefaultDevice(args: INsCapabilities, deviceName?: string, token?: string, type?: DeviceType, platformVersion?: number): IDevice;
1313
static setDontKeepActivities(args: INsCapabilities, driver: any, value: any): Promise<void>;
1414
static executeShellCommand(driver: any, commandArgs: {
1515
command: string;

lib/device-manager.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import {
88
AndroidController,
99
Platform,
1010
Status,
11-
DeviceType
11+
DeviceType,
12+
sortDescByApiLevelPredicate
1213
} from "mobile-devices-controller";
1314

1415
export class DeviceManager implements IDeviceManager {
@@ -19,6 +20,7 @@ export class DeviceManager implements IDeviceManager {
1920

2021
public async startDevice(args: INsCapabilities): Promise<IDevice> {
2122
args.appiumCaps.platformName = args.appiumCaps.platformName.toLowerCase();
23+
const shouldFullyResetDevice = !args.appiumCaps.udid;
2224
let device: IDevice = DeviceManager.getDefaultDevice(args);
2325
const token = process.env["DEVICE_TOKEN"] || process.env.npm_config_deviceToken;
2426
device.token = token && token.replace("emulator-", "");
@@ -41,7 +43,9 @@ export class DeviceManager implements IDeviceManager {
4143

4244
const searchQuery = args.appiumCaps.udid ? { token: args.appiumCaps.udid } : device;
4345

44-
const foundDevices = await DeviceController.getDevices(searchQuery);
46+
const foundDevices = (await DeviceController.getDevices(searchQuery))
47+
.sort((a, b) => sortDescByApiLevelPredicate(a, b));
48+
4549
if (!foundDevices || foundDevices.length === 0) {
4650
logError("We couldn't find any devices of type: ", searchQuery);
4751
logError("We will try to proceed to appium!");
@@ -88,7 +92,7 @@ export class DeviceManager implements IDeviceManager {
8892
logInfo("Device is connected:", device)
8993
}
9094
if (device.status === Status.SHUTDOWN) {
91-
await DeviceController.startDevice(device, startDeviceOptions);
95+
await DeviceController.startDevice(device, startDeviceOptions, shouldFullyResetDevice);
9296
try {
9397
delete device.process;
9498
} catch (error) { }
@@ -110,12 +114,10 @@ export class DeviceManager implements IDeviceManager {
110114
return device;
111115
}
112116

113-
public async stopDevice(args: INsCapabilities): Promise<any> {
114-
if (DeviceManager._emulators.has(args.runType)
115-
&& !args.reuseDevice
117+
public async stopDevice(device: IDevice, args: INsCapabilities): Promise<any> {
118+
if (!args.reuseDevice
116119
&& !args.isSauceLab
117120
&& !args.ignoreDeviceController) {
118-
const device = DeviceManager._emulators.get(args.runType);
119121
await DeviceManager.kill(device);
120122
}
121123
}

lib/interfaces/device-manager.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { INsCapabilities } from "../interfaces/ns-capabilities";
22
import { IDevice } from "mobile-devices-controller";
33
export interface IDeviceManager {
44
startDevice(args: INsCapabilities): Promise<IDevice>;
5-
stopDevice(args: INsCapabilities): Promise<IDevice>;
5+
stopDevice(device: IDevice, args: INsCapabilities): Promise<IDevice>;
66
installApp(args: INsCapabilities): Promise<void>;
77
uninstallApp(args: INsCapabilities): Promise<void>;
88
getPackageId(device: any, appPath: any): string;

lib/interfaces/device-manager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { IDevice } from "mobile-devices-controller";
33

44
export interface IDeviceManager {
55
startDevice(args: INsCapabilities): Promise<IDevice>
6-
stopDevice(args: INsCapabilities): Promise<IDevice>
6+
stopDevice(device: IDevice, args: INsCapabilities): Promise<IDevice>
77
installApp(args: INsCapabilities): Promise<void>;
88
uninstallApp(args: INsCapabilities): Promise<void>;
99
getPackageId(device, appPath): string;

lib/interfaces/ns-capabilities.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { INsCapabilitiesArgs } from "./ns-capabilities-args";
22
export interface INsCapabilities extends INsCapabilitiesArgs {
3-
validateArgs(): void;
4-
extend(args: INsCapabilitiesArgs): INsCapabilities;
3+
validateArgs?: () => {};
4+
extend?: (args: INsCapabilitiesArgs) => {};
55
}

lib/interfaces/ns-capabilities.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { INsCapabilitiesArgs } from "./ns-capabilities-args";
22

3-
export interface INsCapabilities extends INsCapabilitiesArgs{
4-
validateArgs(): void;
5-
extend(args: INsCapabilitiesArgs): INsCapabilities;
3+
export interface INsCapabilities extends INsCapabilitiesArgs {
4+
validateArgs?: () => {};
5+
extend?: (args: INsCapabilitiesArgs) => {};
66
}
77

lib/ns-capabilities.d.ts

Lines changed: 32 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -5,81 +5,51 @@ import { IDevice } from "mobile-devices-controller";
55
import { IDeviceManager } from "./interfaces/device-manager";
66
export declare class NsCapabilities implements INsCapabilities {
77
private _parser;
8-
private _projectDir;
9-
private _projectBinary;
10-
private _pluginRoot;
11-
private _pluginBinary;
12-
private _port;
13-
private _verbose;
14-
private _appiumCapsLocation;
15-
private _appiumCaps;
16-
private _testFolder;
17-
private _storage;
18-
private _testReports;
19-
private _reuseDevice;
20-
private _devMode;
21-
private _runType;
22-
private _isSauceLab;
23-
private _wdaLocalPort;
24-
private _appName;
25-
private _appPath;
26-
private _path;
27-
private _emulatorOptions;
28-
private _sessionId;
29-
private _capabilitiesName;
30-
private _ignoreDeviceController;
31-
private _relaxedSecurity;
32-
private _cleanApp;
33-
private _attachToDebug;
34-
private _startSession;
35-
private _isValidated;
368
private _automationName;
37-
private _device;
38-
private _deviceManager;
39-
private _exceptions;
40-
private _imagesPath;
41-
constructor(_parser: INsCapabilitiesArgs);
42-
readonly path: string;
43-
readonly projectDir: string;
44-
readonly projectBinary: string;
45-
readonly pluginRoot: string;
46-
readonly pluginBinary: string;
9+
projectDir: string;
10+
projectBinary: string;
11+
pluginRoot: string;
12+
pluginBinary: string;
4713
port: number;
4814
verbose: boolean;
49-
readonly appiumCapsLocation: string;
15+
appiumCapsLocation: string;
5016
appiumCaps: any;
51-
readonly testFolder: string;
52-
readonly storage: string;
53-
readonly testReports: any;
54-
readonly reuseDevice: boolean;
55-
readonly devMode: boolean;
56-
readonly runType: string;
57-
readonly isAndroid: any;
58-
readonly isIOS: boolean;
59-
readonly isSauceLab: boolean;
60-
automationName: AutomationName;
61-
readonly appPath: string;
17+
testFolder: string;
18+
storage: string;
19+
testReports: any;
20+
reuseDevice: boolean;
21+
devMode: boolean;
22+
runType: string;
23+
isSauceLab: boolean;
24+
wdaLocalPort: number;
6225
appName: string;
26+
appPath: string;
27+
path: string;
28+
emulatorOptions: string;
29+
sessionId: string;
30+
capabilitiesName: string;
6331
ignoreDeviceController: boolean;
64-
readonly wdaLocalPort: number;
32+
relaxedSecurity: boolean;
33+
cleanApp: boolean;
34+
attachToDebug: boolean;
35+
startSession: boolean;
36+
isValidated: boolean;
6537
device: IDevice;
66-
readonly emulatorOptions: string;
67-
readonly relaxedSecurity: boolean;
68-
readonly cleanApp: boolean;
69-
readonly attachToDebug: boolean;
70-
sessionId: string;
71-
readonly startSession: boolean;
7238
deviceManager: IDeviceManager;
73-
readonly isValidated: boolean;
74-
readonly imagesPath: string;
39+
exceptions: Array<string>;
40+
imagesPath: string;
41+
constructor(_parser: INsCapabilitiesArgs);
42+
readonly isAndroid: any;
43+
readonly isIOS: boolean;
44+
automationName: AutomationName;
7545
setAutomationNameFromString(automationName: String): void;
7646
extend(args: INsCapabilities): this;
77-
validateArgs(): void;
47+
validateArgs(): any;
7848
private isAndroidPlatform;
79-
private shouldSetFullResetOption;
49+
shouldSetFullResetOption(): void;
8050
private setAutomationName;
8151
tryGetAndroidApiLevel(): number;
8252
private resolveApplication;
83-
private checkMandatoryCapabiliies;
53+
private checkMandatoryCapabilities;
8454
private throwExceptions;
8555
}

0 commit comments

Comments
 (0)