@applitools/driver 1.11.2 → 1.11.4

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/context.js CHANGED
@@ -104,6 +104,70 @@ class Context {
104
104
  get isRef() {
105
105
  return !this._target;
106
106
  }
107
+ async _findElements(selector, options = {}) {
108
+ await this.focus();
109
+ const { parent, all, wait } = options;
110
+ const transformedSelector = specUtils.transformSelector(this._spec, selector, this.driver);
111
+ let elements = [];
112
+ if (wait) {
113
+ if (this._spec.waitForSelector) {
114
+ const element = await this._spec.waitForSelector(this.target, specUtils.transformSelector(this._spec, selector, this.driver), parent, wait);
115
+ if (element)
116
+ elements = [element];
117
+ }
118
+ else {
119
+ let waiting = true;
120
+ const timeout = setTimeout(() => (waiting = false), wait.timeout);
121
+ while (waiting) {
122
+ const element = await this._spec.findElement(this.target, specUtils.transformSelector(this._spec, selector, this.driver), parent);
123
+ if (element) {
124
+ clearTimeout(timeout);
125
+ elements = [element];
126
+ }
127
+ await utils.general.sleep(wait.interval);
128
+ }
129
+ }
130
+ }
131
+ else if (all) {
132
+ elements = await this._spec.findElements(this.target, transformedSelector, parent);
133
+ }
134
+ else {
135
+ const element = await this._spec.findElement(this.target, transformedSelector, parent);
136
+ if (element)
137
+ elements = [element];
138
+ }
139
+ if (specUtils.isCommonSelector(this._spec, selector)) {
140
+ if (elements.length > 0) {
141
+ if (selector.child) {
142
+ elements = await elements.reduce((result, element) => {
143
+ return result.then(async (result) => {
144
+ return result.concat(await this._findElements(selector.child, { parent: element, all, wait }));
145
+ });
146
+ }, Promise.resolve([]));
147
+ }
148
+ else if (selector.shadow) {
149
+ elements = await elements.reduce((result, element) => {
150
+ return result.then(async (result) => {
151
+ const root = await this._spec.executeScript(this.target, snippets.getShadowRoot, [element]);
152
+ return result.concat(root ? await this._findElements(selector.shadow, { parent: root, all, wait }) : []);
153
+ });
154
+ }, Promise.resolve([]));
155
+ }
156
+ else if (selector.frame) {
157
+ elements = await elements.reduce((result, element) => {
158
+ return result.then(async (result) => {
159
+ const context = await this.context(element);
160
+ return result.concat(await context._findElements(selector.frame, { all, wait }));
161
+ });
162
+ }, Promise.resolve([]));
163
+ }
164
+ }
165
+ if (elements.length === 0 && selector.fallback) {
166
+ elements = await this._findElements(selector.fallback, parent);
167
+ }
168
+ }
169
+ return elements;
170
+ }
107
171
  async init() {
108
172
  if (this.isInitialized)
109
173
  return this;
@@ -201,62 +265,21 @@ class Context {
201
265
  });
202
266
  }
203
267
  }
204
- async root(selector) {
205
- var _a;
206
- await this.focus();
207
- const { contextSelectors, elementSelector } = specUtils.splitSelector(this._spec, selector);
208
- let context = this;
209
- for (const contextSelector of contextSelectors) {
210
- try {
211
- context = await context.context(contextSelector);
212
- await context.focus();
213
- }
214
- catch {
215
- return null;
216
- }
217
- }
218
- if ((_a = this.driver.features) === null || _a === void 0 ? void 0 : _a.shadowSelector)
219
- return { context, selector: elementSelector };
220
- let root = null;
221
- let element = null;
222
- let currentSelector = elementSelector;
223
- while (specUtils.isCommonSelector(this._spec, currentSelector) &&
224
- specUtils.isSelector(this._spec, currentSelector.shadow)) {
225
- element = await this._spec.findElement(this.target, specUtils.transformSelector(this._spec, currentSelector, this.driver), root);
226
- if (!element)
227
- return null;
228
- root = await this._spec.executeScript(this.target, snippets.getShadowRoot, [element]);
229
- if (!root)
230
- return null;
231
- currentSelector = currentSelector.shadow;
232
- }
233
- return {
234
- context,
235
- shadow: element && new element_1.Element({ spec: this._spec, context, element, logger: this._logger }),
236
- selector: currentSelector,
237
- };
238
- }
239
268
  async element(elementOrSelector) {
240
269
  if (this._spec.isElement(elementOrSelector)) {
241
270
  return new element_1.Element({ spec: this._spec, context: this, element: elementOrSelector, logger: this._logger });
242
271
  }
243
- else if (specUtils.isSelector(this._spec, elementOrSelector)) {
244
- if (this.isRef) {
245
- return new element_1.Element({ spec: this._spec, context: this, selector: elementOrSelector, logger: this._logger });
246
- }
247
- this._logger.log('Finding element by selector: ', elementOrSelector);
248
- const root = await this.root(elementOrSelector);
249
- if (!root)
250
- return null;
251
- const element = await this._spec.findElement(root.context.target, specUtils.transformSelector(this._spec, root.selector, this.driver), root.shadow && (await root.shadow.getShadowRoot()));
252
- // TODO root.selector is not a full selector from context root to an element, but selector inside a shadow
253
- return element
254
- ? new element_1.Element({ spec: this._spec, context: root.context, element, selector: root.selector, logger: this._logger })
255
- : null;
256
- }
257
- else {
272
+ else if (!specUtils.isSelector(this._spec, elementOrSelector)) {
258
273
  throw new TypeError('Cannot find element using argument of unknown type!');
259
274
  }
275
+ if (this.isRef) {
276
+ return new element_1.Element({ spec: this._spec, context: this, selector: elementOrSelector, logger: this._logger });
277
+ }
278
+ this._logger.log('Finding element by selector: ', elementOrSelector);
279
+ const [element] = await this._findElements(elementOrSelector, { all: false });
280
+ return element
281
+ ? new element_1.Element({ spec: this._spec, context: this, element, selector: elementOrSelector, logger: this._logger })
282
+ : null;
260
283
  }
261
284
  async elements(selectorOrElement) {
262
285
  if (specUtils.isSelector(this._spec, selectorOrElement)) {
@@ -264,17 +287,13 @@ class Context {
264
287
  return [new element_1.Element({ spec: this._spec, context: this, selector: selectorOrElement, logger: this._logger })];
265
288
  }
266
289
  this._logger.log('Finding elements by selector: ', selectorOrElement);
267
- const root = await this.root(selectorOrElement);
268
- if (!root)
269
- return [];
270
- const elements = await this._spec.findElements(root.context.target, specUtils.transformSelector(this._spec, root.selector, this.driver), root.shadow && (await root.shadow.getShadowRoot()));
290
+ const elements = await this._findElements(selectorOrElement, { all: true });
271
291
  return elements.map((element, index) => {
272
- // TODO root.selector is not a full selector from context root to an element, but selector inside a shadow
273
292
  return new element_1.Element({
274
293
  spec: this._spec,
275
- context: root.context,
294
+ context: this,
276
295
  element,
277
- selector: root.selector,
296
+ selector: selectorOrElement,
278
297
  index,
279
298
  logger: this._logger,
280
299
  });
@@ -288,34 +307,10 @@ class Context {
288
307
  }
289
308
  }
290
309
  async waitFor(selector, options) {
291
- var _a, _b;
292
- const root = await this.root(selector);
293
- if (!root)
294
- return null;
295
- options = { state: 'exist', timeout: 10000, interval: 500, ...options };
296
- if (this._spec.waitForSelector) {
297
- const element = await this._spec.waitForSelector(root.context.target, specUtils.transformSelector(this._spec, root.selector, this.driver), (_a = root.shadow) === null || _a === void 0 ? void 0 : _a.target, options);
298
- return element
299
- ? new element_1.Element({ spec: this._spec, context: root.context, element, selector: root.selector, logger: this._logger })
300
- : null;
301
- }
302
- let waiting = true;
303
- const timeout = setTimeout(() => (waiting = false), options.timeout);
304
- while (waiting) {
305
- const element = await this._spec.findElement(root.context.target, specUtils.transformSelector(this._spec, root.selector, this.driver), (_b = root.shadow) === null || _b === void 0 ? void 0 : _b.target);
306
- if (element) {
307
- clearTimeout(timeout);
308
- return new element_1.Element({
309
- spec: this._spec,
310
- context: root.context,
311
- element,
312
- selector: root.selector,
313
- logger: this._logger,
314
- });
315
- }
316
- await utils.general.sleep(options.interval);
317
- }
318
- return null;
310
+ const [element] = await this._findElements(selector, {
311
+ wait: { state: 'exist', timeout: 10000, interval: 500, ...options },
312
+ });
313
+ return element ? new element_1.Element({ spec: this._spec, context: this, element, selector, logger: this._logger }) : null;
319
314
  }
320
315
  async execute(script, arg) {
321
316
  await this.focus();
@@ -345,6 +340,49 @@ class Context {
345
340
  }
346
341
  }
347
342
  }
343
+ async executePoll(script, arg) {
344
+ this._logger.log('Executing poll script');
345
+ const { main: mainScript, poll: pollScript } = utils.types.isString(script) || utils.types.isFunction(script) ? { main: script, poll: script } : script;
346
+ const { main: mainArg, poll: pollArg, executionTimeout = 60000, pollTimeout = 1000, } = !utils.types.has(arg, ['main', 'poll']) ? { main: arg, poll: arg } : arg;
347
+ let isExecutionTimedOut = false;
348
+ const executionTimer = setTimeout(() => (isExecutionTimedOut = true), executionTimeout);
349
+ try {
350
+ let response = deserialize(await this.execute(mainScript, mainArg));
351
+ let chunks = '';
352
+ while (!isExecutionTimedOut) {
353
+ if (response.status === 'ERROR') {
354
+ throw new Error(`Error during execute poll script: '${response.error}'`);
355
+ }
356
+ else if (response.status === 'SUCCESS') {
357
+ return response.value;
358
+ }
359
+ else if (response.status === 'SUCCESS_CHUNKED') {
360
+ chunks += response.value;
361
+ if (response.done)
362
+ return deserialize(chunks);
363
+ }
364
+ else if (response.status === 'WIP') {
365
+ await utils.general.sleep(pollTimeout);
366
+ }
367
+ this._logger.log('Polling...');
368
+ response = deserialize(await this.execute(pollScript, pollArg));
369
+ }
370
+ throw new Error('Poll script execution is timed out');
371
+ }
372
+ finally {
373
+ clearTimeout(executionTimer);
374
+ }
375
+ function deserialize(json) {
376
+ try {
377
+ return JSON.parse(json);
378
+ }
379
+ catch (err) {
380
+ const firstChars = json.slice(0, 100);
381
+ const lastChars = json.slice(-100);
382
+ throw new Error(`Response is not a valid JSON string. length: ${json.length}, first 100 chars: "${firstChars}", last 100 chars: "${lastChars}". error: ${err}`);
383
+ }
384
+ }
385
+ }
348
386
  async getContextElement() {
349
387
  if (this.isMain)
350
388
  return null;
package/dist/driver.js CHANGED
@@ -29,10 +29,11 @@ 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");
32
33
  const capabilities_1 = require("./capabilities");
34
+ const snippets = __importStar(require("@applitools/snippets"));
33
35
  const utils = __importStar(require("@applitools/utils"));
34
36
  const specUtils = __importStar(require("./spec-utils"));
35
- const snippets = require('@applitools/snippets');
36
37
  // eslint-disable-next-line
37
38
  class Driver {
38
39
  constructor(options) {
@@ -135,12 +136,24 @@ class Driver {
135
136
  return (_b = (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.isMobile) !== null && _b !== void 0 ? _b : false;
136
137
  }
137
138
  get isIOS() {
138
- var _a;
139
- return ((_a = this.platformName) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'ios';
139
+ var _a, _b;
140
+ return (_b = (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.isIOS) !== null && _b !== void 0 ? _b : /iOS/i.test(this.platformName);
140
141
  }
141
142
  get isAndroid() {
142
- var _a;
143
- return ((_a = this.platformName) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'android';
143
+ var _a, _b;
144
+ return (_b = (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.isAndroid) !== null && _b !== void 0 ? _b : /Android/i.test(this.platformName);
145
+ }
146
+ get isMac() {
147
+ var _a, _b;
148
+ return (_b = (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.isMac) !== null && _b !== void 0 ? _b : /mac\s?OS/i.test(this.platformName);
149
+ }
150
+ get isWindows() {
151
+ var _a, _b;
152
+ return (_b = (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.isWindows) !== null && _b !== void 0 ? _b : /Windows/i.test(this.platformName);
153
+ }
154
+ get isChromium() {
155
+ var _a, _b;
156
+ return ((_b = (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.isChromium) !== null && _b !== void 0 ? _b : (/(chrome)/i.test(this.browserName) || (/edge/i.test(this.browserName) && Number(this.browserVersion) > 44)));
144
157
  }
145
158
  get isIE() {
146
159
  return /(internet explorer|ie)/i.test(this.browserName);
@@ -152,8 +165,8 @@ class Driver {
152
165
  this._currentContext = context;
153
166
  }
154
167
  async init() {
155
- 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;
156
- var _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18;
168
+ 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;
169
+ var _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34;
157
170
  // NOTE: this is here because saucelabs does not provide right capabilities for the first call
158
171
  await ((_b = (_a = this._spec).getCapabilities) === null || _b === void 0 ? void 0 : _b.call(_a, this.target));
159
172
  const capabilities = await ((_d = (_c = this._spec).getCapabilities) === null || _d === void 0 ? void 0 : _d.call(_c, this.target));
@@ -168,34 +181,54 @@ class Driver {
168
181
  this._driverInfo.isWebView = !!(world === null || world === void 0 ? void 0 : world.isWebView);
169
182
  }
170
183
  if (this.isWeb) {
171
- (_h = (_7 = this._driverInfo).pixelRatio) !== null && _h !== void 0 ? _h : (_7.pixelRatio = await this.execute(snippets.getPixelRatio));
172
- (_j = (_8 = this._driverInfo).viewportScale) !== null && _j !== void 0 ? _j : (_8.viewportScale = await this.execute(snippets.getViewportScale));
173
- (_k = (_9 = this._driverInfo).userAgent) !== null && _k !== void 0 ? _k : (_9.userAgent = await this.execute(snippets.getUserAgent));
184
+ const browserInfo = await this.currentContext.executePoll(snippets.getBrowserInfo);
185
+ (_h = (_19 = this._driverInfo).userAgent) !== null && _h !== void 0 ? _h : (_19.userAgent = browserInfo.userAgent);
186
+ (_j = (_20 = this._driverInfo).pixelRatio) !== null && _j !== void 0 ? _j : (_20.pixelRatio = browserInfo.pixelRatio);
187
+ (_k = (_21 = this._driverInfo).viewportScale) !== null && _k !== void 0 ? _k : (_21.viewportScale = browserInfo.viewportScale);
188
+ if (browserInfo.userAgentData) {
189
+ (_l = (_22 = this._driverInfo).isMobile) !== null && _l !== void 0 ? _l : (_22.isMobile = this._driverInfo.isMobile);
190
+ (_m = (_23 = this._driverInfo).isChromium) !== null && _m !== void 0 ? _m : (_23.isChromium = this._driverInfo.isChromium);
191
+ if (this.isChromium) {
192
+ if (this.isWindows && Number.parseInt(this.browserVersion) >= 107) {
193
+ this._driverInfo.platformVersion = (_o = browserInfo.platformVersion) !== null && _o !== void 0 ? _o : this._driverInfo.platformVersion;
194
+ }
195
+ else if (this.isMac && Number.parseInt(this.browserVersion) >= 90) {
196
+ this._driverInfo.platformVersion = (_p = browserInfo.platformVersion) !== null && _p !== void 0 ? _p : this._driverInfo.platformVersion;
197
+ }
198
+ }
199
+ }
174
200
  if (this._driverInfo.userAgent) {
175
201
  const userAgentInfo = (0, user_agent_1.parseUserAgent)(this._driverInfo.userAgent);
176
- this._driverInfo.browserName = (_l = userAgentInfo.browserName) !== null && _l !== void 0 ? _l : this._driverInfo.browserName;
177
- this._driverInfo.browserVersion = (_m = userAgentInfo.browserVersion) !== null && _m !== void 0 ? _m : this._driverInfo.browserVersion;
202
+ const userAgentDataInfo = browserInfo.userAgentData && (0, user_agent_data_1.parseUserAgentData)(browserInfo.userAgentData);
203
+ this._driverInfo.browserName =
204
+ (_r = (_q = userAgentInfo.browserName) !== null && _q !== void 0 ? _q : userAgentDataInfo.browserName) !== null && _r !== void 0 ? _r : this._driverInfo.browserName;
205
+ this._driverInfo.browserVersion =
206
+ (_t = (_s = userAgentInfo.browserVersion) !== null && _s !== void 0 ? _s : userAgentDataInfo.browserVersion) !== null && _t !== void 0 ? _t : this._driverInfo.browserVersion;
207
+ (_u = (_24 = this._driverInfo).isMobile) !== null && _u !== void 0 ? _u : (_24.isMobile = userAgentDataInfo === null || userAgentDataInfo === void 0 ? void 0 : userAgentDataInfo.isMobile);
208
+ (_v = (_25 = this._driverInfo).isChromium) !== null && _v !== void 0 ? _v : (_25.isChromium = userAgentDataInfo === null || userAgentDataInfo === void 0 ? void 0 : userAgentDataInfo.isChromium);
178
209
  if (this._driverInfo.isMobile) {
179
- (_o = (_10 = this._driverInfo).platformName) !== null && _o !== void 0 ? _o : (_10.platformName = userAgentInfo.platformName);
180
- (_p = (_11 = this._driverInfo).platformVersion) !== null && _p !== void 0 ? _p : (_11.platformVersion = userAgentInfo.platformVersion);
210
+ (_w = (_26 = this._driverInfo).platformName) !== null && _w !== void 0 ? _w : (_26.platformName = (_x = userAgentDataInfo === null || userAgentDataInfo === void 0 ? void 0 : userAgentDataInfo.platformName) !== null && _x !== void 0 ? _x : userAgentInfo.platformName);
211
+ (_y = (_27 = this._driverInfo).platformVersion) !== null && _y !== void 0 ? _y : (_27.platformVersion = (_z = userAgentDataInfo === null || userAgentDataInfo === void 0 ? void 0 : userAgentDataInfo.platformVersion) !== null && _z !== void 0 ? _z : userAgentInfo.platformVersion);
181
212
  }
182
213
  else {
183
- this._driverInfo.platformName = (_q = userAgentInfo.platformName) !== null && _q !== void 0 ? _q : this._driverInfo.platformName;
184
- this._driverInfo.platformVersion = (_r = userAgentInfo.platformVersion) !== null && _r !== void 0 ? _r : this._driverInfo.platformVersion;
214
+ this._driverInfo.platformName =
215
+ (_1 = (_0 = userAgentDataInfo === null || userAgentDataInfo === void 0 ? void 0 : userAgentDataInfo.platformName) !== null && _0 !== void 0 ? _0 : userAgentInfo.platformName) !== null && _1 !== void 0 ? _1 : this._driverInfo.platformName;
216
+ this._driverInfo.platformVersion =
217
+ (_3 = (_2 = userAgentDataInfo === null || userAgentDataInfo === void 0 ? void 0 : userAgentDataInfo.platformVersion) !== null && _2 !== void 0 ? _2 : userAgentInfo.platformVersion) !== null && _3 !== void 0 ? _3 : this._driverInfo.platformVersion;
185
218
  }
186
219
  }
187
- if (!this._driverInfo.isMobile && (this.isAndroid || this.isIOS)) {
220
+ if (!this.isMobile && (this.isAndroid || this.isIOS)) {
188
221
  this._driverInfo.isMobile = true;
189
222
  this._driverInfo.isEmulation = this._driverInfo.isChrome;
190
223
  }
191
- (_s = (_12 = this._driverInfo).features) !== null && _s !== void 0 ? _s : (_12.features = {});
192
- (_t = (_13 = this._driverInfo.features).allCookies) !== null && _t !== void 0 ? _t : (_13.allCookies = this._driverInfo.isChrome || (/chrome/i.test(this._driverInfo.browserName) && !this._driverInfo.isMobile));
224
+ (_4 = (_28 = this._driverInfo).features) !== null && _4 !== void 0 ? _4 : (_28.features = {});
225
+ (_5 = (_29 = this._driverInfo.features).allCookies) !== null && _5 !== void 0 ? _5 : (_29.allCookies = this._driverInfo.isChrome || (/chrome/i.test(this._driverInfo.browserName) && !this._driverInfo.isMobile));
193
226
  }
194
227
  else {
195
228
  // this value always excludes the height of the navigation bar, and sometimes it also excludes the height of the status bar
196
229
  let windowSize = await this._spec.getWindowSize(this.target);
197
- (_u = (_14 = this._driverInfo).displaySize) !== null && _u !== void 0 ? _u : (_14.displaySize = windowSize);
198
- if (((_v = this.orientation) === null || _v === void 0 ? void 0 : _v.startsWith('landscape')) &&
230
+ (_6 = (_30 = this._driverInfo).displaySize) !== null && _6 !== void 0 ? _6 : (_30.displaySize = windowSize);
231
+ if (((_7 = this.orientation) === null || _7 === void 0 ? void 0 : _7.startsWith('landscape')) &&
199
232
  this._driverInfo.displaySize.height > this._driverInfo.displaySize.width) {
200
233
  this._driverInfo.displaySize = {
201
234
  width: this._driverInfo.displaySize.height,
@@ -204,14 +237,14 @@ class Driver {
204
237
  }
205
238
  if (this.isAndroid) {
206
239
  // bar sizes could be extracted only on android
207
- const systemBars = await ((_x = (_w = this._spec).getSystemBars) === null || _x === void 0 ? void 0 : _x.call(_w, this.target).catch(() => null));
240
+ const systemBars = await ((_9 = (_8 = this._spec).getSystemBars) === null || _9 === void 0 ? void 0 : _9.call(_8, this.target).catch(() => null));
208
241
  const { statusBar, navigationBar } = systemBars !== null && systemBars !== void 0 ? systemBars : {};
209
242
  if (statusBar === null || statusBar === void 0 ? void 0 : statusBar.visible) {
210
243
  this._logger.log('Driver status bar', statusBar);
211
244
  const statusBarSize = statusBar.height;
212
245
  // when status bar is overlapping content on android it returns status bar height equal to display height
213
246
  if (statusBarSize < this._driverInfo.displaySize.height) {
214
- this._driverInfo.statusBarSize = Math.max((_y = this._driverInfo.statusBarSize) !== null && _y !== void 0 ? _y : 0, statusBarSize);
247
+ this._driverInfo.statusBarSize = Math.max((_10 = this._driverInfo.statusBarSize) !== null && _10 !== void 0 ? _10 : 0, statusBarSize);
215
248
  }
216
249
  }
217
250
  if (navigationBar === null || navigationBar === void 0 ? void 0 : navigationBar.visible) {
@@ -220,28 +253,28 @@ class Driver {
220
253
  if (navigationBar.x > 0)
221
254
  this._driverInfo.orientation = 'landscape-secondary';
222
255
  // navigation bar size could be its height or width depending on screen orientation
223
- const navigationBarSize = navigationBar[((_z = this.orientation) === null || _z === void 0 ? void 0 : _z.startsWith('landscape')) ? 'width' : 'height'];
256
+ const navigationBarSize = navigationBar[((_11 = this.orientation) === null || _11 === void 0 ? void 0 : _11.startsWith('landscape')) ? 'width' : 'height'];
224
257
  // when navigation bar is invisible on android it returns navigation bar size equal to display size
225
258
  if (navigationBarSize <
226
- this._driverInfo.displaySize[((_0 = this.orientation) === null || _0 === void 0 ? void 0 : _0.startsWith('landscape')) ? 'width' : 'height']) {
227
- this._driverInfo.navigationBarSize = Math.max((_1 = this._driverInfo.navigationBarSize) !== null && _1 !== void 0 ? _1 : 0, navigationBarSize);
259
+ this._driverInfo.displaySize[((_12 = this.orientation) === null || _12 === void 0 ? void 0 : _12.startsWith('landscape')) ? 'width' : 'height']) {
260
+ this._driverInfo.navigationBarSize = Math.max((_13 = this._driverInfo.navigationBarSize) !== null && _13 !== void 0 ? _13 : 0, navigationBarSize);
228
261
  }
229
262
  else {
230
263
  this._driverInfo.navigationBarSize = 0;
231
264
  }
232
265
  }
233
266
  // bar sizes have to be scaled on android
234
- (_15 = this._driverInfo).statusBarSize && (_15.statusBarSize = this._driverInfo.statusBarSize / this.pixelRatio);
235
- (_16 = this._driverInfo).navigationBarSize && (_16.navigationBarSize = this._driverInfo.navigationBarSize / this.pixelRatio);
267
+ (_31 = this._driverInfo).statusBarSize && (_31.statusBarSize = this._driverInfo.statusBarSize / this.pixelRatio);
268
+ (_32 = this._driverInfo).navigationBarSize && (_32.navigationBarSize = this._driverInfo.navigationBarSize / this.pixelRatio);
236
269
  windowSize = utils.geometry.scale(windowSize, 1 / this.pixelRatio);
237
- (_17 = this._driverInfo).displaySize && (_17.displaySize = utils.geometry.scale(this._driverInfo.displaySize, 1 / this.pixelRatio));
270
+ (_33 = this._driverInfo).displaySize && (_33.displaySize = utils.geometry.scale(this._driverInfo.displaySize, 1 / this.pixelRatio));
238
271
  }
239
272
  if (this.isIOS) {
240
- if ((_2 = this.orientation) === null || _2 === void 0 ? void 0 : _2.startsWith('landscape'))
273
+ if ((_14 = this.orientation) === null || _14 === void 0 ? void 0 : _14.startsWith('landscape'))
241
274
  this._driverInfo.statusBarSize = 0;
242
275
  }
243
276
  // calculate viewport location
244
- (_3 = (_18 = this._driverInfo).viewportLocation) !== null && _3 !== void 0 ? _3 : (_18.viewportLocation = {
277
+ (_15 = (_34 = this._driverInfo).viewportLocation) !== null && _15 !== void 0 ? _15 : (_34.viewportLocation = {
245
278
  x: this.orientation === 'landscape' ? this.navigationBarSize : 0,
246
279
  y: this.statusBarSize,
247
280
  });
@@ -250,7 +283,7 @@ class Driver {
250
283
  this._driverInfo.viewportSize = { ...this._driverInfo.displaySize };
251
284
  this._driverInfo.viewportSize.height -= this.statusBarSize;
252
285
  if (this.isAndroid) {
253
- this._driverInfo.viewportSize[((_4 = this.orientation) === null || _4 === void 0 ? void 0 : _4.startsWith('landscape')) ? 'width' : 'height'] -=
286
+ this._driverInfo.viewportSize[((_16 = this.orientation) === null || _16 === void 0 ? void 0 : _16.startsWith('landscape')) ? 'width' : 'height'] -=
254
287
  this.navigationBarSize;
255
288
  }
256
289
  }
@@ -273,12 +306,12 @@ class Driver {
273
306
  }
274
307
  // TODO: if user opts into NML, skip initializing the helpers
275
308
  // init helper lib
276
- if (!((_5 = this._customConfig) === null || _5 === void 0 ? void 0 : _5.disableHelper)) {
309
+ if (!((_17 = this._customConfig) === null || _17 === void 0 ? void 0 : _17.disableHelper)) {
277
310
  this._helper = this.isIOS
278
311
  ? await helper_ios_1.HelperIOS.make({ spec: this._spec, driver: this, logger: this._logger })
279
312
  : await helper_android_1.HelperAndroid.make({ spec: this._spec, driver: this, logger: this._logger });
280
313
  }
281
- this._logger.log(`Helper set to ${(_6 = this._helper) === null || _6 === void 0 ? void 0 : _6.name}`);
314
+ this._logger.log(`Helper set to ${(_18 = this._helper) === null || _18 === void 0 ? void 0 : _18.name}`);
282
315
  }
283
316
  this._logger.log('Combined driver info', this._driverInfo);
284
317
  return this;
@@ -117,16 +117,17 @@ class MockDriver {
117
117
  }
118
118
  return { x: scrollingElement.scrollPosition.x, y: scrollingElement.scrollPosition.y };
119
119
  });
120
- this.mockScript(snippets.getPixelRatio, () => {
121
- return 1;
122
- });
123
120
  this.mockScript(snippets.getShadowRoot, ([element]) => {
124
121
  return element;
125
122
  });
126
- this.mockScript(snippets.getUserAgent, () => {
127
- if (this._ua !== undefined)
128
- return this._ua;
129
- return this.info.isMobile ? DEFAULT_MOBILE_UA : DEFAULT_DESKTOP_UA;
123
+ this.mockScript(snippets.getBrowserInfo, () => {
124
+ return JSON.stringify({
125
+ status: 'SUCCESS',
126
+ value: {
127
+ userAgent: this._ua !== undefined ? this._ua : this.info.isMobile ? DEFAULT_MOBILE_UA : DEFAULT_DESKTOP_UA,
128
+ pixelRatio: 1,
129
+ },
130
+ });
130
131
  });
131
132
  this.mockScript(snippets.getViewportSize, () => {
132
133
  return { width: this._window.rect.width, height: this._window.rect.height };
@@ -34,7 +34,7 @@ exports.isSimpleCommonSelector = isSimpleCommonSelector;
34
34
  function isCommonSelector(spec, selector) {
35
35
  return (utils.types.isPlainObject(selector) &&
36
36
  utils.types.has(selector, 'selector') &&
37
- Object.keys(selector).every(key => ['selector', 'type', 'frame', 'shadow'].includes(key)) &&
37
+ Object.keys(selector).every(key => ['selector', 'type', 'frame', 'shadow', 'child', 'fallback'].includes(key)) &&
38
38
  (utils.types.isString(selector.selector) || spec.isSelector(selector.selector)));
39
39
  }
40
40
  exports.isCommonSelector = isCommonSelector;
@@ -67,7 +67,11 @@ function splitSelector(spec, selector) {
67
67
  activeSelector.selector = targetSelector.selector;
68
68
  if (targetSelector.type)
69
69
  activeSelector.type = targetSelector.type;
70
- if (targetSelector.shadow) {
70
+ if (targetSelector.child) {
71
+ activeSelector = activeSelector.child = {};
72
+ targetSelector = targetSelector.child;
73
+ }
74
+ else if (targetSelector.shadow) {
71
75
  activeSelector = activeSelector.shadow = {};
72
76
  targetSelector = targetSelector.shadow;
73
77
  }
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseUserAgentData = void 0;
4
+ const WINDOWS_VERSIONS = {
5
+ '0.1.0': '7',
6
+ '0.2.0': '8',
7
+ '0.3.0': '8.1',
8
+ '10.0.0': '10',
9
+ '15.0.0': '11',
10
+ };
11
+ function parseUserAgentData(userAgentData) {
12
+ var _a, _b, _c;
13
+ const chromiumBrand = (_a = userAgentData.brands) === null || _a === void 0 ? void 0 : _a.find(brand => /Chromium/i.test(brand.brand));
14
+ const browserBrand = (_c = (_b = userAgentData.brands) === null || _b === void 0 ? void 0 : _b.find(brand => brand !== chromiumBrand && !/Not.?A.?Brand/i.test(brand.brand))) !== null && _c !== void 0 ? _c : chromiumBrand;
15
+ const info = {
16
+ browserName: browserBrand === null || browserBrand === void 0 ? void 0 : browserBrand.brand,
17
+ browserVersion: browserBrand === null || browserBrand === void 0 ? void 0 : browserBrand.version,
18
+ platformName: userAgentData.platform || undefined,
19
+ platformVersion: userAgentData.platformVersion || undefined,
20
+ deviceName: userAgentData.model || undefined,
21
+ isMobile: userAgentData.mobile,
22
+ isChromium: Boolean(chromiumBrand),
23
+ };
24
+ if (info.platformName === 'Windows') {
25
+ info.platformVersion = WINDOWS_VERSIONS[info.platformVersion];
26
+ }
27
+ else if (info.platformName === 'macOS') {
28
+ info.platformName = 'Mac OS X';
29
+ info.platformVersion = info.platformVersion.split(/[._]/, 2).join('.');
30
+ }
31
+ return info;
32
+ }
33
+ exports.parseUserAgentData = parseUserAgentData;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applitools/driver",
3
- "version": "1.11.2",
3
+ "version": "1.11.4",
4
4
  "description": "Applitools universal framework wrapper",
5
5
  "keywords": [
6
6
  "applitools",
@@ -87,9 +87,9 @@
87
87
  }
88
88
  },
89
89
  "dependencies": {
90
- "@applitools/logger": "1.1.28",
91
- "@applitools/snippets": "2.4.6",
92
- "@applitools/utils": "1.3.14",
90
+ "@applitools/logger": "1.1.29",
91
+ "@applitools/snippets": "2.4.7",
92
+ "@applitools/utils": "1.3.15",
93
93
  "semver": "7.3.7"
94
94
  },
95
95
  "devDependencies": {
@@ -47,19 +47,24 @@ export declare class Context<TDriver, TContext, TElement, TSelector> {
47
47
  get isCurrent(): boolean;
48
48
  get isInitialized(): boolean;
49
49
  get isRef(): boolean;
50
+ private _findElements;
50
51
  init(): Promise<this>;
51
52
  focus(): Promise<this>;
52
53
  equals(context: Context<TDriver, TContext, TElement, TSelector> | Element<TDriver, TContext, TElement, TSelector>): Promise<boolean>;
53
54
  context(reference: ContextPlain<TDriver, TContext, TElement, TSelector>): Promise<Context<TDriver, TContext, TElement, TSelector>>;
54
- root(selector: Selector<TSelector>): Promise<{
55
- context: Context<TDriver, TContext, TElement, TSelector>;
56
- shadow?: Element<TDriver, TContext, TElement, TSelector>;
57
- selector: Selector<TSelector>;
58
- }>;
59
55
  element(elementOrSelector: TElement | Selector<TSelector>): Promise<Element<TDriver, TContext, TElement, TSelector>>;
60
56
  elements(selectorOrElement: Selector<TSelector> | TElement): Promise<Element<TDriver, TContext, TElement, TSelector>[]>;
61
57
  waitFor(selector: Selector<TSelector>, options?: WaitOptions): Promise<Element<TDriver, TContext, TElement, TSelector>>;
62
58
  execute(script: ((args: any) => any) | string, arg?: any): Promise<any>;
59
+ executePoll(script: ((arg: any) => any) | string | {
60
+ main: ((arg: any) => any) | string;
61
+ poll: ((arg: any) => any) | string;
62
+ }, arg?: any | {
63
+ main: any;
64
+ poll: any;
65
+ executionTimeout?: number;
66
+ pollTimeout?: number;
67
+ }): Promise<any>;
63
68
  getContextElement(): Promise<Element<TDriver, TContext, TElement, TSelector>>;
64
69
  getScrollingElement(): Promise<Element<TDriver, TContext, TElement, TSelector>>;
65
70
  setScrollingElement(scrollingElement: Element<TDriver, TContext, TElement, TSelector> | TElement | Selector<TSelector>): Promise<void>;
package/types/driver.d.ts CHANGED
@@ -55,6 +55,9 @@ export declare class Driver<TDriver, TContext, TElement, TSelector> {
55
55
  get isMobile(): boolean;
56
56
  get isIOS(): boolean;
57
57
  get isAndroid(): boolean;
58
+ get isMac(): boolean;
59
+ get isWindows(): boolean;
60
+ get isChromium(): boolean;
58
61
  get isIE(): boolean;
59
62
  get isEdgeLegacy(): boolean;
60
63
  updateCurrentContext(context: Context<TDriver, TContext, TElement, TSelector>): void;
@@ -1,7 +1,9 @@
1
1
  export declare type Selector<TSelector = never> = TSelector | string | {
2
2
  selector: TSelector | string;
3
3
  type?: string;
4
+ child?: Selector<TSelector>;
4
5
  shadow?: Selector<TSelector>;
5
6
  frame?: Selector<TSelector>;
7
+ fallback?: Selector<TSelector>;
6
8
  };
7
9
  export declare type CommonSelector = Selector;
@@ -21,11 +21,14 @@ export declare type DriverInfo = {
21
21
  navigationBarSize?: number;
22
22
  isW3C?: boolean;
23
23
  isChrome?: boolean;
24
+ isChromium?: boolean;
24
25
  isEmulation?: boolean;
25
26
  isMobile?: boolean;
26
27
  isNative?: boolean;
27
28
  isAndroid?: boolean;
28
29
  isIOS?: boolean;
30
+ isMac?: boolean;
31
+ isWindows?: boolean;
29
32
  isWebView?: boolean;
30
33
  features?: {
31
34
  shadowSelector?: boolean;
@@ -1,11 +1,6 @@
1
1
  import { type SpecDriver } from './spec-driver';
2
2
  import { type Selector } from './selector';
3
- declare type CommonSelector<TSelector = never> = {
4
- selector: TSelector | string;
5
- type?: string;
6
- shadow?: CommonSelector<TSelector> | TSelector | string;
7
- frame?: CommonSelector<TSelector> | TSelector | string;
8
- };
3
+ declare type CommonSelector<TSelector = never> = Exclude<Selector<TSelector>, TSelector | string>;
9
4
  export declare function isSimpleCommonSelector(selector: any): selector is CommonSelector;
10
5
  export declare function isCommonSelector<TSelector>(spec: Pick<SpecDriver<unknown, unknown, unknown, TSelector>, 'isSelector'>, selector: any): selector is CommonSelector<TSelector>;
11
6
  export declare function isSelector<TSelector>(spec: Pick<SpecDriver<unknown, unknown, unknown, TSelector>, 'isSelector'>, selector: any): selector is Selector<TSelector>;
@@ -0,0 +1,13 @@
1
+ import { type DriverInfo } from './spec-driver';
2
+ declare type UserAgentData = {
3
+ brands: {
4
+ brand: string;
5
+ version: string;
6
+ }[];
7
+ platform: string;
8
+ platformVersion?: string;
9
+ model?: string;
10
+ mobile?: boolean;
11
+ };
12
+ export declare function parseUserAgentData(userAgentData: UserAgentData): DriverInfo;
13
+ export {};