@applitools/driver 1.11.36 → 1.11.38

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
@@ -29,19 +29,17 @@ const logger_1 = require("@applitools/logger");
29
29
  const helper_ios_1 = require("./helper-ios");
30
30
  const helper_android_1 = require("./helper-android");
31
31
  const user_agent_1 = require("./user-agent");
32
- const user_agent_data_1 = require("./user-agent-data");
33
32
  const capabilities_1 = require("./capabilities");
34
33
  const specUtils = __importStar(require("./spec-utils"));
35
34
  const utils = __importStar(require("@applitools/utils"));
36
35
  const snippets = require('@applitools/snippets');
37
- // eslint-disable-next-line
38
36
  class Driver {
39
37
  constructor(options) {
40
38
  var _a, _b, _c, _d, _e, _f, _g, _h, _j;
41
- this._driverInfo = {};
42
39
  this._state = {};
43
40
  this._customConfig = {};
44
41
  this._customConfig = (_a = options.customConfig) !== null && _a !== void 0 ? _a : {};
42
+ this._guid = utils.general.guid();
45
43
  this._spec = options.spec;
46
44
  this._logger = (_c = (_b = options.logger) === null || _b === void 0 ? void 0 : _b.extend({ label: 'driver' })) !== null && _c !== void 0 ? _c : (0, logger_1.makeLogger)({ label: 'driver' });
47
45
  this._target = (_f = (_e = (_d = this._spec).transformDriver) === null || _e === void 0 ? void 0 : _e.call(_d, options.driver)) !== null && _f !== void 0 ? _f : options.driver;
@@ -59,279 +57,339 @@ class Driver {
59
57
  get target() {
60
58
  return this._target;
61
59
  }
60
+ get guid() {
61
+ return this._guid;
62
+ }
62
63
  get currentContext() {
63
64
  return this._currentContext;
64
65
  }
65
66
  get mainContext() {
66
67
  return this._mainContext;
67
68
  }
68
- get features() {
69
- var _a;
70
- return (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.features;
71
- }
72
- get deviceName() {
73
- var _a;
74
- return (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.deviceName;
75
- }
76
- get platformName() {
77
- var _a;
78
- return (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.platformName;
79
- }
80
- get platformVersion() {
81
- var _a;
82
- return (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.platformVersion;
83
- }
84
- get browserName() {
85
- var _a;
86
- return (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.browserName;
87
- }
88
- get browserVersion() {
89
- var _a;
90
- return (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.browserVersion;
91
- }
92
- get userAgent() {
93
- var _a;
94
- return (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.userAgent;
95
- }
96
- get orientation() {
97
- return this._driverInfo.orientation;
98
- }
99
- get pixelRatio() {
100
- var _a;
101
- return (_a = this._driverInfo.pixelRatio) !== null && _a !== void 0 ? _a : 1;
102
- }
103
- get viewportScale() {
104
- var _a;
105
- return (_a = this._driverInfo.viewportScale) !== null && _a !== void 0 ? _a : 1;
106
- }
107
- get statusBarSize() {
108
- var _a;
109
- return (_a = this._driverInfo.statusBarSize) !== null && _a !== void 0 ? _a : (this.isNative ? 0 : undefined);
110
- }
111
- get navigationBarSize() {
112
- var _a;
113
- return (_a = this._driverInfo.navigationBarSize) !== null && _a !== void 0 ? _a : (this.isNative ? 0 : undefined);
69
+ updateCurrentContext(context) {
70
+ this._currentContext = context;
114
71
  }
115
- get isNative() {
116
- var _a, _b;
117
- return (_b = (!this.isWebView && ((_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.isNative))) !== null && _b !== void 0 ? _b : false;
72
+ async refresh() {
73
+ this._driverInfo = undefined;
74
+ this._environment = undefined;
75
+ this._viewport = undefined;
76
+ this._features = undefined;
77
+ this._helper = undefined;
78
+ this._state = {};
79
+ const spec = this._spec;
80
+ let currentContext = this.currentContext.target;
81
+ let contextInfo;
82
+ try {
83
+ contextInfo = await getContextInfo(currentContext);
84
+ }
85
+ catch (err) {
86
+ return this;
87
+ }
88
+ const path = [];
89
+ if (spec.parentContext) {
90
+ while (!contextInfo.isRoot) {
91
+ currentContext = await spec.parentContext(currentContext);
92
+ const contextReference = await findContextReference(currentContext, contextInfo);
93
+ if (!contextReference)
94
+ throw new Error('Unable to find out the chain of frames');
95
+ path.unshift(contextReference);
96
+ contextInfo = await getContextInfo(currentContext);
97
+ }
98
+ }
99
+ else {
100
+ currentContext = await spec.mainContext(currentContext);
101
+ path.push(...(await findContextPath(currentContext, contextInfo)));
102
+ }
103
+ this._currentContext = this._mainContext;
104
+ await this.switchToChildContext(...path);
105
+ return this;
106
+ function transformSelector(selector) {
107
+ return specUtils.transformSelector(spec, selector, { isWeb: true });
108
+ }
109
+ async function getContextInfo(context) {
110
+ const [documentElement, selector, isRoot, isCORS] = await spec.executeScript(context, snippets.getContextInfo);
111
+ return { documentElement, selector, isRoot, isCORS };
112
+ }
113
+ async function getChildContextsInfo(context) {
114
+ const framesInfo = await spec.executeScript(context, snippets.getChildFramesInfo);
115
+ return framesInfo.map(([contextElement, isCORS]) => ({
116
+ contextElement,
117
+ isCORS,
118
+ }));
119
+ }
120
+ async function isEqualElements(context, element1, element2) {
121
+ return spec.executeScript(context, snippets.isEqualElements, [element1, element2]).catch(() => false);
122
+ }
123
+ async function findContextReference(context, contextInfo) {
124
+ if (contextInfo.selector) {
125
+ const contextElement = await spec.findElement(context, transformSelector({ type: 'xpath', selector: contextInfo.selector }));
126
+ if (contextElement)
127
+ return contextElement;
128
+ }
129
+ for (const childContextInfo of await getChildContextsInfo(context)) {
130
+ if (childContextInfo.isCORS !== contextInfo.isCORS)
131
+ continue;
132
+ const childContext = await spec.childContext(context, childContextInfo.contextElement);
133
+ const contentDocument = await spec.findElement(childContext, transformSelector('html'));
134
+ const isWantedContext = await isEqualElements(childContext, contentDocument, contextInfo.documentElement);
135
+ await spec.parentContext(childContext);
136
+ if (isWantedContext)
137
+ return childContextInfo.contextElement;
138
+ }
139
+ return null;
140
+ }
141
+ async function findContextPath(context, contextInfo, contextPath = []) {
142
+ const contentDocument = await spec.findElement(context, transformSelector('html'));
143
+ if (await isEqualElements(context, contentDocument, contextInfo.documentElement)) {
144
+ return contextPath;
145
+ }
146
+ for (const childContextInfo of await getChildContextsInfo(context)) {
147
+ const childContext = await spec.childContext(context, childContextInfo.contextElement);
148
+ const possibleContextPath = [...contextPath, childContextInfo.contextElement];
149
+ const wantedContextPath = await findContextPath(childContext, contextInfo, possibleContextPath);
150
+ await spec.mainContext(context);
151
+ if (wantedContextPath)
152
+ return wantedContextPath;
153
+ for (const contextElement of contextPath) {
154
+ await spec.childContext(context, contextElement);
155
+ }
156
+ }
157
+ }
118
158
  }
119
- get isWebView() {
159
+ async getDriverInfo({ force } = {}) {
120
160
  var _a, _b, _c;
121
- return (_c = (((_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.isNative) && ((_b = this._driverInfo) === null || _b === void 0 ? void 0 : _b.isWebView))) !== null && _c !== void 0 ? _c : false;
122
- }
123
- get isWeb() {
124
- return this.isWebView || !this.isNative;
125
- }
126
- get isEmulation() {
127
- var _a, _b;
128
- return (_b = (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.isEmulation) !== null && _b !== void 0 ? _b : false;
129
- }
130
- get isMobile() {
131
- var _a, _b;
132
- return (_b = (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.isMobile) !== null && _b !== void 0 ? _b : false;
133
- }
134
- get isIOS() {
135
- var _a, _b;
136
- return (_b = (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.isIOS) !== null && _b !== void 0 ? _b : (!!this.platformName && /iOS/i.test(this.platformName));
137
- }
138
- get isAndroid() {
139
- var _a, _b;
140
- return (_b = (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.isAndroid) !== null && _b !== void 0 ? _b : (!!this.platformName && /Android/i.test(this.platformName));
141
- }
142
- get isMac() {
143
- var _a, _b;
144
- return (_b = (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.isMac) !== null && _b !== void 0 ? _b : (!!this.platformName && /mac\s?OS/i.test(this.platformName));
145
- }
146
- get isWindows() {
147
- var _a, _b;
148
- return (_b = (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.isWindows) !== null && _b !== void 0 ? _b : (!!this.platformName && /Windows/i.test(this.platformName));
149
- }
150
- get isChromium() {
151
- var _a, _b;
152
- return ((_b = (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.isChromium) !== null && _b !== void 0 ? _b : (!!this.browserName &&
153
- (/(chrome)/i.test(this.browserName) || (/edge/i.test(this.browserName) && Number(this.browserVersion) > 44))));
154
- }
155
- get isIE() {
156
- return !!this.browserName && /(internet explorer|ie)/i.test(this.browserName);
157
- }
158
- get isEdgeLegacy() {
159
- return !!this.browserName && /edge/i.test(this.browserName) && Number(this.browserVersion) <= 44;
160
- }
161
- get isECClient() {
162
- var _a;
163
- return !!((_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.isECClient);
161
+ if (!this._driverInfo || force) {
162
+ this._driverInfo = (_c = (await ((_b = (_a = this._spec).getDriverInfo) === null || _b === void 0 ? void 0 : _b.call(_a, this.target)))) !== null && _c !== void 0 ? _c : {};
163
+ this._logger.log('Extracted driver info', this._driverInfo);
164
+ }
165
+ return this._driverInfo;
164
166
  }
165
- get isEC() {
166
- return this.isECClient || (!!this.remoteHostname && /exec-wus.applitools.com/.test(this.remoteHostname));
167
+ async getCapabilities({ force } = {}) {
168
+ var _a, _b, _c, _d, _e;
169
+ if (((_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.capabilities) === undefined || force) {
170
+ (_b = this._driverInfo) !== null && _b !== void 0 ? _b : (this._driverInfo = {});
171
+ this._driverInfo.capabilities = (_e = (await ((_d = (_c = this._spec).getCapabilities) === null || _d === void 0 ? void 0 : _d.call(_c, this.target)))) !== null && _e !== void 0 ? _e : null;
172
+ this._logger.log('Extracted driver capabilities', this._driverInfo.capabilities);
173
+ }
174
+ return this._driverInfo.capabilities;
167
175
  }
168
- get sessionId() {
169
- var _a;
170
- return (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.sessionId;
176
+ async getUserAgent({ force } = {}) {
177
+ var _a, _b, _c, _d, _e;
178
+ var _f;
179
+ if (((_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.userAgent) === undefined || force) {
180
+ (_b = this._driverInfo) !== null && _b !== void 0 ? _b : (this._driverInfo = {});
181
+ (_c = (_f = this._driverInfo).userAgent) !== null && _c !== void 0 ? _c : (_f.userAgent = (_d = (await this.currentContext.executePoll(snippets.getUserAgent))) !== null && _d !== void 0 ? _d : null);
182
+ this._logger.log('Extracted user agent', this._driverInfo.userAgent);
183
+ }
184
+ return (_e = this._driverInfo.userAgent) !== null && _e !== void 0 ? _e : null;
171
185
  }
172
- get remoteHostname() {
186
+ async getUserAgentLegacy({ force } = {}) {
173
187
  var _a;
174
- return (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.remoteHostname;
175
- }
176
- updateCurrentContext(context) {
177
- this._currentContext = context;
178
- }
179
- async init() {
180
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18;
181
- var _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33;
182
- // NOTE: this is here because saucelabs does not provide right capabilities for the first call
183
- await ((_b = (_a = this._spec).getCapabilities) === null || _b === void 0 ? void 0 : _b.call(_a, this.target));
184
- const capabilities = await ((_d = (_c = this._spec).getCapabilities) === null || _d === void 0 ? void 0 : _d.call(_c, this.target));
185
- this._logger.log('Driver capabilities', capabilities);
186
- const capabilitiesInfo = capabilities && (0, capabilities_1.parseCapabilities)(capabilities);
187
- const driverInfo = await ((_f = (_e = this._spec).getDriverInfo) === null || _f === void 0 ? void 0 : _f.call(_e, this.target));
188
- this._driverInfo = { ...capabilitiesInfo, ...driverInfo };
189
- (_g = (_19 = this._driverInfo).remoteHostname) !== null && _g !== void 0 ? _g : (_19.remoteHostname = (_k = (_j = (_h = this._spec).extractHostName) === null || _j === void 0 ? void 0 : _j.call(_h, this.target)) !== null && _k !== void 0 ? _k : undefined);
190
- if (this.isMobile) {
191
- this._driverInfo.orientation =
192
- (_l = (await this.getOrientation().catch(() => undefined))) !== null && _l !== void 0 ? _l : this._driverInfo.orientation;
193
- const world = await this.getCurrentWorld();
194
- if (world) {
195
- const [home] = (await this.getWorlds());
196
- this._driverInfo.isWebView = world !== home;
197
- }
198
- }
199
- if (this.isWeb) {
200
- const browserInfo = await this.currentContext.executePoll(snippets.getBrowserInfo);
201
- (_m = (_20 = this._driverInfo).userAgent) !== null && _m !== void 0 ? _m : (_20.userAgent = browserInfo.userAgent);
202
- (_o = (_21 = this._driverInfo).pixelRatio) !== null && _o !== void 0 ? _o : (_21.pixelRatio = browserInfo.pixelRatio);
203
- (_p = (_22 = this._driverInfo).viewportScale) !== null && _p !== void 0 ? _p : (_22.viewportScale = browserInfo.viewportScale);
204
- if (browserInfo.userAgentData && this.isChromium) {
205
- if (this.isWindows && Number.parseInt(this.browserVersion) >= 107) {
206
- this._driverInfo.platformVersion = (_q = browserInfo.platformVersion) !== null && _q !== void 0 ? _q : this._driverInfo.platformVersion;
207
- }
208
- else if (this.isMac && Number.parseInt(this.browserVersion) >= 90) {
209
- this._driverInfo.platformVersion = (_r = browserInfo.platformVersion) !== null && _r !== void 0 ? _r : this._driverInfo.platformVersion;
188
+ const userAgent = await this.getUserAgent({ force });
189
+ return utils.types.isObject(userAgent) ? (_a = userAgent === null || userAgent === void 0 ? void 0 : userAgent.legacy) !== null && _a !== void 0 ? _a : null : userAgent;
190
+ }
191
+ async getEnvironment() {
192
+ var _a, _b, _c, _d;
193
+ var _e;
194
+ if (!this._environment) {
195
+ const driverInfo = await this.getDriverInfo();
196
+ this._environment = { ...driverInfo.environment };
197
+ const capabilities = await this.getCapabilities();
198
+ const capabilitiesEnvironment = capabilities ? (0, capabilities_1.extractCapabilitiesEnvironment)(capabilities) : null;
199
+ this._logger.log('Extracted capabilities environment', capabilitiesEnvironment);
200
+ this._environment = { ...this._environment, ...capabilitiesEnvironment };
201
+ if (this._environment.isMobile && !this._environment.browserName) {
202
+ const world = await this.getCurrentWorld();
203
+ if (!!(world === null || world === void 0 ? void 0 : world.includes('WEBVIEW'))) {
204
+ this._environment.isNative = true;
205
+ this._environment.isWeb = true;
210
206
  }
211
207
  }
212
- if (this._driverInfo.userAgent) {
213
- const userAgentInfo = (0, user_agent_1.parseUserAgent)(this._driverInfo.userAgent);
214
- const userAgentDataInfo = browserInfo.userAgentData && (0, user_agent_data_1.parseUserAgentData)(browserInfo.userAgentData);
215
- this._driverInfo.browserName =
216
- (_t = (_s = userAgentInfo.browserName) !== null && _s !== void 0 ? _s : userAgentDataInfo === null || userAgentDataInfo === void 0 ? void 0 : userAgentDataInfo.browserName) !== null && _t !== void 0 ? _t : this._driverInfo.browserName;
217
- this._driverInfo.browserVersion =
218
- (_v = (_u = userAgentInfo.browserVersion) !== null && _u !== void 0 ? _u : userAgentDataInfo === null || userAgentDataInfo === void 0 ? void 0 : userAgentDataInfo.browserVersion) !== null && _v !== void 0 ? _v : this._driverInfo.browserVersion;
219
- (_w = (_23 = this._driverInfo).isMobile) !== null && _w !== void 0 ? _w : (_23.isMobile = userAgentDataInfo === null || userAgentDataInfo === void 0 ? void 0 : userAgentDataInfo.isMobile);
220
- (_x = (_24 = this._driverInfo).isChromium) !== null && _x !== void 0 ? _x : (_24.isChromium = userAgentDataInfo === null || userAgentDataInfo === void 0 ? void 0 : userAgentDataInfo.isChromium);
221
- if (this._driverInfo.isMobile) {
222
- (_y = (_25 = this._driverInfo).platformName) !== null && _y !== void 0 ? _y : (_25.platformName = (_z = userAgentDataInfo === null || userAgentDataInfo === void 0 ? void 0 : userAgentDataInfo.platformName) !== null && _z !== void 0 ? _z : userAgentInfo.platformName);
223
- (_0 = (_26 = this._driverInfo).platformVersion) !== null && _0 !== void 0 ? _0 : (_26.platformVersion = (_1 = userAgentDataInfo === null || userAgentDataInfo === void 0 ? void 0 : userAgentDataInfo.platformVersion) !== null && _1 !== void 0 ? _1 : userAgentInfo.platformVersion);
224
- }
225
- else {
226
- this._driverInfo.platformName =
227
- (_3 = (_2 = userAgentDataInfo === null || userAgentDataInfo === void 0 ? void 0 : userAgentDataInfo.platformName) !== null && _2 !== void 0 ? _2 : userAgentInfo.platformName) !== null && _3 !== void 0 ? _3 : this._driverInfo.platformName;
228
- this._driverInfo.platformVersion =
229
- (_5 = (_4 = userAgentDataInfo === null || userAgentDataInfo === void 0 ? void 0 : userAgentDataInfo.platformVersion) !== null && _4 !== void 0 ? _4 : userAgentInfo.platformVersion) !== null && _5 !== void 0 ? _5 : this._driverInfo.platformVersion;
230
- }
208
+ (_a = (_e = this._environment).isWeb) !== null && _a !== void 0 ? _a : (_e.isWeb = !this._environment.isNative);
209
+ if (this._environment.isWeb) {
210
+ const userAgent = await this.getUserAgent();
211
+ const userAgentEnvironment = userAgent ? (0, user_agent_1.extractUserAgentEnvironment)(userAgent) : null;
212
+ this._logger.log('Extracted user agent environment', userAgentEnvironment);
213
+ this._environment = {
214
+ ...this._environment,
215
+ ...userAgentEnvironment,
216
+ // NOTE: not really necessary, but some user agents for mobile devices (iPads) may return a wrong platform info
217
+ ...(this._environment.isMobile
218
+ ? {
219
+ platformName: (_b = this._environment.platformName) !== null && _b !== void 0 ? _b : userAgentEnvironment === null || userAgentEnvironment === void 0 ? void 0 : userAgentEnvironment.platformName,
220
+ platformVersion: (_c = this._environment.platformVersion) !== null && _c !== void 0 ? _c : userAgentEnvironment === null || userAgentEnvironment === void 0 ? void 0 : userAgentEnvironment.platformVersion,
221
+ }
222
+ : {}),
223
+ };
231
224
  }
232
- if (!this.isMobile && (this.isAndroid || this.isIOS)) {
233
- this._driverInfo.isMobile = true;
234
- this._driverInfo.isEmulation = this._driverInfo.isChrome;
225
+ if (this._environment.browserName) {
226
+ this._environment.isIE = /(internet explorer|ie)/i.test(this._environment.browserName);
227
+ this._environment.isEdgeLegacy =
228
+ /edge/i.test(this._environment.browserName) && Number(this._environment.browserVersion) <= 44;
229
+ this._environment.isEdge =
230
+ /edge/i.test(this._environment.browserName) && Number(this._environment.browserVersion) > 44;
231
+ this._environment.isChrome = /chrome/i.test(this._environment.browserName);
232
+ this._environment.isChromium = this._environment.isChrome || this._environment.isEdge;
235
233
  }
236
- (_6 = (_27 = this._driverInfo).features) !== null && _6 !== void 0 ? _6 : (_27.features = {});
237
- (_7 = (_28 = this._driverInfo.features).allCookies) !== null && _7 !== void 0 ? _7 : (_28.allCookies = this._driverInfo.isChrome ||
238
- (!!this._driverInfo.browserName && /chrome/i.test(this._driverInfo.browserName) && !this._driverInfo.isMobile));
239
- }
240
- else {
241
- // this value always excludes the height of the navigation bar, and sometimes it also excludes the height of the status bar
242
- let windowSize = await this._spec.getWindowSize(this.target);
243
- (_8 = (_29 = this._driverInfo).displaySize) !== null && _8 !== void 0 ? _8 : (_29.displaySize = windowSize);
244
- if (((_9 = this.orientation) === null || _9 === void 0 ? void 0 : _9.startsWith('landscape')) &&
245
- this._driverInfo.displaySize.height > this._driverInfo.displaySize.width) {
246
- this._driverInfo.displaySize = {
247
- width: this._driverInfo.displaySize.height,
248
- height: this._driverInfo.displaySize.width,
249
- };
234
+ if (this._environment.platformName) {
235
+ this._environment.isWindows = /Windows/i.test(this._environment.platformName);
236
+ this._environment.isMac = /mac\s?OS/i.test(this._environment.platformName);
237
+ this._environment.isAndroid = /Android/i.test(this._environment.platformName);
238
+ this._environment.isIOS = /iOS/i.test(this._environment.platformName);
250
239
  }
251
- if (this.isAndroid) {
252
- // bar sizes could be extracted only on android
253
- const systemBars = await ((_11 = (_10 = this._spec).getSystemBars) === null || _11 === void 0 ? void 0 : _11.call(_10, this.target).catch(() => null));
254
- const { statusBar, navigationBar } = systemBars !== null && systemBars !== void 0 ? systemBars : {};
255
- if (statusBar === null || statusBar === void 0 ? void 0 : statusBar.visible) {
256
- this._logger.log('Driver status bar', statusBar);
257
- const statusBarSize = statusBar.height;
258
- // when status bar is overlapping content on android it returns status bar height equal to display height
259
- if (statusBarSize < this._driverInfo.displaySize.height) {
260
- this._driverInfo.statusBarSize = Math.max((_12 = this._driverInfo.statusBarSize) !== null && _12 !== void 0 ? _12 : 0, statusBarSize);
261
- }
240
+ if (!this._environment.isMobile &&
241
+ this._environment.isWeb &&
242
+ (this._environment.isAndroid || this._environment.isIOS)) {
243
+ this._environment.isMobile = true;
244
+ this._environment.isEmulation = this._environment.isChromium;
245
+ }
246
+ this._environment.isEC =
247
+ this._environment.isECClient || /exec-wus.applitools.com/.test((_d = (await this.getDriverUrl())) !== null && _d !== void 0 ? _d : '');
248
+ this._logger.log('Extracted environment', this._environment);
249
+ }
250
+ return this._environment;
251
+ }
252
+ async getViewport() {
253
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
254
+ var _t, _u, _v, _w, _x, _y, _z, _0, _1;
255
+ if (!this._viewport) {
256
+ const environment = await this.getEnvironment();
257
+ const driverInfo = await this.getDriverInfo();
258
+ this._viewport = { ...driverInfo.viewport };
259
+ if (environment.isMobile) {
260
+ if (!this._viewport.orientation) {
261
+ const orientation = await this.getOrientation();
262
+ if (orientation)
263
+ this._viewport.orientation = orientation;
262
264
  }
263
- if (navigationBar === null || navigationBar === void 0 ? void 0 : navigationBar.visible) {
264
- this._logger.log('Driver navigation size', navigationBar);
265
- // if navigation bar is placed on the right side is screen the the orientation is landscape-secondary
266
- if (navigationBar.x > 0)
267
- this._driverInfo.orientation = 'landscape-secondary';
268
- // navigation bar size could be its height or width depending on screen orientation
269
- const navigationBarSize = navigationBar[((_13 = this.orientation) === null || _13 === void 0 ? void 0 : _13.startsWith('landscape')) ? 'width' : 'height'];
270
- // when navigation bar is invisible on android it returns navigation bar size equal to display size
271
- if (navigationBarSize <
272
- this._driverInfo.displaySize[((_14 = this.orientation) === null || _14 === void 0 ? void 0 : _14.startsWith('landscape')) ? 'width' : 'height']) {
273
- this._driverInfo.navigationBarSize = Math.max((_15 = this._driverInfo.navigationBarSize) !== null && _15 !== void 0 ? _15 : 0, navigationBarSize);
265
+ }
266
+ if (environment.isNative) {
267
+ const capabilities = await this.getCapabilities();
268
+ const capabilitiesViewport = capabilities ? (0, capabilities_1.extractCapabilitiesViewport)(capabilities) : null;
269
+ this._logger.log('Extracted capabilities viewport', capabilitiesViewport);
270
+ this._viewport = { ...capabilitiesViewport, ...this._viewport };
271
+ (_a = (_t = this._viewport).pixelRatio) !== null && _a !== void 0 ? _a : (_t.pixelRatio = 1);
272
+ // this value always excludes the height of the navigation bar, and sometimes it also excludes the height of the status bar
273
+ let windowSize = await this._spec.getWindowSize(this.target);
274
+ (_b = (_u = this._viewport).displaySize) !== null && _b !== void 0 ? _b : (_u.displaySize = windowSize);
275
+ if (((_c = this._viewport.orientation) === null || _c === void 0 ? void 0 : _c.startsWith('landscape')) &&
276
+ this._viewport.displaySize.height > this._viewport.displaySize.width) {
277
+ this._viewport.displaySize = utils.geometry.rotate(this._viewport.displaySize, 90);
278
+ }
279
+ if (environment.isAndroid) {
280
+ // bar sizes could be extracted only on android
281
+ const { statusBar, navigationBar } = (_f = (await ((_e = (_d = this._spec).getSystemBars) === null || _e === void 0 ? void 0 : _e.call(_d, this.target).catch(() => undefined)))) !== null && _f !== void 0 ? _f : {};
282
+ if (statusBar === null || statusBar === void 0 ? void 0 : statusBar.visible) {
283
+ this._logger.log('Driver status bar', statusBar);
284
+ const statusBarSize = statusBar.height;
285
+ // when status bar is overlapping content on android it returns status bar height equal to display height
286
+ if (statusBarSize < this._viewport.displaySize.height) {
287
+ this._viewport.statusBarSize = Math.max((_g = this._viewport.statusBarSize) !== null && _g !== void 0 ? _g : 0, statusBarSize);
288
+ }
274
289
  }
275
- else {
276
- this._driverInfo.navigationBarSize = 0;
290
+ if (navigationBar === null || navigationBar === void 0 ? void 0 : navigationBar.visible) {
291
+ this._logger.log('Driver navigation size', navigationBar);
292
+ // if navigation bar is placed on the right side is screen the the orientation is landscape-secondary
293
+ if (navigationBar.x > 0)
294
+ this._viewport.orientation = 'landscape-secondary';
295
+ // navigation bar size could be its height or width depending on screen orientation
296
+ const navigationBarSize = navigationBar[((_h = this._viewport.orientation) === null || _h === void 0 ? void 0 : _h.startsWith('landscape')) ? 'width' : 'height'];
297
+ // when navigation bar is invisible on android it returns navigation bar size equal to display size
298
+ if (navigationBarSize <
299
+ this._viewport.displaySize[((_j = this._viewport.orientation) === null || _j === void 0 ? void 0 : _j.startsWith('landscape')) ? 'width' : 'height']) {
300
+ this._viewport.navigationBarSize = Math.max((_k = this._viewport.navigationBarSize) !== null && _k !== void 0 ? _k : 0, navigationBarSize);
301
+ }
302
+ else {
303
+ this._viewport.navigationBarSize = 0;
304
+ }
277
305
  }
306
+ // bar sizes have to be scaled on android
307
+ (_v = this._viewport).statusBarSize && (_v.statusBarSize = this._viewport.statusBarSize / this._viewport.pixelRatio);
308
+ (_w = this._viewport).navigationBarSize && (_w.navigationBarSize = this._viewport.navigationBarSize / this._viewport.pixelRatio);
309
+ windowSize = utils.geometry.scale(windowSize, 1 / this._viewport.pixelRatio);
310
+ (_x = this._viewport).displaySize && (_x.displaySize = utils.geometry.scale(this._viewport.displaySize, 1 / this._viewport.pixelRatio));
278
311
  }
279
- // bar sizes have to be scaled on android
280
- (_30 = this._driverInfo).statusBarSize && (_30.statusBarSize = this._driverInfo.statusBarSize / this.pixelRatio);
281
- (_31 = this._driverInfo).navigationBarSize && (_31.navigationBarSize = this._driverInfo.navigationBarSize / this.pixelRatio);
282
- windowSize = utils.geometry.scale(windowSize, 1 / this.pixelRatio);
283
- (_32 = this._driverInfo).displaySize && (_32.displaySize = utils.geometry.scale(this._driverInfo.displaySize, 1 / this.pixelRatio));
284
- }
285
- if (this.isIOS) {
286
- if ((_16 = this.orientation) === null || _16 === void 0 ? void 0 : _16.startsWith('landscape'))
287
- this._driverInfo.statusBarSize = 0;
288
- }
289
- // calculate viewport location
290
- (_17 = (_33 = this._driverInfo).viewportLocation) !== null && _17 !== void 0 ? _17 : (_33.viewportLocation = {
291
- x: this.orientation === 'landscape' ? this.navigationBarSize : 0,
292
- y: this.statusBarSize,
293
- });
294
- // calculate viewport size
295
- if (!this._driverInfo.viewportSize) {
296
- this._driverInfo.viewportSize = { ...this._driverInfo.displaySize };
297
- this._driverInfo.viewportSize.height -= this.statusBarSize;
298
- if (this.isAndroid) {
299
- this._driverInfo.viewportSize[((_18 = this.orientation) === null || _18 === void 0 ? void 0 : _18.startsWith('landscape')) ? 'width' : 'height'] -=
300
- this.navigationBarSize;
312
+ if (environment.isIOS) {
313
+ if ((_l = this._viewport.orientation) === null || _l === void 0 ? void 0 : _l.startsWith('landscape'))
314
+ this._viewport.statusBarSize = 0;
301
315
  }
302
- }
303
- // calculate safe area
304
- if (this.isIOS && !this._driverInfo.safeArea) {
305
- this._driverInfo.safeArea = { x: 0, y: 0, ...this._driverInfo.displaySize };
306
- const topElement = await this.element({
307
- type: '-ios class chain',
308
- selector: '**/XCUIElementTypeNavigationBar',
316
+ (_m = (_y = this._viewport).statusBarSize) !== null && _m !== void 0 ? _m : (_y.statusBarSize = 0);
317
+ // calculate viewport location
318
+ (_o = (_z = this._viewport).viewportLocation) !== null && _o !== void 0 ? _o : (_z.viewportLocation = {
319
+ x: this._viewport.orientation === 'landscape' ? (_p = this._viewport.navigationBarSize) !== null && _p !== void 0 ? _p : 0 : 0,
320
+ y: this._viewport.statusBarSize,
309
321
  });
310
- if (topElement) {
311
- const topRegion = await this._spec.getElementRegion(this.target, topElement.target);
312
- const topOffset = topRegion.y + topRegion.height;
313
- this._driverInfo.safeArea.y = topOffset;
314
- this._driverInfo.safeArea.height -= topOffset;
322
+ // calculate viewport size
323
+ if (!this._viewport.viewportSize) {
324
+ this._viewport.viewportSize = { ...this._viewport.displaySize };
325
+ this._viewport.viewportSize.height -= this._viewport.statusBarSize;
326
+ if (environment.isAndroid) {
327
+ this._viewport.viewportSize[((_q = this._viewport.orientation) === null || _q === void 0 ? void 0 : _q.startsWith('landscape')) ? 'width' : 'height'] -=
328
+ this._viewport.navigationBarSize;
329
+ }
315
330
  }
316
- const bottomElement = await this.element({
317
- type: '-ios class chain',
318
- selector: '**/XCUIElementTypeTabBar',
319
- });
320
- if (bottomElement) {
321
- const bottomRegion = await this._spec.getElementRegion(this.target, bottomElement.target);
322
- const bottomOffset = bottomRegion.height;
323
- this._driverInfo.safeArea.height -= bottomOffset;
331
+ // calculate safe area
332
+ if (!environment.isWeb && environment.isIOS && !this._viewport.safeArea) {
333
+ this._viewport.safeArea = { x: 0, y: 0, ...this._viewport.displaySize };
334
+ const topElement = await this.element({
335
+ type: '-ios class chain',
336
+ selector: '**/XCUIElementTypeNavigationBar',
337
+ });
338
+ if (topElement) {
339
+ const topRegion = await this._spec.getElementRegion(this.target, topElement.target);
340
+ const topOffset = topRegion.y + topRegion.height;
341
+ this._viewport.safeArea.y = topOffset;
342
+ this._viewport.safeArea.height -= topOffset;
343
+ }
344
+ const bottomElement = await this.element({
345
+ type: '-ios class chain',
346
+ selector: '**/XCUIElementTypeTabBar',
347
+ });
348
+ if (bottomElement) {
349
+ const bottomRegion = await this._spec.getElementRegion(this.target, bottomElement.target);
350
+ const bottomOffset = bottomRegion.height;
351
+ this._viewport.safeArea.height -= bottomOffset;
352
+ }
324
353
  }
325
354
  }
355
+ if (environment.isWeb) {
356
+ const browserViewport = await this.execute(snippets.getViewport);
357
+ this._viewport = { ...browserViewport, ...this._viewport };
358
+ }
359
+ (_r = (_0 = this._viewport).pixelRatio) !== null && _r !== void 0 ? _r : (_0.pixelRatio = 1);
360
+ (_s = (_1 = this._viewport).viewportScale) !== null && _s !== void 0 ? _s : (_1.viewportScale = 1);
361
+ this._logger.log('Extracted viewport', this._viewport);
326
362
  }
327
- this._logger.log('Combined driver info', this._driverInfo);
328
- return this;
363
+ return this._viewport;
364
+ }
365
+ async getFeatures() {
366
+ var _a;
367
+ var _b;
368
+ if (!this._features) {
369
+ const driverInfo = await this.getDriverInfo();
370
+ this._features = { ...driverInfo.features };
371
+ const environment = await this.getEnvironment();
372
+ (_a = (_b = this._features).allCookies) !== null && _a !== void 0 ? _a : (_b.allCookies = environment.isChromium || !environment.isMobile);
373
+ this._logger.log('Extracted driver features', this._features);
374
+ }
375
+ return this._features;
376
+ }
377
+ async getSessionId() {
378
+ var _a;
379
+ const driverInfo = await this.getDriverInfo();
380
+ return (_a = driverInfo.sessionId) !== null && _a !== void 0 ? _a : null;
381
+ }
382
+ async getDriverUrl() {
383
+ var _a;
384
+ const driverInfo = await this.getDriverInfo();
385
+ return (_a = driverInfo.remoteHostname) !== null && _a !== void 0 ? _a : null;
329
386
  }
330
387
  async getHelper() {
331
388
  var _a, _b, _c;
332
389
  if (this._helper === undefined) {
333
- this._logger.log(`Extracting helper for ${this.isIOS ? 'ios' : 'android'}`);
334
- this._helper = this.isIOS
390
+ const environment = await this.getEnvironment();
391
+ this._logger.log(`Extracting helper for ${environment.isIOS ? 'ios' : 'android'}`);
392
+ this._helper = environment.isIOS
335
393
  ? await helper_ios_1.HelperIOS.make({ spec: this._spec, driver: this, logger: this._logger })
336
394
  : await helper_android_1.HelperAndroid.make({ spec: this._spec, driver: this, logger: this._logger });
337
395
  this._logger.log(`Extracted helper of type ${(_a = this._helper) === null || _a === void 0 ? void 0 : _a.name}`);
@@ -342,12 +400,15 @@ class Driver {
342
400
  async extractBrokerUrl() {
343
401
  var _a;
344
402
  var _b;
345
- if (!this.isNative)
403
+ const environment = await this.getEnvironment();
404
+ if (!environment.isNative)
346
405
  return null;
347
406
  this._logger.log('Broker url extraction is started');
348
- (_a = (_b = this._state).nmlElement) !== null && _a !== void 0 ? _a : (_b.nmlElement = await this.element({ type: 'accessibility id', selector: 'Applitools_View' }));
349
- if (!this._state.nmlElement)
407
+ (_a = (_b = this._state).nmlElement) !== null && _a !== void 0 ? _a : (_b.nmlElement = await this.waitFor({ type: 'accessibility id', selector: 'Applitools_View' }, { timeout: 10000 }));
408
+ if (!this._state.nmlElement) {
409
+ this._logger.log('Broker url extraction is failed due to absence of nml element');
350
410
  return null;
411
+ }
351
412
  try {
352
413
  let result;
353
414
  do {
@@ -367,53 +428,15 @@ class Driver {
367
428
  return this.extractBrokerUrl();
368
429
  }
369
430
  }
370
- // About the concept of a "World":
371
- //
372
- // Since "context" is an overloaded term from frames, we have decided to use
373
- // the concept of a "world" when switching between mobile app contexts (e.g., native and webview(s))
374
- //
375
- // Notes:
376
- // - two new functions need to be added to a spec driver for this to work (`getCurrentWorld` and `switchWorld`)
377
- // - you can see a reference implementation of this in spec-driver-webdriverio
378
- // - if a world id is provided it will be used for switching
379
- // - if a world id is not provided, the first non-native world will be used
380
- // (regardless of which world the driver is currently switched into)
381
- // - before switching, the current world context is stored so it can switched back to later
382
- // (with the `restoreState` option)
383
- // - the native app world can be switched to (with the `goHome` option)
384
- async switchWorld(options) {
431
+ async getSessionMetadata() {
385
432
  var _a, _b;
386
- if ((options === null || options === void 0 ? void 0 : options.restoreState) && !this._state.world)
387
- return;
388
- if (!this._spec.getCurrentWorld || !this._spec.switchWorld) {
389
- this._logger.warn('world switching not implemented in the spec driver, skipping');
390
- return;
391
- }
392
- this._logger.log('switchWorld called with', options ? options : 'no options');
393
- const current = (await this.getCurrentWorld());
394
- if (!this._state.world) {
395
- this._logger.log('storing current world id for future restoration', current);
396
- this._state.world = current;
397
- }
398
- let world;
399
- if (options === null || options === void 0 ? void 0 : options.id)
400
- world = options.id;
401
- else if (options === null || options === void 0 ? void 0 : options.restoreState)
402
- world = this._state.world;
403
- else {
404
- const [home, next] = (await this.getWorlds());
405
- if (options === null || options === void 0 ? void 0 : options.goHome)
406
- world = home;
407
- else
408
- world = next;
409
- }
410
- this._logger.log('switching world with', world);
411
433
  try {
412
- await ((_b = (_a = this._spec).switchWorld) === null || _b === void 0 ? void 0 : _b.call(_a, this.target, world));
413
- await this.init();
434
+ const metadata = await ((_b = (_a = this._spec).getSessionMetadata) === null || _b === void 0 ? void 0 : _b.call(_a, this.target));
435
+ this._logger.log('Extracted session metadata', metadata);
436
+ return metadata;
414
437
  }
415
- catch (error) {
416
- throw new Error(`Unable to switch worlds, the original error was: ${error.message}`);
438
+ catch (err) {
439
+ this._logger.warn('Failed to extract session metadata due to the error', err);
417
440
  }
418
441
  }
419
442
  async getWorlds() {
@@ -422,7 +445,7 @@ class Driver {
422
445
  this._logger.log('Extracting worlds');
423
446
  try {
424
447
  let worlds = [];
425
- for (let attempt = 0; worlds.length <= 1 && attempt < 5; ++attempt) {
448
+ for (let attempt = 0; worlds.length <= 1 && attempt < 3; ++attempt) {
426
449
  if (attempt > 0)
427
450
  await utils.general.sleep(500);
428
451
  worlds = await this._spec.getWorlds(this.target);
@@ -436,12 +459,11 @@ class Driver {
436
459
  }
437
460
  }
438
461
  async getCurrentWorld() {
439
- var _a, _b;
440
462
  if (!this._spec.getCurrentWorld)
441
463
  return null;
442
464
  try {
443
465
  this._logger.log('Extracting current world');
444
- const current = await ((_b = (_a = this._spec).getCurrentWorld) === null || _b === void 0 ? void 0 : _b.call(_a, this.target));
466
+ const current = await this._spec.getCurrentWorld(this.target);
445
467
  this._logger.log('Current world was extracted', current);
446
468
  return current;
447
469
  }
@@ -450,85 +472,20 @@ class Driver {
450
472
  return null;
451
473
  }
452
474
  }
453
- async getSessionMetadata() {
454
- var _a, _b;
455
- if (this.isECClient)
456
- return await ((_b = (_a = this._spec).getSessionMetadata) === null || _b === void 0 ? void 0 : _b.call(_a, this.target));
457
- }
458
- async refreshContexts() {
459
- if (this.isNative)
460
- return this.currentContext;
461
- const spec = this._spec;
462
- let currentContext = this.currentContext.target;
463
- let contextInfo = await getContextInfo(currentContext);
464
- const path = [];
465
- if (spec.parentContext) {
466
- while (!contextInfo.isRoot) {
467
- currentContext = await spec.parentContext(currentContext);
468
- const contextReference = await findContextReference(currentContext, contextInfo);
469
- if (!contextReference)
470
- throw new Error('Unable to find out the chain of frames');
471
- path.unshift(contextReference);
472
- contextInfo = await getContextInfo(currentContext);
473
- }
474
- }
475
- else {
476
- currentContext = await spec.mainContext(currentContext);
477
- path.push(...(await findContextPath(currentContext, contextInfo)));
478
- }
479
- this._currentContext = this._mainContext;
480
- return this.switchToChildContext(...path);
481
- function transformSelector(selector) {
482
- return specUtils.transformSelector(spec, selector, { isWeb: true });
483
- }
484
- async function getContextInfo(context) {
485
- const [documentElement, selector, isRoot, isCORS] = await spec.executeScript(context, snippets.getContextInfo);
486
- return { documentElement, selector, isRoot, isCORS };
487
- }
488
- async function getChildContextsInfo(context) {
489
- const framesInfo = await spec.executeScript(context, snippets.getChildFramesInfo);
490
- return framesInfo.map(([contextElement, isCORS]) => ({
491
- contextElement,
492
- isCORS,
493
- }));
494
- }
495
- async function isEqualElements(context, element1, element2) {
496
- return spec.executeScript(context, snippets.isEqualElements, [element1, element2]).catch(() => false);
475
+ async switchWorld(name) {
476
+ name !== null && name !== void 0 ? name : (name = 'NATIVE_APP');
477
+ this._logger.log('Switching world to', name);
478
+ if (!this._spec.switchWorld) {
479
+ this._logger.error('Unable to switch world due to missed implementation');
480
+ throw new Error('Unable to switch world due to missed implementation');
497
481
  }
498
- async function findContextReference(context, contextInfo) {
499
- if (contextInfo.selector) {
500
- const contextElement = await spec.findElement(context, transformSelector({ type: 'xpath', selector: contextInfo.selector }));
501
- if (contextElement)
502
- return contextElement;
503
- }
504
- for (const childContextInfo of await getChildContextsInfo(context)) {
505
- if (childContextInfo.isCORS !== contextInfo.isCORS)
506
- continue;
507
- const childContext = await spec.childContext(context, childContextInfo.contextElement);
508
- const contentDocument = await spec.findElement(childContext, transformSelector('html'));
509
- const isWantedContext = await isEqualElements(childContext, contentDocument, contextInfo.documentElement);
510
- await spec.parentContext(childContext);
511
- if (isWantedContext)
512
- return childContextInfo.contextElement;
513
- }
514
- return null;
482
+ try {
483
+ await this._spec.switchWorld(this.target, name);
484
+ this.refresh();
515
485
  }
516
- async function findContextPath(context, contextInfo, contextPath = []) {
517
- const contentDocument = await spec.findElement(context, transformSelector('html'));
518
- if (await isEqualElements(context, contentDocument, contextInfo.documentElement)) {
519
- return contextPath;
520
- }
521
- for (const childContextInfo of await getChildContextsInfo(context)) {
522
- const childContext = await spec.childContext(context, childContextInfo.contextElement);
523
- const possibleContextPath = [...contextPath, childContextInfo.contextElement];
524
- const wantedContextPath = await findContextPath(childContext, contextInfo, possibleContextPath);
525
- await spec.mainContext(context);
526
- if (wantedContextPath)
527
- return wantedContextPath;
528
- for (const contextElement of contextPath) {
529
- await spec.childContext(context, contextElement);
530
- }
531
- }
486
+ catch (error) {
487
+ this._logger.error('Unable to switch world due to the error', error);
488
+ throw new Error(`Unable to switch world, the original error was: ${error.message}`);
532
489
  }
533
490
  }
534
491
  async switchTo(context) {
@@ -578,14 +535,16 @@ class Driver {
578
535
  }
579
536
  }
580
537
  async switchToMainContext() {
581
- if (this.isNative)
538
+ const environment = await this.getEnvironment();
539
+ if (environment.isNative)
582
540
  throw new Error('Contexts are supported only for web drivers');
583
541
  this._logger.log('Switching to the main context');
584
542
  await this._spec.mainContext(this.currentContext.target);
585
543
  return (this._currentContext = this._mainContext);
586
544
  }
587
545
  async switchToParentContext(elevation = 1) {
588
- if (this.isNative)
546
+ const environment = await this.getEnvironment();
547
+ if (environment.isNative)
589
548
  throw new Error('Contexts are supported only for web drivers');
590
549
  this._logger.log('Switching to a parent context with elevation:', elevation);
591
550
  if (this.currentContext.path.length <= elevation) {
@@ -609,7 +568,8 @@ class Driver {
609
568
  return this.currentContext;
610
569
  }
611
570
  async switchToChildContext(...references) {
612
- if (this.isNative)
571
+ const environment = await this.getEnvironment();
572
+ if (environment.isNative)
613
573
  throw new Error('Contexts are supported only for web drivers');
614
574
  this._logger.log('Switching to a child context with depth:', references.length);
615
575
  for (const reference of references) {
@@ -621,19 +581,19 @@ class Driver {
621
581
  return this.currentContext;
622
582
  }
623
583
  async normalizeRegion(region) {
624
- if (this.isWeb)
584
+ const environment = await this.getEnvironment();
585
+ if (environment.isWeb)
625
586
  return region;
587
+ const viewport = await this.getViewport();
626
588
  let normalizedRegion = region;
627
- if (this.isAndroid) {
628
- normalizedRegion = utils.geometry.scale(normalizedRegion, 1 / this.pixelRatio);
589
+ if (environment.isAndroid) {
590
+ normalizedRegion = utils.geometry.scale(normalizedRegion, 1 / viewport.pixelRatio);
629
591
  }
630
- if (this.isIOS &&
631
- this._driverInfo.safeArea &&
632
- utils.geometry.isIntersected(normalizedRegion, this._driverInfo.safeArea)) {
633
- normalizedRegion = utils.geometry.intersect(normalizedRegion, this._driverInfo.safeArea);
592
+ if (environment.isIOS && viewport.safeArea && utils.geometry.isIntersected(normalizedRegion, viewport.safeArea)) {
593
+ normalizedRegion = utils.geometry.intersect(normalizedRegion, viewport.safeArea);
634
594
  }
635
- if (this._driverInfo.viewportLocation) {
636
- normalizedRegion = utils.geometry.offsetNegative(normalizedRegion, this._driverInfo.viewportLocation);
595
+ if (viewport.viewportLocation) {
596
+ normalizedRegion = utils.geometry.offsetNegative(normalizedRegion, viewport.viewportLocation);
637
597
  }
638
598
  if (normalizedRegion.y < 0) {
639
599
  normalizedRegion.height += normalizedRegion.y;
@@ -645,18 +605,6 @@ class Driver {
645
605
  await context.focus();
646
606
  return context.getRegionInViewport(region);
647
607
  }
648
- async element(selector) {
649
- return this.currentContext.element(selector);
650
- }
651
- async elements(selector) {
652
- return this.currentContext.elements(selector);
653
- }
654
- async waitFor(selector, options) {
655
- return this.currentContext.waitFor(selector, options);
656
- }
657
- async execute(script, arg) {
658
- return this.currentContext.execute(script, arg);
659
- }
660
608
  async takeScreenshot() {
661
609
  const image = await this._spec.takeScreenshot(this.target);
662
610
  if (utils.types.isString(image)) {
@@ -664,25 +612,20 @@ class Driver {
664
612
  }
665
613
  return image;
666
614
  }
667
- async getViewportRegion() {
668
- var _a, _b;
669
- return {
670
- ...((_b = (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.viewportLocation) !== null && _b !== void 0 ? _b : { x: 0, y: 0 }),
671
- ...(await this.getViewportSize()),
672
- };
673
- }
674
615
  async getViewportSize() {
675
616
  var _a;
617
+ const environment = await this.getEnvironment();
676
618
  let size;
677
- if (this.isNative) {
678
- if ((_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.viewportSize) {
619
+ if (environment.isNative && !environment.isWeb) {
620
+ const viewport = await this.getViewport();
621
+ if (viewport.viewportSize) {
679
622
  this._logger.log('Extracting viewport size from native driver using cached value');
680
- size = this._driverInfo.viewportSize;
623
+ size = viewport.viewportSize;
681
624
  }
682
625
  else {
683
626
  this._logger.log('Extracting viewport size from native driver');
684
- size = await this.getDisplaySize();
685
- size.height -= this.statusBarSize;
627
+ size = (await this.getDisplaySize());
628
+ size.height -= (_a = viewport.statusBarSize) !== null && _a !== void 0 ? _a : 0;
686
629
  }
687
630
  this._logger.log(`Rounding viewport size using`, this._customConfig.useCeilForViewportSize ? 'ceil' : 'round');
688
631
  if (this._customConfig.useCeilForViewportSize) {
@@ -698,13 +641,15 @@ class Driver {
698
641
  }
699
642
  else {
700
643
  this._logger.log('Extracting viewport size from web driver using js snippet');
701
- size = await this.mainContext.execute(snippets.getViewportSize);
644
+ const viewport = await this.mainContext.execute(snippets.getViewport);
645
+ size = viewport.viewportSize;
702
646
  }
703
647
  this._logger.log('Extracted viewport size', size);
704
648
  return size;
705
649
  }
706
650
  async setViewportSize(size) {
707
- if (this.isMobile)
651
+ const environment = await this.getEnvironment();
652
+ if (environment.isMobile)
708
653
  return;
709
654
  if (this._spec.setViewportSize) {
710
655
  this._logger.log('Setting viewport size to', size, 'using spec method');
@@ -739,30 +684,34 @@ class Driver {
739
684
  throw new Error('Failed to set viewport size!');
740
685
  }
741
686
  async getDisplaySize() {
742
- var _a, _b;
743
- if (this.isWeb && !this.isMobile)
687
+ var _a;
688
+ const environment = await this.getEnvironment();
689
+ if (!environment.isNative)
744
690
  return undefined;
745
- if ((_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.displaySize) {
746
- this._logger.log('Extracting display size from native driver using cached value');
747
- return this._driverInfo.displaySize;
691
+ const viewport = await this.getViewport();
692
+ if (viewport === null || viewport === void 0 ? void 0 : viewport.displaySize) {
693
+ this._logger.log('Extracting display size from native driver using cached value', viewport.displaySize);
694
+ return viewport.displaySize;
748
695
  }
749
696
  let size = await this._spec.getWindowSize(this.target);
750
- if (((_b = (await this.getOrientation())) === null || _b === void 0 ? void 0 : _b.startsWith('landscape')) && size.height > size.width) {
697
+ if (((_a = (await this.getOrientation())) === null || _a === void 0 ? void 0 : _a.startsWith('landscape')) && size.height > size.width) {
751
698
  size = { width: size.height, height: size.width };
752
699
  }
753
- const normalizedSize = this.isAndroid ? utils.geometry.scale(size, 1 / this.pixelRatio) : size;
700
+ const normalizedSize = environment.isAndroid ? utils.geometry.scale(size, 1 / viewport.pixelRatio) : size;
754
701
  this._logger.log('Extracted and normalized display size:', normalizedSize);
755
702
  return normalizedSize;
756
703
  }
757
704
  async getOrientation() {
758
- if (this.isWeb && !this.isMobile)
705
+ var _a, _b;
706
+ const environment = await this.getEnvironment();
707
+ if (!environment.isMobile)
759
708
  return undefined;
760
- if (this.isAndroid) {
709
+ if (environment.isAndroid) {
761
710
  this._logger.log('Extracting device orientation using adb command on android');
762
711
  const rotation = await this.execute('mobile:shell', {
763
712
  command: "dumpsys window | grep 'mCurrentRotation' | cut -d = -f2",
764
713
  })
765
- .then(r => { var _a; return (_a = r === null || r === void 0 ? void 0 : r.trim) === null || _a === void 0 ? void 0 : _a.call(r); })
714
+ .then(rotation => { var _a; return (_a = rotation === null || rotation === void 0 ? void 0 : rotation.trim) === null || _a === void 0 ? void 0 : _a.call(rotation); })
766
715
  .catch(() => null);
767
716
  if (rotation) {
768
717
  let orientation = undefined;
@@ -779,44 +728,63 @@ class Driver {
779
728
  }
780
729
  }
781
730
  this._logger.log('Extracting device orientation');
782
- const orientation = await this._spec.getOrientation(this.target);
731
+ const orientation = await ((_b = (_a = this._spec).getOrientation) === null || _b === void 0 ? void 0 : _b.call(_a, this.target));
783
732
  this._logger.log('Extracted device orientation:', orientation);
784
733
  return orientation;
785
734
  }
786
735
  async setOrientation(orientation) {
787
- if (this.isWeb && !this.isMobile)
736
+ const environment = await this.getEnvironment();
737
+ if (!environment.isMobile)
788
738
  return undefined;
789
739
  this._logger.log('Set device orientation:', orientation);
790
740
  await this._spec.setOrientation(this.target, orientation);
791
741
  }
792
742
  async getCookies() {
793
- var _a, _b, _c, _d, _e;
794
- var _f;
795
- if (this.isNative || !((_a = this.features) === null || _a === void 0 ? void 0 : _a.allCookies))
743
+ var _a, _b, _c;
744
+ const environment = await this.getEnvironment();
745
+ const features = await this.getFeatures();
746
+ if (environment.isNative || !features.allCookies)
796
747
  return [];
797
748
  try {
798
- return (_d = (await ((_c = (_b = this._spec).getCookies) === null || _c === void 0 ? void 0 : _c.call(_b, this.target)))) !== null && _d !== void 0 ? _d : [];
749
+ const cookies = await ((_b = (_a = this._spec).getCookies) === null || _b === void 0 ? void 0 : _b.call(_a, this.target));
750
+ this._logger.log('Extracted driver cookies', cookies);
751
+ return cookies !== null && cookies !== void 0 ? cookies : [];
799
752
  }
800
753
  catch (error) {
801
- (_e = (_f = this._driverInfo).features) !== null && _e !== void 0 ? _e : (_f.features = {});
802
- this._driverInfo.features.allCookies = false;
754
+ this._logger.error('Error while extracting driver cookies', error);
755
+ (_c = this._features) !== null && _c !== void 0 ? _c : (this._features = {});
756
+ this._features.allCookies = false;
803
757
  throw error;
804
758
  }
805
759
  }
806
760
  async getTitle() {
807
- if (this.isNative)
761
+ const environment = await this.getEnvironment();
762
+ if (environment.isNative)
808
763
  return undefined;
809
764
  const title = await this._spec.getTitle(this.target);
810
765
  this._logger.log('Extracted title:', title);
811
766
  return title;
812
767
  }
813
768
  async getUrl() {
814
- if (this.isNative)
769
+ const environment = await this.getEnvironment();
770
+ if (environment.isNative)
815
771
  return undefined;
816
772
  const url = await this._spec.getUrl(this.target);
817
773
  this._logger.log('Extracted url:', url);
818
774
  return url;
819
775
  }
776
+ async element(selector) {
777
+ return this.currentContext.element(selector);
778
+ }
779
+ async elements(selector) {
780
+ return this.currentContext.elements(selector);
781
+ }
782
+ async waitFor(selector, options) {
783
+ return this.currentContext.waitFor(selector, options);
784
+ }
785
+ async execute(script, arg) {
786
+ return this.currentContext.execute(script, arg);
787
+ }
820
788
  async visit(url) {
821
789
  var _a, _b;
822
790
  await ((_b = (_a = this._spec).visit) === null || _b === void 0 ? void 0 : _b.call(_a, this.target, url));
@@ -829,8 +797,6 @@ function isDriver(driver, spec) {
829
797
  exports.isDriver = isDriver;
830
798
  async function makeDriver(options) {
831
799
  const driver = options.driver instanceof Driver ? options.driver : new Driver(options);
832
- await driver.init();
833
- await driver.refreshContexts();
834
- return driver;
800
+ return driver.refresh();
835
801
  }
836
802
  exports.makeDriver = makeDriver;