@applitools/driver 1.3.3 → 1.4.1

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/CHANGELOG.md CHANGED
@@ -3,6 +3,26 @@
3
3
  ## Unreleased
4
4
 
5
5
 
6
+ ## 1.4.1 - 2021/12/16
7
+
8
+ - updated to @applitools/snippets@2.1.8 (from 2.1.7)
9
+
10
+ ## 1.4.0 - 2021/12/16
11
+
12
+ - improve native apps scrolling automation
13
+ - fix ios safe area related issues
14
+ - add helper library abstraction to cover appium edge cases
15
+ - made `setViewportSize` more reliable in worst case scenario and faster in best case scenario
16
+ - updated to @applitools/types@1.0.22 (from 1.0.21)
17
+
18
+ ## 1.3.5 - 2021/11/23
19
+
20
+ - updated to @applitools/types@1.0.21 (from 1.0.20)
21
+
22
+ ## 1.3.4 - 2021/11/18
23
+
24
+ - fix capabilities parsing for native apps
25
+
6
26
  ## 1.3.3 - 2021/11/14
7
27
 
8
28
  - do not throw if `getCookies` method is missed in spec driver
@@ -4,7 +4,9 @@ exports.parseCapabilities = void 0;
4
4
  function parseCapabilities(capabilities) {
5
5
  var _a, _b, _c, _d, _e, _f, _g, _h;
6
6
  const info = {
7
- browserName: ((_a = capabilities.browserName) !== null && _a !== void 0 ? _a : (_b = capabilities.desired) === null || _b === void 0 ? void 0 : _b.browserName) || undefined,
7
+ browserName: !capabilities.app && !capabilities.bundleId
8
+ ? ((_a = capabilities.browserName) !== null && _a !== void 0 ? _a : (_b = capabilities.desired) === null || _b === void 0 ? void 0 : _b.browserName) || undefined
9
+ : undefined,
8
10
  browserVersion: ((_c = capabilities.browserVersion) !== null && _c !== void 0 ? _c : capabilities.version) || undefined,
9
11
  platformName: ((_e = (_d = capabilities.platformName) !== null && _d !== void 0 ? _d : capabilities.platform) !== null && _e !== void 0 ? _e : (_f = capabilities.desired) === null || _f === void 0 ? void 0 : _f.platformName) || undefined,
10
12
  platformVersion: capabilities.platformVersion || undefined,
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.checkSpecDriver = void 0;
7
+ const strict_1 = __importDefault(require("assert/strict"));
8
+ const snippets = require('@applitools/snippets');
9
+ async function checkSpecDriver(options) {
10
+ const { spec, driver } = options;
11
+ const context = extractContext(driver);
12
+ const tests = {
13
+ 'execute script with echo snippet': async () => {
14
+ const arg = [1, '23', false, { a: 4, b: [5] }, null];
15
+ const result = await spec.executeScript(context, 'return arguments[0]', arg);
16
+ strict_1.default.deepEqual(result, arg, 'script returns an array of json data');
17
+ },
18
+ 'execute script with functional script': async () => {
19
+ const arg = { a: 2, b: 1, c: 7 };
20
+ function script(arg) {
21
+ return arg;
22
+ }
23
+ const result = await spec.executeScript(context, script, arg);
24
+ strict_1.default.deepEqual(result, arg, 'script returns an array of json data from functional script');
25
+ },
26
+ 'execute script with return value of dom element': async () => {
27
+ const element = await spec.executeScript(context, 'return document.documentElement');
28
+ const isHtmlElement = await spec.executeScript(context, 'return arguments[0] === document.documentElement', element);
29
+ strict_1.default.ok(isHtmlElement, 'script returns an element and could be executed with an element');
30
+ },
31
+ 'execute script with nested element references': async () => {
32
+ const elements = await spec.executeScript(context, 'return [{html: document.documentElement, body: document.body}]');
33
+ const isElements = await spec.executeScript(context, 'return arguments[0][0].html === document.documentElement && arguments[0][0].html === document.documentElement', elements);
34
+ strict_1.default.ok(isElements, 'script returns elements inside nested structure and could be executed with a nested structure of elements');
35
+ },
36
+ 'find element with string selector': async () => {
37
+ const selector = transformSelector('html>body>h1');
38
+ const element = await spec.findElement(context, selector);
39
+ const isWantedElement = await spec.executeScript(context, `return arguments[0] === document.querySelector("${selector}")`, element);
40
+ strict_1.default.ok(isWantedElement, `returns element by string selector - "${selector}"`);
41
+ },
42
+ 'find element with spec selector': async () => {
43
+ const cssSelector = transformSelector({ type: 'css', selector: 'html>body>h1' });
44
+ const xpathSelector = transformSelector({ type: 'xpath', selector: '//html/body/h1' });
45
+ const verificationScript = `return arguments[0] === document.querySelector('html>body>h1')`;
46
+ const cssElement = await spec.findElement(context, cssSelector);
47
+ const isCssElement = await spec.executeScript(context, verificationScript, cssElement);
48
+ strict_1.default.ok(isCssElement, `returns element by spec selector - ${JSON.stringify(cssSelector)}`);
49
+ const xpathElement = await spec.findElement(context, xpathSelector);
50
+ const isXpathElement = await spec.executeScript(context, verificationScript, xpathElement);
51
+ strict_1.default.ok(isXpathElement, `returns element by spec selector - ${JSON.stringify(xpathSelector)}`);
52
+ },
53
+ 'find element with unresolvable selector': async () => {
54
+ const selector = transformSelector('unresolvable_selector');
55
+ const element = await spec.findElement(context, selector);
56
+ strict_1.default.equal(element, null, `returns null by unresolvable selector - "${selector}"`);
57
+ },
58
+ 'find elements with string selector': async () => {
59
+ const selector = transformSelector('html p');
60
+ const elements = await spec.findElements(context, selector);
61
+ const isExpectedElements = await spec.executeScript(context, `var expected = arguments[0]; return Array.prototype.every.call(document.querySelectorAll("${selector}"), function(element, index) { return element === expected[index] })`, elements);
62
+ strict_1.default.ok(isExpectedElements, `returns elements by string selector - "${selector}"`);
63
+ },
64
+ 'find elements with spec selector': async () => {
65
+ const cssSelector = transformSelector({ type: 'css', selector: 'html p' });
66
+ const xpathSelector = transformSelector({ type: 'xpath', selector: '//html//p' });
67
+ const verificationScript = `var expected = arguments[0]; return Array.prototype.every.call(document.querySelectorAll('html p'), function(element, index) { return element === expected[index] })`;
68
+ const cssElements = await spec.findElements(context, cssSelector);
69
+ const isCssElements = await spec.executeScript(context, verificationScript, cssElements);
70
+ strict_1.default.ok(isCssElements, `returns elements by spec selector - ${JSON.stringify(cssSelector)}`);
71
+ const xpathElements = await spec.findElements(context, xpathSelector);
72
+ const isXpathElements = await spec.executeScript(context, verificationScript, xpathElements);
73
+ strict_1.default.ok(isXpathElements, `returns element by spec selector - ${JSON.stringify(xpathSelector)}`);
74
+ },
75
+ 'find elements with unresolvable selector': async () => {
76
+ const selector = transformSelector('unresolvable_selector');
77
+ const element = await spec.findElements(context, selector);
78
+ strict_1.default.deepEqual(element, [], `returns empty array by unresolvable selector - "${selector}"`);
79
+ },
80
+ 'child context': async () => {
81
+ const element = await spec.findElement(context, transformSelector('[name="frame1"]'));
82
+ const childContext = await spec.childContext(context, element);
83
+ const inFrame = await spec.executeScript(childContext, 'return window.frameElement.name === "frame1"');
84
+ strict_1.default.ok(inFrame, 'returns or switches to a child context');
85
+ strict_1.default.ok(typeof spec.mainContext === 'function', 'spec.mainContext also needs to be implemented in order to test spec.childContext');
86
+ await spec.mainContext(context);
87
+ },
88
+ 'is equal elements': async () => {
89
+ if (!spec.isEqualElements)
90
+ return { skipped: true };
91
+ const htmlEl = await spec.findElement(context, transformSelector('html'));
92
+ const htmlEl2 = await spec.executeScript(context, 'return document.documentElement');
93
+ strict_1.default.ok(await spec.isEqualElements(context, htmlEl, htmlEl2), 'elements should be equal');
94
+ const bodyEl = await spec.executeScript(context, 'return document.body');
95
+ strict_1.default.ok(!(await spec.isEqualElements(context, htmlEl, bodyEl)), 'elements should not be equal');
96
+ strict_1.default.ok(!(await spec.isEqualElements(context, htmlEl, undefined)), 'isEqualElements should return false if one of the arguments is falsy');
97
+ strict_1.default.ok(!(await spec.isEqualElements(context, undefined, htmlEl)), 'isEqualElements should return false if one of the arguments is falsy');
98
+ },
99
+ 'main context': async () => {
100
+ const mainDocument1 = await spec.findElement(context, transformSelector('html'));
101
+ const childContext1 = await spec.childContext(context, await spec.findElement(context, transformSelector('[name="frame1"]')));
102
+ const childContext2 = await spec.childContext(childContext1, await spec.findElement(childContext1, transformSelector('[name="frame1-1"]')));
103
+ const frameDocument = await spec.findElement(childContext2, transformSelector('html'));
104
+ strict_1.default.ok(!(await isEqualElements(childContext2, mainDocument1, frameDocument)));
105
+ const mainContext = await spec.mainContext(childContext2);
106
+ const mainDocument2 = await spec.findElement(mainContext, transformSelector('html'));
107
+ strict_1.default.ok(await isEqualElements(mainContext, mainDocument2, mainDocument1));
108
+ },
109
+ 'parent context': async () => {
110
+ const parentContext1 = await spec.childContext(context, await spec.findElement(context, transformSelector('[name="frame1"]')));
111
+ const parentDocument1 = await spec.findElement(parentContext1, transformSelector('html'));
112
+ const frameContext = await spec.childContext(parentContext1, await spec.findElement(parentContext1, transformSelector('[name="frame1-1"]')));
113
+ const frameDocument = await spec.findElement(frameContext, transformSelector('html'));
114
+ strict_1.default.ok(!(await isEqualElements(frameContext, parentDocument1, frameDocument)));
115
+ const parentContext2 = await spec.parentContext(frameContext);
116
+ const parentDocument2 = await spec.findElement(parentContext2, transformSelector('html'));
117
+ strict_1.default.ok(await isEqualElements(parentContext2, parentDocument2, parentDocument1));
118
+ await spec.mainContext(context);
119
+ },
120
+ 'get title': async () => {
121
+ const title = await spec.getTitle(driver);
122
+ strict_1.default.equal(title, 'Cross SDK test', 'returns title of the current page');
123
+ },
124
+ 'get url': async () => {
125
+ const url = await spec.getUrl(driver);
126
+ strict_1.default.equal(url, 'https://applitools.github.io/demo/TestPages/FramesTestPage/', 'returns url of the current page');
127
+ },
128
+ 'is driver': async () => {
129
+ strict_1.default.ok(await spec.isDriver(driver), 'driver should be considered a driver :)');
130
+ strict_1.default.ok(!(await spec.isDriver(undefined)), 'undefined should not be considered a driver');
131
+ strict_1.default.ok(!(await spec.isDriver(3)), 'number should not be considered a driver');
132
+ strict_1.default.ok(!(await spec.isDriver('str')), 'string should not be considered a driver');
133
+ },
134
+ 'is element': async () => {
135
+ const el = await spec.findElement(context, transformSelector('html'));
136
+ strict_1.default.ok(await spec.isElement(el), 'element should be considered an element :)');
137
+ strict_1.default.ok(!(await spec.isElement(undefined)), 'undefined should not be considered an element');
138
+ strict_1.default.ok(!(await spec.isElement(3)), 'number should not be considered an element');
139
+ strict_1.default.ok(!(await spec.isElement('str')), 'str should not be considered an element');
140
+ },
141
+ // 'is selector': async () => {}, // hard to test this
142
+ // 'set window size': async () => {}, // hard to test this
143
+ // 'get window size': async () => {}, // hard to test this
144
+ };
145
+ const report = [];
146
+ await spec.visit(driver, 'https://applitools.github.io/demo/TestPages/FramesTestPage/');
147
+ for (const [test, check] of Object.entries(tests)) {
148
+ try {
149
+ const result = (await check()) || { success: true };
150
+ report.push(Object.assign({ test }, result));
151
+ }
152
+ catch (error) {
153
+ report.push({ test, error: { message: error.message, expected: error.expected, actual: error.actual } });
154
+ }
155
+ }
156
+ return report;
157
+ function isEqualElements(context, element1, element2) {
158
+ var _a, _b;
159
+ return ((_b = (_a = spec.isEqualElements) === null || _a === void 0 ? void 0 : _a.call(spec, context, element1, element2)) !== null && _b !== void 0 ? _b : spec.executeScript(context, snippets.isEqualElements, [element1, element2]).catch(() => false));
160
+ }
161
+ function extractContext(driver) {
162
+ var _a, _b;
163
+ return (_b = (_a = spec.extractContext) === null || _a === void 0 ? void 0 : _a.call(spec, driver)) !== null && _b !== void 0 ? _b : driver;
164
+ }
165
+ function transformSelector(selector) {
166
+ var _a, _b;
167
+ return (_b = (_a = spec.transformSelector) === null || _a === void 0 ? void 0 : _a.call(spec, selector)) !== null && _b !== void 0 ? _b : selector;
168
+ }
169
+ }
170
+ exports.checkSpecDriver = checkSpecDriver;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
+ }) : (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ o[k2] = m[k];
8
+ }));
9
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ __exportStar(require("./check-spec-driver"), exports);
package/dist/driver.js CHANGED
@@ -22,6 +22,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
22
22
  exports.Driver = void 0;
23
23
  const utils = __importStar(require("@applitools/utils"));
24
24
  const context_1 = require("./context");
25
+ const helper_ios_1 = require("./helper-ios");
26
+ const helper_android_1 = require("./helper-android");
25
27
  const utils_1 = require("./utils");
26
28
  const user_agent_1 = require("./user-agent");
27
29
  const capabilities_1 = require("./capabilities");
@@ -59,6 +61,9 @@ class Driver {
59
61
  get mainContext() {
60
62
  return this._mainContext;
61
63
  }
64
+ get helper() {
65
+ return this._helper;
66
+ }
62
67
  get features() {
63
68
  var _a;
64
69
  return (_a = this._driverInfo) === null || _a === void 0 ? void 0 : _a.features;
@@ -140,7 +145,7 @@ class Driver {
140
145
  const userAgentInfo = user_agent_1.parseUserAgent(this._driverInfo.userAgent);
141
146
  this._driverInfo.browserName = (_g = userAgentInfo.browserName) !== null && _g !== void 0 ? _g : this._driverInfo.browserName;
142
147
  this._driverInfo.browserVersion = (_h = userAgentInfo.browserVersion) !== null && _h !== void 0 ? _h : this._driverInfo.browserVersion;
143
- if (!this._driverInfo.isMobile) {
148
+ if (this._driverInfo.isMobile) {
144
149
  (_j = (_u = this._driverInfo).platformName) !== null && _j !== void 0 ? _j : (_u.platformName = userAgentInfo.platformName);
145
150
  (_k = (_v = this._driverInfo).platformVersion) !== null && _k !== void 0 ? _k : (_v.platformVersion = userAgentInfo.platformVersion);
146
151
  }
@@ -153,24 +158,48 @@ class Driver {
153
158
  (_p = (_x = this._driverInfo.features).allCookies) !== null && _p !== void 0 ? _p : (_x.allCookies = /chrome/i.test(this._driverInfo.browserName) && !this._driverInfo.isMobile);
154
159
  }
155
160
  else {
156
- if (this.isNative) {
157
- const barsHeight = await ((_r = (_q = this._spec).getBarsHeight) === null || _r === void 0 ? void 0 : _r.call(_q, this.target).catch(() => undefined));
158
- if (barsHeight) {
159
- this._driverInfo.statusBarHeight = Math.max(barsHeight.statusBarHeight, driverInfo.statusBarHeight);
160
- this._driverInfo.navigationBarHeight = Math.max(barsHeight.navigationBarHeight, driverInfo.navigationBarHeight);
161
- }
162
- if (this.isAndroid) {
163
- this._driverInfo.statusBarHeight /= this.pixelRatio;
164
- this._driverInfo.navigationBarHeight /= this.pixelRatio;
161
+ const barsHeight = await ((_r = (_q = this._spec).getBarsHeight) === null || _r === void 0 ? void 0 : _r.call(_q, this.target).catch(() => undefined));
162
+ const displaySize = await this.getDisplaySize();
163
+ // calculate status and navigation bars sizes
164
+ if (barsHeight) {
165
+ // when status bar is overlapping content on android it returns status bar height equal to viewport height
166
+ if (this.isAndroid && barsHeight.statusBarHeight / this.pixelRatio < displaySize.height) {
167
+ this._driverInfo.statusBarHeight = Math.max(this._driverInfo.statusBarHeight, barsHeight.statusBarHeight);
165
168
  }
169
+ this._driverInfo.navigationBarHeight = Math.max(this._driverInfo.navigationBarHeight, barsHeight.navigationBarHeight);
170
+ }
171
+ if (this.isAndroid) {
172
+ this._driverInfo.statusBarHeight /= this.pixelRatio;
173
+ this._driverInfo.navigationBarHeight /= this.pixelRatio;
166
174
  }
175
+ // calculate viewport size
167
176
  if (!this._driverInfo.viewportSize) {
168
- const displaySize = await this.getDisplaySize();
169
177
  this._driverInfo.viewportSize = {
170
178
  width: displaySize.width,
171
179
  height: displaySize.height - this._driverInfo.statusBarHeight,
172
180
  };
173
181
  }
182
+ // calculate safe area
183
+ if (this.isIOS && !this._driverInfo.safeArea) {
184
+ this._driverInfo.safeArea = Object.assign({ x: 0, y: 0 }, displaySize);
185
+ const topElement = await this.element({ type: 'class name', selector: 'XCUIElementTypeNavigationBar' });
186
+ if (topElement) {
187
+ const topRegion = await this._spec.getElementRegion(this.target, topElement.target);
188
+ const topOffset = topRegion.y + topRegion.height;
189
+ this._driverInfo.safeArea.y = topOffset;
190
+ this._driverInfo.safeArea.height -= topOffset;
191
+ }
192
+ const bottomElement = await this.element({ type: 'class name', selector: 'XCUIElementTypeTabBar' });
193
+ if (bottomElement) {
194
+ const bottomRegion = await this._spec.getElementRegion(this.target, bottomElement.target);
195
+ const bottomOffset = bottomRegion.height;
196
+ this._driverInfo.safeArea.height -= bottomOffset;
197
+ }
198
+ }
199
+ // init helper lib
200
+ this._helper = this.isIOS
201
+ ? await helper_ios_1.HelperIOS.make({ spec: this._spec, driver: this, logger: this._logger })
202
+ : await helper_android_1.HelperAndroid.make({ spec: this._spec, driver: this, logger: this._logger });
174
203
  }
175
204
  this._logger.log('Combined driver info', this._driverInfo);
176
205
  return this;
@@ -339,7 +368,13 @@ class Driver {
339
368
  if (this.isWeb || !utils.types.has(this._driverInfo, ['viewportSize', 'statusBarHeight']))
340
369
  return region;
341
370
  const scaledRegion = this.isAndroid ? utils.geometry.scale(region, 1 / this.pixelRatio) : region;
342
- return utils.geometry.offsetNegative(scaledRegion, { x: 0, y: this.statusBarHeight });
371
+ const safeRegion = this.isIOS ? utils.geometry.intersect(scaledRegion, this._driverInfo.safeArea) : scaledRegion;
372
+ const offsetRegion = utils.geometry.offsetNegative(safeRegion, { x: 0, y: this.statusBarHeight });
373
+ if (offsetRegion.y < 0) {
374
+ offsetRegion.height += offsetRegion.y;
375
+ offsetRegion.y = 0;
376
+ }
377
+ return offsetRegion;
343
378
  }
344
379
  async getRegionInViewport(context, region) {
345
380
  await context.focus();
@@ -411,9 +446,12 @@ class Driver {
411
446
  };
412
447
  this._logger.log(`Attempt #${attempt} to set viewport size by setting window size to`, requiredWindowSize);
413
448
  await this._spec.setWindowSize(this.target, requiredWindowSize);
414
- await utils.general.sleep(3000);
415
- currentWindowSize = requiredWindowSize;
449
+ const prevViewportSize = currentViewportSize;
416
450
  currentViewportSize = await this.getViewportSize();
451
+ if (utils.geometry.equals(currentViewportSize, prevViewportSize)) {
452
+ currentViewportSize = await this.getViewportSize();
453
+ }
454
+ currentWindowSize = requiredWindowSize;
417
455
  if (utils.geometry.equals(currentViewportSize, requiredViewportSize))
418
456
  return;
419
457
  this._logger.log(`Attempt #${attempt} to set viewport size failed. Current viewport:`, currentViewportSize);
package/dist/element.js CHANGED
@@ -18,6 +18,17 @@ var __importStar = (this && this.__importStar) || function (mod) {
18
18
  __setModuleDefault(result, mod);
19
19
  return result;
20
20
  };
21
+ var __rest = (this && this.__rest) || function (s, e) {
22
+ var t = {};
23
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
24
+ t[p] = s[p];
25
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
26
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
27
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
28
+ t[p[i]] = s[p[i]];
29
+ }
30
+ return t;
31
+ };
21
32
  Object.defineProperty(exports, "__esModule", { value: true });
22
33
  exports.Element = void 0;
23
34
  const utils = __importStar(require("@applitools/utils"));
@@ -112,10 +123,7 @@ class Element {
112
123
  return this.context.execute(snippets.getElementRect, [this, true]);
113
124
  }
114
125
  else {
115
- this._logger.log('Extracting region of native element with selector', this.selector);
116
- const region = await this._spec.getElementRegion(this.driver.target, this.target);
117
- this._logger.log('Extracted native region', region);
118
- return this.driver.normalizeRegion(region);
126
+ return this.getRegion();
119
127
  }
120
128
  });
121
129
  this._logger.log('Extracted client region', region);
@@ -125,7 +133,7 @@ class Element {
125
133
  if (this._state.contentSize)
126
134
  return this._state.contentSize;
127
135
  const size = await this.withRefresh(async () => {
128
- var _a;
136
+ var _a, _b, _c;
129
137
  if (this.driver.isWeb) {
130
138
  this._logger.log('Extracting content size of web element with selector', this.selector);
131
139
  return this.context.execute(snippets.getElementContentSize, [this]);
@@ -133,81 +141,37 @@ class Element {
133
141
  else {
134
142
  this._logger.log('Extracting content size of native element with selector', this.selector);
135
143
  try {
144
+ const _d = await this.getAttribute('contentSize')
145
+ .then(data => {
146
+ const contentSize = JSON.parse(data);
147
+ return {
148
+ touchPadding: contentSize.touchPadding,
149
+ x: contentSize.left,
150
+ y: contentSize.top,
151
+ width: contentSize.width,
152
+ height: (this.driver.isAndroid ? contentSize.height : 0) + contentSize.scrollableOffset,
153
+ };
154
+ })
155
+ .catch(() => {
156
+ return this._spec.getElementRegion(this.driver.target, this.target);
157
+ }), { touchPadding } = _d, contentRegion = __rest(_d, ["touchPadding"]);
158
+ this._logger.log('Extracted native content size attribute', contentRegion);
159
+ const contentSize = await ((_a = this.driver.helper) === null || _a === void 0 ? void 0 : _a.getContentSize(this));
160
+ this._logger.log('Extracted native content size with helper library', contentSize);
161
+ this._state.contentSize = {
162
+ width: Math.max((_b = contentSize === null || contentSize === void 0 ? void 0 : contentSize.width) !== null && _b !== void 0 ? _b : 0, contentRegion.width),
163
+ height: Math.max((_c = contentSize === null || contentSize === void 0 ? void 0 : contentSize.height) !== null && _c !== void 0 ? _c : 0, contentRegion.height),
164
+ };
165
+ this._touchPadding = touchPadding !== null && touchPadding !== void 0 ? touchPadding : this._touchPadding;
136
166
  if (this.driver.isAndroid) {
137
- const className = await this.getAttribute('className');
138
- if ([
139
- 'android.widget.ListView',
140
- 'android.widget.GridView',
141
- 'android.support.v7.widget.RecyclerView',
142
- // 'androidx.recyclerview.widget.RecyclerView',
143
- 'androidx.viewpager2.widget.ViewPager2',
144
- ].includes(className)) {
145
- this._logger.log('Trying to extract content size using android helper library');
146
- const helperElement = await this.driver.element({
147
- type: '-android uiautomator',
148
- selector: 'new UiSelector().description("EyesAppiumHelper")',
149
- });
150
- if (helperElement) {
151
- const elementRegion = await this._spec.getElementRegion(this.driver.target, this.target);
152
- await helperElement.click();
153
- const info = await this._spec.getElementText(this.driver.target, helperElement.target);
154
- this._state.contentSize = utils.geometry.scale({ width: elementRegion.width, height: Number(info) }, 1 / this.driver.pixelRatio);
155
- }
156
- else {
157
- this._logger.log('Helper library for android was not detected');
158
- }
159
- }
160
- }
161
- else if (this.driver.isIOS) {
162
- const type = await this.getAttribute('type');
163
- if (type === 'XCUIElementTypeScrollView') {
164
- const elementRegion = await this._spec.getElementRegion(this.driver.target, this.target);
165
- const [childElement] = await this.driver.elements({
166
- type: 'xpath',
167
- selector: '//XCUIElementTypeScrollView[1]/*', // We cannot be sure that our element is the first one
168
- });
169
- const childElementRegion = await this._spec.getElementRegion(this.driver.target, childElement.target);
170
- this._state.contentSize = {
171
- width: elementRegion.width,
172
- height: childElementRegion.y + childElementRegion.height - elementRegion.y,
173
- };
174
- }
175
- else if (type === 'XCUIElementTypeCollectionView') {
176
- this._logger.log('Trying to extract content size using ios helper library');
177
- const helperElement = await this.driver.element({
178
- type: 'name',
179
- selector: 'applitools_grab_scrollable_data_button',
180
- });
181
- if (helperElement) {
182
- const helperElementRegion = await this._spec.getElementRegion(this.driver.target, helperElement.target);
183
- await this._spec.performAction(this.driver.target, [
184
- { action: 'tap', x: helperElementRegion.x, y: helperElementRegion.y },
185
- { action: 'wait', ms: 1000 },
186
- { action: 'release' },
187
- ]);
188
- const infoElement = await this.driver.element({ type: 'name', selector: 'applitools_content_size_label' });
189
- const info = await this._spec.getElementText(this.driver.target, infoElement.target);
190
- if (info) {
191
- const [_, width, height] = info.match(/\{(\d+),\s?(\d+)\}/);
192
- this._state.contentSize = { width: Number(width), height: Number(height) };
193
- }
194
- }
195
- else {
196
- this._logger.log('Helper library for ios was not detected');
197
- }
198
- }
167
+ this._state.contentSize = utils.geometry.scale(this._state.contentSize, 1 / this.driver.pixelRatio);
199
168
  }
200
- if (!this._state.contentSize) {
201
- const data = JSON.parse(await this.getAttribute('contentSize'));
202
- this._logger.log('Extracted native content size attribute', data);
203
- this._state.contentSize = this.driver.isIOS
204
- ? { width: data.width, height: data.scrollableOffset }
205
- : utils.geometry.scale({ width: data.width, height: data.height + data.scrollableOffset }, 1 / this.driver.pixelRatio);
206
- this._touchPadding = (_a = data.touchPadding) !== null && _a !== void 0 ? _a : this._touchPadding;
169
+ if (contentRegion.y < this.driver.statusBarHeight) {
170
+ this._state.contentSize.height -= this.driver.statusBarHeight - contentRegion.y;
207
171
  }
172
+ // android has a bug when after extracting 'contentSize' attribute the element is being scrolled by undetermined number of pixels
208
173
  if (this.driver.isAndroid) {
209
174
  this._logger.log('Stabilizing android scroll offset');
210
- // android has a bug when after extracting 'contentSize' attribute the element is being scrolled by undetermined number of pixels
211
175
  const originalScrollOffset = await this.getScrollOffset();
212
176
  this._state.scrollOffset = { x: -1, y: -1 };
213
177
  await this.scrollTo({ x: 0, y: 0 });
@@ -260,7 +224,7 @@ class Element {
260
224
  if (this.driver.isWeb)
261
225
  this._touchPadding = 0;
262
226
  else if (this.driver.isIOS)
263
- this._touchPadding = 14;
227
+ this._touchPadding = 10;
264
228
  else if (this.driver.isAndroid) {
265
229
  const { touchPadding } = JSON.parse(await this.getAttribute('contentSize'));
266
230
  this._touchPadding = touchPadding !== null && touchPadding !== void 0 ? touchPadding : 0;
@@ -268,6 +232,19 @@ class Element {
268
232
  }
269
233
  return this._touchPadding;
270
234
  }
235
+ async getText() {
236
+ const text = await this.withRefresh(async () => {
237
+ if (this.driver.isWeb) {
238
+ return '';
239
+ }
240
+ else {
241
+ this._logger.log('Extracting text of native element with selector', this.selector);
242
+ return this._spec.getElementText(this.driver.target, this.target);
243
+ }
244
+ });
245
+ this._logger.log('Extracted element text', text);
246
+ return text;
247
+ }
271
248
  async getAttribute(name) {
272
249
  if (this.driver.isWeb) {
273
250
  const properties = await this.context.execute(snippets.getElementProperties, [this, [name]]);
@@ -284,7 +261,7 @@ class Element {
284
261
  }
285
262
  async scrollTo(offset) {
286
263
  return this.withRefresh(async () => {
287
- offset = { x: Math.round(offset.x), y: Math.round(offset.y) };
264
+ offset = utils.geometry.round(offset);
288
265
  if (this.driver.isWeb) {
289
266
  let actualOffset = await this.context.execute(snippets.scrollTo, [this, offset]);
290
267
  // iOS has an issue when scroll offset is read immediately after it is been set it will always return the exact value that was set
@@ -297,62 +274,69 @@ class Element {
297
274
  if (utils.geometry.equals(offset, currentScrollOffset))
298
275
  return currentScrollOffset;
299
276
  const contentSize = await this.getContentSize();
300
- const scrollableRegion = await this._spec.getElementRegion(this.driver.target, this.target);
301
- const scaledScrollableRegion = this.driver.isAndroid
302
- ? utils.geometry.scale(scrollableRegion, 1 / this.driver.pixelRatio)
277
+ const scrollableRegion = await this.getClientRegion();
278
+ const effectiveRegion = this.driver.isAndroid
279
+ ? utils.geometry.scale(scrollableRegion, this.driver.pixelRatio)
303
280
  : scrollableRegion;
304
281
  const maxOffset = {
305
- x: Math.round(scaledScrollableRegion.width * (contentSize.width / scaledScrollableRegion.width - 1)),
306
- y: Math.round(scaledScrollableRegion.height * (contentSize.height / scaledScrollableRegion.height - 1)),
282
+ x: Math.round(scrollableRegion.width * (contentSize.width / scrollableRegion.width - 1)),
283
+ y: Math.round(scrollableRegion.height * (contentSize.height / scrollableRegion.height - 1)),
307
284
  };
308
- let requiredOffset;
309
- let remainingOffset;
310
- if (offset.x === 0 && offset.y === 0) {
311
- requiredOffset = offset;
312
- // if it has to be scrolled to the very beginning, then scroll maximum amount of pixels and a bit extra to be sure
313
- remainingOffset = { x: -(maxOffset.x + 0), y: -(maxOffset.y + 0) };
314
- }
315
- else {
316
- requiredOffset = { x: Math.min(offset.x, maxOffset.x), y: Math.min(offset.y, maxOffset.y) };
317
- remainingOffset = utils.geometry.offsetNegative(requiredOffset, currentScrollOffset);
318
- // if it has to be scrolled to the very end, then do a bit of extra scrolling to be sure
319
- // if (requiredOffset.x === maxOffset.x) remainingOffset.x += 100
320
- // if (requiredOffset.y === maxOffset.y) remainingOffset.y += 100
321
- }
322
- // if (requiredOffset.x === 0) remainingOffset.x -= 100
323
- // if (requiredOffset.y === 0) remainingOffset.y -= 100
324
- // if (requiredOffset.x === maxOffset.x) remainingOffset.x += 100
325
- // if (requiredOffset.y === maxOffset.y) remainingOffset.y += 100
285
+ const requiredOffset = { x: Math.min(offset.x, maxOffset.x), y: Math.min(offset.y, maxOffset.y) };
286
+ let remainingOffset = offset.x === 0 && offset.y === 0
287
+ ? { x: -maxOffset.x, y: -maxOffset.y } // if it has to be scrolled to the very beginning, then scroll maximum amount of pixels
288
+ : utils.geometry.offsetNegative(requiredOffset, currentScrollOffset);
326
289
  if (this.driver.isAndroid) {
327
290
  remainingOffset = utils.geometry.scale(remainingOffset, this.driver.pixelRatio);
328
291
  }
329
- const actions = [];
330
- const xPadding = Math.floor(scrollableRegion.width * 0.1);
331
- const yTrack = Math.floor(scrollableRegion.y + scrollableRegion.height / 2); // center
332
- const xLeft = scrollableRegion.y + xPadding;
292
+ const touchPadding = await this.getTouchPadding();
293
+ const xPadding = Math.max(Math.floor(effectiveRegion.width * 0.1), touchPadding);
294
+ const yTrack = Math.floor(effectiveRegion.y + effectiveRegion.height / 2); // center
295
+ const xLeft = effectiveRegion.y + xPadding;
333
296
  const xDirection = remainingOffset.y > 0 ? 'right' : 'left';
297
+ const xGap = xDirection === 'right' ? -touchPadding : touchPadding;
334
298
  let xRemaining = Math.abs(remainingOffset.x);
335
299
  while (xRemaining > 0) {
336
- const xRight = scrollableRegion.x + Math.min(xRemaining + xPadding, scrollableRegion.width - xPadding);
300
+ const xRight = effectiveRegion.x + Math.min(xRemaining + xPadding, effectiveRegion.width - xPadding);
337
301
  const [xStart, xEnd] = xDirection === 'right' ? [xRight, xLeft] : [xLeft, xRight];
338
- actions.push({ action: 'press', x: xStart, y: yTrack }, { action: 'wait', ms: 1500 }, { action: 'moveTo', x: xEnd, y: yTrack }, { action: 'release' });
302
+ await this._spec.performAction(this.driver.target, [
303
+ { action: 'press', y: yTrack, x: xStart },
304
+ { action: 'wait', ms: 100 },
305
+ { action: 'moveTo', y: yTrack, x: xStart + xGap },
306
+ { action: 'wait', ms: 100 },
307
+ { action: 'moveTo', y: yTrack, x: xEnd + xGap },
308
+ { action: 'wait', ms: 100 },
309
+ { action: 'moveTo', y: yTrack + 1, x: xEnd + xGap },
310
+ { action: 'release' },
311
+ ]);
339
312
  xRemaining -= xRight - xLeft;
340
313
  }
341
- const yPadding = Math.floor(scrollableRegion.height * 0.1);
342
- const xTrack = Math.floor(scrollableRegion.x + 5); // a little bit off left border
343
- const yTop = scrollableRegion.y + yPadding;
314
+ const yPadding = Math.max(Math.floor(effectiveRegion.height * 0.1), touchPadding);
315
+ const xTrack = Math.floor(effectiveRegion.x + 5); // a little bit off left border
316
+ const yBottom = effectiveRegion.y + effectiveRegion.height - yPadding;
344
317
  const yDirection = remainingOffset.y > 0 ? 'down' : 'up';
345
- let yRemaining = Math.abs(remainingOffset.y) + (await this.getTouchPadding()) * 2;
318
+ const yGap = yDirection === 'down' ? -touchPadding : touchPadding;
319
+ let yRemaining = Math.abs(remainingOffset.y);
346
320
  while (yRemaining > 0) {
347
- const yBottom = scrollableRegion.y + Math.min(yRemaining + yPadding, scrollableRegion.height - yPadding);
321
+ const yTop = Math.max(yBottom - yRemaining, effectiveRegion.y + yPadding);
348
322
  const [yStart, yEnd] = yDirection === 'down' ? [yBottom, yTop] : [yTop, yBottom];
349
- actions.push({ action: 'press', x: xTrack, y: yStart }, { action: 'wait', ms: 1500 }, { action: 'moveTo', x: xTrack, y: yEnd }, { action: 'wait', ms: 1500 }, { action: 'release' });
323
+ await this._spec.performAction(this.driver.target, [
324
+ { action: 'press', x: xTrack, y: yStart },
325
+ { action: 'wait', ms: 100 },
326
+ { action: 'moveTo', x: xTrack, y: yStart + yGap },
327
+ { action: 'wait', ms: 100 },
328
+ { action: 'moveTo', x: xTrack, y: yEnd + yGap },
329
+ { action: 'wait', ms: 100 },
330
+ { action: 'moveTo', x: xTrack + 1, y: yEnd + yGap },
331
+ { action: 'release' },
332
+ ]);
350
333
  yRemaining -= yBottom - yTop;
351
334
  }
352
- if (actions.length > 0) {
353
- await this._spec.performAction(this.driver.target, actions);
354
- }
355
- this._state.scrollOffset = requiredOffset;
335
+ const actualScrollableRegion = await this.getClientRegion();
336
+ this._state.scrollOffset = utils.geometry.offsetNegative(requiredOffset, {
337
+ x: scrollableRegion.x - actualScrollableRegion.x,
338
+ y: scrollableRegion.y - actualScrollableRegion.y,
339
+ });
356
340
  return this._state.scrollOffset;
357
341
  }
358
342
  });
@@ -394,6 +378,9 @@ class Element {
394
378
  async click() {
395
379
  await this._spec.click(this.context.target, this.target);
396
380
  }
381
+ async type(value) {
382
+ await this._spec.type(this.context.target, this.target, value);
383
+ }
397
384
  async preserveState() {
398
385
  if (this.driver.isNative)
399
386
  return;
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HelperAndroid = void 0;
4
+ class HelperAndroid {
5
+ constructor(options) {
6
+ this._spec = options.spec;
7
+ this._element = options.element;
8
+ this._legacy = options.legacy;
9
+ this._logger = options.logger;
10
+ }
11
+ static async make(options) {
12
+ const { spec, driver, logger } = options;
13
+ let legacy = false;
14
+ let element = await driver.element({
15
+ type: '-android uiautomator',
16
+ selector: 'new UiSelector().description("EyesAppiumHelperEDT")',
17
+ });
18
+ if (!element) {
19
+ legacy = true;
20
+ element = await driver.element({
21
+ type: '-android uiautomator',
22
+ selector: 'new UiSelector().description("EyesAppiumHelper")',
23
+ });
24
+ }
25
+ return element ? new HelperAndroid({ spec, element, legacy, logger }) : null;
26
+ }
27
+ async _getElementId(element) {
28
+ const resourceId = await element.getAttribute('resource-id');
29
+ if (!resourceId)
30
+ return null;
31
+ return resourceId.split('/')[1];
32
+ }
33
+ async getContentSize(element) {
34
+ let contentHeight;
35
+ if (this._legacy) {
36
+ await this._element.click();
37
+ contentHeight = await this._element.getText();
38
+ }
39
+ else {
40
+ const elementId = this._getElementId(element);
41
+ if (!elementId)
42
+ return null;
43
+ await this._element.type(`offset;${elementId};0;0;0`);
44
+ await this._element.click();
45
+ contentHeight = await this._element.getText();
46
+ await this._element.type('');
47
+ }
48
+ const region = await this._spec.getElementRegion(this._element.driver.target, element.target);
49
+ return { width: region.width, height: Number(contentHeight) };
50
+ }
51
+ async getRegion(element) {
52
+ if (this._legacy)
53
+ return null;
54
+ const elementId = await this._getElementId(element);
55
+ if (!elementId)
56
+ return null;
57
+ await this._element.type(`getRect;${elementId};0;0`);
58
+ await this._element.click();
59
+ const regionString = await this._element.getText();
60
+ await this._element.type('');
61
+ const [, x, y, height, width] = regionString.match(/\[(-?\d+(?:\.\d+)?);(-?\d+(?:\.\d+)?);(-?\d+(?:\.\d+)?);(-?\d+(?:\.\d+)?)\]/);
62
+ const region = { x: Number(x), y: Number(y), width: Number(width), height: Number(height) };
63
+ if (Number.isNaN(region.x + region.y + region.width + region.height))
64
+ return null;
65
+ return region;
66
+ }
67
+ }
68
+ exports.HelperAndroid = HelperAndroid;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HelperIOS = void 0;
4
+ class HelperIOS {
5
+ constructor(options) {
6
+ this._driver = options.driver;
7
+ this._element = options.element;
8
+ this._spec = options.spec;
9
+ this._logger = options.logger;
10
+ }
11
+ static async make(options) {
12
+ const { spec, driver, logger } = options;
13
+ const element = await driver.element({ type: 'name', selector: 'applitools_grab_scrollable_data_button' });
14
+ return element ? new HelperIOS({ driver, element, spec, logger }) : null;
15
+ }
16
+ async getContentSize(_element) {
17
+ await this._element.click();
18
+ const sizeLabel = await this._driver.element({ type: 'name', selector: 'applitools_content_size_label' });
19
+ const sizeString = await (sizeLabel === null || sizeLabel === void 0 ? void 0 : sizeLabel.getText());
20
+ if (!sizeString)
21
+ return null;
22
+ const [, width, height] = sizeString.match(/\{(-?\d+(?:\.\d+)?),\s?(-?\d+(?:\.\d+)?)\}/);
23
+ const contentSize = { width: Number(width), height: Number(height) };
24
+ if (Number.isNaN(contentSize.width + contentSize.height))
25
+ return null;
26
+ const paddingLabel = await this._driver.element({ type: 'name', selector: 'applitools_content_offset_label' });
27
+ const paddingString = await (paddingLabel === null || paddingLabel === void 0 ? void 0 : paddingLabel.getText());
28
+ if (!paddingString)
29
+ return contentSize;
30
+ const [, x, y] = paddingString.match(/\{(-?\d+(?:\.\d+)?),\s?(-?\d+(?:\.\d+)?)\}/);
31
+ const contentOffset = { x: Number(x), y: Number(y) };
32
+ if (!Number.isNaN(contentOffset.x))
33
+ contentSize.width -= contentOffset.x;
34
+ if (!Number.isNaN(contentOffset.y))
35
+ contentSize.height -= contentOffset.y;
36
+ return contentSize;
37
+ }
38
+ }
39
+ exports.HelperIOS = HelperIOS;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applitools/driver",
3
- "version": "1.3.3",
3
+ "version": "1.4.1",
4
4
  "description": "Applitools universal framework wrapper",
5
5
  "keywords": [
6
6
  "applitools",
@@ -34,12 +34,19 @@
34
34
  "./fake": {
35
35
  "default": "./dist/fake/index.js",
36
36
  "types": "./types/fake/index.d.ts"
37
+ },
38
+ "./debug": {
39
+ "default": "./dist/debug/index.js",
40
+ "types": "./types/debug/index.d.ts"
37
41
  }
38
42
  },
39
43
  "typesVersions": {
40
44
  "*": {
41
45
  "fake": [
42
46
  "./types/fake/index.d.ts"
47
+ ],
48
+ "debug": [
49
+ "./types/debug/index.d.ts"
43
50
  ]
44
51
  }
45
52
  },
@@ -62,8 +69,8 @@
62
69
  }
63
70
  },
64
71
  "dependencies": {
65
- "@applitools/snippets": "2.1.7",
66
- "@applitools/types": "1.0.20",
72
+ "@applitools/snippets": "2.1.8",
73
+ "@applitools/types": "1.0.22",
67
74
  "@applitools/utils": "1.2.4"
68
75
  },
69
76
  "devDependencies": {
@@ -0,0 +1,20 @@
1
+ import type { SpecDriver } from '@applitools/types';
2
+ export declare function checkSpecDriver<TDriver, TContext, TElement, TSelector>(options: {
3
+ spec: SpecDriver<TDriver, TContext, TElement, TSelector>;
4
+ driver: TDriver;
5
+ }): Promise<({
6
+ skipped: boolean;
7
+ test: string;
8
+ error?: undefined;
9
+ } | {
10
+ success: boolean;
11
+ test: string;
12
+ error?: undefined;
13
+ } | {
14
+ test: string;
15
+ error: {
16
+ message: any;
17
+ expected: any;
18
+ actual: any;
19
+ };
20
+ })[]>;
@@ -0,0 +1 @@
1
+ export * from './check-spec-driver';
package/types/driver.d.ts CHANGED
@@ -2,6 +2,8 @@
2
2
  import type * as types from '@applitools/types';
3
3
  import { Context, ContextReference } from './context';
4
4
  import { Element } from './element';
5
+ import { HelperIOS } from './helper-ios';
6
+ import { HelperAndroid } from './helper-android';
5
7
  export declare class Driver<TDriver, TContext, TElement, TSelector> {
6
8
  private _target;
7
9
  private _mainContext;
@@ -9,6 +11,7 @@ export declare class Driver<TDriver, TContext, TElement, TSelector> {
9
11
  private _driverInfo;
10
12
  private _logger;
11
13
  private _utils;
14
+ private _helper?;
12
15
  protected readonly _spec: types.SpecDriver<TDriver, TContext, TElement, TSelector>;
13
16
  constructor(options: {
14
17
  spec: types.SpecDriver<TDriver, TContext, TElement, TSelector>;
@@ -18,6 +21,7 @@ export declare class Driver<TDriver, TContext, TElement, TSelector> {
18
21
  get target(): TDriver;
19
22
  get currentContext(): Context<TDriver, TContext, TElement, TSelector>;
20
23
  get mainContext(): Context<TDriver, TContext, TElement, TSelector>;
24
+ get helper(): HelperAndroid<TDriver, TContext, TElement, TSelector> | HelperIOS<TDriver, TContext, TElement, TSelector>;
21
25
  get features(): {
22
26
  shadowSelector?: boolean;
23
27
  allCookies?: boolean;
@@ -37,6 +37,7 @@ export declare class Element<TDriver, TContext, TElement, TSelector> {
37
37
  isScrollable(): Promise<boolean>;
38
38
  isRoot(): Promise<boolean>;
39
39
  getTouchPadding(): Promise<number>;
40
+ getText(): Promise<string>;
40
41
  getAttribute(name: string): Promise<string>;
41
42
  setAttribute(name: string, value: string): Promise<void>;
42
43
  scrollTo(offset: types.Location): Promise<types.Location>;
@@ -45,6 +46,7 @@ export declare class Element<TDriver, TContext, TElement, TSelector> {
45
46
  getTranslateOffset(): Promise<types.Location>;
46
47
  getInnerOffset(): Promise<types.Location>;
47
48
  click(): Promise<void>;
49
+ type(value: string): Promise<void>;
48
50
  preserveState(): Promise<ElementState>;
49
51
  restoreState(state?: ElementState): Promise<void>;
50
52
  hideScrollbars(): Promise<void>;
@@ -20,7 +20,7 @@ export declare class MockDriver {
20
20
  browserVersion: any;
21
21
  };
22
22
  executeScript(script: any, args?: any[]): Promise<any>;
23
- findElement(selector: any, rootElement: any): Promise<any>;
23
+ findElement(selector: any, rootElement?: any): Promise<any>;
24
24
  findElements(selector: any, rootElement: any): Promise<any>;
25
25
  switchToFrame(reference: any): Promise<this>;
26
26
  switchToParentFrame(): Promise<this>;
@@ -0,0 +1,23 @@
1
+ import type * as types from '@applitools/types';
2
+ import type { Driver } from './driver';
3
+ import type { Element } from './element';
4
+ export declare class HelperAndroid<TDriver, TContext, TElement, TSelector> {
5
+ static make<TDriver, TContext, TElement, TSelector>(options: {
6
+ spec: types.SpecDriver<TDriver, TContext, TElement, TSelector>;
7
+ driver: Driver<TDriver, TContext, TElement, TSelector>;
8
+ logger: any;
9
+ }): Promise<HelperAndroid<TDriver, TContext, TElement, TSelector> | null>;
10
+ private readonly _spec;
11
+ private readonly _element;
12
+ private readonly _legacy;
13
+ private _logger;
14
+ constructor(options: {
15
+ spec: types.SpecDriver<TDriver, TContext, TElement, TSelector>;
16
+ element: Element<TDriver, TContext, TElement, TSelector>;
17
+ legacy: boolean;
18
+ logger?: any;
19
+ });
20
+ _getElementId(element: Element<TDriver, TContext, TElement, TSelector>): Promise<string>;
21
+ getContentSize(element: Element<TDriver, TContext, TElement, TSelector>): Promise<types.Size>;
22
+ getRegion(element: Element<TDriver, TContext, TElement, TSelector>): Promise<types.Region>;
23
+ }
@@ -0,0 +1,21 @@
1
+ import type * as types from '@applitools/types';
2
+ import type { Driver } from './driver';
3
+ import type { Element } from './element';
4
+ export declare class HelperIOS<TDriver, TContext, TElement, TSelector> {
5
+ static make<TDriver, TContext, TElement, TSelector>(options: {
6
+ spec: types.SpecDriver<TDriver, TContext, TElement, TSelector>;
7
+ driver: Driver<TDriver, TContext, TElement, TSelector>;
8
+ logger: any;
9
+ }): Promise<HelperIOS<TDriver, TContext, TElement, TSelector> | null>;
10
+ private readonly _driver;
11
+ private readonly _element;
12
+ private readonly _spec;
13
+ private _logger;
14
+ constructor(options: {
15
+ driver: Driver<TDriver, TContext, TElement, TSelector>;
16
+ element: Element<TDriver, TContext, TElement, TSelector>;
17
+ spec: types.SpecDriver<TDriver, TContext, TElement, TSelector>;
18
+ logger?: any;
19
+ });
20
+ getContentSize(_element: Element<TDriver, TContext, TElement, TSelector>): Promise<types.Size>;
21
+ }