@applitools/driver 1.4.17-beta.2 → 1.5.2

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/dist/driver.js CHANGED
@@ -1,519 +1,519 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
- }) : (function(o, m, k, k2) {
6
- if (k2 === undefined) k2 = k;
7
- o[k2] = m[k];
8
- }));
9
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
- Object.defineProperty(o, "default", { enumerable: true, value: v });
11
- }) : function(o, v) {
12
- o["default"] = v;
13
- });
14
- var __importStar = (this && this.__importStar) || function (mod) {
15
- if (mod && mod.__esModule) return mod;
16
- var result = {};
17
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
- __setModuleDefault(result, mod);
19
- return result;
20
- };
21
- Object.defineProperty(exports, "__esModule", { value: true });
22
- exports.Driver = void 0;
23
- const utils = __importStar(require("@applitools/utils"));
24
- const specUtils = __importStar(require("./spec-utils"));
25
- const context_1 = require("./context");
26
- const helper_ios_1 = require("./helper-ios");
27
- const helper_android_1 = require("./helper-android");
28
- const user_agent_1 = require("./user-agent");
29
- const capabilities_1 = require("./capabilities");
30
- const snippets = require('@applitools/snippets');
31
- // eslint-disable-next-line
32
- class Driver {
33
- constructor(options) {
34
- var _a, _b, _c, _d, _e, _f;
35
- if (options.driver instanceof Driver)
36
- return options.driver;
37
- this._spec = options.spec;
38
- if (options.logger)
39
- this._logger = options.logger;
40
- if (this._spec.isDriver(options.driver)) {
41
- this._target = (_c = (_b = (_a = this._spec).transformDriver) === null || _b === void 0 ? void 0 : _b.call(_a, options.driver)) !== null && _c !== void 0 ? _c : options.driver;
42
- }
43
- else {
44
- throw new TypeError('Driver constructor called with argument of unknown type!');
45
- }
46
- this._mainContext = new context_1.Context({
47
- spec: this._spec,
48
- context: (_f = (_e = (_d = this._spec).extractContext) === null || _e === void 0 ? void 0 : _e.call(_d, this._target)) !== null && _f !== void 0 ? _f : this._target,
49
- driver: this,
50
- logger: this._logger,
51
- });
52
- this._currentContext = this._mainContext;
53
- }
54
- get target() {
55
- return this._target;
56
- }
57
- get currentContext() {
58
- return this._currentContext;
59
- }
60
- get mainContext() {
61
- return this._mainContext;
62
- }
63
- get helper() {
64
- return this._helper;
65
- }
66
- get features() {
67
- var _a;
68
- return (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.features;
69
- }
70
- get deviceName() {
71
- var _a;
72
- return (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.deviceName;
73
- }
74
- get platformName() {
75
- var _a;
76
- return (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.platformName;
77
- }
78
- get platformVersion() {
79
- var _a;
80
- return (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.platformVersion;
81
- }
82
- get browserName() {
83
- var _a;
84
- return (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.browserName;
85
- }
86
- get browserVersion() {
87
- var _a;
88
- return (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.browserVersion;
89
- }
90
- get userAgent() {
91
- var _a;
92
- return (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.userAgent;
93
- }
94
- get orientation() {
95
- return this._driverInfo.orientation;
96
- }
97
- get pixelRatio() {
98
- var _a;
99
- return (_a = this._driverInfo.pixelRatio) !== null && _a !== void 0 ? _a : 1;
100
- }
101
- get viewportScale() {
102
- var _a;
103
- return (_a = this._driverInfo.viewportScale) !== null && _a !== void 0 ? _a : 1;
104
- }
105
- get statusBarHeight() {
106
- var _a;
107
- return (_a = this._driverInfo.statusBarHeight) !== null && _a !== void 0 ? _a : (this.isNative ? 0 : undefined);
108
- }
109
- get navigationBarHeight() {
110
- var _a;
111
- return (_a = this._driverInfo.navigationBarHeight) !== null && _a !== void 0 ? _a : (this.isNative ? 0 : undefined);
112
- }
113
- get isNative() {
114
- var _a, _b;
115
- return (_b = (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.isNative) !== null && _b !== void 0 ? _b : false;
116
- }
117
- get isWeb() {
118
- return !this.isNative;
119
- }
120
- get isMobile() {
121
- var _a, _b;
122
- return (_b = (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.isMobile) !== null && _b !== void 0 ? _b : false;
123
- }
124
- get isIOS() {
125
- return this.platformName === 'iOS';
126
- }
127
- get isAndroid() {
128
- return this.platformName === 'Android';
129
- }
130
- get isIE() {
131
- return /(internet explorer|ie)/i.test(this.browserName);
132
- }
133
- get isEdgeLegacy() {
134
- return /edge/i.test(this.browserName) && Number(this.browserVersion) <= 44;
135
- }
136
- updateCurrentContext(context) {
137
- this._currentContext = context;
138
- }
139
- async init() {
140
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
141
- var _w, _x, _y, _z, _0, _1, _2, _3;
142
- const capabilities = await ((_b = (_a = this._spec).getCapabilities) === null || _b === void 0 ? void 0 : _b.call(_a, this.target));
143
- this._logger.log('Driver capabilities', capabilities);
144
- const capabilitiesInfo = capabilities ? capabilities_1.parseCapabilities(capabilities) : undefined;
145
- const driverInfo = await ((_d = (_c = this._spec).getDriverInfo) === null || _d === void 0 ? void 0 : _d.call(_c, this.target));
146
- this._driverInfo = Object.assign(Object.assign({}, capabilitiesInfo), driverInfo);
147
- if (this.isWeb) {
148
- (_e = (_w = this._driverInfo).pixelRatio) !== null && _e !== void 0 ? _e : (_w.pixelRatio = await this.execute(snippets.getPixelRatio));
149
- (_f = (_x = this._driverInfo).viewportScale) !== null && _f !== void 0 ? _f : (_x.viewportScale = await this.execute(snippets.getViewportScale));
150
- (_g = (_y = this._driverInfo).userAgent) !== null && _g !== void 0 ? _g : (_y.userAgent = await this.execute(snippets.getUserAgent));
151
- if (this._driverInfo.userAgent) {
152
- const userAgentInfo = user_agent_1.parseUserAgent(this._driverInfo.userAgent);
153
- this._driverInfo.browserName = (_h = userAgentInfo.browserName) !== null && _h !== void 0 ? _h : this._driverInfo.browserName;
154
- this._driverInfo.browserVersion = (_j = userAgentInfo.browserVersion) !== null && _j !== void 0 ? _j : this._driverInfo.browserVersion;
155
- if (this._driverInfo.isMobile) {
156
- (_k = (_z = this._driverInfo).platformName) !== null && _k !== void 0 ? _k : (_z.platformName = userAgentInfo.platformName);
157
- (_l = (_0 = this._driverInfo).platformVersion) !== null && _l !== void 0 ? _l : (_0.platformVersion = userAgentInfo.platformVersion);
158
- }
159
- else {
160
- this._driverInfo.platformName = (_m = userAgentInfo.platformName) !== null && _m !== void 0 ? _m : this._driverInfo.platformName;
161
- this._driverInfo.platformVersion = (_o = userAgentInfo.platformVersion) !== null && _o !== void 0 ? _o : this._driverInfo.platformVersion;
162
- }
163
- }
164
- (_p = (_1 = this._driverInfo).features) !== null && _p !== void 0 ? _p : (_1.features = {});
165
- (_q = (_2 = this._driverInfo.features).allCookies) !== null && _q !== void 0 ? _q : (_2.allCookies = /chrome/i.test(this._driverInfo.browserName) && !this._driverInfo.isMobile);
166
- }
167
- else {
168
- const barsHeight = await ((_s = (_r = this._spec).getBarsHeight) === null || _s === void 0 ? void 0 : _s.call(_r, this.target).catch(() => undefined));
169
- const displaySize = await this.getDisplaySize();
170
- // calculate status and navigation bars sizes
171
- if (barsHeight) {
172
- // when status bar is overlapping content on android it returns status bar height equal to viewport height
173
- if (this.isAndroid && barsHeight.statusBarHeight / this.pixelRatio < displaySize.height) {
174
- this._driverInfo.statusBarHeight = Math.max((_t = this._driverInfo.statusBarHeight) !== null && _t !== void 0 ? _t : 0, barsHeight.statusBarHeight);
175
- }
176
- this._driverInfo.navigationBarHeight = Math.max((_u = this._driverInfo.navigationBarHeight) !== null && _u !== void 0 ? _u : 0, barsHeight.navigationBarHeight);
177
- }
178
- if (this.isAndroid) {
179
- this._driverInfo.statusBarHeight /= this.pixelRatio;
180
- this._driverInfo.navigationBarHeight /= this.pixelRatio;
181
- }
182
- // calculate viewport size
183
- if (!this._driverInfo.viewportSize) {
184
- this._driverInfo.viewportSize = {
185
- width: displaySize.width,
186
- height: displaySize.height - this._driverInfo.statusBarHeight,
187
- };
188
- }
189
- // calculate safe area
190
- if (this.isIOS && !this._driverInfo.safeArea) {
191
- this._driverInfo.safeArea = Object.assign({ x: 0, y: 0 }, displaySize);
192
- const topElement = await this.element({ type: '-ios class chain', selector: '**/XCUIElementTypeNavigationBar' });
193
- if (topElement) {
194
- const topRegion = await this._spec.getElementRegion(this.target, topElement.target);
195
- const topOffset = topRegion.y + topRegion.height;
196
- this._driverInfo.safeArea.y = topOffset;
197
- this._driverInfo.safeArea.height -= topOffset;
198
- }
199
- const bottomElement = await this.element({ type: '-ios class chain', selector: '**/XCUIElementTypeTabBar' });
200
- if (bottomElement) {
201
- const bottomRegion = await this._spec.getElementRegion(this.target, bottomElement.target);
202
- const bottomOffset = bottomRegion.height;
203
- this._driverInfo.safeArea.height -= bottomOffset;
204
- }
205
- }
206
- // init helper lib
207
- this._helper = this.isIOS
208
- ? await helper_ios_1.HelperIOS.make({ spec: this._spec, driver: this, logger: this._logger })
209
- : await helper_android_1.HelperAndroid.make({ spec: this._spec, driver: this, logger: this._logger });
210
- }
211
- if (this.isMobile) {
212
- (_v = (_3 = this._driverInfo).orientation) !== null && _v !== void 0 ? _v : (_3.orientation = await this.getOrientation().catch(() => undefined));
213
- }
214
- this._logger.log('Combined driver info', this._driverInfo);
215
- return this;
216
- }
217
- async refreshContexts() {
218
- if (this.isNative)
219
- return this.currentContext;
220
- const spec = this._spec;
221
- let currentContext = this.currentContext.target;
222
- let contextInfo = await getContextInfo(currentContext);
223
- const path = [];
224
- if (spec.parentContext) {
225
- while (!contextInfo.isRoot) {
226
- currentContext = await spec.parentContext(currentContext);
227
- const contextReference = await findContextReference(currentContext, contextInfo);
228
- if (!contextReference)
229
- throw new Error('Unable to find out the chain of frames');
230
- path.unshift(contextReference);
231
- contextInfo = await getContextInfo(currentContext);
232
- }
233
- }
234
- else {
235
- currentContext = await spec.mainContext(currentContext);
236
- path.push(...(await findContextPath(currentContext, contextInfo)));
237
- }
238
- this._currentContext = this._mainContext;
239
- return this.switchToChildContext(...path);
240
- function transformSelector(selector) {
241
- return specUtils.transformSelector(spec, selector, { isWeb: true });
242
- }
243
- async function getContextInfo(context) {
244
- const [documentElement, selector, isRoot, isCORS] = await spec.executeScript(context, snippets.getContextInfo);
245
- return { documentElement, selector, isRoot, isCORS };
246
- }
247
- async function getChildContextsInfo(context) {
248
- const framesInfo = await spec.executeScript(context, snippets.getChildFramesInfo);
249
- return framesInfo.map(([contextElement, isCORS]) => ({ contextElement, isCORS }));
250
- }
251
- async function isEqualElements(context, element1, element2) {
252
- return spec.executeScript(context, snippets.isEqualElements, [element1, element2]).catch(() => false);
253
- }
254
- async function findContextReference(context, contextInfo) {
255
- if (contextInfo.selector) {
256
- const contextElement = await spec.findElement(context, transformSelector({ type: 'xpath', selector: contextInfo.selector }));
257
- if (contextElement)
258
- return contextElement;
259
- }
260
- for (const childContextInfo of await getChildContextsInfo(context)) {
261
- if (childContextInfo.isCORS !== contextInfo.isCORS)
262
- continue;
263
- const childContext = await spec.childContext(context, childContextInfo.contextElement);
264
- const contentDocument = await spec.findElement(childContext, transformSelector('html'));
265
- const isWantedContext = await isEqualElements(childContext, contentDocument, contextInfo.documentElement);
266
- await spec.parentContext(childContext);
267
- if (isWantedContext)
268
- return childContextInfo.contextElement;
269
- }
270
- }
271
- async function findContextPath(context, contextInfo, contextPath = []) {
272
- const contentDocument = await spec.findElement(context, transformSelector('html'));
273
- if (await isEqualElements(context, contentDocument, contextInfo.documentElement)) {
274
- return contextPath;
275
- }
276
- for (const childContextInfo of await getChildContextsInfo(context)) {
277
- const childContext = await spec.childContext(context, childContextInfo.contextElement);
278
- const possibleContextPath = [...contextPath, childContextInfo.contextElement];
279
- const wantedContextPath = await findContextPath(childContext, contextInfo, possibleContextPath);
280
- await spec.mainContext(context);
281
- if (wantedContextPath)
282
- return wantedContextPath;
283
- for (const contextElement of contextPath) {
284
- await spec.childContext(context, contextElement);
285
- }
286
- }
287
- }
288
- }
289
- async switchTo(context) {
290
- if (await this.currentContext.equals(context)) {
291
- this._currentContext = context;
292
- return;
293
- }
294
- const currentPath = this.currentContext.path;
295
- const requiredPath = context.path;
296
- let diffIndex = -1;
297
- for (const [index, context] of requiredPath.entries()) {
298
- if (currentPath[index] && !(await currentPath[index].equals(context))) {
299
- diffIndex = index;
300
- break;
301
- }
302
- }
303
- if (diffIndex === 0) {
304
- throw new Error('Cannot switch to the context, because it has different main context');
305
- }
306
- else if (diffIndex === -1) {
307
- if (currentPath.length === requiredPath.length) {
308
- // required and current paths are the same
309
- return this.currentContext;
310
- }
311
- else if (requiredPath.length > currentPath.length) {
312
- // current path is a sub-path of required path
313
- return this.switchToChildContext(...requiredPath.slice(currentPath.length));
314
- }
315
- else if (currentPath.length - requiredPath.length <= requiredPath.length) {
316
- // required path is a sub-path of current path
317
- return this.switchToParentContext(currentPath.length - requiredPath.length);
318
- }
319
- else {
320
- // required path is a sub-path of current path
321
- await this.switchToMainContext();
322
- return this.switchToChildContext(...requiredPath);
323
- }
324
- }
325
- else if (currentPath.length - diffIndex <= diffIndex) {
326
- // required path is different from current or they are partially intersected
327
- // chose an optimal way to traverse from current context to target context
328
- await this.switchToParentContext(currentPath.length - diffIndex);
329
- return this.switchToChildContext(...requiredPath.slice(diffIndex));
330
- }
331
- else {
332
- await this.switchToMainContext();
333
- return this.switchToChildContext(...requiredPath);
334
- }
335
- }
336
- async switchToMainContext() {
337
- if (this.isNative)
338
- throw new Error('Contexts are supported only for web drivers');
339
- this._logger.log('Switching to the main context');
340
- await this._spec.mainContext(this.currentContext.target);
341
- return (this._currentContext = this._mainContext);
342
- }
343
- async switchToParentContext(elevation = 1) {
344
- if (this.isNative)
345
- throw new Error('Contexts are supported only for web drivers');
346
- this._logger.log('Switching to a parent context with elevation:', elevation);
347
- if (this.currentContext.path.length <= elevation) {
348
- return this.switchToMainContext();
349
- }
350
- try {
351
- while (elevation > 0) {
352
- await this._spec.parentContext(this.currentContext.target);
353
- this._currentContext = this._currentContext.parent;
354
- elevation -= 1;
355
- }
356
- }
357
- catch (err) {
358
- this._logger.warn('Unable to switch to a parent context due to error', err);
359
- this._logger.log('Applying workaround to switch to the parent frame');
360
- const path = this.currentContext.path.slice(1, -elevation);
361
- await this.switchToMainContext();
362
- await this.switchToChildContext(...path);
363
- elevation = 0;
364
- }
365
- return this.currentContext;
366
- }
367
- async switchToChildContext(...references) {
368
- if (this.isNative)
369
- throw new Error('Contexts are supported only for web drivers');
370
- this._logger.log('Switching to a child context with depth:', references.length);
371
- for (const reference of references) {
372
- if (reference === this.mainContext)
373
- continue;
374
- const context = await this.currentContext.context(reference);
375
- await context.focus();
376
- }
377
- return this.currentContext;
378
- }
379
- async normalizeRegion(region) {
380
- if (this.isWeb || !utils.types.has(this._driverInfo, ['viewportSize', 'statusBarHeight']))
381
- return region;
382
- const scaledRegion = this.isAndroid ? utils.geometry.scale(region, 1 / this.pixelRatio) : region;
383
- const safeRegion = this.isIOS ? utils.geometry.intersect(scaledRegion, this._driverInfo.safeArea) : scaledRegion;
384
- const offsetRegion = utils.geometry.offsetNegative(safeRegion, { x: 0, y: this.statusBarHeight });
385
- if (offsetRegion.y < 0) {
386
- offsetRegion.height += offsetRegion.y;
387
- offsetRegion.y = 0;
388
- }
389
- return offsetRegion;
390
- }
391
- async getRegionInViewport(context, region) {
392
- await context.focus();
393
- return context.getRegionInViewport(region);
394
- }
395
- async element(selector) {
396
- return this.currentContext.element(selector);
397
- }
398
- async elements(selector) {
399
- return this.currentContext.elements(selector);
400
- }
401
- async execute(script, arg) {
402
- return this.currentContext.execute(script, arg);
403
- }
404
- async takeScreenshot() {
405
- const image = await this._spec.takeScreenshot(this.target);
406
- if (utils.types.isString(image)) {
407
- return Buffer.from(image.replace(/[\r\n]+/g, ''), 'base64');
408
- }
409
- return image;
410
- }
411
- async getViewportSize() {
412
- var _a;
413
- let size;
414
- if (this.isNative) {
415
- this._logger.log('Extracting viewport size from native driver');
416
- if ((_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.viewportSize) {
417
- size = this._driverInfo.viewportSize;
418
- }
419
- else {
420
- size = await this.getDisplaySize();
421
- if (size.height > size.width) {
422
- const orientation = await this.getOrientation();
423
- if (orientation === 'landscape') {
424
- size = { width: size.height, height: size.width };
425
- }
426
- }
427
- }
428
- size = utils.geometry.round(size);
429
- }
430
- else if (this._spec.getViewportSize) {
431
- this._logger.log('Extracting viewport size from web driver using spec method');
432
- size = await this._spec.getViewportSize(this.target);
433
- }
434
- else {
435
- this._logger.log('Extracting viewport size from web driver using js snippet');
436
- size = await this.mainContext.execute(snippets.getViewportSize);
437
- }
438
- this._logger.log('Extracted viewport size', size);
439
- return size;
440
- }
441
- async setViewportSize(size) {
442
- if (this.isMobile)
443
- return;
444
- if (this._spec.setViewportSize) {
445
- this._logger.log('Setting viewport size to', size, 'using spec method');
446
- await this._spec.setViewportSize(this.target, size);
447
- return;
448
- }
449
- this._logger.log('Setting viewport size to', size, 'using workaround');
450
- const requiredViewportSize = size;
451
- let currentViewportSize = await this.getViewportSize();
452
- if (utils.geometry.equals(currentViewportSize, requiredViewportSize))
453
- return;
454
- let currentWindowSize = await this._spec.getWindowSize(this.target);
455
- this._logger.log('Extracted window size', currentWindowSize);
456
- let attempt = 0;
457
- while (attempt++ < 3) {
458
- const requiredWindowSize = {
459
- width: currentWindowSize.width + (requiredViewportSize.width - currentViewportSize.width),
460
- height: currentWindowSize.height + (requiredViewportSize.height - currentViewportSize.height),
461
- };
462
- this._logger.log(`Attempt #${attempt} to set viewport size by setting window size to`, requiredWindowSize);
463
- await this._spec.setWindowSize(this.target, requiredWindowSize);
464
- const prevViewportSize = currentViewportSize;
465
- currentViewportSize = await this.getViewportSize();
466
- if (utils.geometry.equals(currentViewportSize, prevViewportSize)) {
467
- currentViewportSize = await this.getViewportSize();
468
- }
469
- currentWindowSize = requiredWindowSize;
470
- if (utils.geometry.equals(currentViewportSize, requiredViewportSize))
471
- return;
472
- this._logger.log(`Attempt #${attempt} to set viewport size failed. Current viewport:`, currentViewportSize);
473
- }
474
- throw new Error('Failed to set viewport size!');
475
- }
476
- async getDisplaySize() {
477
- if (this.isWeb && !this.isMobile)
478
- return;
479
- const size = await this._spec.getWindowSize(this.target);
480
- return this.isAndroid ? utils.geometry.scale(size, 1 / this.pixelRatio) : size;
481
- }
482
- async getOrientation() {
483
- if (this.isWeb && !this.isMobile)
484
- return;
485
- const orientation = this._spec.getOrientation(this.target);
486
- this._logger.log('Extracted device orientation:', orientation);
487
- return orientation;
488
- }
489
- async getCookies() {
490
- var _a, _b, _c;
491
- if (this.isNative || !this.features.allCookies)
492
- return [];
493
- try {
494
- return (_c = (await ((_b = (_a = this._spec).getCookies) === null || _b === void 0 ? void 0 : _b.call(_a, this.target)))) !== null && _c !== void 0 ? _c : [];
495
- }
496
- catch (error) {
497
- this._driverInfo.features.allCookies = false;
498
- throw error;
499
- }
500
- }
501
- async getTitle() {
502
- if (this.isNative)
503
- return null;
504
- const title = await this._spec.getTitle(this.target);
505
- this._logger.log('Extracted title:', title);
506
- return title;
507
- }
508
- async getUrl() {
509
- if (this.isNative)
510
- return null;
511
- const url = this._spec.getUrl(this.target);
512
- this._logger.log('Extracted url:', url);
513
- return url;
514
- }
515
- async visit(url) {
516
- await this._spec.visit(this.target, url);
517
- }
518
- }
519
- exports.Driver = Driver;
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
11
+ }) : function(o, v) {
12
+ o["default"] = v;
13
+ });
14
+ var __importStar = (this && this.__importStar) || function (mod) {
15
+ if (mod && mod.__esModule) return mod;
16
+ var result = {};
17
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18
+ __setModuleDefault(result, mod);
19
+ return result;
20
+ };
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.Driver = void 0;
23
+ const utils = __importStar(require("@applitools/utils"));
24
+ const specUtils = __importStar(require("./spec-utils"));
25
+ const context_1 = require("./context");
26
+ const helper_ios_1 = require("./helper-ios");
27
+ const helper_android_1 = require("./helper-android");
28
+ const user_agent_1 = require("./user-agent");
29
+ const capabilities_1 = require("./capabilities");
30
+ const snippets = require('@applitools/snippets');
31
+ // eslint-disable-next-line
32
+ class Driver {
33
+ constructor(options) {
34
+ var _a, _b, _c, _d, _e, _f;
35
+ if (options.driver instanceof Driver)
36
+ return options.driver;
37
+ this._spec = options.spec;
38
+ if (options.logger)
39
+ this._logger = options.logger;
40
+ if (this._spec.isDriver(options.driver)) {
41
+ this._target = (_c = (_b = (_a = this._spec).transformDriver) === null || _b === void 0 ? void 0 : _b.call(_a, options.driver)) !== null && _c !== void 0 ? _c : options.driver;
42
+ }
43
+ else {
44
+ throw new TypeError('Driver constructor called with argument of unknown type!');
45
+ }
46
+ this._mainContext = new context_1.Context({
47
+ spec: this._spec,
48
+ context: (_f = (_e = (_d = this._spec).extractContext) === null || _e === void 0 ? void 0 : _e.call(_d, this._target)) !== null && _f !== void 0 ? _f : this._target,
49
+ driver: this,
50
+ logger: this._logger,
51
+ });
52
+ this._currentContext = this._mainContext;
53
+ }
54
+ get target() {
55
+ return this._target;
56
+ }
57
+ get currentContext() {
58
+ return this._currentContext;
59
+ }
60
+ get mainContext() {
61
+ return this._mainContext;
62
+ }
63
+ get helper() {
64
+ return this._helper;
65
+ }
66
+ get features() {
67
+ var _a;
68
+ return (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.features;
69
+ }
70
+ get deviceName() {
71
+ var _a;
72
+ return (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.deviceName;
73
+ }
74
+ get platformName() {
75
+ var _a;
76
+ return (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.platformName;
77
+ }
78
+ get platformVersion() {
79
+ var _a;
80
+ return (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.platformVersion;
81
+ }
82
+ get browserName() {
83
+ var _a;
84
+ return (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.browserName;
85
+ }
86
+ get browserVersion() {
87
+ var _a;
88
+ return (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.browserVersion;
89
+ }
90
+ get userAgent() {
91
+ var _a;
92
+ return (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.userAgent;
93
+ }
94
+ get orientation() {
95
+ return this._driverInfo.orientation;
96
+ }
97
+ get pixelRatio() {
98
+ var _a;
99
+ return (_a = this._driverInfo.pixelRatio) !== null && _a !== void 0 ? _a : 1;
100
+ }
101
+ get viewportScale() {
102
+ var _a;
103
+ return (_a = this._driverInfo.viewportScale) !== null && _a !== void 0 ? _a : 1;
104
+ }
105
+ get statusBarHeight() {
106
+ var _a;
107
+ return (_a = this._driverInfo.statusBarHeight) !== null && _a !== void 0 ? _a : (this.isNative ? 0 : undefined);
108
+ }
109
+ get navigationBarHeight() {
110
+ var _a;
111
+ return (_a = this._driverInfo.navigationBarHeight) !== null && _a !== void 0 ? _a : (this.isNative ? 0 : undefined);
112
+ }
113
+ get isNative() {
114
+ var _a, _b;
115
+ return (_b = (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.isNative) !== null && _b !== void 0 ? _b : false;
116
+ }
117
+ get isWeb() {
118
+ return !this.isNative;
119
+ }
120
+ get isMobile() {
121
+ var _a, _b;
122
+ return (_b = (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.isMobile) !== null && _b !== void 0 ? _b : false;
123
+ }
124
+ get isIOS() {
125
+ return this.platformName === 'iOS';
126
+ }
127
+ get isAndroid() {
128
+ return this.platformName === 'Android';
129
+ }
130
+ get isIE() {
131
+ return /(internet explorer|ie)/i.test(this.browserName);
132
+ }
133
+ get isEdgeLegacy() {
134
+ return /edge/i.test(this.browserName) && Number(this.browserVersion) <= 44;
135
+ }
136
+ updateCurrentContext(context) {
137
+ this._currentContext = context;
138
+ }
139
+ async init() {
140
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v;
141
+ var _w, _x, _y, _z, _0, _1, _2, _3;
142
+ const capabilities = await ((_b = (_a = this._spec).getCapabilities) === null || _b === void 0 ? void 0 : _b.call(_a, this.target));
143
+ this._logger.log('Driver capabilities', capabilities);
144
+ const capabilitiesInfo = capabilities ? capabilities_1.parseCapabilities(capabilities) : undefined;
145
+ const driverInfo = await ((_d = (_c = this._spec).getDriverInfo) === null || _d === void 0 ? void 0 : _d.call(_c, this.target));
146
+ this._driverInfo = Object.assign(Object.assign({}, capabilitiesInfo), driverInfo);
147
+ if (this.isWeb) {
148
+ (_e = (_w = this._driverInfo).pixelRatio) !== null && _e !== void 0 ? _e : (_w.pixelRatio = await this.execute(snippets.getPixelRatio));
149
+ (_f = (_x = this._driverInfo).viewportScale) !== null && _f !== void 0 ? _f : (_x.viewportScale = await this.execute(snippets.getViewportScale));
150
+ (_g = (_y = this._driverInfo).userAgent) !== null && _g !== void 0 ? _g : (_y.userAgent = await this.execute(snippets.getUserAgent));
151
+ if (this._driverInfo.userAgent) {
152
+ const userAgentInfo = user_agent_1.parseUserAgent(this._driverInfo.userAgent);
153
+ this._driverInfo.browserName = (_h = userAgentInfo.browserName) !== null && _h !== void 0 ? _h : this._driverInfo.browserName;
154
+ this._driverInfo.browserVersion = (_j = userAgentInfo.browserVersion) !== null && _j !== void 0 ? _j : this._driverInfo.browserVersion;
155
+ if (this._driverInfo.isMobile) {
156
+ (_k = (_z = this._driverInfo).platformName) !== null && _k !== void 0 ? _k : (_z.platformName = userAgentInfo.platformName);
157
+ (_l = (_0 = this._driverInfo).platformVersion) !== null && _l !== void 0 ? _l : (_0.platformVersion = userAgentInfo.platformVersion);
158
+ }
159
+ else {
160
+ this._driverInfo.platformName = (_m = userAgentInfo.platformName) !== null && _m !== void 0 ? _m : this._driverInfo.platformName;
161
+ this._driverInfo.platformVersion = (_o = userAgentInfo.platformVersion) !== null && _o !== void 0 ? _o : this._driverInfo.platformVersion;
162
+ }
163
+ }
164
+ (_p = (_1 = this._driverInfo).features) !== null && _p !== void 0 ? _p : (_1.features = {});
165
+ (_q = (_2 = this._driverInfo.features).allCookies) !== null && _q !== void 0 ? _q : (_2.allCookies = /chrome/i.test(this._driverInfo.browserName) && !this._driverInfo.isMobile);
166
+ }
167
+ else {
168
+ const barsHeight = await ((_s = (_r = this._spec).getBarsHeight) === null || _s === void 0 ? void 0 : _s.call(_r, this.target).catch(() => undefined));
169
+ const displaySize = await this.getDisplaySize();
170
+ // calculate status and navigation bars sizes
171
+ if (barsHeight) {
172
+ // when status bar is overlapping content on android it returns status bar height equal to viewport height
173
+ if (this.isAndroid && barsHeight.statusBarHeight / this.pixelRatio < displaySize.height) {
174
+ this._driverInfo.statusBarHeight = Math.max((_t = this._driverInfo.statusBarHeight) !== null && _t !== void 0 ? _t : 0, barsHeight.statusBarHeight);
175
+ }
176
+ this._driverInfo.navigationBarHeight = Math.max((_u = this._driverInfo.navigationBarHeight) !== null && _u !== void 0 ? _u : 0, barsHeight.navigationBarHeight);
177
+ }
178
+ if (this.isAndroid) {
179
+ this._driverInfo.statusBarHeight /= this.pixelRatio;
180
+ this._driverInfo.navigationBarHeight /= this.pixelRatio;
181
+ }
182
+ // calculate viewport size
183
+ if (!this._driverInfo.viewportSize) {
184
+ this._driverInfo.viewportSize = {
185
+ width: displaySize.width,
186
+ height: displaySize.height - this._driverInfo.statusBarHeight,
187
+ };
188
+ }
189
+ // calculate safe area
190
+ if (this.isIOS && !this._driverInfo.safeArea) {
191
+ this._driverInfo.safeArea = Object.assign({ x: 0, y: 0 }, displaySize);
192
+ const topElement = await this.element({ type: '-ios class chain', selector: '**/XCUIElementTypeNavigationBar' });
193
+ if (topElement) {
194
+ const topRegion = await this._spec.getElementRegion(this.target, topElement.target);
195
+ const topOffset = topRegion.y + topRegion.height;
196
+ this._driverInfo.safeArea.y = topOffset;
197
+ this._driverInfo.safeArea.height -= topOffset;
198
+ }
199
+ const bottomElement = await this.element({ type: '-ios class chain', selector: '**/XCUIElementTypeTabBar' });
200
+ if (bottomElement) {
201
+ const bottomRegion = await this._spec.getElementRegion(this.target, bottomElement.target);
202
+ const bottomOffset = bottomRegion.height;
203
+ this._driverInfo.safeArea.height -= bottomOffset;
204
+ }
205
+ }
206
+ // init helper lib
207
+ this._helper = this.isIOS
208
+ ? await helper_ios_1.HelperIOS.make({ spec: this._spec, driver: this, logger: this._logger })
209
+ : await helper_android_1.HelperAndroid.make({ spec: this._spec, driver: this, logger: this._logger });
210
+ }
211
+ if (this.isMobile) {
212
+ (_v = (_3 = this._driverInfo).orientation) !== null && _v !== void 0 ? _v : (_3.orientation = await this.getOrientation().catch(() => undefined));
213
+ }
214
+ this._logger.log('Combined driver info', this._driverInfo);
215
+ return this;
216
+ }
217
+ async refreshContexts() {
218
+ if (this.isNative)
219
+ return this.currentContext;
220
+ const spec = this._spec;
221
+ let currentContext = this.currentContext.target;
222
+ let contextInfo = await getContextInfo(currentContext);
223
+ const path = [];
224
+ if (spec.parentContext) {
225
+ while (!contextInfo.isRoot) {
226
+ currentContext = await spec.parentContext(currentContext);
227
+ const contextReference = await findContextReference(currentContext, contextInfo);
228
+ if (!contextReference)
229
+ throw new Error('Unable to find out the chain of frames');
230
+ path.unshift(contextReference);
231
+ contextInfo = await getContextInfo(currentContext);
232
+ }
233
+ }
234
+ else {
235
+ currentContext = await spec.mainContext(currentContext);
236
+ path.push(...(await findContextPath(currentContext, contextInfo)));
237
+ }
238
+ this._currentContext = this._mainContext;
239
+ return this.switchToChildContext(...path);
240
+ function transformSelector(selector) {
241
+ return specUtils.transformSelector(spec, selector, { isWeb: true });
242
+ }
243
+ async function getContextInfo(context) {
244
+ const [documentElement, selector, isRoot, isCORS] = await spec.executeScript(context, snippets.getContextInfo);
245
+ return { documentElement, selector, isRoot, isCORS };
246
+ }
247
+ async function getChildContextsInfo(context) {
248
+ const framesInfo = await spec.executeScript(context, snippets.getChildFramesInfo);
249
+ return framesInfo.map(([contextElement, isCORS]) => ({ contextElement, isCORS }));
250
+ }
251
+ async function isEqualElements(context, element1, element2) {
252
+ return spec.executeScript(context, snippets.isEqualElements, [element1, element2]).catch(() => false);
253
+ }
254
+ async function findContextReference(context, contextInfo) {
255
+ if (contextInfo.selector) {
256
+ const contextElement = await spec.findElement(context, transformSelector({ type: 'xpath', selector: contextInfo.selector }));
257
+ if (contextElement)
258
+ return contextElement;
259
+ }
260
+ for (const childContextInfo of await getChildContextsInfo(context)) {
261
+ if (childContextInfo.isCORS !== contextInfo.isCORS)
262
+ continue;
263
+ const childContext = await spec.childContext(context, childContextInfo.contextElement);
264
+ const contentDocument = await spec.findElement(childContext, transformSelector('html'));
265
+ const isWantedContext = await isEqualElements(childContext, contentDocument, contextInfo.documentElement);
266
+ await spec.parentContext(childContext);
267
+ if (isWantedContext)
268
+ return childContextInfo.contextElement;
269
+ }
270
+ }
271
+ async function findContextPath(context, contextInfo, contextPath = []) {
272
+ const contentDocument = await spec.findElement(context, transformSelector('html'));
273
+ if (await isEqualElements(context, contentDocument, contextInfo.documentElement)) {
274
+ return contextPath;
275
+ }
276
+ for (const childContextInfo of await getChildContextsInfo(context)) {
277
+ const childContext = await spec.childContext(context, childContextInfo.contextElement);
278
+ const possibleContextPath = [...contextPath, childContextInfo.contextElement];
279
+ const wantedContextPath = await findContextPath(childContext, contextInfo, possibleContextPath);
280
+ await spec.mainContext(context);
281
+ if (wantedContextPath)
282
+ return wantedContextPath;
283
+ for (const contextElement of contextPath) {
284
+ await spec.childContext(context, contextElement);
285
+ }
286
+ }
287
+ }
288
+ }
289
+ async switchTo(context) {
290
+ if (await this.currentContext.equals(context)) {
291
+ this._currentContext = context;
292
+ return;
293
+ }
294
+ const currentPath = this.currentContext.path;
295
+ const requiredPath = context.path;
296
+ let diffIndex = -1;
297
+ for (const [index, context] of requiredPath.entries()) {
298
+ if (currentPath[index] && !(await currentPath[index].equals(context))) {
299
+ diffIndex = index;
300
+ break;
301
+ }
302
+ }
303
+ if (diffIndex === 0) {
304
+ throw new Error('Cannot switch to the context, because it has different main context');
305
+ }
306
+ else if (diffIndex === -1) {
307
+ if (currentPath.length === requiredPath.length) {
308
+ // required and current paths are the same
309
+ return this.currentContext;
310
+ }
311
+ else if (requiredPath.length > currentPath.length) {
312
+ // current path is a sub-path of required path
313
+ return this.switchToChildContext(...requiredPath.slice(currentPath.length));
314
+ }
315
+ else if (currentPath.length - requiredPath.length <= requiredPath.length) {
316
+ // required path is a sub-path of current path
317
+ return this.switchToParentContext(currentPath.length - requiredPath.length);
318
+ }
319
+ else {
320
+ // required path is a sub-path of current path
321
+ await this.switchToMainContext();
322
+ return this.switchToChildContext(...requiredPath);
323
+ }
324
+ }
325
+ else if (currentPath.length - diffIndex <= diffIndex) {
326
+ // required path is different from current or they are partially intersected
327
+ // chose an optimal way to traverse from current context to target context
328
+ await this.switchToParentContext(currentPath.length - diffIndex);
329
+ return this.switchToChildContext(...requiredPath.slice(diffIndex));
330
+ }
331
+ else {
332
+ await this.switchToMainContext();
333
+ return this.switchToChildContext(...requiredPath);
334
+ }
335
+ }
336
+ async switchToMainContext() {
337
+ if (this.isNative)
338
+ throw new Error('Contexts are supported only for web drivers');
339
+ this._logger.log('Switching to the main context');
340
+ await this._spec.mainContext(this.currentContext.target);
341
+ return (this._currentContext = this._mainContext);
342
+ }
343
+ async switchToParentContext(elevation = 1) {
344
+ if (this.isNative)
345
+ throw new Error('Contexts are supported only for web drivers');
346
+ this._logger.log('Switching to a parent context with elevation:', elevation);
347
+ if (this.currentContext.path.length <= elevation) {
348
+ return this.switchToMainContext();
349
+ }
350
+ try {
351
+ while (elevation > 0) {
352
+ await this._spec.parentContext(this.currentContext.target);
353
+ this._currentContext = this._currentContext.parent;
354
+ elevation -= 1;
355
+ }
356
+ }
357
+ catch (err) {
358
+ this._logger.warn('Unable to switch to a parent context due to error', err);
359
+ this._logger.log('Applying workaround to switch to the parent frame');
360
+ const path = this.currentContext.path.slice(1, -elevation);
361
+ await this.switchToMainContext();
362
+ await this.switchToChildContext(...path);
363
+ elevation = 0;
364
+ }
365
+ return this.currentContext;
366
+ }
367
+ async switchToChildContext(...references) {
368
+ if (this.isNative)
369
+ throw new Error('Contexts are supported only for web drivers');
370
+ this._logger.log('Switching to a child context with depth:', references.length);
371
+ for (const reference of references) {
372
+ if (reference === this.mainContext)
373
+ continue;
374
+ const context = await this.currentContext.context(reference);
375
+ await context.focus();
376
+ }
377
+ return this.currentContext;
378
+ }
379
+ async normalizeRegion(region) {
380
+ if (this.isWeb || !utils.types.has(this._driverInfo, ['viewportSize', 'statusBarHeight']))
381
+ return region;
382
+ const scaledRegion = this.isAndroid ? utils.geometry.scale(region, 1 / this.pixelRatio) : region;
383
+ const safeRegion = this.isIOS ? utils.geometry.intersect(scaledRegion, this._driverInfo.safeArea) : scaledRegion;
384
+ const offsetRegion = utils.geometry.offsetNegative(safeRegion, { x: 0, y: this.statusBarHeight });
385
+ if (offsetRegion.y < 0) {
386
+ offsetRegion.height += offsetRegion.y;
387
+ offsetRegion.y = 0;
388
+ }
389
+ return offsetRegion;
390
+ }
391
+ async getRegionInViewport(context, region) {
392
+ await context.focus();
393
+ return context.getRegionInViewport(region);
394
+ }
395
+ async element(selector) {
396
+ return this.currentContext.element(selector);
397
+ }
398
+ async elements(selector) {
399
+ return this.currentContext.elements(selector);
400
+ }
401
+ async execute(script, arg) {
402
+ return this.currentContext.execute(script, arg);
403
+ }
404
+ async takeScreenshot() {
405
+ const image = await this._spec.takeScreenshot(this.target);
406
+ if (utils.types.isString(image)) {
407
+ return Buffer.from(image.replace(/[\r\n]+/g, ''), 'base64');
408
+ }
409
+ return image;
410
+ }
411
+ async getViewportSize() {
412
+ var _a;
413
+ let size;
414
+ if (this.isNative) {
415
+ this._logger.log('Extracting viewport size from native driver');
416
+ if ((_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.viewportSize) {
417
+ size = this._driverInfo.viewportSize;
418
+ }
419
+ else {
420
+ size = await this.getDisplaySize();
421
+ if (size.height > size.width) {
422
+ const orientation = await this.getOrientation();
423
+ if (orientation === 'landscape') {
424
+ size = { width: size.height, height: size.width };
425
+ }
426
+ }
427
+ }
428
+ size = utils.geometry.round(size);
429
+ }
430
+ else if (this._spec.getViewportSize) {
431
+ this._logger.log('Extracting viewport size from web driver using spec method');
432
+ size = await this._spec.getViewportSize(this.target);
433
+ }
434
+ else {
435
+ this._logger.log('Extracting viewport size from web driver using js snippet');
436
+ size = await this.mainContext.execute(snippets.getViewportSize);
437
+ }
438
+ this._logger.log('Extracted viewport size', size);
439
+ return size;
440
+ }
441
+ async setViewportSize(size) {
442
+ if (this.isMobile)
443
+ return;
444
+ if (this._spec.setViewportSize) {
445
+ this._logger.log('Setting viewport size to', size, 'using spec method');
446
+ await this._spec.setViewportSize(this.target, size);
447
+ return;
448
+ }
449
+ this._logger.log('Setting viewport size to', size, 'using workaround');
450
+ const requiredViewportSize = size;
451
+ let currentViewportSize = await this.getViewportSize();
452
+ if (utils.geometry.equals(currentViewportSize, requiredViewportSize))
453
+ return;
454
+ let currentWindowSize = await this._spec.getWindowSize(this.target);
455
+ this._logger.log('Extracted window size', currentWindowSize);
456
+ let attempt = 0;
457
+ while (attempt++ < 3) {
458
+ const requiredWindowSize = {
459
+ width: currentWindowSize.width + (requiredViewportSize.width - currentViewportSize.width),
460
+ height: currentWindowSize.height + (requiredViewportSize.height - currentViewportSize.height),
461
+ };
462
+ this._logger.log(`Attempt #${attempt} to set viewport size by setting window size to`, requiredWindowSize);
463
+ await this._spec.setWindowSize(this.target, requiredWindowSize);
464
+ const prevViewportSize = currentViewportSize;
465
+ currentViewportSize = await this.getViewportSize();
466
+ if (utils.geometry.equals(currentViewportSize, prevViewportSize)) {
467
+ currentViewportSize = await this.getViewportSize();
468
+ }
469
+ currentWindowSize = requiredWindowSize;
470
+ if (utils.geometry.equals(currentViewportSize, requiredViewportSize))
471
+ return;
472
+ this._logger.log(`Attempt #${attempt} to set viewport size failed. Current viewport:`, currentViewportSize);
473
+ }
474
+ throw new Error('Failed to set viewport size!');
475
+ }
476
+ async getDisplaySize() {
477
+ if (this.isWeb && !this.isMobile)
478
+ return;
479
+ const size = await this._spec.getWindowSize(this.target);
480
+ return this.isAndroid ? utils.geometry.scale(size, 1 / this.pixelRatio) : size;
481
+ }
482
+ async getOrientation() {
483
+ if (this.isWeb && !this.isMobile)
484
+ return;
485
+ const orientation = this._spec.getOrientation(this.target);
486
+ this._logger.log('Extracted device orientation:', orientation);
487
+ return orientation;
488
+ }
489
+ async getCookies() {
490
+ var _a, _b, _c;
491
+ if (this.isNative || !this.features.allCookies)
492
+ return [];
493
+ try {
494
+ return (_c = (await ((_b = (_a = this._spec).getCookies) === null || _b === void 0 ? void 0 : _b.call(_a, this.target)))) !== null && _c !== void 0 ? _c : [];
495
+ }
496
+ catch (error) {
497
+ this._driverInfo.features.allCookies = false;
498
+ throw error;
499
+ }
500
+ }
501
+ async getTitle() {
502
+ if (this.isNative)
503
+ return null;
504
+ const title = await this._spec.getTitle(this.target);
505
+ this._logger.log('Extracted title:', title);
506
+ return title;
507
+ }
508
+ async getUrl() {
509
+ if (this.isNative)
510
+ return null;
511
+ const url = this._spec.getUrl(this.target);
512
+ this._logger.log('Extracted url:', url);
513
+ return url;
514
+ }
515
+ async visit(url) {
516
+ await this._spec.visit(this.target, url);
517
+ }
518
+ }
519
+ exports.Driver = Driver;