appium 3.5.0 → 3.5.1
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/build/lib/appium.d.ts.map +1 -1
- package/build/lib/appium.js +43 -45
- package/build/lib/appium.js.map +1 -1
- package/build/lib/bidi-commands.d.ts.map +1 -1
- package/build/lib/bidi-commands.js +34 -29
- package/build/lib/bidi-commands.js.map +1 -1
- package/build/lib/bootstrap/appium-initializer.d.ts.map +1 -1
- package/build/lib/bootstrap/appium-initializer.js +13 -13
- package/build/lib/bootstrap/appium-initializer.js.map +1 -1
- package/build/lib/bootstrap/appium-main-runner.d.ts.map +1 -1
- package/build/lib/bootstrap/appium-main-runner.js +2 -2
- package/build/lib/bootstrap/appium-main-runner.js.map +1 -1
- package/build/lib/bootstrap/config-file.d.ts.map +1 -1
- package/build/lib/bootstrap/config-file.js +11 -11
- package/build/lib/bootstrap/config-file.js.map +1 -1
- package/build/lib/bootstrap/grid-v3-register.d.ts.map +1 -1
- package/build/lib/bootstrap/grid-v3-register.js +9 -6
- package/build/lib/bootstrap/grid-v3-register.js.map +1 -1
- package/build/lib/bootstrap/main-helpers.d.ts +1 -1
- package/build/lib/bootstrap/main-helpers.d.ts.map +1 -1
- package/build/lib/bootstrap/main-helpers.js +19 -20
- package/build/lib/bootstrap/main-helpers.js.map +1 -1
- package/build/lib/bootstrap/node-helpers.d.ts +1 -1
- package/build/lib/bootstrap/node-helpers.d.ts.map +1 -1
- package/build/lib/bootstrap/node-helpers.js +7 -14
- package/build/lib/bootstrap/node-helpers.js.map +1 -1
- package/build/lib/bootstrap/startup-config.d.ts.map +1 -1
- package/build/lib/bootstrap/startup-config.js +32 -30
- package/build/lib/bootstrap/startup-config.js.map +1 -1
- package/build/lib/cli/args.d.ts +3 -2
- package/build/lib/cli/args.d.ts.map +1 -1
- package/build/lib/cli/args.js +2 -5
- package/build/lib/cli/args.js.map +1 -1
- package/build/lib/cli/driver-command.d.ts +1 -2
- package/build/lib/cli/driver-command.d.ts.map +1 -1
- package/build/lib/cli/driver-command.js +7 -8
- package/build/lib/cli/driver-command.js.map +1 -1
- package/build/lib/cli/extension-command.d.ts +2 -2
- package/build/lib/cli/extension-command.d.ts.map +1 -1
- package/build/lib/cli/extension-command.js +100 -66
- package/build/lib/cli/extension-command.js.map +1 -1
- package/build/lib/cli/extension.d.ts.map +1 -1
- package/build/lib/cli/extension.js.map +1 -1
- package/build/lib/cli/parser.d.ts.map +1 -1
- package/build/lib/cli/parser.js +21 -14
- package/build/lib/cli/parser.js.map +1 -1
- package/build/lib/cli/plugin-command.d.ts +1 -1
- package/build/lib/cli/plugin-command.d.ts.map +1 -1
- package/build/lib/cli/plugin-command.js +5 -5
- package/build/lib/cli/plugin-command.js.map +1 -1
- package/build/lib/cli/setup-command.d.ts +1 -1
- package/build/lib/cli/setup-command.d.ts.map +1 -1
- package/build/lib/cli/setup-command.js +14 -19
- package/build/lib/cli/setup-command.js.map +1 -1
- package/build/lib/cli/utils.d.ts.map +1 -1
- package/build/lib/cli/utils.js +3 -2
- package/build/lib/cli/utils.js.map +1 -1
- package/build/lib/doctor/doctor.d.ts +0 -1
- package/build/lib/doctor/doctor.d.ts.map +1 -1
- package/build/lib/doctor/doctor.js +12 -17
- package/build/lib/doctor/doctor.js.map +1 -1
- package/build/lib/extension/driver-config.d.ts.map +1 -1
- package/build/lib/extension/driver-config.js +11 -12
- package/build/lib/extension/driver-config.js.map +1 -1
- package/build/lib/extension/extension-config.d.ts.map +1 -1
- package/build/lib/extension/extension-config.js +28 -27
- package/build/lib/extension/extension-config.js.map +1 -1
- package/build/lib/extension/index.d.ts.map +1 -1
- package/build/lib/extension/index.js +13 -16
- package/build/lib/extension/index.js.map +1 -1
- package/build/lib/extension/manifest.d.ts +3 -2
- package/build/lib/extension/manifest.d.ts.map +1 -1
- package/build/lib/extension/manifest.js +19 -22
- package/build/lib/extension/manifest.js.map +1 -1
- package/build/lib/extension/plugin-config.d.ts.map +1 -1
- package/build/lib/extension/plugin-config.js +7 -9
- package/build/lib/extension/plugin-config.js.map +1 -1
- package/build/lib/helpers/build.d.ts +0 -1
- package/build/lib/helpers/build.d.ts.map +1 -1
- package/build/lib/helpers/build.js +2 -4
- package/build/lib/helpers/build.js.map +1 -1
- package/build/lib/helpers/capability.d.ts.map +1 -1
- package/build/lib/helpers/capability.js +27 -22
- package/build/lib/helpers/capability.js.map +1 -1
- package/build/lib/helpers/network.d.ts.map +1 -1
- package/build/lib/helpers/network.js +4 -3
- package/build/lib/helpers/network.js.map +1 -1
- package/build/lib/insecure-features.d.ts.map +1 -1
- package/build/lib/insecure-features.js +9 -13
- package/build/lib/insecure-features.js.map +1 -1
- package/build/lib/inspector-commands.d.ts.map +1 -1
- package/build/lib/inspector-commands.js +29 -28
- package/build/lib/inspector-commands.js.map +1 -1
- package/build/lib/logsink.d.ts.map +1 -1
- package/build/lib/logsink.js +8 -7
- package/build/lib/logsink.js.map +1 -1
- package/build/lib/schema/arg-spec.d.ts.map +1 -1
- package/build/lib/schema/arg-spec.js +5 -8
- package/build/lib/schema/arg-spec.js.map +1 -1
- package/build/lib/schema/cli-args.d.ts.map +1 -1
- package/build/lib/schema/cli-args.js +20 -19
- package/build/lib/schema/cli-args.js.map +1 -1
- package/build/lib/schema/cli-transformers.d.ts.map +1 -1
- package/build/lib/schema/cli-transformers.js.map +1 -1
- package/build/lib/schema/schema.d.ts.map +1 -1
- package/build/lib/schema/schema.js +28 -21
- package/build/lib/schema/schema.js.map +1 -1
- package/build/lib/utils/hash.d.ts +5 -0
- package/build/lib/utils/hash.d.ts.map +1 -0
- package/build/lib/{utils.js → utils/hash.js} +3 -21
- package/build/lib/utils/hash.js.map +1 -0
- package/build/lib/utils/index.d.ts +8 -0
- package/build/lib/utils/index.d.ts.map +1 -0
- package/build/lib/utils/index.js +31 -0
- package/build/lib/utils/index.js.map +1 -0
- package/build/lib/utils/is-package-changed.d.ts +16 -0
- package/build/lib/utils/is-package-changed.d.ts.map +1 -0
- package/build/lib/utils/is-package-changed.js +62 -0
- package/build/lib/utils/is-package-changed.js.map +1 -0
- package/build/lib/utils/object.d.ts +120 -0
- package/build/lib/utils/object.d.ts.map +1 -0
- package/build/lib/utils/object.js +288 -0
- package/build/lib/utils/object.js.map +1 -0
- package/build/lib/{extension → utils}/package-changed.d.ts +0 -1
- package/build/lib/utils/package-changed.d.ts.map +1 -0
- package/build/lib/{extension → utils}/package-changed.js +3 -4
- package/build/lib/utils/package-changed.js.map +1 -0
- package/build/lib/utils/package-json.d.ts +9 -0
- package/build/lib/utils/package-json.d.ts.map +1 -0
- package/build/lib/utils/package-json.js +32 -0
- package/build/lib/utils/package-json.js.map +1 -0
- package/build/lib/utils/resolve-from.d.ts +11 -0
- package/build/lib/utils/resolve-from.d.ts.map +1 -0
- package/build/lib/utils/resolve-from.js +41 -0
- package/build/lib/utils/resolve-from.js.map +1 -0
- package/build/types/cli.d.ts.map +1 -1
- package/build/types/index.d.ts.map +1 -1
- package/build/types/manifest/base.d.ts.map +1 -1
- package/build/types/manifest/v3.d.ts.map +1 -1
- package/build/types/manifest/v4.d.ts.map +1 -1
- package/lib/appium.ts +59 -55
- package/lib/bidi-commands.ts +106 -60
- package/lib/bootstrap/appium-initializer.ts +27 -19
- package/lib/bootstrap/appium-main-runner.ts +8 -4
- package/lib/bootstrap/config-file.ts +33 -16
- package/lib/bootstrap/grid-v3-register.ts +26 -19
- package/lib/bootstrap/main-helpers.ts +25 -19
- package/lib/bootstrap/node-helpers.ts +19 -22
- package/lib/bootstrap/startup-config.ts +42 -39
- package/lib/cli/args.ts +3 -4
- package/lib/cli/driver-command.ts +19 -13
- package/lib/cli/extension-command.ts +208 -143
- package/lib/cli/extension.ts +4 -6
- package/lib/cli/parser.ts +32 -30
- package/lib/cli/plugin-command.ts +20 -9
- package/lib/cli/setup-command.ts +54 -39
- package/lib/cli/utils.ts +4 -3
- package/lib/doctor/doctor.ts +15 -17
- package/lib/extension/driver-config.ts +22 -17
- package/lib/extension/extension-config.ts +74 -66
- package/lib/extension/index.ts +42 -25
- package/lib/extension/manifest.ts +34 -31
- package/lib/extension/plugin-config.ts +15 -10
- package/lib/helpers/build.ts +6 -5
- package/lib/helpers/capability.ts +40 -35
- package/lib/helpers/network.ts +6 -5
- package/lib/insecure-features.ts +16 -14
- package/lib/inspector-commands.ts +72 -40
- package/lib/logsink.ts +22 -26
- package/lib/schema/arg-spec.ts +9 -8
- package/lib/schema/cli-args-guards.ts +4 -4
- package/lib/schema/cli-args.ts +25 -21
- package/lib/schema/cli-transformers.ts +6 -2
- package/lib/schema/format-errors.ts +1 -1
- package/lib/schema/schema.ts +52 -38
- package/lib/{utils.ts → utils/hash.ts} +2 -19
- package/lib/utils/index.ts +23 -0
- package/lib/utils/is-package-changed.ts +78 -0
- package/lib/utils/object.ts +312 -0
- package/lib/{extension → utils}/package-changed.ts +6 -7
- package/lib/utils/package-json.ts +36 -0
- package/lib/utils/resolve-from.ts +40 -0
- package/package.json +13 -16
- package/scripts/autoinstall-extensions.js +8 -8
- package/tsconfig.json +8 -2
- package/types/cli.ts +18 -18
- package/types/index.ts +2 -2
- package/types/manifest/base.ts +2 -2
- package/types/manifest/v3.ts +2 -2
- package/types/manifest/v4.ts +2 -2
- package/build/lib/extension/package-changed.d.ts.map +0 -1
- package/build/lib/extension/package-changed.js.map +0 -1
- package/build/lib/utils.d.ts +0 -13
- package/build/lib/utils.d.ts.map +0 -1
- package/build/lib/utils.js.map +0 -1
package/lib/bidi-commands.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {util} from '@appium/support';
|
|
2
2
|
import {promisify} from 'node:util';
|
|
3
|
+
import {capitalize} from './utils';
|
|
3
4
|
import type {ExtensionCore} from '@appium/base-driver';
|
|
4
5
|
import {errors} from '@appium/base-driver';
|
|
5
6
|
import {BIDI_BASE_PATH, BIDI_EVENT_NAME} from './constants';
|
|
@@ -14,7 +15,7 @@ import type {
|
|
|
14
15
|
ExternalDriver,
|
|
15
16
|
StringRecord,
|
|
16
17
|
Plugin,
|
|
17
|
-
BiDiResultData
|
|
18
|
+
BiDiResultData,
|
|
18
19
|
} from '@appium/types';
|
|
19
20
|
|
|
20
21
|
type ExtensionPlugin = Plugin & ExtensionCore;
|
|
@@ -30,7 +31,6 @@ interface InitBiDiSocketResult {
|
|
|
30
31
|
logSocketErr: LogSocketError;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
|
-
|
|
34
34
|
const MIN_WS_CODE_VAL = 1000;
|
|
35
35
|
const MAX_WS_CODE_VAL = 1015;
|
|
36
36
|
const WS_FALLBACK_CODE = 1011; // server encountered an error while fulfilling request
|
|
@@ -50,8 +50,9 @@ export function determineBiDiHost(address: string): string {
|
|
|
50
50
|
return address;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
const nonLocalInterfaces = fetchInterfaces(address === V4_BROADCAST_IP ? 4 : 6)
|
|
54
|
-
|
|
53
|
+
const nonLocalInterfaces = fetchInterfaces(address === V4_BROADCAST_IP ? 4 : 6).filter(
|
|
54
|
+
(iface) => !iface.internal,
|
|
55
|
+
);
|
|
55
56
|
return nonLocalInterfaces.length === 1 ? nonLocalInterfaces[0].address : os.hostname();
|
|
56
57
|
}
|
|
57
58
|
|
|
@@ -63,13 +64,11 @@ export function determineBiDiHost(address: string): string {
|
|
|
63
64
|
export function onBidiConnection(this: AppiumDriver, ws: WebSocket, req: IncomingMessage): void {
|
|
64
65
|
try {
|
|
65
66
|
const initBiDiSocketFunc: OmitThisParameter<typeof initBidiSocket> = initBidiSocket.bind(this);
|
|
66
|
-
const {bidiHandlerDriver, bidiHandlerPlugins, proxyClient, send, sendToProxy, logSocketErr} =
|
|
67
|
-
ws,
|
|
68
|
-
req,
|
|
69
|
-
);
|
|
67
|
+
const {bidiHandlerDriver, bidiHandlerPlugins, proxyClient, send, sendToProxy, logSocketErr} =
|
|
68
|
+
initBiDiSocketFunc(ws, req);
|
|
70
69
|
|
|
71
|
-
const initBidiSocketHandlersFunc: OmitThisParameter<typeof initBidiSocketHandlers> =
|
|
72
|
-
.bind(this);
|
|
70
|
+
const initBidiSocketHandlersFunc: OmitThisParameter<typeof initBidiSocketHandlers> =
|
|
71
|
+
initBidiSocketHandlers.bind(this);
|
|
73
72
|
initBidiSocketHandlersFunc(
|
|
74
73
|
ws,
|
|
75
74
|
proxyClient,
|
|
@@ -80,12 +79,12 @@ export function onBidiConnection(this: AppiumDriver, ws: WebSocket, req: Incomin
|
|
|
80
79
|
logSocketErr,
|
|
81
80
|
);
|
|
82
81
|
if (proxyClient) {
|
|
83
|
-
const initBidiProxyHandlersFunc: OmitThisParameter<typeof initBidiProxyHandlers> =
|
|
84
|
-
.bind(bidiHandlerDriver);
|
|
82
|
+
const initBidiProxyHandlersFunc: OmitThisParameter<typeof initBidiProxyHandlers> =
|
|
83
|
+
initBidiProxyHandlers.bind(bidiHandlerDriver);
|
|
85
84
|
initBidiProxyHandlersFunc(proxyClient, ws, send);
|
|
86
85
|
}
|
|
87
|
-
const initBidiEventListenersFunc: OmitThisParameter<typeof initBidiEventListeners> =
|
|
88
|
-
.bind(this);
|
|
86
|
+
const initBidiEventListenersFunc: OmitThisParameter<typeof initBidiEventListeners> =
|
|
87
|
+
initBidiEventListeners.bind(this);
|
|
89
88
|
initBidiEventListenersFunc(ws, bidiHandlerDriver, bidiHandlerPlugins, send);
|
|
90
89
|
} catch (err) {
|
|
91
90
|
this.log.error(err);
|
|
@@ -104,20 +103,21 @@ export async function onBidiMessage(
|
|
|
104
103
|
this: AppiumDriver,
|
|
105
104
|
data: Buffer,
|
|
106
105
|
driver: AnyDriver,
|
|
107
|
-
plugins: ExtensionPlugin[]
|
|
106
|
+
plugins: ExtensionPlugin[],
|
|
108
107
|
): Promise<SuccessBiDiCommandResponse | ErrorBiDiCommandResponse> {
|
|
109
108
|
let resMessage: SuccessBiDiCommandResponse | ErrorBiDiCommandResponse;
|
|
110
109
|
let id: number = 0;
|
|
111
110
|
const driverLog = driver.log;
|
|
112
|
-
const dataTruncated =
|
|
111
|
+
const dataTruncated = util.truncateString(data.toString(), {length: MAX_LOGGED_DATA_LENGTH});
|
|
113
112
|
try {
|
|
114
113
|
let method: string;
|
|
115
114
|
let params: StringRecord;
|
|
116
115
|
try {
|
|
117
116
|
({id, method, params} = JSON.parse(data.toString('utf8')));
|
|
118
117
|
} catch (err) {
|
|
118
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
119
119
|
throw new errors.InvalidArgumentError(
|
|
120
|
-
`Could not parse Bidi command '${dataTruncated}': ${
|
|
120
|
+
`Could not parse Bidi command '${dataTruncated}': ${message}`,
|
|
121
121
|
);
|
|
122
122
|
}
|
|
123
123
|
driverLog.info(`--> BIDI message #${id}`);
|
|
@@ -131,7 +131,12 @@ export async function onBidiMessage(
|
|
|
131
131
|
`Missing params for BiDi operation in '${dataTruncated}`,
|
|
132
132
|
);
|
|
133
133
|
}
|
|
134
|
-
const executeWrappedCommand = wrapCommandWithPlugins(
|
|
134
|
+
const executeWrappedCommand = wrapCommandWithPlugins(
|
|
135
|
+
driver as ExtensionCore,
|
|
136
|
+
plugins,
|
|
137
|
+
method,
|
|
138
|
+
params,
|
|
139
|
+
);
|
|
135
140
|
const result = await executeWrappedCommand();
|
|
136
141
|
resMessage = {
|
|
137
142
|
id,
|
|
@@ -139,15 +144,24 @@ export async function onBidiMessage(
|
|
|
139
144
|
result,
|
|
140
145
|
};
|
|
141
146
|
} catch (err) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
147
|
+
if (
|
|
148
|
+
err !== null &&
|
|
149
|
+
typeof err === 'object' &&
|
|
150
|
+
'bidiErrObject' in err &&
|
|
151
|
+
typeof (err as {bidiErrObject: unknown}).bidiErrObject === 'function'
|
|
152
|
+
) {
|
|
153
|
+
resMessage = (
|
|
154
|
+
err as {bidiErrObject: (msgId: number) => ErrorBiDiCommandResponse}
|
|
155
|
+
).bidiErrObject(id);
|
|
156
|
+
} else {
|
|
157
|
+
resMessage = {
|
|
145
158
|
id,
|
|
146
159
|
type: 'error',
|
|
147
160
|
error: errors.UnknownError.error(),
|
|
148
|
-
message:
|
|
149
|
-
stacktrace:
|
|
161
|
+
message: err instanceof Error ? err.message : String(err),
|
|
162
|
+
stacktrace: err instanceof Error ? err.stack : undefined,
|
|
150
163
|
};
|
|
164
|
+
}
|
|
151
165
|
}
|
|
152
166
|
driverLog.info(`<-- BIDI message #${id}`);
|
|
153
167
|
return resMessage;
|
|
@@ -191,11 +205,19 @@ export function cleanupBidiSockets(this: AppiumDriver, sessionId: string): void
|
|
|
191
205
|
delete this.bidiProxyClients[sessionId];
|
|
192
206
|
}
|
|
193
207
|
|
|
194
|
-
function wrapCommandWithPlugins(
|
|
208
|
+
function wrapCommandWithPlugins(
|
|
209
|
+
driver: ExtensionCore,
|
|
210
|
+
plugins: ExtensionCore[],
|
|
211
|
+
method: string,
|
|
212
|
+
params: StringRecord,
|
|
213
|
+
): () => Promise<BiDiResultData> {
|
|
195
214
|
const [moduleName, methodName] = method.split('.');
|
|
196
215
|
let next = async () => await driver.executeBidiCommand(method, params);
|
|
197
216
|
for (const plugin of plugins.filter((p) => p.doesBidiCommandExist(moduleName, methodName))) {
|
|
198
|
-
next = (
|
|
217
|
+
next = (
|
|
218
|
+
(_next) => async () =>
|
|
219
|
+
await plugin.executeBidiCommand(method, params, _next, driver)
|
|
220
|
+
)(next);
|
|
199
221
|
}
|
|
200
222
|
return next;
|
|
201
223
|
}
|
|
@@ -207,7 +229,11 @@ function wrapCommandWithPlugins(driver: ExtensionCore, plugins: ExtensionCore[],
|
|
|
207
229
|
* @param ws The websocket connection object
|
|
208
230
|
* @param req The connection pathname, which might include the session id
|
|
209
231
|
*/
|
|
210
|
-
function initBidiSocket(
|
|
232
|
+
function initBidiSocket(
|
|
233
|
+
this: AppiumDriver,
|
|
234
|
+
ws: WebSocket,
|
|
235
|
+
req: IncomingMessage,
|
|
236
|
+
): InitBiDiSocketResult {
|
|
211
237
|
const pathname = req.url;
|
|
212
238
|
if (!pathname) {
|
|
213
239
|
throw new Error('Invalid connection request: pathname missing from request');
|
|
@@ -260,22 +286,24 @@ function initBidiSocket(this: AppiumDriver, ws: WebSocket, req: IncomingMessage)
|
|
|
260
286
|
throw new Error(
|
|
261
287
|
`Got request for ${driverName} to proxy bidi connections to upstream socket with ` +
|
|
262
288
|
`url ${bidiProxyUrl}, but this was not a valid url`,
|
|
263
|
-
{cause: e}
|
|
289
|
+
{cause: e},
|
|
264
290
|
);
|
|
265
291
|
}
|
|
266
|
-
this.log.info(
|
|
267
|
-
|
|
292
|
+
this.log.info(
|
|
293
|
+
`Bidi connection for ${driverName} will be proxied to ${bidiProxyUrl}. ` +
|
|
294
|
+
`Plugins will not handle bidi commands`,
|
|
295
|
+
);
|
|
268
296
|
proxyClient = new WebSocket(bidiProxyUrl);
|
|
269
297
|
this.bidiProxyClients[sessionId] = proxyClient;
|
|
270
298
|
} else {
|
|
271
|
-
bidiHandlerPlugins.push(...this.pluginsForSession(sessionId) as ExtensionPlugin[]);
|
|
299
|
+
bidiHandlerPlugins.push(...(this.pluginsForSession(sessionId) as ExtensionPlugin[]));
|
|
272
300
|
}
|
|
273
301
|
} else {
|
|
274
302
|
this.log.info('Bidi websocket connection made to main server');
|
|
275
303
|
// no need to store the socket connection if it's to the main server since it will just
|
|
276
304
|
// stay open as long as the server itself is and will close when the server closes.
|
|
277
305
|
bidiHandlerDriver = this; // eslint-disable-line @typescript-eslint/no-this-alias
|
|
278
|
-
bidiHandlerPlugins.push(...this.pluginsForSession() as ExtensionPlugin[]);
|
|
306
|
+
bidiHandlerPlugins.push(...(this.pluginsForSession() as ExtensionPlugin[]));
|
|
279
307
|
}
|
|
280
308
|
|
|
281
309
|
const driverLog = bidiHandlerDriver.log;
|
|
@@ -287,13 +315,15 @@ function initBidiSocket(this: AppiumDriver, ws: WebSocket, req: IncomingMessage)
|
|
|
287
315
|
// 1. Make it async-await friendly
|
|
288
316
|
// 2. Do some logging if there's a send error
|
|
289
317
|
const sendFactory = (socket: WebSocket) => {
|
|
290
|
-
const socketSend = promisify(socket.send.bind(socket)) as (
|
|
318
|
+
const socketSend = promisify(socket.send.bind(socket)) as (
|
|
319
|
+
data: string | Buffer,
|
|
320
|
+
) => Promise<void>;
|
|
291
321
|
return async (data: string | Buffer) => {
|
|
292
322
|
try {
|
|
293
323
|
await assertIsOpen(socket);
|
|
294
324
|
await socketSend(data);
|
|
295
325
|
} catch (err) {
|
|
296
|
-
logSocketErr(err);
|
|
326
|
+
logSocketErr(err instanceof Error ? err : new Error(String(err)));
|
|
297
327
|
}
|
|
298
328
|
};
|
|
299
329
|
};
|
|
@@ -338,8 +368,8 @@ function initBidiProxyHandlers(
|
|
|
338
368
|
`Upstream bidi socket closed connection (code ${code}, reason: '${reason}'). ` +
|
|
339
369
|
`Closing proxy connection to client`,
|
|
340
370
|
);
|
|
341
|
-
const intCode: number =
|
|
342
|
-
if (
|
|
371
|
+
const intCode: number = typeof code === 'number' ? (code as number) : parseInt(code, 10);
|
|
372
|
+
if (Number.isNaN(intCode) || intCode < MIN_WS_CODE_VAL || intCode > MAX_WS_CODE_VAL) {
|
|
343
373
|
driverLog.warn(
|
|
344
374
|
`Received code ${code} from upstream socket, but this is not a valid ` +
|
|
345
375
|
`websocket code. Rewriting to ${WS_FALLBACK_CODE} for ws compatibility`,
|
|
@@ -417,7 +447,7 @@ function initBidiSocketHandlers(
|
|
|
417
447
|
}
|
|
418
448
|
|
|
419
449
|
const eventLogCounts = BIDI_EVENTS_MAP.get(bidiHandlerDriver);
|
|
420
|
-
if (!
|
|
450
|
+
if (!util.isEmpty(eventLogCounts)) {
|
|
421
451
|
driverLog.debug(`BiDi events statistics: ${JSON.stringify(eventLogCounts, null, 2)}`);
|
|
422
452
|
}
|
|
423
453
|
});
|
|
@@ -444,19 +474,31 @@ function initBidiEventListeners(
|
|
|
444
474
|
const eventLogCounts: Record<string, number> = BIDI_EVENTS_MAP.get(bidiHandlerDriver) ?? {};
|
|
445
475
|
BIDI_EVENTS_MAP.set(bidiHandlerDriver, eventLogCounts);
|
|
446
476
|
const eventListenerFactory = (extType: 'driver' | 'plugin', ext: ExtensionCore) => {
|
|
447
|
-
const eventListener = async ({
|
|
477
|
+
const eventListener = async ({
|
|
478
|
+
context,
|
|
479
|
+
method,
|
|
480
|
+
params = {},
|
|
481
|
+
}: {
|
|
482
|
+
context?: string;
|
|
483
|
+
method: string;
|
|
484
|
+
params?: StringRecord;
|
|
485
|
+
}) => {
|
|
448
486
|
// if the driver didn't specify a context, use the empty context
|
|
449
487
|
if (!context) {
|
|
450
488
|
context = '';
|
|
451
489
|
}
|
|
452
490
|
if (!method || !params) {
|
|
453
|
-
ext.log?.warn(
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
491
|
+
ext.log?.warn(
|
|
492
|
+
// some old plugins might not have the `log` property
|
|
493
|
+
`${capitalize(extType)} emitted a bidi event that was malformed. Require method and params keys ` +
|
|
494
|
+
`(with optional context). But instead received: ${util.truncateString(
|
|
495
|
+
JSON.stringify({
|
|
496
|
+
context,
|
|
497
|
+
method,
|
|
498
|
+
params,
|
|
499
|
+
}),
|
|
500
|
+
{length: MAX_LOGGED_DATA_LENGTH},
|
|
501
|
+
)}`,
|
|
460
502
|
);
|
|
461
503
|
return;
|
|
462
504
|
}
|
|
@@ -472,14 +514,15 @@ function initBidiEventListeners(
|
|
|
472
514
|
}
|
|
473
515
|
|
|
474
516
|
const eventSubs = bidiHandlerDriver.bidiEventSubs[method];
|
|
475
|
-
if (
|
|
517
|
+
if (Array.isArray(eventSubs) && eventSubs.includes(context)) {
|
|
476
518
|
if (method in eventLogCounts) {
|
|
477
519
|
++eventLogCounts[method];
|
|
478
520
|
} else {
|
|
479
|
-
ext.log?.debug(
|
|
521
|
+
ext.log?.debug(
|
|
522
|
+
// some old plugins might not have the `log` property
|
|
480
523
|
`<-- BIDI EVENT ${method} (context: '${context}', ` +
|
|
481
|
-
|
|
482
|
-
|
|
524
|
+
`params: ${util.truncateString(JSON.stringify(params), {length: MAX_LOGGED_DATA_LENGTH})}). ` +
|
|
525
|
+
`All further similar events won't be logged.`,
|
|
483
526
|
);
|
|
484
527
|
eventLogCounts[method] = 1;
|
|
485
528
|
}
|
|
@@ -490,17 +533,17 @@ function initBidiEventListeners(
|
|
|
490
533
|
};
|
|
491
534
|
return eventListener;
|
|
492
535
|
};
|
|
493
|
-
bidiHandlerDriver.eventEmitter.on(
|
|
536
|
+
bidiHandlerDriver.eventEmitter.on(
|
|
537
|
+
BIDI_EVENT_NAME,
|
|
538
|
+
eventListenerFactory('driver', bidiHandlerDriver as ExtensionCore),
|
|
539
|
+
);
|
|
494
540
|
for (const plugin of bidiHandlerPlugins) {
|
|
495
541
|
// some old plugins might not have the eventEmitter property
|
|
496
542
|
plugin.eventEmitter?.on(BIDI_EVENT_NAME, eventListenerFactory('plugin', plugin));
|
|
497
543
|
}
|
|
498
544
|
}
|
|
499
545
|
|
|
500
|
-
async function assertIsOpen(
|
|
501
|
-
ws: WebSocket,
|
|
502
|
-
timeoutMs: number = 5000,
|
|
503
|
-
): Promise<WebSocket> {
|
|
546
|
+
async function assertIsOpen(ws: WebSocket, timeoutMs: number = 5000): Promise<WebSocket> {
|
|
504
547
|
if (ws.readyState === ws.OPEN) {
|
|
505
548
|
return ws;
|
|
506
549
|
}
|
|
@@ -513,12 +556,15 @@ async function assertIsOpen(
|
|
|
513
556
|
// The socket is in CONNECTING state. Wait up to `timeoutMs` until it is open
|
|
514
557
|
try {
|
|
515
558
|
await new Promise((resolve, reject) => {
|
|
516
|
-
setTimeout(
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
559
|
+
setTimeout(
|
|
560
|
+
() =>
|
|
561
|
+
reject(
|
|
562
|
+
new Error(
|
|
563
|
+
`The BiDi web socket at ${ws.url} did not ` + `open after ${timeoutMs}ms timeout`,
|
|
564
|
+
),
|
|
565
|
+
),
|
|
566
|
+
timeoutMs,
|
|
567
|
+
);
|
|
522
568
|
ws.once('error', reject);
|
|
523
569
|
errorListener = reject;
|
|
524
570
|
ws.once('open', resolve);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {init as logsinkInit} from '../logsink';
|
|
2
2
|
import {log as logger} from '../logger';
|
|
3
3
|
import {util, env} from '@appium/support';
|
|
4
|
-
import _ from 'lodash';
|
|
5
4
|
import type {DriverOpts} from '@appium/types';
|
|
5
|
+
import {defaultsDeep} from '../utils';
|
|
6
6
|
import {AppiumDriver, type AppiumDriverConstraints} from '../appium';
|
|
7
7
|
import {runExtensionCommand} from '../cli/extension';
|
|
8
8
|
import {runSetupCommand} from '../cli/setup-command';
|
|
@@ -88,7 +88,9 @@ export class AppiumInitializer {
|
|
|
88
88
|
private async parsePreConfigArgs<
|
|
89
89
|
Cmd extends CliCommand,
|
|
90
90
|
SubCmd extends CliExtensionSubcommand | CliCommandSetupSubcommand | void,
|
|
91
|
-
>(
|
|
91
|
+
>(
|
|
92
|
+
args?: Args<Cmd, SubCmd>,
|
|
93
|
+
): Promise<{preConfigArgs: PreConfigArgs; throwInsteadOfExit: boolean}> {
|
|
92
94
|
const parser = await getParser();
|
|
93
95
|
let throwInsteadOfExit = false;
|
|
94
96
|
|
|
@@ -97,7 +99,10 @@ export class AppiumInitializer {
|
|
|
97
99
|
throwInsteadOfExit = true;
|
|
98
100
|
delete args.throwInsteadOfExit;
|
|
99
101
|
}
|
|
100
|
-
const preConfigArgs = {
|
|
102
|
+
const preConfigArgs = {
|
|
103
|
+
...args,
|
|
104
|
+
subcommand: args.subcommand ?? SERVER_SUBCOMMAND,
|
|
105
|
+
} as PreConfigArgs;
|
|
101
106
|
ArgParser.normalizeServerArgs(preConfigArgs);
|
|
102
107
|
return {preConfigArgs, throwInsteadOfExit};
|
|
103
108
|
}
|
|
@@ -106,7 +111,7 @@ export class AppiumInitializer {
|
|
|
106
111
|
}
|
|
107
112
|
|
|
108
113
|
private assertConfigFileOk(configResult: Awaited<ReturnType<typeof readConfigFile>>): void {
|
|
109
|
-
if (!
|
|
114
|
+
if (!util.isEmpty(configResult.errors)) {
|
|
110
115
|
throw new Error(
|
|
111
116
|
`Errors in config file ${configResult.filepath}:\n ${configResult.reason ?? configResult.errors}`,
|
|
112
117
|
);
|
|
@@ -122,15 +127,20 @@ export class AppiumInitializer {
|
|
|
122
127
|
appiumHomeSourceName: string,
|
|
123
128
|
): Promise<InitResult<Cmd>> {
|
|
124
129
|
const defaults = getDefaultsForSchema(false);
|
|
125
|
-
const serverArgs =
|
|
130
|
+
const serverArgs = defaultsDeep(
|
|
126
131
|
{},
|
|
127
|
-
preConfigArgs,
|
|
128
|
-
configResult.config?.server,
|
|
129
|
-
defaults,
|
|
130
|
-
) as ParsedArgs<CliCommandServer>;
|
|
132
|
+
preConfigArgs as Record<string, unknown>,
|
|
133
|
+
configResult.config?.server as Record<string, unknown> | undefined,
|
|
134
|
+
defaults as Record<string, unknown>,
|
|
135
|
+
) as unknown as ParsedArgs<CliCommandServer>;
|
|
131
136
|
|
|
132
137
|
if (preConfigArgs.showConfig) {
|
|
133
|
-
showConfig(
|
|
138
|
+
showConfig(
|
|
139
|
+
getNonDefaultServerArgs(preConfigArgs as Args),
|
|
140
|
+
configResult,
|
|
141
|
+
defaults,
|
|
142
|
+
serverArgs,
|
|
143
|
+
);
|
|
134
144
|
return {} as InitResult<Cmd>;
|
|
135
145
|
}
|
|
136
146
|
|
|
@@ -167,19 +177,17 @@ export class AppiumInitializer {
|
|
|
167
177
|
if (!serverArgs.logFilters) {
|
|
168
178
|
return;
|
|
169
179
|
}
|
|
170
|
-
const {issues, rules} = await logger
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
});
|
|
174
|
-
if (!
|
|
180
|
+
const {issues, rules} = await logger
|
|
181
|
+
.unwrap()
|
|
182
|
+
.loadSecureValuesPreprocessingRules(serverArgs.logFilters);
|
|
183
|
+
const argToLog = util.truncateString(JSON.stringify(serverArgs.logFilters), {length: 150});
|
|
184
|
+
if (!util.isEmpty(issues)) {
|
|
175
185
|
throw new Error(
|
|
176
186
|
`The log filtering rules config ${argToLog} has issues: ` + JSON.stringify(issues, null, 2),
|
|
177
187
|
);
|
|
178
188
|
}
|
|
179
|
-
if (
|
|
180
|
-
logger.warn(
|
|
181
|
-
`Found no log filtering rules in the ${argToLog} config. ` + `Is that expected?`,
|
|
182
|
-
);
|
|
189
|
+
if (util.isEmpty(rules)) {
|
|
190
|
+
logger.warn(`Found no log filtering rules in the ${argToLog} config. ` + `Is that expected?`);
|
|
183
191
|
} else {
|
|
184
192
|
logger.info(`Loaded ${util.pluralize('filtering rule', rules.length, true)}`);
|
|
185
193
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {log as logger} from '../logger';
|
|
2
|
-
import
|
|
2
|
+
import {util} from '@appium/support';
|
|
3
3
|
import type {AppiumServer} from '@appium/types';
|
|
4
4
|
import {getActivePlugins, getActiveDrivers} from '../extension';
|
|
5
5
|
import registerNode from './grid-v3-register';
|
|
@@ -37,12 +37,16 @@ export class AppiumMainRunner {
|
|
|
37
37
|
async run<
|
|
38
38
|
Cmd extends CliCommand = CliCommandServer,
|
|
39
39
|
SubCmd extends CliExtensionSubcommand | CliCommandSetupSubcommand | void = void,
|
|
40
|
-
>(
|
|
41
|
-
|
|
40
|
+
>(
|
|
41
|
+
initResult: InitResult<Cmd>,
|
|
42
|
+
args?: Args<Cmd, SubCmd>,
|
|
43
|
+
): Promise<Cmd extends CliCommandServer ? AppiumServer : void> {
|
|
44
|
+
if (util.isEmpty(initResult)) {
|
|
42
45
|
return undefined as Cmd extends CliCommandServer ? AppiumServer : void;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
|
-
const {appiumDriver, pluginConfig, driverConfig, parsedArgs, appiumHome} =
|
|
48
|
+
const {appiumDriver, pluginConfig, driverConfig, parsedArgs, appiumHome} =
|
|
49
|
+
initResult as ServerInitData;
|
|
46
50
|
|
|
47
51
|
const pluginClasses = await getActivePlugins(
|
|
48
52
|
pluginConfig,
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type {IOutputError} from '@sidvind/better-ajv-errors';
|
|
2
2
|
import type {ErrorObject, SchemaObject} from 'ajv';
|
|
3
3
|
import {lilconfig, type LoaderSync, type LilconfigResult} from 'lilconfig';
|
|
4
|
-
import
|
|
4
|
+
import {util} from '@appium/support';
|
|
5
5
|
import * as yaml from 'yaml';
|
|
6
|
+
import {camelCase, getPath, mapKeys, mapValues} from '../utils';
|
|
6
7
|
import type {AppiumConfig, NormalizedAppiumConfig} from '@appium/types';
|
|
7
8
|
import {getSchema, validate} from '../schema/schema';
|
|
8
9
|
import {formatErrors} from '../schema/format-errors';
|
|
@@ -48,7 +49,7 @@ type LilconfigAsyncSearcher = ReturnType<typeof lilconfig>;
|
|
|
48
49
|
*/
|
|
49
50
|
export async function readConfigFile(
|
|
50
51
|
filepath?: string,
|
|
51
|
-
opts: ReadConfigFileOptions = {}
|
|
52
|
+
opts: ReadConfigFileOptions = {},
|
|
52
53
|
): Promise<ReadConfigFileResult> {
|
|
53
54
|
const lc = lilconfig('appium', {
|
|
54
55
|
loaders: {
|
|
@@ -67,7 +68,7 @@ export async function readConfigFile(
|
|
|
67
68
|
try {
|
|
68
69
|
let configResult: ReadConfigFileResult;
|
|
69
70
|
const errors = validate(result.config) as ErrorObject[];
|
|
70
|
-
if (
|
|
71
|
+
if (util.isEmpty(errors)) {
|
|
71
72
|
configResult = {...result, errors};
|
|
72
73
|
} else {
|
|
73
74
|
const reason = formatErrors(errors, result.config as Record<string, unknown>, {
|
|
@@ -98,19 +99,31 @@ export async function readConfigFile(
|
|
|
98
99
|
export function normalizeConfig(config: AppiumConfig): NormalizedAppiumConfig {
|
|
99
100
|
const schema = getSchema();
|
|
100
101
|
|
|
101
|
-
const isSchemaTypeObject = (
|
|
102
|
-
|
|
102
|
+
const isSchemaTypeObject = (
|
|
103
|
+
schemaObj: SchemaObject | Record<string, unknown> | undefined,
|
|
104
|
+
): boolean =>
|
|
105
|
+
Boolean(
|
|
106
|
+
(schemaObj as SchemaObject | undefined)?.properties ||
|
|
107
|
+
(schemaObj as SchemaObject | undefined)?.type === 'object',
|
|
108
|
+
);
|
|
103
109
|
|
|
104
110
|
const normalize = (rootConfig: AppiumConfig, section?: string): Record<string, unknown> => {
|
|
105
|
-
const obj =
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
+
const obj =
|
|
112
|
+
section === undefined
|
|
113
|
+
? rootConfig
|
|
114
|
+
: (getPath(rootConfig, section, rootConfig) as Record<string, unknown>);
|
|
115
|
+
|
|
116
|
+
const mappedObj = mapKeys(obj as Record<string, unknown>, (_v, prop) =>
|
|
117
|
+
String(
|
|
118
|
+
getPath(
|
|
119
|
+
schema,
|
|
120
|
+
`properties.server.properties.${prop}.appiumCliDest`,
|
|
121
|
+
camelCase(String(prop)),
|
|
122
|
+
),
|
|
123
|
+
),
|
|
111
124
|
);
|
|
112
125
|
|
|
113
|
-
return
|
|
126
|
+
return mapValues(mappedObj, (value, property) => {
|
|
114
127
|
const nextSection = section ? `${section}.${property}` : property;
|
|
115
128
|
return isSchemaTypeObject((schema as any).properties?.[property])
|
|
116
129
|
? normalize(rootConfig, nextSection)
|
|
@@ -130,7 +143,7 @@ function yamlLoader(filepath: string, content: string): unknown {
|
|
|
130
143
|
} catch (e) {
|
|
131
144
|
throw new Error(
|
|
132
145
|
`The YAML config at '${filepath}' cannot be loaded. Original error: ${(e as Error).message}`,
|
|
133
|
-
{cause: e}
|
|
146
|
+
{cause: e},
|
|
134
147
|
);
|
|
135
148
|
}
|
|
136
149
|
}
|
|
@@ -147,7 +160,7 @@ function jsonLoader(filepath: string, content: string): unknown {
|
|
|
147
160
|
rawConfig.delete(filepath);
|
|
148
161
|
throw new Error(
|
|
149
162
|
`The JSON config at '${filepath}' cannot be loaded. Original error: ${(e as Error).message}`,
|
|
150
|
-
{cause: e}
|
|
163
|
+
{cause: e},
|
|
151
164
|
);
|
|
152
165
|
}
|
|
153
166
|
}
|
|
@@ -155,13 +168,17 @@ function jsonLoader(filepath: string, content: string): unknown {
|
|
|
155
168
|
/**
|
|
156
169
|
* Loads a config file from an explicit path
|
|
157
170
|
*/
|
|
158
|
-
async function loadConfigFile(
|
|
171
|
+
async function loadConfigFile(
|
|
172
|
+
lc: LilconfigAsyncSearcher,
|
|
173
|
+
filepath: string,
|
|
174
|
+
): Promise<LilconfigResult> {
|
|
159
175
|
try {
|
|
160
176
|
// removing "await" will cause any rejection to _not_ be caught in this block!
|
|
161
177
|
return await lc.load(filepath);
|
|
162
178
|
} catch (err) {
|
|
163
179
|
if ((err as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
164
|
-
(err as NodeJS.ErrnoException).message =
|
|
180
|
+
(err as NodeJS.ErrnoException).message =
|
|
181
|
+
`Config file not found at user-provided path: ${filepath}`;
|
|
165
182
|
throw err;
|
|
166
183
|
} else if (err instanceof SyntaxError) {
|
|
167
184
|
// generally invalid JSON
|