appium-webdriveragent 14.2.0 → 15.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/WebDriverAgentLib/Info.plist +2 -2
- package/build/lib/types.d.ts +44 -4
- package/build/lib/types.d.ts.map +1 -1
- package/build/lib/utils/index.d.ts +11 -0
- package/build/lib/utils/index.d.ts.map +1 -0
- package/build/lib/utils/index.js +27 -0
- package/build/lib/utils/index.js.map +1 -0
- package/build/lib/utils/module.d.ts +6 -0
- package/build/lib/utils/module.d.ts.map +1 -0
- package/build/lib/utils/module.js +31 -0
- package/build/lib/utils/module.js.map +1 -0
- package/build/lib/utils/platform.d.ts +7 -0
- package/build/lib/utils/platform.d.ts.map +1 -0
- package/build/lib/utils/platform.js +13 -0
- package/build/lib/utils/platform.js.map +1 -0
- package/build/lib/utils/processes.d.ts +23 -0
- package/build/lib/utils/processes.d.ts.map +1 -0
- package/build/lib/utils/processes.js +132 -0
- package/build/lib/utils/processes.js.map +1 -0
- package/build/lib/utils/security.d.ts +5 -0
- package/build/lib/utils/security.d.ts.map +1 -0
- package/build/lib/utils/security.js +15 -0
- package/build/lib/utils/security.js.map +1 -0
- package/build/lib/utils/xctestrun.d.ts +51 -0
- package/build/lib/utils/xctestrun.d.ts.map +1 -0
- package/build/lib/utils/xctestrun.js +120 -0
- package/build/lib/utils/xctestrun.js.map +1 -0
- package/build/lib/wda-strategies.d.ts +69 -0
- package/build/lib/wda-strategies.d.ts.map +1 -0
- package/build/lib/wda-strategies.js +253 -0
- package/build/lib/wda-strategies.js.map +1 -0
- package/build/lib/webdriveragent.d.ts +3 -14
- package/build/lib/webdriveragent.d.ts.map +1 -1
- package/build/lib/webdriveragent.js +78 -127
- package/build/lib/webdriveragent.js.map +1 -1
- package/build/lib/xcodebuild.d.ts.map +1 -1
- package/build/lib/xcodebuild.js +29 -7
- package/build/lib/xcodebuild.js.map +1 -1
- package/lib/types.ts +58 -4
- package/lib/utils/index.ts +20 -0
- package/lib/utils/module.ts +29 -0
- package/lib/utils/platform.ts +10 -0
- package/lib/utils/processes.ts +135 -0
- package/lib/utils/security.ts +15 -0
- package/lib/utils/xctestrun.ts +160 -0
- package/lib/wda-strategies.ts +340 -0
- package/lib/webdriveragent.ts +89 -163
- package/lib/xcodebuild.ts +34 -17
- package/package.json +3 -4
- package/build/lib/utils.d.ts +0 -105
- package/build/lib/utils.d.ts.map +0 -1
- package/build/lib/utils.js +0 -413
- package/build/lib/utils.js.map +0 -1
- package/lib/utils.ts +0 -442
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import {fs, plist, util} from '@appium/support';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import {arch} from 'node:os';
|
|
4
|
+
import {log} from '../logger';
|
|
5
|
+
import type {DeviceInfo} from '../types';
|
|
6
|
+
import {isTvOS} from './platform';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Arguments for setting xctestrun file
|
|
10
|
+
*/
|
|
11
|
+
export interface XctestrunFileArgs {
|
|
12
|
+
deviceInfo: DeviceInfo;
|
|
13
|
+
sdkVersion: string;
|
|
14
|
+
bootstrapPath: string;
|
|
15
|
+
wdaRemotePort: number | string;
|
|
16
|
+
wdaBindingIP?: string;
|
|
17
|
+
maxHttpRequestBodySize?: number | string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Creates xctestrun file per device & platform version.
|
|
22
|
+
* We expect to have WebDriverAgentRunner_iphoneos${sdkVersion|platformVersion}-arm64.xctestrun for real device
|
|
23
|
+
* and WebDriverAgentRunner_iphonesimulator${sdkVersion|platformVersion}-${x86_64|arm64}.xctestrun for simulator located @bootstrapPath
|
|
24
|
+
* Newer Xcode (Xcode 10.0 at least) generates xctestrun file following sdkVersion.
|
|
25
|
+
* e.g. Xcode which has iOS SDK Version 12.2 on an intel Mac host machine generates WebDriverAgentRunner_iphonesimulator.2-x86_64.xctestrun
|
|
26
|
+
* even if the cap has platform version 11.4
|
|
27
|
+
*
|
|
28
|
+
* @param args
|
|
29
|
+
* @return returns xctestrunFilePath for given device
|
|
30
|
+
* @throws if WebDriverAgentRunner_iphoneos${sdkVersion|platformVersion}-arm64.xctestrun for real device
|
|
31
|
+
* or WebDriverAgentRunner_iphonesimulator${sdkVersion|platformVersion}-x86_64.xctestrun for simulator is not found @bootstrapPath,
|
|
32
|
+
* then it will throw a file not found exception
|
|
33
|
+
*/
|
|
34
|
+
export async function setXctestrunFile(args: XctestrunFileArgs): Promise<string> {
|
|
35
|
+
const {
|
|
36
|
+
deviceInfo,
|
|
37
|
+
sdkVersion,
|
|
38
|
+
bootstrapPath,
|
|
39
|
+
wdaRemotePort,
|
|
40
|
+
wdaBindingIP,
|
|
41
|
+
maxHttpRequestBodySize,
|
|
42
|
+
} = args;
|
|
43
|
+
const xctestrunFilePath = await getXctestrunFilePath(deviceInfo, sdkVersion, bootstrapPath);
|
|
44
|
+
const xctestRunContent = await plist.parsePlistFile(xctestrunFilePath);
|
|
45
|
+
const updateWDAPort = getAdditionalRunContent(
|
|
46
|
+
deviceInfo.platformName,
|
|
47
|
+
wdaRemotePort,
|
|
48
|
+
wdaBindingIP,
|
|
49
|
+
maxHttpRequestBodySize,
|
|
50
|
+
);
|
|
51
|
+
const newXctestRunContent = mergeObjects(xctestRunContent, updateWDAPort);
|
|
52
|
+
await plist.updatePlistFile(xctestrunFilePath, newXctestRunContent, true);
|
|
53
|
+
|
|
54
|
+
return xctestrunFilePath;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Return the WDA object which appends existing xctest runner content
|
|
59
|
+
* @param platformName - The name of the platform
|
|
60
|
+
* @param wdaRemotePort - The remote port number
|
|
61
|
+
* @param wdaBindingIP - The IP address to bind to. If not given, it binds to all interfaces.
|
|
62
|
+
* @param maxHttpRequestBodySize - The maximum HTTP request body size in bytes.
|
|
63
|
+
* @return returns a runner object which has USE_PORT and optionally USE_IP
|
|
64
|
+
*/
|
|
65
|
+
export function getAdditionalRunContent(
|
|
66
|
+
platformName: string,
|
|
67
|
+
wdaRemotePort: number | string,
|
|
68
|
+
wdaBindingIP?: string,
|
|
69
|
+
maxHttpRequestBodySize?: number | string,
|
|
70
|
+
): Record<string, any> {
|
|
71
|
+
const runner = `WebDriverAgentRunner${isTvOS(platformName) ? '_tvOS' : ''}`;
|
|
72
|
+
return {
|
|
73
|
+
[runner]: {
|
|
74
|
+
EnvironmentVariables: {
|
|
75
|
+
// USE_PORT must be 'string'
|
|
76
|
+
USE_PORT: `${wdaRemotePort}`,
|
|
77
|
+
...(wdaBindingIP ? {USE_IP: wdaBindingIP} : {}),
|
|
78
|
+
...(maxHttpRequestBodySize
|
|
79
|
+
? {MAX_HTTP_REQUEST_BODY_SIZE: `${maxHttpRequestBodySize}`}
|
|
80
|
+
: {}),
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Return the path of xctestrun if it exists
|
|
88
|
+
* @param deviceInfo
|
|
89
|
+
* @param sdkVersion - The Xcode SDK version of OS.
|
|
90
|
+
* @param bootstrapPath - The folder path containing xctestrun file.
|
|
91
|
+
*/
|
|
92
|
+
export async function getXctestrunFilePath(
|
|
93
|
+
deviceInfo: DeviceInfo,
|
|
94
|
+
sdkVersion: string,
|
|
95
|
+
bootstrapPath: string,
|
|
96
|
+
): Promise<string> {
|
|
97
|
+
// First try the SDK path, for Xcode 10 (at least)
|
|
98
|
+
const sdkBased: [string, string] = [
|
|
99
|
+
path.resolve(bootstrapPath, `${deviceInfo.udid}_${sdkVersion}.xctestrun`),
|
|
100
|
+
sdkVersion,
|
|
101
|
+
];
|
|
102
|
+
// Next try Platform path, for earlier Xcode versions
|
|
103
|
+
const platformBased: [string, string] = [
|
|
104
|
+
path.resolve(bootstrapPath, `${deviceInfo.udid}_${deviceInfo.platformVersion}.xctestrun`),
|
|
105
|
+
deviceInfo.platformVersion,
|
|
106
|
+
];
|
|
107
|
+
|
|
108
|
+
for (const [filePath, version] of [sdkBased, platformBased]) {
|
|
109
|
+
if (await fs.exists(filePath)) {
|
|
110
|
+
log.info(`Using '${filePath}' as xctestrun file`);
|
|
111
|
+
return filePath;
|
|
112
|
+
}
|
|
113
|
+
const originalXctestrunFile = path.resolve(
|
|
114
|
+
bootstrapPath,
|
|
115
|
+
getXctestrunFileName(deviceInfo, version),
|
|
116
|
+
);
|
|
117
|
+
if (await fs.exists(originalXctestrunFile)) {
|
|
118
|
+
// If this is first time run for given device, then first generate xctestrun file for device.
|
|
119
|
+
// We need to have a xctestrun file **per device** because we cannot have same wda port for all devices.
|
|
120
|
+
await fs.copyFile(originalXctestrunFile, filePath);
|
|
121
|
+
log.info(`Using '${filePath}' as xctestrun file copied by '${originalXctestrunFile}'`);
|
|
122
|
+
return filePath;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
throw new Error(
|
|
127
|
+
`If you are using 'useXctestrunFile' capability then you ` +
|
|
128
|
+
`need to have a xctestrun file (expected: ` +
|
|
129
|
+
`'${path.resolve(bootstrapPath, getXctestrunFileName(deviceInfo, sdkVersion))}')`,
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Return the name of xctestrun file
|
|
135
|
+
* @param deviceInfo
|
|
136
|
+
* @param version - The Xcode SDK version of OS.
|
|
137
|
+
* @return returns xctestrunFilePath for given device
|
|
138
|
+
*/
|
|
139
|
+
export function getXctestrunFileName(deviceInfo: DeviceInfo, version: string): string {
|
|
140
|
+
const archSuffix = deviceInfo.isRealDevice
|
|
141
|
+
? `os${version}-arm64`
|
|
142
|
+
: `simulator${version}-${arch() === 'arm64' ? 'arm64' : 'x86_64'}`;
|
|
143
|
+
return `WebDriverAgentRunner_${isTvOS(deviceInfo.platformName) ? 'tvOS_appletv' : 'iphone'}${archSuffix}.xctestrun`;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function mergeObjects<T extends Record<string, any>, U extends Record<string, any>>(
|
|
147
|
+
target: T,
|
|
148
|
+
source: U,
|
|
149
|
+
): T & U {
|
|
150
|
+
const output: Record<string, any> = {...target};
|
|
151
|
+
for (const [key, sourceValue] of Object.entries(source)) {
|
|
152
|
+
const targetValue = output[key];
|
|
153
|
+
if (util.isPlainObject(targetValue) && util.isPlainObject(sourceValue)) {
|
|
154
|
+
output[key] = mergeObjects(targetValue, sourceValue);
|
|
155
|
+
continue;
|
|
156
|
+
}
|
|
157
|
+
output[key] = sourceValue;
|
|
158
|
+
}
|
|
159
|
+
return output as T & U;
|
|
160
|
+
}
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
import {exec} from 'teen_process';
|
|
2
|
+
import {fs} from '@appium/support';
|
|
3
|
+
import type {AppiumLogger, StringRecord} from '@appium/types';
|
|
4
|
+
import {getPIDsListeningOnPort, resetTestProcesses} from './utils';
|
|
5
|
+
import type {NoSessionProxy} from './no-session-proxy';
|
|
6
|
+
import type {XcodeBuild} from './xcodebuild';
|
|
7
|
+
import type {
|
|
8
|
+
AppleDevice,
|
|
9
|
+
RealDevicePreinstalledHostOps,
|
|
10
|
+
RealDeviceXcodebuildHostOps,
|
|
11
|
+
SimulatorHostOps,
|
|
12
|
+
WdaHostOps,
|
|
13
|
+
WdaLaunchEnvironment,
|
|
14
|
+
WdaStartupStrategyName,
|
|
15
|
+
} from './types';
|
|
16
|
+
|
|
17
|
+
const WDA_AGENT_PORT = 8100;
|
|
18
|
+
const HOST_OPS_REQUIRED_MESSAGE =
|
|
19
|
+
'Host operations must be provided to launch or terminate preinstalled WebDriverAgent';
|
|
20
|
+
|
|
21
|
+
export interface WdaStartupStrategy {
|
|
22
|
+
readonly name: WdaStartupStrategyName;
|
|
23
|
+
launch(sessionId: string): Promise<StringRecord | null>;
|
|
24
|
+
quit(): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface WdaStartupStrategyContext {
|
|
28
|
+
readonly argsWebDriverAgentUrl?: string;
|
|
29
|
+
readonly webDriverAgentUrl?: string;
|
|
30
|
+
readonly usePreinstalledWDA?: boolean;
|
|
31
|
+
readonly useXctestrunFile?: boolean;
|
|
32
|
+
readonly usePrebuiltWDA?: boolean;
|
|
33
|
+
readonly prebuildWDA?: boolean;
|
|
34
|
+
readonly isRealDevice: boolean;
|
|
35
|
+
readonly device: AppleDevice;
|
|
36
|
+
readonly agentPath: string;
|
|
37
|
+
readonly bootstrapPath: string;
|
|
38
|
+
readonly bundleIdForXctest: string;
|
|
39
|
+
readonly wdaLocalPort?: number;
|
|
40
|
+
readonly wdaRemotePort: number;
|
|
41
|
+
readonly wdaBindingIP?: string;
|
|
42
|
+
readonly wdaLaunchTimeout: number;
|
|
43
|
+
readonly mjpegServerPort?: number;
|
|
44
|
+
readonly maxHttpRequestBodySize?: number;
|
|
45
|
+
readonly platformName?: string;
|
|
46
|
+
readonly platformVersion?: string;
|
|
47
|
+
readonly log: AppiumLogger;
|
|
48
|
+
readonly hostOps: Required<WdaHostOps>;
|
|
49
|
+
setWebDriverAgentUrl(value?: string): void;
|
|
50
|
+
setUrl(value: string): void;
|
|
51
|
+
setupProxies(sessionId: string): void;
|
|
52
|
+
getStatus(timeoutMs?: number): Promise<StringRecord | null>;
|
|
53
|
+
cleanupProjectIfFresh(): Promise<void>;
|
|
54
|
+
xcodebuild(): XcodeBuild;
|
|
55
|
+
noSessionProxy(): NoSessionProxy;
|
|
56
|
+
setStarted(started: boolean): void;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
class ExistingWdaUrlStrategy implements WdaStartupStrategy {
|
|
60
|
+
readonly name = 'existing-url' as const;
|
|
61
|
+
|
|
62
|
+
constructor(private readonly ctx: WdaStartupStrategyContext) {}
|
|
63
|
+
|
|
64
|
+
async launch(sessionId: string): Promise<StringRecord | null> {
|
|
65
|
+
this.ctx.log.info(`Using provided WebdriverAgent at '${this.ctx.webDriverAgentUrl}'`);
|
|
66
|
+
this.ctx.setUrl(this.ctx.webDriverAgentUrl as string);
|
|
67
|
+
this.ctx.setupProxies(sessionId);
|
|
68
|
+
return await this.ctx.getStatus();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async quit(): Promise<void> {
|
|
72
|
+
this.ctx.log.debug(
|
|
73
|
+
'Stopping neither xcodebuild nor XCTest session since WDA lifecycle is not managed by this driver',
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
class SimulatorWdaStrategy implements WdaStartupStrategy {
|
|
79
|
+
readonly name = 'simulator' as const;
|
|
80
|
+
|
|
81
|
+
constructor(private readonly ctx: WdaStartupStrategyContext) {}
|
|
82
|
+
|
|
83
|
+
async launch(sessionId: string): Promise<StringRecord | null> {
|
|
84
|
+
if (this.ctx.usePreinstalledWDA) {
|
|
85
|
+
return await launchPreinstalled(this.ctx, this.ctx.hostOps.simulator, sessionId);
|
|
86
|
+
}
|
|
87
|
+
return await launchWithXcodebuild(this.ctx, sessionId);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async quit(): Promise<void> {
|
|
91
|
+
if (this.ctx.usePreinstalledWDA) {
|
|
92
|
+
await terminatePreinstalled(this.ctx, this.ctx.hostOps.simulator);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
await quitXcodebuild(this.ctx);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
class RealDeviceXcodebuildStrategy implements WdaStartupStrategy {
|
|
100
|
+
readonly name = 'real-device-xcodebuild' as const;
|
|
101
|
+
|
|
102
|
+
constructor(private readonly ctx: WdaStartupStrategyContext) {}
|
|
103
|
+
|
|
104
|
+
async launch(sessionId: string): Promise<StringRecord | null> {
|
|
105
|
+
return await launchWithXcodebuild(this.ctx, sessionId);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
async quit(): Promise<void> {
|
|
109
|
+
await quitXcodebuild(this.ctx);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
class RealDevicePreinstalledStrategy implements WdaStartupStrategy {
|
|
114
|
+
readonly name = 'real-device-preinstalled' as const;
|
|
115
|
+
|
|
116
|
+
constructor(private readonly ctx: WdaStartupStrategyContext) {}
|
|
117
|
+
|
|
118
|
+
async launch(sessionId: string): Promise<StringRecord | null> {
|
|
119
|
+
return await launchPreinstalled(this.ctx, this.ctx.hostOps.realDevicePreinstalled, sessionId);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async quit(): Promise<void> {
|
|
123
|
+
await terminatePreinstalled(this.ctx, this.ctx.hostOps.realDevicePreinstalled);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Selects the WDA startup strategy for the provided launch arguments.
|
|
129
|
+
*/
|
|
130
|
+
export function selectWdaStartupStrategyName(args: {
|
|
131
|
+
realDevice?: boolean;
|
|
132
|
+
webDriverAgentUrl?: string;
|
|
133
|
+
usePreinstalledWDA?: boolean;
|
|
134
|
+
}): WdaStartupStrategyName {
|
|
135
|
+
if (args.webDriverAgentUrl) {
|
|
136
|
+
return 'existing-url';
|
|
137
|
+
}
|
|
138
|
+
if (!args.realDevice) {
|
|
139
|
+
return 'simulator';
|
|
140
|
+
}
|
|
141
|
+
if (args.usePreinstalledWDA) {
|
|
142
|
+
return 'real-device-preinstalled';
|
|
143
|
+
}
|
|
144
|
+
return 'real-device-xcodebuild';
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Creates a WDA startup strategy for the current facade state.
|
|
149
|
+
*/
|
|
150
|
+
export function createWdaStartupStrategy(ctx: WdaStartupStrategyContext): WdaStartupStrategy {
|
|
151
|
+
const startupStrategy = selectWdaStartupStrategyName({
|
|
152
|
+
realDevice: ctx.isRealDevice,
|
|
153
|
+
webDriverAgentUrl: ctx.webDriverAgentUrl,
|
|
154
|
+
usePreinstalledWDA: ctx.usePreinstalledWDA,
|
|
155
|
+
});
|
|
156
|
+
switch (startupStrategy) {
|
|
157
|
+
case 'existing-url':
|
|
158
|
+
return new ExistingWdaUrlStrategy(ctx);
|
|
159
|
+
case 'simulator':
|
|
160
|
+
return new SimulatorWdaStrategy(ctx);
|
|
161
|
+
case 'real-device-preinstalled':
|
|
162
|
+
return new RealDevicePreinstalledStrategy(ctx);
|
|
163
|
+
case 'real-device-xcodebuild':
|
|
164
|
+
return new RealDeviceXcodebuildStrategy(ctx);
|
|
165
|
+
default:
|
|
166
|
+
throw new Error(`Unknown WDA startup strategy: ${startupStrategy}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Creates default host operations for flows the package can own directly.
|
|
172
|
+
*/
|
|
173
|
+
export function createDefaultWdaHostOps(): Required<WdaHostOps> {
|
|
174
|
+
return {
|
|
175
|
+
simulator: createDefaultSimulatorWdaHostOps(),
|
|
176
|
+
realDevicePreinstalled: createDefaultRealDevicePreinstalledHostOps(),
|
|
177
|
+
realDeviceXcodebuild: createDefaultRealDeviceXcodebuildHostOps(),
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Creates default simulator host operations.
|
|
183
|
+
*/
|
|
184
|
+
export function createDefaultSimulatorWdaHostOps(): SimulatorHostOps {
|
|
185
|
+
return {
|
|
186
|
+
async launchPreinstalled() {
|
|
187
|
+
throw new Error(HOST_OPS_REQUIRED_MESSAGE);
|
|
188
|
+
},
|
|
189
|
+
async terminate() {
|
|
190
|
+
throw new Error(HOST_OPS_REQUIRED_MESSAGE);
|
|
191
|
+
},
|
|
192
|
+
async resetTestProcesses({udid, isSimulator}) {
|
|
193
|
+
await resetTestProcesses(udid, isSimulator);
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Creates default real-device preinstalled host operations.
|
|
200
|
+
*/
|
|
201
|
+
export function createDefaultRealDevicePreinstalledHostOps(): RealDevicePreinstalledHostOps {
|
|
202
|
+
return {
|
|
203
|
+
async launchPreinstalled() {
|
|
204
|
+
throw new Error(HOST_OPS_REQUIRED_MESSAGE);
|
|
205
|
+
},
|
|
206
|
+
async terminate() {
|
|
207
|
+
throw new Error(HOST_OPS_REQUIRED_MESSAGE);
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Creates default real-device xcodebuild host operations.
|
|
214
|
+
*/
|
|
215
|
+
export function createDefaultRealDeviceXcodebuildHostOps(): RealDeviceXcodebuildHostOps {
|
|
216
|
+
return {
|
|
217
|
+
async resetTestProcesses({udid, isSimulator}) {
|
|
218
|
+
await resetTestProcesses(udid, isSimulator);
|
|
219
|
+
},
|
|
220
|
+
async cleanupObsoleteProcesses({udid, port, commandLineIncludes}) {
|
|
221
|
+
const obsoletePids = await getPIDsListeningOnPort(
|
|
222
|
+
port,
|
|
223
|
+
(cmdLine) =>
|
|
224
|
+
cmdLine.includes(commandLineIncludes) &&
|
|
225
|
+
!cmdLine.toLowerCase().includes(udid.toLowerCase()),
|
|
226
|
+
);
|
|
227
|
+
|
|
228
|
+
if (obsoletePids.length > 0) {
|
|
229
|
+
await exec('kill', obsoletePids);
|
|
230
|
+
}
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
async function launchWithXcodebuild(
|
|
236
|
+
ctx: WdaStartupStrategyContext,
|
|
237
|
+
sessionId: string,
|
|
238
|
+
): Promise<StringRecord | null> {
|
|
239
|
+
ctx.log.info('Launching WebDriverAgent on the device');
|
|
240
|
+
|
|
241
|
+
ctx.setupProxies(sessionId);
|
|
242
|
+
|
|
243
|
+
if (!ctx.useXctestrunFile && !(await fs.exists(ctx.agentPath))) {
|
|
244
|
+
throw new Error(
|
|
245
|
+
`Trying to use WebDriverAgent project at '${ctx.agentPath}' but the ` + 'file does not exist',
|
|
246
|
+
);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
if (ctx.useXctestrunFile || ctx.usePrebuiltWDA) {
|
|
250
|
+
ctx.log.info('Skipped WDA project cleanup according to the provided capabilities');
|
|
251
|
+
} else {
|
|
252
|
+
await ctx.cleanupProjectIfFresh();
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
const resetTestProcesses = ctx.isRealDevice
|
|
256
|
+
? ctx.hostOps.realDeviceXcodebuild.resetTestProcesses
|
|
257
|
+
: ctx.hostOps.simulator.resetTestProcesses;
|
|
258
|
+
await resetTestProcesses?.({
|
|
259
|
+
udid: ctx.device.udid,
|
|
260
|
+
isSimulator: !ctx.isRealDevice,
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
const xcodebuild = ctx.xcodebuild();
|
|
264
|
+
await xcodebuild.init(ctx.noSessionProxy());
|
|
265
|
+
|
|
266
|
+
if (ctx.prebuildWDA) {
|
|
267
|
+
await xcodebuild.prebuild();
|
|
268
|
+
}
|
|
269
|
+
return (await xcodebuild.start()) as StringRecord | null;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
async function launchPreinstalled(
|
|
273
|
+
ctx: WdaStartupStrategyContext,
|
|
274
|
+
hostOps: SimulatorHostOps | RealDevicePreinstalledHostOps,
|
|
275
|
+
sessionId: string,
|
|
276
|
+
): Promise<StringRecord | null> {
|
|
277
|
+
const xctestEnv = createPreinstalledWdaEnvironment(ctx);
|
|
278
|
+
ctx.log.info('Launching WebDriverAgent on the device without xcodebuild');
|
|
279
|
+
await hostOps.launchPreinstalled({
|
|
280
|
+
udid: ctx.device.udid,
|
|
281
|
+
bundleId: ctx.bundleIdForXctest,
|
|
282
|
+
env: xctestEnv,
|
|
283
|
+
wdaLocalPort: ctx.wdaLocalPort,
|
|
284
|
+
wdaRemotePort: ctx.wdaRemotePort,
|
|
285
|
+
platformName: ctx.platformName,
|
|
286
|
+
platformVersion: ctx.platformVersion,
|
|
287
|
+
timeoutMs: ctx.wdaLaunchTimeout,
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
ctx.setupProxies(sessionId);
|
|
291
|
+
let status: StringRecord | null;
|
|
292
|
+
try {
|
|
293
|
+
status = await ctx.getStatus(ctx.wdaLaunchTimeout);
|
|
294
|
+
} catch {
|
|
295
|
+
throw new Error(
|
|
296
|
+
`Failed to start the preinstalled WebDriverAgent in ${ctx.wdaLaunchTimeout} ms. ` +
|
|
297
|
+
`The WebDriverAgent might not be properly built or the device might be locked. ` +
|
|
298
|
+
`The 'appium:wdaLaunchTimeout' capability modifies the timeout.`,
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
ctx.setStarted(true);
|
|
302
|
+
return status;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
async function terminatePreinstalled(
|
|
306
|
+
ctx: WdaStartupStrategyContext,
|
|
307
|
+
hostOps: SimulatorHostOps | RealDevicePreinstalledHostOps,
|
|
308
|
+
): Promise<void> {
|
|
309
|
+
ctx.log.info('Stopping the XCTest session');
|
|
310
|
+
try {
|
|
311
|
+
await hostOps.terminate({
|
|
312
|
+
udid: ctx.device.udid,
|
|
313
|
+
bundleId: ctx.bundleIdForXctest,
|
|
314
|
+
});
|
|
315
|
+
} catch (e: any) {
|
|
316
|
+
ctx.log.warn(e.message);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
async function quitXcodebuild(ctx: WdaStartupStrategyContext): Promise<void> {
|
|
321
|
+
ctx.log.info('Shutting down sub-processes');
|
|
322
|
+
await ctx.xcodebuild().quit();
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function createPreinstalledWdaEnvironment(ctx: WdaStartupStrategyContext): WdaLaunchEnvironment {
|
|
326
|
+
const xctestEnv: WdaLaunchEnvironment = {
|
|
327
|
+
USE_PORT: ctx.wdaLocalPort || WDA_AGENT_PORT,
|
|
328
|
+
WDA_PRODUCT_BUNDLE_IDENTIFIER: ctx.bundleIdForXctest,
|
|
329
|
+
};
|
|
330
|
+
if (ctx.mjpegServerPort) {
|
|
331
|
+
xctestEnv.MJPEG_SERVER_PORT = ctx.mjpegServerPort;
|
|
332
|
+
}
|
|
333
|
+
if (ctx.wdaBindingIP) {
|
|
334
|
+
xctestEnv.USE_IP = ctx.wdaBindingIP;
|
|
335
|
+
}
|
|
336
|
+
if (ctx.maxHttpRequestBodySize) {
|
|
337
|
+
xctestEnv.MAX_HTTP_REQUEST_BODY_SIZE = ctx.maxHttpRequestBodySize;
|
|
338
|
+
}
|
|
339
|
+
return xctestEnv;
|
|
340
|
+
}
|