@appium/base-driver 10.2.0 → 10.2.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.
Files changed (127) hide show
  1. package/LICENSE +201 -0
  2. package/build/lib/basedriver/capabilities.js +7 -7
  3. package/build/lib/basedriver/capabilities.js.map +1 -1
  4. package/build/lib/basedriver/commands/event.d.ts +1 -1
  5. package/build/lib/basedriver/commands/event.d.ts.map +1 -1
  6. package/build/lib/basedriver/commands/execute.d.ts +1 -1
  7. package/build/lib/basedriver/commands/execute.d.ts.map +1 -1
  8. package/build/lib/basedriver/commands/find.d.ts +1 -1
  9. package/build/lib/basedriver/commands/find.d.ts.map +1 -1
  10. package/build/lib/basedriver/commands/mixin.d.ts +1 -1
  11. package/build/lib/basedriver/commands/mixin.d.ts.map +1 -1
  12. package/build/lib/basedriver/commands/timeout.d.ts +1 -1
  13. package/build/lib/basedriver/commands/timeout.d.ts.map +1 -1
  14. package/build/lib/basedriver/device-settings.d.ts +14 -23
  15. package/build/lib/basedriver/device-settings.d.ts.map +1 -1
  16. package/build/lib/basedriver/device-settings.js +11 -26
  17. package/build/lib/basedriver/device-settings.js.map +1 -1
  18. package/build/lib/basedriver/helpers.d.ts +36 -57
  19. package/build/lib/basedriver/helpers.d.ts.map +1 -1
  20. package/build/lib/basedriver/helpers.js +148 -239
  21. package/build/lib/basedriver/helpers.js.map +1 -1
  22. package/build/lib/basedriver/logger.d.ts +1 -2
  23. package/build/lib/basedriver/logger.d.ts.map +1 -1
  24. package/build/lib/basedriver/logger.js +2 -2
  25. package/build/lib/basedriver/logger.js.map +1 -1
  26. package/build/lib/basedriver/validation.d.ts.map +1 -1
  27. package/build/lib/basedriver/validation.js +3 -3
  28. package/build/lib/basedriver/validation.js.map +1 -1
  29. package/build/lib/constants.d.ts +1 -1
  30. package/build/lib/constants.d.ts.map +1 -1
  31. package/build/lib/express/crash.d.ts +8 -2
  32. package/build/lib/express/crash.d.ts.map +1 -1
  33. package/build/lib/express/crash.js +6 -0
  34. package/build/lib/express/crash.js.map +1 -1
  35. package/build/lib/express/express-logging.d.ts +12 -2
  36. package/build/lib/express/express-logging.d.ts.map +1 -1
  37. package/build/lib/express/express-logging.js +34 -26
  38. package/build/lib/express/express-logging.js.map +1 -1
  39. package/build/lib/express/idempotency.d.ts +4 -10
  40. package/build/lib/express/idempotency.d.ts.map +1 -1
  41. package/build/lib/express/idempotency.js +69 -73
  42. package/build/lib/express/idempotency.js.map +1 -1
  43. package/build/lib/express/logger.d.ts +1 -2
  44. package/build/lib/express/logger.d.ts.map +1 -1
  45. package/build/lib/express/logger.js +2 -2
  46. package/build/lib/express/logger.js.map +1 -1
  47. package/build/lib/express/middleware.d.ts +37 -41
  48. package/build/lib/express/middleware.d.ts.map +1 -1
  49. package/build/lib/express/middleware.js +48 -60
  50. package/build/lib/express/middleware.js.map +1 -1
  51. package/build/lib/express/server.d.ts +57 -101
  52. package/build/lib/express/server.d.ts.map +1 -1
  53. package/build/lib/express/server.js +51 -128
  54. package/build/lib/express/server.js.map +1 -1
  55. package/build/lib/express/static.d.ts +10 -5
  56. package/build/lib/express/static.d.ts.map +1 -1
  57. package/build/lib/express/static.js +32 -42
  58. package/build/lib/express/static.js.map +1 -1
  59. package/build/lib/express/websocket.d.ts +22 -6
  60. package/build/lib/express/websocket.d.ts.map +1 -1
  61. package/build/lib/express/websocket.js +10 -15
  62. package/build/lib/express/websocket.js.map +1 -1
  63. package/build/lib/helpers/capabilities.d.ts +4 -16
  64. package/build/lib/helpers/capabilities.d.ts.map +1 -1
  65. package/build/lib/helpers/capabilities.js +36 -48
  66. package/build/lib/helpers/capabilities.js.map +1 -1
  67. package/build/lib/jsonwp-status/status.d.ts +113 -158
  68. package/build/lib/jsonwp-status/status.d.ts.map +1 -1
  69. package/build/lib/jsonwp-status/status.js +10 -14
  70. package/build/lib/jsonwp-status/status.js.map +1 -1
  71. package/build/lib/protocol/bidi-commands.d.ts +31 -36
  72. package/build/lib/protocol/bidi-commands.d.ts.map +1 -1
  73. package/build/lib/protocol/bidi-commands.js +5 -5
  74. package/build/lib/protocol/bidi-commands.js.map +1 -1
  75. package/build/lib/protocol/errors.d.ts.map +1 -1
  76. package/build/lib/protocol/helpers.d.ts +7 -11
  77. package/build/lib/protocol/helpers.d.ts.map +1 -1
  78. package/build/lib/protocol/helpers.js +5 -9
  79. package/build/lib/protocol/helpers.js.map +1 -1
  80. package/build/lib/protocol/index.d.ts +4 -21
  81. package/build/lib/protocol/index.d.ts.map +1 -1
  82. package/build/lib/protocol/index.js.map +1 -1
  83. package/build/lib/protocol/protocol.d.ts +15 -1
  84. package/build/lib/protocol/protocol.d.ts.map +1 -1
  85. package/build/lib/protocol/protocol.js +50 -20
  86. package/build/lib/protocol/protocol.js.map +1 -1
  87. package/build/lib/protocol/routes.d.ts +8 -15
  88. package/build/lib/protocol/routes.d.ts.map +1 -1
  89. package/build/lib/protocol/routes.js +18 -33
  90. package/build/lib/protocol/routes.js.map +1 -1
  91. package/lib/basedriver/capabilities.ts +1 -1
  92. package/lib/basedriver/commands/event.ts +2 -2
  93. package/lib/basedriver/commands/execute.ts +2 -2
  94. package/lib/basedriver/commands/find.ts +2 -2
  95. package/lib/basedriver/commands/mixin.ts +1 -1
  96. package/lib/basedriver/commands/timeout.ts +2 -2
  97. package/lib/basedriver/{device-settings.js → device-settings.ts} +24 -35
  98. package/lib/basedriver/{helpers.js → helpers.ts} +208 -266
  99. package/lib/basedriver/logger.ts +3 -0
  100. package/lib/basedriver/validation.ts +2 -2
  101. package/lib/constants.ts +1 -1
  102. package/lib/express/crash.ts +15 -0
  103. package/lib/express/express-logging.ts +84 -0
  104. package/lib/express/{idempotency.js → idempotency.ts} +105 -89
  105. package/lib/express/logger.ts +3 -0
  106. package/lib/express/middleware.ts +187 -0
  107. package/lib/express/{server.js → server.ts} +175 -167
  108. package/lib/express/static.ts +77 -0
  109. package/lib/express/websocket.ts +81 -0
  110. package/lib/helpers/capabilities.ts +83 -0
  111. package/lib/jsonwp-status/{status.js → status.ts} +12 -15
  112. package/lib/protocol/{bidi-commands.js → bidi-commands.ts} +7 -5
  113. package/lib/protocol/errors.ts +1 -1
  114. package/lib/protocol/{helpers.js → helpers.ts} +8 -11
  115. package/lib/protocol/protocol.ts +57 -26
  116. package/lib/protocol/{routes.js → routes.ts} +29 -40
  117. package/package.json +11 -11
  118. package/tsconfig.json +3 -1
  119. package/lib/basedriver/logger.js +0 -4
  120. package/lib/express/crash.js +0 -11
  121. package/lib/express/express-logging.js +0 -60
  122. package/lib/express/logger.js +0 -4
  123. package/lib/express/middleware.js +0 -171
  124. package/lib/express/static.js +0 -76
  125. package/lib/express/websocket.js +0 -79
  126. package/lib/helpers/capabilities.js +0 -93
  127. /package/lib/protocol/{index.js → index.ts} +0 -0
@@ -1,60 +0,0 @@
1
- import _ from 'lodash';
2
- import '@colors/colors';
3
- import morgan from 'morgan';
4
- import log from './logger';
5
- import {MAX_LOG_BODY_LENGTH} from '../constants';
6
- import {logger} from '@appium/support';
7
-
8
- // Copied the morgan compile function over so that cooler formats
9
- // may be configured
10
- function compile(fmt) {
11
- // escape quotes
12
- fmt = fmt.replace(/"/g, '\\"');
13
- fmt = fmt.replace(/:([-\w]{2,})(?:\[([^\]]+)\])?/g, function replace(_, name, arg) {
14
- return `"\n + (tokens["${name}"](req, res, "${arg}") || "-") + "`;
15
- });
16
- let js = ` return "${fmt}";`;
17
- return new Function('tokens, req, res', js);
18
- }
19
-
20
- function requestEndLoggingFormat(tokens, req, res) {
21
- let status = res.statusCode;
22
- let statusStr = ':status';
23
- if (status >= 500) {
24
- statusStr = statusStr.red;
25
- } else if (status >= 400) {
26
- statusStr = statusStr.yellow;
27
- } else if (status >= 300) {
28
- statusStr = statusStr.cyan;
29
- } else {
30
- statusStr = statusStr.green;
31
- }
32
- let fn = compile(
33
- `${'<-- :method :url '.white}${statusStr} ${':response-time ms - :res[content-length]'.grey}`
34
- );
35
- return fn(tokens, req, res);
36
- }
37
-
38
- const endLogFormatter = morgan((tokens, req, res) => {
39
- log.info(requestEndLoggingFormat(tokens, req, res), (res.jsonResp || '').grey);
40
- });
41
-
42
- const requestStartLoggingFormat = compile(`${'-->'.white} ${':method'.white} ${':url'.white}`);
43
-
44
- const startLogFormatter = morgan(
45
- (tokens, req, res) => {
46
- // morgan output is redirected straight to winston
47
- let reqBody = '';
48
- if (req.body) {
49
- try {
50
- reqBody = _.truncate(_.isString(req.body) ? req.body : JSON.stringify(req.body), {
51
- length: MAX_LOG_BODY_LENGTH,
52
- });
53
- } catch {}
54
- }
55
- log.info(requestStartLoggingFormat(tokens, req, res), logger.markSensitive(reqBody.grey));
56
- },
57
- {immediate: true}
58
- );
59
-
60
- export {endLogFormatter, startLogFormatter};
@@ -1,4 +0,0 @@
1
- import {logger} from '@appium/support';
2
-
3
- const log = logger.getLogger('HTTP');
4
- export default log;
@@ -1,171 +0,0 @@
1
- import _ from 'lodash';
2
- import log from './logger';
3
- import {errors} from '../protocol';
4
- export {handleIdempotency} from './idempotency';
5
- import {match} from 'path-to-regexp';
6
- import {util} from '@appium/support';
7
- import {calcSignature} from '../helpers/session';
8
- import {getResponseForW3CError} from '../protocol/errors';
9
-
10
- const SESSION_ID_PATTERN = /\/session\/([^/]+)/;
11
-
12
- /**
13
- *
14
- * @param {import('express').Request} req
15
- * @param {import('express').Response} res
16
- * @param {import('express').NextFunction} next
17
- * @returns {any}
18
- */
19
- export function allowCrossDomain(req, res, next) {
20
- res.header('Access-Control-Allow-Origin', '*');
21
- res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, OPTIONS, DELETE');
22
- res.header(
23
- 'Access-Control-Allow-Headers',
24
- 'Cache-Control, Pragma, Origin, X-Requested-With, Content-Type, Accept, User-Agent'
25
- );
26
-
27
- // need to respond 200 to OPTIONS
28
- if ('OPTIONS' === req.method) {
29
- return res.sendStatus(200);
30
- }
31
- next();
32
- }
33
-
34
- /**
35
- * @param {string} basePath
36
- * @returns {import('express').RequestHandler}
37
- */
38
- export function allowCrossDomainAsyncExecute(basePath) {
39
- return (req, res, next) => {
40
- // there are two paths for async responses, so cover both
41
- // https://regex101.com/r/txYiEz/1
42
- const receiveAsyncResponseRegExp = new RegExp(
43
- `${_.escapeRegExp(basePath)}/session/[a-f0-9-]+/(appium/)?receive_async_response`
44
- );
45
- if (!receiveAsyncResponseRegExp.test(req.url)) {
46
- return next();
47
- }
48
- allowCrossDomain(req, res, next);
49
- };
50
- }
51
-
52
- /**
53
- *
54
- * @param {import('express').Request} req
55
- * @param {import('express').Response} res
56
- * @param {import('express').NextFunction} next
57
- * @returns {any}
58
- */
59
- export function handleLogContext(req, res, next) {
60
- const requestId = fetchHeaderValue(req, 'x-request-id') || util.uuidV4();
61
-
62
- const sessionId = SESSION_ID_PATTERN.exec(req.url)?.[1];
63
- const sessionInfo = sessionId ? {sessionId, sessionSignature: calcSignature(sessionId)} : {};
64
- const isSensitiveHeaderValue = fetchHeaderValue(req, 'x-appium-is-sensitive');
65
-
66
- log.updateAsyncContext({
67
- requestId,
68
- ...sessionInfo,
69
- isSensitive: ['true', '1', 'yes'].includes(_.toLower(isSensitiveHeaderValue)),
70
- }, true);
71
-
72
- return next();
73
- }
74
-
75
- /**
76
- *
77
- * @param {import('express').Request} req
78
- * @param {import('express').Response} res
79
- * @param {import('express').NextFunction} next
80
- * @returns {any}
81
- */
82
- export function defaultToJSONContentType(req, res, next) {
83
- if (!req.headers['content-type']) {
84
- req.headers['content-type'] = 'application/json; charset=utf-8';
85
- }
86
- next();
87
- }
88
-
89
- /**
90
- * Core function to handle WebSocket upgrade requests by matching the request path
91
- * against registered WebSocket handlers in the webSocketsMapping.
92
- *
93
- * @param {import('http').IncomingMessage} req - The HTTP request
94
- * @param {import('stream').Duplex} socket - The network socket
95
- * @param {Buffer} head - The first packet of the upgraded stream
96
- * @param {import('@appium/types').StringRecord<import('@appium/types').WSServer>} webSocketsMapping - Mapping of paths to WebSocket servers
97
- * @returns {boolean} - Returns true if the upgrade was handled, false otherwise
98
- */
99
- export function tryHandleWebSocketUpgrade(req, socket, head, webSocketsMapping) {
100
- if (_.toLower(req.headers?.upgrade) !== 'websocket') {
101
- return false;
102
- }
103
-
104
- let currentPathname;
105
- try {
106
- currentPathname = new URL(req.url ?? '', 'http://localhost').pathname;
107
- } catch {
108
- currentPathname = req.url ?? '';
109
- }
110
- for (const [pathname, wsServer] of _.toPairs(webSocketsMapping)) {
111
- if (match(pathname)(currentPathname)) {
112
- wsServer.handleUpgrade(req, socket, head, (ws) => {
113
- wsServer.emit('connection', ws, req);
114
- });
115
- return true;
116
- }
117
- }
118
- log.info(`Did not match the websocket upgrade request at ${currentPathname} to any known route`);
119
- return false;
120
- }
121
-
122
- /**
123
- *
124
- * @param {import('@appium/types').StringRecord<import('@appium/types').WSServer>} webSocketsMapping
125
- * @returns {import('express').RequestHandler}
126
- */
127
- export function handleUpgrade(webSocketsMapping) {
128
- return (req, res, next) => {
129
- if (tryHandleWebSocketUpgrade(req, req.socket, Buffer.from(''), webSocketsMapping)) {
130
- return;
131
- }
132
- next();
133
- };
134
- }
135
-
136
- /**
137
- * @param {Error} err
138
- * @param {import('express').Request} req
139
- * @param {import('express').Response} res
140
- * @param {import('express').NextFunction} next
141
- */
142
- export function catchAllHandler(err, req, res, next) {
143
- if (res.headersSent) {
144
- return next(err);
145
- }
146
-
147
- log.error(`Uncaught error: ${err.message}`);
148
- const [status, body] = getResponseForW3CError(err);
149
- res.status(status).json(body);
150
- }
151
-
152
- /**
153
- * @param {import('express').Request} req
154
- * @param {import('express').Response} res
155
- */
156
- export function catch404Handler(req, res) {
157
- log.debug(`No route found for ${req.url}`);
158
- const [status, body] = getResponseForW3CError(new errors.UnknownCommandError());
159
- res.status(status).json(body);
160
- }
161
-
162
- /**
163
- * @param {import('express').Request} req
164
- * @param {string} name
165
- * @returns {string | undefined}
166
- */
167
- function fetchHeaderValue(req, name) {
168
- return _.isArray(req.headers[name])
169
- ? req.headers[name][0]
170
- : req.headers[name];
171
- }
@@ -1,76 +0,0 @@
1
- import path from 'node:path';
2
- import log from './logger';
3
- import _ from 'lodash';
4
- import {fs} from '@appium/support';
5
- import B from 'bluebird';
6
-
7
- let STATIC_DIR = path.resolve(__dirname, '..', '..', '..', 'static');
8
- if (_.isNull(path.resolve(__dirname).match(/build[/\\]lib[/\\]express$/))) {
9
- // in some contexts we are not in the build directory,
10
- // so we don't want to go back the extra level
11
- STATIC_DIR = path.resolve(__dirname, '..', '..', 'static');
12
- }
13
-
14
- async function guineaPigTemplate(req, res, page) {
15
- const delay = parseInt(req.params.delay || req.query.delay || 0, 10);
16
- const throwError = req.params.throwError || req.query.throwError || '';
17
- let params = {
18
- throwError,
19
- serverTime: new Date(),
20
- userAgent: req.headers['user-agent'],
21
- comment: 'None',
22
- };
23
- if (req.method === 'POST') {
24
- params.comment = req.body.comments || params.comment;
25
- }
26
- log.debug(`Sending guinea pig response with params: ${JSON.stringify(params)}`);
27
- if (delay) {
28
- log.debug(`Waiting ${delay}ms before responding`);
29
- await B.delay(delay);
30
- }
31
- res.set('content-type', 'text/html');
32
- res.cookie('guineacookie1', 'i am a cookie value', {path: '/'});
33
- res.cookie('guineacookie2', 'cookié2', {path: '/'});
34
- res.cookie('guineacookie3', 'cant access this', {
35
- domain: '.blargimarg.com',
36
- path: '/',
37
- });
38
- res.send((await getTemplate(page))(params));
39
- }
40
-
41
- /*
42
- * Dynamic page mapped to /test/guinea-pig
43
- */
44
- async function guineaPig(req, res) {
45
- return await guineaPigTemplate(req, res, 'guinea-pig.html');
46
- }
47
-
48
- /*
49
- * Dynamic page mapped to /test/guinea-pig-scrollable
50
- */
51
- async function guineaPigScrollable(req, res) {
52
- return await guineaPigTemplate(req, res, 'guinea-pig-scrollable.html');
53
- }
54
-
55
- /*
56
- * Dynamic page mapped to /test/guinea-pig-app-banner
57
- */
58
- async function guineaPigAppBanner(req, res) {
59
- return await guineaPigTemplate(req, res, 'guinea-pig-app-banner.html');
60
- }
61
-
62
- /*
63
- * Dynamic page mapped to /welcome
64
- */
65
- async function welcome(req, res) {
66
- let params = {message: "Let's browse!"};
67
- log.debug(`Sending welcome response with params: ${JSON.stringify(params)}`);
68
- res.send((await getTemplate('welcome.html'))(params));
69
- }
70
-
71
- async function getTemplate(templateName) {
72
- let content = await fs.readFile(path.resolve(STATIC_DIR, 'test', templateName));
73
- return _.template(content.toString());
74
- }
75
-
76
- export {guineaPig, guineaPigScrollable, guineaPigAppBanner, welcome, STATIC_DIR};
@@ -1,79 +0,0 @@
1
-
2
- import _ from 'lodash';
3
- import B from 'bluebird';
4
-
5
- const DEFAULT_WS_PATHNAME_PREFIX = '/ws';
6
-
7
- /**
8
- * @this {AppiumServer}
9
- * @type {AppiumServer['addWebSocketHandler']}
10
- */
11
- async function addWebSocketHandler(handlerPathname, handlerServer) {
12
- this.webSocketsMapping[handlerPathname] = handlerServer;
13
- }
14
-
15
- /**
16
- * @this {AppiumServer}
17
- * @type {AppiumServer['getWebSocketHandlers']}
18
- */
19
- async function getWebSocketHandlers(keysFilter = null) {
20
- return _.toPairs(this.webSocketsMapping).reduce((acc, [pathname, wsServer]) => {
21
- if (!_.isString(keysFilter) || pathname.includes(keysFilter)) {
22
- acc[pathname] = wsServer;
23
- }
24
- return acc;
25
- }, {});
26
- }
27
-
28
- /**
29
- * @this {AppiumServer}
30
- * @type {AppiumServer['removeWebSocketHandler']}
31
- */
32
- async function removeWebSocketHandler(handlerPathname) {
33
- const wsServer = this.webSocketsMapping?.[handlerPathname];
34
- if (!wsServer) {
35
- return false;
36
- }
37
-
38
- try {
39
- wsServer.close();
40
- for (const client of wsServer.clients || []) {
41
- client.terminate();
42
- }
43
- return true;
44
- } catch {
45
- // ignore
46
- } finally {
47
- delete this.webSocketsMapping[handlerPathname];
48
- }
49
- return false;
50
- }
51
-
52
- /**
53
- *
54
- * @this {AppiumServer}
55
- * @type {AppiumServer['removeAllWebSocketHandlers']}
56
- */
57
- async function removeAllWebSocketHandlers() {
58
- if (_.isEmpty(this.webSocketsMapping)) {
59
- return false;
60
- }
61
-
62
- return _.some(
63
- await B.all(
64
- _.keys(this.webSocketsMapping).map((pathname) => this.removeWebSocketHandler(pathname))
65
- )
66
- );
67
- }
68
-
69
- export {
70
- addWebSocketHandler,
71
- removeWebSocketHandler,
72
- removeAllWebSocketHandlers,
73
- getWebSocketHandlers,
74
- DEFAULT_WS_PATHNAME_PREFIX,
75
- };
76
-
77
- /**
78
- * @typedef {import('@appium/types').AppiumServer} AppiumServer
79
- */
@@ -1,93 +0,0 @@
1
- // @ts-check
2
-
3
- import _ from 'lodash';
4
-
5
- /**
6
- * Determine whether the given argument is valid
7
- * W3C capabilities instance.
8
- *
9
- * @param {any} caps
10
- * @returns {caps is import('@appium/types').W3CCapabilities}
11
- */
12
- export function isW3cCaps(caps) {
13
- if (!_.isPlainObject(caps)) {
14
- return false;
15
- }
16
-
17
- const isFirstMatchValid = () =>
18
- _.isArray(caps.firstMatch) &&
19
- !_.isEmpty(caps.firstMatch) &&
20
- _.every(caps.firstMatch, _.isPlainObject);
21
- const isAlwaysMatchValid = () => _.isPlainObject(caps.alwaysMatch);
22
- if (_.has(caps, 'firstMatch') && _.has(caps, 'alwaysMatch')) {
23
- return isFirstMatchValid() && isAlwaysMatchValid();
24
- }
25
- if (_.has(caps, 'firstMatch')) {
26
- return isFirstMatchValid();
27
- }
28
- if (_.has(caps, 'alwaysMatch')) {
29
- return isAlwaysMatchValid();
30
- }
31
- return false;
32
- }
33
-
34
- /**
35
- *
36
- * @template {Constraints} C
37
- * @param {any} oldCaps
38
- * @param {C} desiredCapConstraints
39
- * @param {AppiumLogger} log
40
- * @returns {Capabilities<C>}
41
- */
42
- export function fixCaps(oldCaps, desiredCapConstraints, log) {
43
- let caps = _.clone(oldCaps);
44
-
45
- // boolean capabilities can be passed in as strings 'false' and 'true'
46
- // which we want to translate into boolean values
47
- let booleanCaps = _.keys(_.pickBy(desiredCapConstraints, (k) => k.isBoolean === true));
48
- for (let cap of booleanCaps) {
49
- let value = oldCaps[cap];
50
- if (_.isString(value)) {
51
- value = value.toLowerCase();
52
- if (value === 'true' || value === 'false') {
53
- log.warn(
54
- `Capability '${cap}' changed from string to boolean. This may cause unexpected behavior`
55
- );
56
- caps[cap] = value === 'true';
57
- }
58
- }
59
- }
60
-
61
- // int capabilities are often sent in as strings by frameworks
62
- let intCaps = /** @type {import('type-fest').KeyAsString<typeof caps>[]} */ (
63
- _.keys(_.pickBy(desiredCapConstraints, (k) => k.isNumber === true))
64
- );
65
- for (let cap of intCaps) {
66
- let value = oldCaps[cap];
67
- if (_.isString(value)) {
68
- value = value.trim();
69
- let newValue = parseInt(value, 10);
70
- if (value !== `${newValue}`) {
71
- newValue = parseFloat(value);
72
- }
73
- log.warn(
74
- `Capability '${cap}' changed from string ('${value}') to integer (${newValue}). This may cause unexpected behavior`
75
- );
76
- caps[cap] = newValue;
77
- }
78
- }
79
-
80
- return caps;
81
- }
82
-
83
- /**
84
- * @typedef {import('@appium/types').Constraints} Constraints
85
- * @typedef {import('@appium/types').AppiumLogger} AppiumLogger
86
- * @typedef {import('@appium/types').StringRecord} StringRecord
87
- * @typedef {import('@appium/types').BaseDriverCapConstraints} BaseDriverCapConstraints
88
- */
89
-
90
- /**
91
- * @template {Constraints} C
92
- * @typedef {import('@appium/types').Capabilities<C>} Capabilities
93
- */
File without changes