@applitools/driver 1.9.1 → 1.9.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/driver.js CHANGED
@@ -175,13 +175,14 @@ class Driver {
175
175
  // this value always excludes the height of the navigation bar, and sometimes it also excludes the height of the status bar
176
176
  let windowSize = await this._spec.getWindowSize(this.target);
177
177
  (_r = (_4 = this._driverInfo).displaySize) !== null && _r !== void 0 ? _r : (_4.displaySize = windowSize);
178
+ const orientation = await this.getOrientation();
178
179
  if (this.isAndroid) {
179
180
  // bar sizes could be extracted only on android
180
181
  const barsSize = await ((_t = (_s = this._spec).getBarsSize) === null || _t === void 0 ? void 0 : _t.call(_s, this.target).catch(() => undefined));
181
182
  if (barsSize) {
182
183
  this._logger.log('Driver bars size', barsSize);
183
184
  // navigation bar height is replaced with the width in landscape orientation on android (due to the bug in appium)
184
- if ((await this.getOrientation()) === 'landscape')
185
+ if (orientation === 'landscape')
185
186
  barsSize.navigationBarHeight = barsSize.navigationBarWidth;
186
187
  // when status bar is overlapping content on android it returns status bar height equal to viewport height
187
188
  if (barsSize.statusBarHeight < this._driverInfo.displaySize.height) {
@@ -201,10 +202,18 @@ class Driver {
201
202
  // calculate viewport size
202
203
  if (!this._driverInfo.viewportSize) {
203
204
  if (this.navigationBarHeight > 1) {
204
- this._driverInfo.viewportSize = {
205
- width: this._driverInfo.displaySize.width,
206
- height: this._driverInfo.displaySize.height - this.statusBarHeight - this.navigationBarHeight,
207
- };
205
+ if (orientation === 'landscape') {
206
+ this._driverInfo.viewportSize = {
207
+ width: this._driverInfo.displaySize.height - this.navigationBarHeight,
208
+ height: this._driverInfo.displaySize.width - this.statusBarHeight,
209
+ };
210
+ }
211
+ else {
212
+ this._driverInfo.viewportSize = {
213
+ width: this._driverInfo.displaySize.width,
214
+ height: this._driverInfo.displaySize.height - this.statusBarHeight - this.navigationBarHeight,
215
+ };
216
+ }
208
217
  }
209
218
  else {
210
219
  this._driverInfo.viewportSize = {
@@ -454,12 +463,6 @@ class Driver {
454
463
  else {
455
464
  this._logger.log('Extracting viewport size from native driver');
456
465
  size = await this.getDisplaySize();
457
- if (size.height > size.width) {
458
- const orientation = await this.getOrientation();
459
- if (orientation === 'landscape') {
460
- size = { width: size.height, height: size.width };
461
- }
462
- }
463
466
  size.height -= this.statusBarHeight;
464
467
  }
465
468
  this._logger.log(`Rounding viewport size using`, this._customConfig.useCeilForViewportSize ? 'ceil' : 'round');
@@ -520,11 +523,14 @@ class Driver {
520
523
  var _a;
521
524
  if (this.isWeb && !this.isMobile)
522
525
  return;
523
- if ((_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.viewportSize) {
526
+ if ((_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.displaySize) {
524
527
  this._logger.log('Extracting display size from native driver using cached value');
525
528
  return this._driverInfo.displaySize;
526
529
  }
527
- const size = await this._spec.getWindowSize(this.target);
530
+ let size = await this._spec.getWindowSize(this.target);
531
+ if ((await this.getOrientation()) === 'landscape' && size.height > size.width) {
532
+ size = { width: size.height, height: size.width };
533
+ }
528
534
  const normalizedSize = this.isAndroid ? utils.geometry.scale(size, 1 / this.pixelRatio) : size;
529
535
  this._logger.log('Extracted and normalized display size:', normalizedSize);
530
536
  return normalizedSize;
package/dist/element.js CHANGED
@@ -278,18 +278,24 @@ class Element {
278
278
  });
279
279
  }
280
280
  async getTouchPadding() {
281
+ var _a, _b;
281
282
  if (this._state.touchPadding == null) {
282
283
  if (this.driver.isWeb)
283
284
  this._state.touchPadding = 0;
284
285
  else if (this.driver.isIOS)
285
286
  this._state.touchPadding = 10;
286
287
  else if (this.driver.isAndroid) {
287
- const touchPadding = await this.getAttribute('contentSize')
288
- .then(data => JSON.parse(data).touchPadding)
289
- .catch(err => {
290
- this._logger.warn(`Unable to get the attribute 'contentSize' when looking up 'touchPadding' due to the following error: '${err.message}'`);
291
- });
292
- this._state.touchPadding = touchPadding !== null && touchPadding !== void 0 ? touchPadding : 20;
288
+ if (((_a = this.driver.helper) === null || _a === void 0 ? void 0 : _a.name) === 'android') {
289
+ this._state.touchPadding = await ((_b = this.driver.helper) === null || _b === void 0 ? void 0 : _b.getTouchPadding());
290
+ }
291
+ else {
292
+ const touchPadding = await this.getAttribute('contentSize')
293
+ .then(data => JSON.parse(data).touchPadding)
294
+ .catch(err => {
295
+ this._logger.warn(`Unable to get the attribute 'contentSize' when looking up 'touchPadding' due to the following error: '${err.message}'`);
296
+ });
297
+ this._state.touchPadding = touchPadding !== null && touchPadding !== void 0 ? touchPadding : 20;
298
+ }
293
299
  this._logger.log('Touch padding set:', this._state.touchPadding);
294
300
  }
295
301
  }
@@ -311,8 +317,11 @@ class Element {
311
317
  async getAttribute(name) {
312
318
  var _a;
313
319
  // we assumes that attributes are not changed during the session
314
- if ((_a = this._state.attributes) === null || _a === void 0 ? void 0 : _a[name])
320
+ if ((_a = this._state.attributes) === null || _a === void 0 ? void 0 : _a[name]) {
321
+ if (this._state.attributes[name] instanceof Error)
322
+ throw this._state.attributes[name];
315
323
  return this._state.attributes[name];
324
+ }
316
325
  const value = await this.withRefresh(async () => {
317
326
  var _a;
318
327
  var _b;
@@ -322,17 +331,24 @@ class Element {
322
331
  }
323
332
  else {
324
333
  this._logger.log(`Extracting "${name}" attribute of native element with selector`, this.selector);
325
- const value = await this._spec.getElementAttribute(this.driver.target, this.target, name);
326
334
  (_a = (_b = this._state).attributes) !== null && _a !== void 0 ? _a : (_b.attributes = {});
327
- this._state.attributes[name] = value;
328
- if (this.driver.isAndroid && name === 'contentSize') {
329
- // android has a bug when after extracting 'contentSize' attribute the element is being scrolled by undetermined number of pixels
330
- this._logger.log('Stabilizing android scroll offset');
331
- const originalScrollOffset = await this.getScrollOffset();
332
- await this.scrollTo({ x: 0, y: 0 }, { force: true });
333
- await this.scrollTo(originalScrollOffset);
335
+ try {
336
+ this._state.attributes[name] = await this._spec.getElementAttribute(this.driver.target, this.target, name);
337
+ return this._state.attributes[name];
338
+ }
339
+ catch (err) {
340
+ this._state.attributes[name] = err;
341
+ throw err;
342
+ }
343
+ finally {
344
+ if (this.driver.isAndroid && name === 'contentSize') {
345
+ // android has a bug when after extracting 'contentSize' attribute the element is being scrolled by undetermined number of pixels
346
+ this._logger.log('Stabilizing android scroll offset');
347
+ const originalScrollOffset = await this.getScrollOffset();
348
+ await this.scrollTo({ x: 0, y: 0 }, { force: true });
349
+ await this.scrollTo(originalScrollOffset);
350
+ }
334
351
  }
335
- return value;
336
352
  }
337
353
  });
338
354
  this._logger.log(`Extracted element "${name}" attribute:`, value);
@@ -345,6 +361,7 @@ class Element {
345
361
  }
346
362
  async scrollTo(offset, options) {
347
363
  return this.withRefresh(async () => {
364
+ var _a;
348
365
  offset = utils.geometry.round({ x: Math.max(offset.x, 0), y: Math.max(offset.y, 0) });
349
366
  if (this.driver.isWeb) {
350
367
  let actualOffset = await this.context.execute(snippets.scrollTo, [this, offset]);
@@ -364,17 +381,23 @@ class Element {
364
381
  y: Math.round(scrollableRegion.height * (contentSize.height / scrollableRegion.height - 1)),
365
382
  };
366
383
  const requiredOffset = { x: Math.min(offset.x, maxOffset.x), y: Math.min(offset.y, maxOffset.y) };
384
+ if (((_a = this.driver.helper) === null || _a === void 0 ? void 0 : _a.name) === 'android' && utils.geometry.equals(requiredOffset, { x: 0, y: 0 })) {
385
+ await this.driver.helper.scrollToTop(this);
386
+ this._state.scrollOffset = requiredOffset;
387
+ return this._state.scrollOffset;
388
+ }
367
389
  let effectiveRegion = scrollableRegion;
368
390
  let remainingOffset = utils.geometry.equals(requiredOffset, { x: 0, y: 0 })
369
391
  ? { x: -maxOffset.x, y: -maxOffset.y } // if it has to be scrolled to the very beginning, then scroll maximum amount of pixels
370
392
  : utils.geometry.offsetNegative(requiredOffset, currentScrollOffset);
371
393
  if (this.driver.isAndroid) {
372
- remainingOffset = utils.geometry.scale(remainingOffset, this.driver.pixelRatio);
373
- effectiveRegion = utils.geometry.scale(scrollableRegion, this.driver.pixelRatio);
394
+ remainingOffset = utils.geometry.round(utils.geometry.scale(remainingOffset, this.driver.pixelRatio));
395
+ effectiveRegion = utils.geometry.round(utils.geometry.scale(effectiveRegion, this.driver.pixelRatio));
374
396
  }
375
397
  const actions = [];
376
- const touchPadding = await this.getTouchPadding();
377
398
  const isPager = await this.isPager();
399
+ const touchPadding = await this.getTouchPadding();
400
+ // horizontal scrolling
378
401
  const xPadding = Math.max(Math.floor(effectiveRegion.width * 0.07), touchPadding);
379
402
  const yTrack = Math.floor(effectiveRegion.y + effectiveRegion.height / 2); // center
380
403
  const xLeft = effectiveRegion.y + xPadding;
@@ -414,6 +437,7 @@ class Element {
414
437
  }
415
438
  xRemaining -= xRight - xLeft;
416
439
  }
440
+ // vertical scrolling
417
441
  const yPadding = Math.max(Math.floor(effectiveRegion.height * 0.07), touchPadding);
418
442
  const xTrack = Math.floor(effectiveRegion.x + 5); // a little bit off left border
419
443
  const yBottom = effectiveRegion.y + effectiveRegion.height - yPadding;
@@ -464,10 +488,10 @@ class Element {
464
488
  await this._spec.performAction(this.driver.target, [].concat(...actions));
465
489
  }
466
490
  const actualScrollableRegion = await this.getClientRegion();
467
- this._state.scrollOffset = utils.geometry.offsetNegative(requiredOffset, {
491
+ this._state.scrollOffset = utils.geometry.round(utils.geometry.offsetNegative(requiredOffset, {
468
492
  x: scrollableRegion.x - actualScrollableRegion.x,
469
493
  y: scrollableRegion.y - actualScrollableRegion.y,
470
- });
494
+ }));
471
495
  return this._state.scrollOffset;
472
496
  }
473
497
  });
@@ -7,6 +7,7 @@ class HelperAndroid {
7
7
  this._element = options.element;
8
8
  this._legacy = options.legacy;
9
9
  this._logger = options.logger;
10
+ this.name = this._legacy ? 'android-legacy' : 'android';
10
11
  }
11
12
  static async make(options) {
12
13
  const { spec, driver, logger } = options;
@@ -64,5 +65,34 @@ class HelperAndroid {
64
65
  return null;
65
66
  return region;
66
67
  }
68
+ async scrollToTop(element) {
69
+ if (this._legacy)
70
+ return null;
71
+ const elementId = await this._getElementId(element);
72
+ if (!elementId)
73
+ return null;
74
+ await this._element.type(`moveToTop;${elementId};0;0`);
75
+ await this._element.click();
76
+ await this._element.type('');
77
+ }
78
+ async scrollBy(element, offset) {
79
+ if (this._legacy)
80
+ return null;
81
+ const elementId = await this._getElementId(element);
82
+ if (!elementId)
83
+ return null;
84
+ await this._element.type(`scroll;${elementId};${offset.y};0;0`);
85
+ await this._element.click();
86
+ await this._element.type('');
87
+ }
88
+ async getTouchPadding() {
89
+ if (this._legacy)
90
+ return null;
91
+ await this._element.type(`getTouchPadding;0;0;0;0`);
92
+ await this._element.click();
93
+ const touchPaddingString = await this._element.getText();
94
+ await this._element.type('');
95
+ return Number(touchPaddingString);
96
+ }
67
97
  }
68
98
  exports.HelperAndroid = HelperAndroid;
@@ -7,6 +7,7 @@ class HelperIOS {
7
7
  this._element = options.element;
8
8
  this._spec = options.spec;
9
9
  this._logger = options.logger;
10
+ this.name = 'ios';
10
11
  }
11
12
  static async make(options) {
12
13
  const { spec, driver, logger } = options;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applitools/driver",
3
- "version": "1.9.1",
3
+ "version": "1.9.4",
4
4
  "description": "Applitools universal framework wrapper",
5
5
  "keywords": [
6
6
  "applitools",
@@ -24,6 +24,9 @@
24
24
  "name": "Applitools Team",
25
25
  "email": "team@applitools.com"
26
26
  },
27
+ "aliases": [
28
+ "driver"
29
+ ],
27
30
  "exports": {
28
31
  ".": {
29
32
  "types": "./types/index.d.ts",
@@ -73,13 +76,13 @@
73
76
  }
74
77
  },
75
78
  "dependencies": {
76
- "@applitools/logger": "1.1.10",
77
- "@applitools/snippets": "2.2.3",
78
- "@applitools/types": "1.4.7",
79
- "@applitools/utils": "1.3.6"
79
+ "@applitools/logger": "1.1.12",
80
+ "@applitools/snippets": "2.4.2",
81
+ "@applitools/types": "1.5.3",
82
+ "@applitools/utils": "1.3.8"
80
83
  },
81
84
  "devDependencies": {
82
- "@applitools/bongo": "^2.1.4",
85
+ "@applitools/bongo": "^2.1.5",
83
86
  "@types/mocha": "^9.1.1",
84
87
  "@types/node": "^17.0.31",
85
88
  "@typescript-eslint/eslint-plugin": "^5.22.0",
@@ -5,7 +5,7 @@ export declare type ElementState<TElement> = {
5
5
  contentSize?: types.Size;
6
6
  scrollOffset?: types.Location;
7
7
  transforms?: any;
8
- attributes?: Record<string, string>;
8
+ attributes?: Record<string, string | Error>;
9
9
  touchPadding?: number;
10
10
  containedElements?: Map<TElement, boolean>;
11
11
  };
@@ -12,6 +12,7 @@ export declare class HelperAndroid<TDriver, TContext, TElement, TSelector> {
12
12
  private readonly _element;
13
13
  private readonly _legacy;
14
14
  private _logger;
15
+ readonly name: 'android' | 'android-legacy';
15
16
  constructor(options: {
16
17
  spec: types.SpecDriver<TDriver, TContext, TElement, TSelector>;
17
18
  element: Element<TDriver, TContext, TElement, TSelector>;
@@ -21,4 +22,7 @@ export declare class HelperAndroid<TDriver, TContext, TElement, TSelector> {
21
22
  _getElementId(element: Element<TDriver, TContext, TElement, TSelector>): Promise<string>;
22
23
  getContentSize(element: Element<TDriver, TContext, TElement, TSelector>): Promise<types.Size>;
23
24
  getRegion(element: Element<TDriver, TContext, TElement, TSelector>): Promise<types.Region>;
25
+ scrollToTop(element: Element<TDriver, TContext, TElement, TSelector>): Promise<void>;
26
+ scrollBy(element: Element<TDriver, TContext, TElement, TSelector>, offset: types.Location): Promise<void>;
27
+ getTouchPadding(): Promise<number>;
24
28
  }
@@ -12,6 +12,7 @@ export declare class HelperIOS<TDriver, TContext, TElement, TSelector> {
12
12
  private readonly _element;
13
13
  private readonly _spec;
14
14
  private _logger;
15
+ readonly name: 'ios';
15
16
  constructor(options: {
16
17
  driver: Driver<TDriver, TContext, TElement, TSelector>;
17
18
  element: Element<TDriver, TContext, TElement, TSelector>;