@applitools/driver 1.11.37 → 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,7 +400,8 @@ 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
407
  (_a = (_b = this._state).nmlElement) !== null && _a !== void 0 ? _a : (_b.nmlElement = await this.waitFor({ type: 'accessibility id', selector: 'Applitools_View' }, { timeout: 10000 }));
@@ -369,53 +428,15 @@ class Driver {
369
428
  return this.extractBrokerUrl();
370
429
  }
371
430
  }
372
- // About the concept of a "World":
373
- //
374
- // Since "context" is an overloaded term from frames, we have decided to use
375
- // the concept of a "world" when switching between mobile app contexts (e.g., native and webview(s))
376
- //
377
- // Notes:
378
- // - two new functions need to be added to a spec driver for this to work (`getCurrentWorld` and `switchWorld`)
379
- // - you can see a reference implementation of this in spec-driver-webdriverio
380
- // - if a world id is provided it will be used for switching
381
- // - if a world id is not provided, the first non-native world will be used
382
- // (regardless of which world the driver is currently switched into)
383
- // - before switching, the current world context is stored so it can switched back to later
384
- // (with the `restoreState` option)
385
- // - the native app world can be switched to (with the `goHome` option)
386
- async switchWorld(options) {
431
+ async getSessionMetadata() {
387
432
  var _a, _b;
388
- if ((options === null || options === void 0 ? void 0 : options.restoreState) && !this._state.world)
389
- return;
390
- if (!this._spec.getCurrentWorld || !this._spec.switchWorld) {
391
- this._logger.warn('world switching not implemented in the spec driver, skipping');
392
- return;
393
- }
394
- this._logger.log('switchWorld called with', options ? options : 'no options');
395
- const current = (await this.getCurrentWorld());
396
- if (!this._state.world) {
397
- this._logger.log('storing current world id for future restoration', current);
398
- this._state.world = current;
399
- }
400
- let world;
401
- if (options === null || options === void 0 ? void 0 : options.id)
402
- world = options.id;
403
- else if (options === null || options === void 0 ? void 0 : options.restoreState)
404
- world = this._state.world;
405
- else {
406
- const [home, next] = (await this.getWorlds());
407
- if (options === null || options === void 0 ? void 0 : options.goHome)
408
- world = home;
409
- else
410
- world = next;
411
- }
412
- this._logger.log('switching world with', world);
413
433
  try {
414
- await ((_b = (_a = this._spec).switchWorld) === null || _b === void 0 ? void 0 : _b.call(_a, this.target, world));
415
- 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;
416
437
  }
417
- catch (error) {
418
- 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);
419
440
  }
420
441
  }
421
442
  async getWorlds() {
@@ -424,7 +445,7 @@ class Driver {
424
445
  this._logger.log('Extracting worlds');
425
446
  try {
426
447
  let worlds = [];
427
- for (let attempt = 0; worlds.length <= 1 && attempt < 5; ++attempt) {
448
+ for (let attempt = 0; worlds.length <= 1 && attempt < 3; ++attempt) {
428
449
  if (attempt > 0)
429
450
  await utils.general.sleep(500);
430
451
  worlds = await this._spec.getWorlds(this.target);
@@ -438,12 +459,11 @@ class Driver {
438
459
  }
439
460
  }
440
461
  async getCurrentWorld() {
441
- var _a, _b;
442
462
  if (!this._spec.getCurrentWorld)
443
463
  return null;
444
464
  try {
445
465
  this._logger.log('Extracting current world');
446
- 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);
447
467
  this._logger.log('Current world was extracted', current);
448
468
  return current;
449
469
  }
@@ -452,85 +472,20 @@ class Driver {
452
472
  return null;
453
473
  }
454
474
  }
455
- async getSessionMetadata() {
456
- var _a, _b;
457
- if (this.isECClient)
458
- return await ((_b = (_a = this._spec).getSessionMetadata) === null || _b === void 0 ? void 0 : _b.call(_a, this.target));
459
- }
460
- async refreshContexts() {
461
- if (this.isNative)
462
- return this.currentContext;
463
- const spec = this._spec;
464
- let currentContext = this.currentContext.target;
465
- let contextInfo = await getContextInfo(currentContext);
466
- const path = [];
467
- if (spec.parentContext) {
468
- while (!contextInfo.isRoot) {
469
- currentContext = await spec.parentContext(currentContext);
470
- const contextReference = await findContextReference(currentContext, contextInfo);
471
- if (!contextReference)
472
- throw new Error('Unable to find out the chain of frames');
473
- path.unshift(contextReference);
474
- contextInfo = await getContextInfo(currentContext);
475
- }
476
- }
477
- else {
478
- currentContext = await spec.mainContext(currentContext);
479
- path.push(...(await findContextPath(currentContext, contextInfo)));
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');
480
481
  }
481
- this._currentContext = this._mainContext;
482
- return this.switchToChildContext(...path);
483
- function transformSelector(selector) {
484
- return specUtils.transformSelector(spec, selector, { isWeb: true });
485
- }
486
- async function getContextInfo(context) {
487
- const [documentElement, selector, isRoot, isCORS] = await spec.executeScript(context, snippets.getContextInfo);
488
- return { documentElement, selector, isRoot, isCORS };
489
- }
490
- async function getChildContextsInfo(context) {
491
- const framesInfo = await spec.executeScript(context, snippets.getChildFramesInfo);
492
- return framesInfo.map(([contextElement, isCORS]) => ({
493
- contextElement,
494
- isCORS,
495
- }));
496
- }
497
- async function isEqualElements(context, element1, element2) {
498
- return spec.executeScript(context, snippets.isEqualElements, [element1, element2]).catch(() => false);
499
- }
500
- async function findContextReference(context, contextInfo) {
501
- if (contextInfo.selector) {
502
- const contextElement = await spec.findElement(context, transformSelector({ type: 'xpath', selector: contextInfo.selector }));
503
- if (contextElement)
504
- return contextElement;
505
- }
506
- for (const childContextInfo of await getChildContextsInfo(context)) {
507
- if (childContextInfo.isCORS !== contextInfo.isCORS)
508
- continue;
509
- const childContext = await spec.childContext(context, childContextInfo.contextElement);
510
- const contentDocument = await spec.findElement(childContext, transformSelector('html'));
511
- const isWantedContext = await isEqualElements(childContext, contentDocument, contextInfo.documentElement);
512
- await spec.parentContext(childContext);
513
- if (isWantedContext)
514
- return childContextInfo.contextElement;
515
- }
516
- return null;
482
+ try {
483
+ await this._spec.switchWorld(this.target, name);
484
+ this.refresh();
517
485
  }
518
- async function findContextPath(context, contextInfo, contextPath = []) {
519
- const contentDocument = await spec.findElement(context, transformSelector('html'));
520
- if (await isEqualElements(context, contentDocument, contextInfo.documentElement)) {
521
- return contextPath;
522
- }
523
- for (const childContextInfo of await getChildContextsInfo(context)) {
524
- const childContext = await spec.childContext(context, childContextInfo.contextElement);
525
- const possibleContextPath = [...contextPath, childContextInfo.contextElement];
526
- const wantedContextPath = await findContextPath(childContext, contextInfo, possibleContextPath);
527
- await spec.mainContext(context);
528
- if (wantedContextPath)
529
- return wantedContextPath;
530
- for (const contextElement of contextPath) {
531
- await spec.childContext(context, contextElement);
532
- }
533
- }
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}`);
534
489
  }
535
490
  }
536
491
  async switchTo(context) {
@@ -580,14 +535,16 @@ class Driver {
580
535
  }
581
536
  }
582
537
  async switchToMainContext() {
583
- if (this.isNative)
538
+ const environment = await this.getEnvironment();
539
+ if (environment.isNative)
584
540
  throw new Error('Contexts are supported only for web drivers');
585
541
  this._logger.log('Switching to the main context');
586
542
  await this._spec.mainContext(this.currentContext.target);
587
543
  return (this._currentContext = this._mainContext);
588
544
  }
589
545
  async switchToParentContext(elevation = 1) {
590
- if (this.isNative)
546
+ const environment = await this.getEnvironment();
547
+ if (environment.isNative)
591
548
  throw new Error('Contexts are supported only for web drivers');
592
549
  this._logger.log('Switching to a parent context with elevation:', elevation);
593
550
  if (this.currentContext.path.length <= elevation) {
@@ -611,7 +568,8 @@ class Driver {
611
568
  return this.currentContext;
612
569
  }
613
570
  async switchToChildContext(...references) {
614
- if (this.isNative)
571
+ const environment = await this.getEnvironment();
572
+ if (environment.isNative)
615
573
  throw new Error('Contexts are supported only for web drivers');
616
574
  this._logger.log('Switching to a child context with depth:', references.length);
617
575
  for (const reference of references) {
@@ -623,19 +581,19 @@ class Driver {
623
581
  return this.currentContext;
624
582
  }
625
583
  async normalizeRegion(region) {
626
- if (this.isWeb)
584
+ const environment = await this.getEnvironment();
585
+ if (environment.isWeb)
627
586
  return region;
587
+ const viewport = await this.getViewport();
628
588
  let normalizedRegion = region;
629
- if (this.isAndroid) {
630
- normalizedRegion = utils.geometry.scale(normalizedRegion, 1 / this.pixelRatio);
589
+ if (environment.isAndroid) {
590
+ normalizedRegion = utils.geometry.scale(normalizedRegion, 1 / viewport.pixelRatio);
631
591
  }
632
- if (this.isIOS &&
633
- this._driverInfo.safeArea &&
634
- utils.geometry.isIntersected(normalizedRegion, this._driverInfo.safeArea)) {
635
- 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);
636
594
  }
637
- if (this._driverInfo.viewportLocation) {
638
- normalizedRegion = utils.geometry.offsetNegative(normalizedRegion, this._driverInfo.viewportLocation);
595
+ if (viewport.viewportLocation) {
596
+ normalizedRegion = utils.geometry.offsetNegative(normalizedRegion, viewport.viewportLocation);
639
597
  }
640
598
  if (normalizedRegion.y < 0) {
641
599
  normalizedRegion.height += normalizedRegion.y;
@@ -647,18 +605,6 @@ class Driver {
647
605
  await context.focus();
648
606
  return context.getRegionInViewport(region);
649
607
  }
650
- async element(selector) {
651
- return this.currentContext.element(selector);
652
- }
653
- async elements(selector) {
654
- return this.currentContext.elements(selector);
655
- }
656
- async waitFor(selector, options) {
657
- return this.currentContext.waitFor(selector, options);
658
- }
659
- async execute(script, arg) {
660
- return this.currentContext.execute(script, arg);
661
- }
662
608
  async takeScreenshot() {
663
609
  const image = await this._spec.takeScreenshot(this.target);
664
610
  if (utils.types.isString(image)) {
@@ -666,25 +612,20 @@ class Driver {
666
612
  }
667
613
  return image;
668
614
  }
669
- async getViewportRegion() {
670
- var _a, _b;
671
- return {
672
- ...((_b = (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.viewportLocation) !== null && _b !== void 0 ? _b : { x: 0, y: 0 }),
673
- ...(await this.getViewportSize()),
674
- };
675
- }
676
615
  async getViewportSize() {
677
616
  var _a;
617
+ const environment = await this.getEnvironment();
678
618
  let size;
679
- if (this.isNative) {
680
- 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) {
681
622
  this._logger.log('Extracting viewport size from native driver using cached value');
682
- size = this._driverInfo.viewportSize;
623
+ size = viewport.viewportSize;
683
624
  }
684
625
  else {
685
626
  this._logger.log('Extracting viewport size from native driver');
686
- size = await this.getDisplaySize();
687
- size.height -= this.statusBarSize;
627
+ size = (await this.getDisplaySize());
628
+ size.height -= (_a = viewport.statusBarSize) !== null && _a !== void 0 ? _a : 0;
688
629
  }
689
630
  this._logger.log(`Rounding viewport size using`, this._customConfig.useCeilForViewportSize ? 'ceil' : 'round');
690
631
  if (this._customConfig.useCeilForViewportSize) {
@@ -700,13 +641,15 @@ class Driver {
700
641
  }
701
642
  else {
702
643
  this._logger.log('Extracting viewport size from web driver using js snippet');
703
- size = await this.mainContext.execute(snippets.getViewportSize);
644
+ const viewport = await this.mainContext.execute(snippets.getViewport);
645
+ size = viewport.viewportSize;
704
646
  }
705
647
  this._logger.log('Extracted viewport size', size);
706
648
  return size;
707
649
  }
708
650
  async setViewportSize(size) {
709
- if (this.isMobile)
651
+ const environment = await this.getEnvironment();
652
+ if (environment.isMobile)
710
653
  return;
711
654
  if (this._spec.setViewportSize) {
712
655
  this._logger.log('Setting viewport size to', size, 'using spec method');
@@ -741,30 +684,34 @@ class Driver {
741
684
  throw new Error('Failed to set viewport size!');
742
685
  }
743
686
  async getDisplaySize() {
744
- var _a, _b;
745
- if (this.isWeb && !this.isMobile)
687
+ var _a;
688
+ const environment = await this.getEnvironment();
689
+ if (!environment.isNative)
746
690
  return undefined;
747
- if ((_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.displaySize) {
748
- this._logger.log('Extracting display size from native driver using cached value');
749
- 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;
750
695
  }
751
696
  let size = await this._spec.getWindowSize(this.target);
752
- 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) {
753
698
  size = { width: size.height, height: size.width };
754
699
  }
755
- 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;
756
701
  this._logger.log('Extracted and normalized display size:', normalizedSize);
757
702
  return normalizedSize;
758
703
  }
759
704
  async getOrientation() {
760
- if (this.isWeb && !this.isMobile)
705
+ var _a, _b;
706
+ const environment = await this.getEnvironment();
707
+ if (!environment.isMobile)
761
708
  return undefined;
762
- if (this.isAndroid) {
709
+ if (environment.isAndroid) {
763
710
  this._logger.log('Extracting device orientation using adb command on android');
764
711
  const rotation = await this.execute('mobile:shell', {
765
712
  command: "dumpsys window | grep 'mCurrentRotation' | cut -d = -f2",
766
713
  })
767
- .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); })
768
715
  .catch(() => null);
769
716
  if (rotation) {
770
717
  let orientation = undefined;
@@ -781,44 +728,63 @@ class Driver {
781
728
  }
782
729
  }
783
730
  this._logger.log('Extracting device orientation');
784
- 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));
785
732
  this._logger.log('Extracted device orientation:', orientation);
786
733
  return orientation;
787
734
  }
788
735
  async setOrientation(orientation) {
789
- if (this.isWeb && !this.isMobile)
736
+ const environment = await this.getEnvironment();
737
+ if (!environment.isMobile)
790
738
  return undefined;
791
739
  this._logger.log('Set device orientation:', orientation);
792
740
  await this._spec.setOrientation(this.target, orientation);
793
741
  }
794
742
  async getCookies() {
795
- var _a, _b, _c, _d, _e;
796
- var _f;
797
- 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)
798
747
  return [];
799
748
  try {
800
- 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 : [];
801
752
  }
802
753
  catch (error) {
803
- (_e = (_f = this._driverInfo).features) !== null && _e !== void 0 ? _e : (_f.features = {});
804
- 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;
805
757
  throw error;
806
758
  }
807
759
  }
808
760
  async getTitle() {
809
- if (this.isNative)
761
+ const environment = await this.getEnvironment();
762
+ if (environment.isNative)
810
763
  return undefined;
811
764
  const title = await this._spec.getTitle(this.target);
812
765
  this._logger.log('Extracted title:', title);
813
766
  return title;
814
767
  }
815
768
  async getUrl() {
816
- if (this.isNative)
769
+ const environment = await this.getEnvironment();
770
+ if (environment.isNative)
817
771
  return undefined;
818
772
  const url = await this._spec.getUrl(this.target);
819
773
  this._logger.log('Extracted url:', url);
820
774
  return url;
821
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
+ }
822
788
  async visit(url) {
823
789
  var _a, _b;
824
790
  await ((_b = (_a = this._spec).visit) === null || _b === void 0 ? void 0 : _b.call(_a, this.target, url));
@@ -831,8 +797,6 @@ function isDriver(driver, spec) {
831
797
  exports.isDriver = isDriver;
832
798
  async function makeDriver(options) {
833
799
  const driver = options.driver instanceof Driver ? options.driver : new Driver(options);
834
- await driver.init();
835
- await driver.refreshContexts();
836
- return driver;
800
+ return driver.refresh();
837
801
  }
838
802
  exports.makeDriver = makeDriver;