@percy/webdriver-utils 1.27.5-alpha.0 → 1.27.5-beta.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/dist/driver.js +43 -36
- package/dist/index.js +1 -0
- package/dist/metadata/desktopMetaData.js +1 -1
- package/dist/providers/automateProvider.js +21 -11
- package/dist/providers/genericProvider.js +131 -39
- package/package.json +5 -5
- package/dist/util/utils.js +0 -8
package/dist/driver.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import utils from '@percy/sdk-utils';
|
|
2
2
|
import Cache from './util/cache.js';
|
|
3
|
-
import httpsAgent from './util/utils.js';
|
|
4
3
|
const {
|
|
5
4
|
request
|
|
6
5
|
} = utils;
|
|
@@ -11,14 +10,20 @@ export default class Driver {
|
|
|
11
10
|
this.executorUrl = executorUrl.includes('@') ? `https://${executorUrl.split('@')[1]}` : executorUrl;
|
|
12
11
|
this.passedCapabilities = passedCapabilities;
|
|
13
12
|
}
|
|
13
|
+
static requestPostOptions(command) {
|
|
14
|
+
return {
|
|
15
|
+
method: 'POST',
|
|
16
|
+
headers: {
|
|
17
|
+
'Content-Type': 'application/json;charset=utf-8'
|
|
18
|
+
},
|
|
19
|
+
body: JSON.stringify(command)
|
|
20
|
+
};
|
|
21
|
+
}
|
|
14
22
|
async getCapabilites() {
|
|
15
23
|
return await Cache.withCache(Cache.caps, this.sessionId, async () => {
|
|
16
24
|
try {
|
|
17
|
-
const options = {
|
|
18
|
-
agent: httpsAgent()
|
|
19
|
-
};
|
|
20
25
|
const baseUrl = `${this.executorUrl}/session/${this.sessionId}`;
|
|
21
|
-
const caps = JSON.parse((await request(baseUrl
|
|
26
|
+
const caps = JSON.parse((await request(baseUrl)).body);
|
|
22
27
|
return caps.value;
|
|
23
28
|
} catch (err) {
|
|
24
29
|
log.warn(`Falling back to legacy protocol, Error: ${err.message}`);
|
|
@@ -27,11 +32,8 @@ export default class Driver {
|
|
|
27
32
|
});
|
|
28
33
|
}
|
|
29
34
|
async getWindowSize() {
|
|
30
|
-
const options = {
|
|
31
|
-
agent: httpsAgent()
|
|
32
|
-
};
|
|
33
35
|
const baseUrl = `${this.executorUrl}/session/${this.sessionId}/window/current/size`;
|
|
34
|
-
const windowSize = JSON.parse((await request(baseUrl
|
|
36
|
+
const windowSize = JSON.parse((await request(baseUrl)).body);
|
|
35
37
|
return windowSize;
|
|
36
38
|
}
|
|
37
39
|
|
|
@@ -45,48 +47,53 @@ export default class Driver {
|
|
|
45
47
|
if (!command.script.includes('browserstack_executor')) {
|
|
46
48
|
command.script = `/* percy_automate_script */ \n ${command.script}`;
|
|
47
49
|
}
|
|
48
|
-
const options =
|
|
49
|
-
method: 'POST',
|
|
50
|
-
headers: {
|
|
51
|
-
'Content-Type': 'application/json;charset=utf-8'
|
|
52
|
-
},
|
|
53
|
-
agent: httpsAgent(),
|
|
54
|
-
body: JSON.stringify(command)
|
|
55
|
-
};
|
|
50
|
+
const options = Driver.requestPostOptions(command);
|
|
56
51
|
const baseUrl = `${this.executorUrl}/session/${this.sessionId}/execute/sync`;
|
|
57
52
|
const response = JSON.parse((await request(baseUrl, options)).body);
|
|
58
53
|
return response;
|
|
59
54
|
}
|
|
60
55
|
async takeScreenshot() {
|
|
61
|
-
const options = {
|
|
62
|
-
agent: httpsAgent()
|
|
63
|
-
};
|
|
64
56
|
const baseUrl = `${this.executorUrl}/session/${this.sessionId}/screenshot`;
|
|
65
|
-
const screenShot = JSON.parse((await request(baseUrl
|
|
57
|
+
const screenShot = JSON.parse((await request(baseUrl)).body);
|
|
66
58
|
return screenShot.value;
|
|
67
59
|
}
|
|
68
60
|
async rect(elementId) {
|
|
69
|
-
const options = {
|
|
70
|
-
agent: httpsAgent()
|
|
71
|
-
};
|
|
72
61
|
const baseUrl = `${this.executorUrl}/session/${this.sessionId}/element/${elementId}/rect`;
|
|
73
|
-
const response = JSON.parse((await request(baseUrl
|
|
62
|
+
const response = JSON.parse((await request(baseUrl)).body);
|
|
74
63
|
return response.value;
|
|
75
64
|
}
|
|
76
65
|
async findElement(using, value) {
|
|
77
|
-
const options = {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
},
|
|
82
|
-
agent: httpsAgent(),
|
|
83
|
-
body: JSON.stringify({
|
|
84
|
-
using,
|
|
85
|
-
value
|
|
86
|
-
})
|
|
87
|
-
};
|
|
66
|
+
const options = Driver.requestPostOptions({
|
|
67
|
+
using,
|
|
68
|
+
value
|
|
69
|
+
});
|
|
88
70
|
const baseUrl = `${this.executorUrl}/session/${this.sessionId}/element`;
|
|
89
71
|
const response = JSON.parse((await request(baseUrl, options)).body);
|
|
90
72
|
return response.value;
|
|
91
73
|
}
|
|
74
|
+
async findElementBoundingBox(using, value) {
|
|
75
|
+
if (using === 'xpath') {
|
|
76
|
+
return await this.findElementXpath(value);
|
|
77
|
+
} else if (using === 'css selector') {
|
|
78
|
+
return await this.findElementSelector(value);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async findElementXpath(xpath) {
|
|
82
|
+
xpath = xpath.replace(/'/g, '"');
|
|
83
|
+
const command = {
|
|
84
|
+
script: `return document.evaluate('${xpath}', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.getBoundingClientRect();`,
|
|
85
|
+
args: []
|
|
86
|
+
};
|
|
87
|
+
const response = await this.executeScript(command);
|
|
88
|
+
return response.value;
|
|
89
|
+
}
|
|
90
|
+
async findElementSelector(selector) {
|
|
91
|
+
selector = selector.replace('\\', '\\\\');
|
|
92
|
+
const command = {
|
|
93
|
+
script: `return document.querySelector('${selector}').getBoundingClientRect();`,
|
|
94
|
+
args: []
|
|
95
|
+
};
|
|
96
|
+
const response = await this.executeScript(command);
|
|
97
|
+
return response.value;
|
|
98
|
+
}
|
|
92
99
|
}
|
package/dist/index.js
CHANGED
|
@@ -23,6 +23,7 @@ export default class WebdriverUtils {
|
|
|
23
23
|
const comparisonData = await automate.screenshot(snapshotName, options);
|
|
24
24
|
comparisonData.metadata.cliScreenshotStartTime = startTime;
|
|
25
25
|
comparisonData.metadata.cliScreenshotEndTime = Date.now();
|
|
26
|
+
log.debug(`[${snapshotName}] : Comparison Data: ${JSON.stringify(comparisonData)}`);
|
|
26
27
|
return comparisonData;
|
|
27
28
|
} catch (e) {
|
|
28
29
|
log.error(`[${snapshotName}] : Error - ${e.message}`);
|
|
@@ -49,7 +49,7 @@ export default class DesktopMetaData {
|
|
|
49
49
|
async screenResolution() {
|
|
50
50
|
return await Cache.withCache(Cache.resolution, this.driver.sessionId, async () => {
|
|
51
51
|
const data = await this.driver.executeScript({
|
|
52
|
-
script: 'return [(window.screen.width * window.devicePixelRatio).toString(), (window.screen.height * window.devicePixelRatio).toString()];',
|
|
52
|
+
script: 'return [parseInt(window.screen.width * window.devicePixelRatio).toString(), parseInt(window.screen.height * window.devicePixelRatio).toString()];',
|
|
53
53
|
args: []
|
|
54
54
|
});
|
|
55
55
|
const screenInfo = data.value;
|
|
@@ -47,8 +47,7 @@ export default class AutomateProvider extends GenericProvider {
|
|
|
47
47
|
error = e;
|
|
48
48
|
throw e;
|
|
49
49
|
} finally {
|
|
50
|
-
|
|
51
|
-
await this.percyScreenshotEnd(name, (_response = response) === null || _response === void 0 ? void 0 : (_response$body = _response.body) === null || _response$body === void 0 ? void 0 : _response$body.link, `${error}`);
|
|
50
|
+
await this.percyScreenshotEnd(name, error);
|
|
52
51
|
}
|
|
53
52
|
return response;
|
|
54
53
|
}
|
|
@@ -61,23 +60,38 @@ export default class AutomateProvider extends GenericProvider {
|
|
|
61
60
|
percyBuildUrl: this.buildInfo.url,
|
|
62
61
|
state: 'begin'
|
|
63
62
|
});
|
|
63
|
+
// Selenium Hub, set status error Code to 13 if an error is thrown
|
|
64
|
+
// Handling error with Selenium dialect is != W3C
|
|
65
|
+
if ((result === null || result === void 0 ? void 0 : result.status) === 13) throw new Error((result === null || result === void 0 ? void 0 : result.value) || 'Got invalid error response');
|
|
64
66
|
this._markedPercy = result.success;
|
|
65
67
|
return result;
|
|
66
68
|
} catch (e) {
|
|
69
|
+
var _e$response, _JSON$parse, _e$response2;
|
|
67
70
|
log.debug(`[${name}] : Could not mark Automate session as percy`);
|
|
68
71
|
log.error(`[${name}] : error: ${e.toString()}`);
|
|
69
|
-
|
|
72
|
+
/**
|
|
73
|
+
* - Handling Error when dialect is W3C
|
|
74
|
+
* ERROR response format from SeleniumHUB `{
|
|
75
|
+
* sessionId: ...,
|
|
76
|
+
* status: 13,
|
|
77
|
+
* value: { error: '', message: ''}
|
|
78
|
+
* }
|
|
79
|
+
*/
|
|
80
|
+
const errResponse = (e === null || e === void 0 ? void 0 : (_e$response = e.response) === null || _e$response === void 0 ? void 0 : _e$response.body) && ((_JSON$parse = JSON.parse(e === null || e === void 0 ? void 0 : (_e$response2 = e.response) === null || _e$response2 === void 0 ? void 0 : _e$response2.body)) === null || _JSON$parse === void 0 ? void 0 : _JSON$parse.value) || {};
|
|
81
|
+
const errMessage = (errResponse === null || errResponse === void 0 ? void 0 : errResponse.message) || (errResponse === null || errResponse === void 0 ? void 0 : errResponse.error) || (e === null || e === void 0 ? void 0 : e.message) || (e === null || e === void 0 ? void 0 : e.error) || (e === null || e === void 0 ? void 0 : e.value) || e.toString();
|
|
82
|
+
throw new Error(errMessage);
|
|
70
83
|
}
|
|
71
84
|
});
|
|
72
85
|
}
|
|
73
|
-
async percyScreenshotEnd(name,
|
|
86
|
+
async percyScreenshotEnd(name, error) {
|
|
74
87
|
return await TimeIt.run('percyScreenshotEnd', async () => {
|
|
75
88
|
try {
|
|
89
|
+
var _this$buildInfo;
|
|
76
90
|
await this.browserstackExecutor('percyScreenshot', {
|
|
77
91
|
name,
|
|
78
|
-
percyScreenshotUrl,
|
|
79
|
-
status:
|
|
80
|
-
statusMessage,
|
|
92
|
+
percyScreenshotUrl: (_this$buildInfo = this.buildInfo) === null || _this$buildInfo === void 0 ? void 0 : _this$buildInfo.url,
|
|
93
|
+
status: error ? 'failure' : 'success',
|
|
94
|
+
statusMessage: error ? `${error}` : '',
|
|
81
95
|
state: 'end'
|
|
82
96
|
});
|
|
83
97
|
} catch (e) {
|
|
@@ -168,10 +182,6 @@ export default class AutomateProvider extends GenericProvider {
|
|
|
168
182
|
} = await this.metaData.windowSize();
|
|
169
183
|
const resolution = await this.metaData.screenResolution();
|
|
170
184
|
const orientation = (_ref = this.metaData.orientation() || automateCaps.deviceOrientation) === null || _ref === void 0 ? void 0 : _ref.toLowerCase();
|
|
171
|
-
|
|
172
|
-
// for android window size only constitutes of browser viewport, hence adding nav / status / url bar heights
|
|
173
|
-
[this.header, this.footer] = await this.getHeaderFooter(deviceName, osVersion, browserName);
|
|
174
|
-
height = this.metaData.device() && (osName === null || osName === void 0 ? void 0 : osName.toLowerCase()) === 'android' ? height + this.header + this.footer : height;
|
|
175
185
|
return {
|
|
176
186
|
name: deviceName,
|
|
177
187
|
osName,
|
|
@@ -2,12 +2,6 @@ import utils from '@percy/sdk-utils';
|
|
|
2
2
|
import MetaDataResolver from '../metadata/metaDataResolver.js';
|
|
3
3
|
import Tile from '../util/tile.js';
|
|
4
4
|
import Driver from '../driver.js';
|
|
5
|
-
import Cache from '../util/cache.js';
|
|
6
|
-
import httpsAgent from '../util/utils.js';
|
|
7
|
-
const {
|
|
8
|
-
request
|
|
9
|
-
} = utils;
|
|
10
|
-
const DEVICES_CONFIG_URL = 'https://storage.googleapis.com/percy-utils/devices.json';
|
|
11
5
|
const log = utils.logger('webdriver-utils:genericProvider');
|
|
12
6
|
export default class GenericProvider {
|
|
13
7
|
clientInfo = new Set();
|
|
@@ -27,6 +21,14 @@ export default class GenericProvider {
|
|
|
27
21
|
this.debugUrl = null;
|
|
28
22
|
this.header = 0;
|
|
29
23
|
this.footer = 0;
|
|
24
|
+
this.statusBarHeight = 0;
|
|
25
|
+
this.pageXShiftFactor = 0;
|
|
26
|
+
this.pageYShiftFactor = 0;
|
|
27
|
+
this.currentTag = null;
|
|
28
|
+
this.removeElementShiftFactor = 50000;
|
|
29
|
+
this.initialScrollFactor = {
|
|
30
|
+
value: [0, 0]
|
|
31
|
+
};
|
|
30
32
|
}
|
|
31
33
|
addDefaultOptions() {
|
|
32
34
|
this.options.freezeAnimation = this.options.freezeAnimatedImage || this.options.freezeAnimation || false;
|
|
@@ -51,6 +53,22 @@ export default class GenericProvider {
|
|
|
51
53
|
if (i) this.environmentInfo.add(i);
|
|
52
54
|
}
|
|
53
55
|
}
|
|
56
|
+
async getInitialPosition() {
|
|
57
|
+
if (this.currentTag.osName === 'iOS') {
|
|
58
|
+
this.initialScrollFactor = await this.driver.executeScript({
|
|
59
|
+
script: 'return [parseInt(window.scrollX), parseInt(window.scrollY)];',
|
|
60
|
+
args: []
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async scrollToInitialPosition(x, y) {
|
|
65
|
+
if (this.currentTag.osName === 'iOS') {
|
|
66
|
+
await this.driver.executeScript({
|
|
67
|
+
script: `window.scrollTo(${x}, ${y})`,
|
|
68
|
+
args: []
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
54
72
|
async screenshot(name, {
|
|
55
73
|
ignoreRegionXpaths = [],
|
|
56
74
|
ignoreRegionSelectors = [],
|
|
@@ -69,6 +87,8 @@ export default class GenericProvider {
|
|
|
69
87
|
log.debug(`[${name}] : Tag ${JSON.stringify(tag)}`);
|
|
70
88
|
const tiles = await this.getTiles(this.header, this.footer, fullscreen);
|
|
71
89
|
log.debug(`[${name}] : Tiles ${JSON.stringify(tiles)}`);
|
|
90
|
+
this.currentTag = tag;
|
|
91
|
+
this.statusBarHeight = tiles.tiles[0].statusBarHeight;
|
|
72
92
|
const ignoreRegions = await this.findRegions(ignoreRegionXpaths, ignoreRegionSelectors, ignoreRegionElements, customIgnoreRegions);
|
|
73
93
|
const considerRegions = await this.findRegions(considerRegionXpaths, considerRegionSelectors, considerRegionElements, customConsiderRegions);
|
|
74
94
|
await this.setDebugUrl();
|
|
@@ -133,9 +153,6 @@ export default class GenericProvider {
|
|
|
133
153
|
} = await this.metaData.windowSize();
|
|
134
154
|
const resolution = await this.metaData.screenResolution();
|
|
135
155
|
const orientation = this.metaData.orientation();
|
|
136
|
-
[this.header, this.footer] = await this.getHeaderFooter();
|
|
137
|
-
// for android window size only constitutes of browser viewport, hence adding nav / status / url bar heights
|
|
138
|
-
height = this.metaData.osName() === 'android' ? height + this.header + this.footer : height;
|
|
139
156
|
return {
|
|
140
157
|
name: this.metaData.deviceName(),
|
|
141
158
|
osName: this.metaData.osName(),
|
|
@@ -153,29 +170,62 @@ export default class GenericProvider {
|
|
|
153
170
|
async setDebugUrl() {
|
|
154
171
|
this.debugUrl = 'https://localhost/v1';
|
|
155
172
|
}
|
|
173
|
+
async doTransformations() {
|
|
174
|
+
const hideScrollbarStyle = `
|
|
175
|
+
/* Hide scrollbar for Chrome, Safari and Opera */
|
|
176
|
+
::-webkit-scrollbar {
|
|
177
|
+
display: none !important;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/* Hide scrollbar for IE, Edge and Firefox */
|
|
181
|
+
body, html {
|
|
182
|
+
-ms-overflow-style: none !important; /* IE and Edge */
|
|
183
|
+
scrollbar-width: none !important; /* Firefox */
|
|
184
|
+
}`.replace(/\n/g, '');
|
|
185
|
+
const jsScript = `
|
|
186
|
+
const e = document.createElement('style');
|
|
187
|
+
e.setAttribute('class', 'poa-injected');
|
|
188
|
+
e.innerHTML = '${hideScrollbarStyle}'
|
|
189
|
+
document.head.appendChild(e);`;
|
|
190
|
+
await this.driver.executeScript({
|
|
191
|
+
script: jsScript,
|
|
192
|
+
args: []
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
async undoTransformations(data) {
|
|
196
|
+
const jsScript = `
|
|
197
|
+
const n = document.querySelectorAll('${data}');
|
|
198
|
+
n.forEach((e) => {e.remove()});`;
|
|
199
|
+
await this.driver.executeScript({
|
|
200
|
+
script: jsScript,
|
|
201
|
+
args: []
|
|
202
|
+
});
|
|
203
|
+
}
|
|
156
204
|
async findRegions(xpaths, selectors, elements, customLocations) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
205
|
+
let isRegionPassed = [xpaths, selectors, elements, customLocations].some(regions => regions.length > 0);
|
|
206
|
+
if (isRegionPassed) {
|
|
207
|
+
await this.doTransformations();
|
|
208
|
+
const xpathRegions = await this.getSeleniumRegionsBy('xpath', xpaths);
|
|
209
|
+
const selectorRegions = await this.getSeleniumRegionsBy('css selector', selectors);
|
|
210
|
+
const elementRegions = await this.getSeleniumRegionsByElement(elements);
|
|
211
|
+
const customRegions = await this.getSeleniumRegionsByLocation(customLocations);
|
|
212
|
+
await this.undoTransformations('.poa-injected');
|
|
213
|
+
return [...xpathRegions, ...selectorRegions, ...elementRegions, ...customRegions];
|
|
214
|
+
} else {
|
|
215
|
+
return [];
|
|
216
|
+
}
|
|
162
217
|
}
|
|
163
|
-
async
|
|
164
|
-
const scaleFactor =
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
};
|
|
170
|
-
const size = {
|
|
171
|
-
height: rect.height,
|
|
172
|
-
width: rect.width
|
|
173
|
-
};
|
|
218
|
+
async getRegionObjectFromBoundingBox(selector, element) {
|
|
219
|
+
const scaleFactor = await this.metaData.devicePixelRatio();
|
|
220
|
+
let headerAdjustment = 0;
|
|
221
|
+
if (this.currentTag.osName === 'iOS') {
|
|
222
|
+
headerAdjustment = this.statusBarHeight;
|
|
223
|
+
}
|
|
174
224
|
const coOrdinates = {
|
|
175
|
-
top: Math.floor(
|
|
176
|
-
bottom: Math.ceil((
|
|
177
|
-
left: Math.floor(
|
|
178
|
-
right: Math.ceil((
|
|
225
|
+
top: Math.floor(element.y * scaleFactor) + Math.floor(headerAdjustment),
|
|
226
|
+
bottom: Math.ceil((element.y + element.height) * scaleFactor) + Math.ceil(headerAdjustment),
|
|
227
|
+
left: Math.floor(element.x * scaleFactor),
|
|
228
|
+
right: Math.ceil((element.x + element.width) * scaleFactor)
|
|
179
229
|
};
|
|
180
230
|
const jsonObject = {
|
|
181
231
|
selector,
|
|
@@ -187,9 +237,9 @@ export default class GenericProvider {
|
|
|
187
237
|
const regionsArray = [];
|
|
188
238
|
for (const idx in elements) {
|
|
189
239
|
try {
|
|
190
|
-
const
|
|
240
|
+
const boundingBoxRegion = await this.driver.findElementBoundingBox(findBy, elements[idx]);
|
|
191
241
|
const selector = `${findBy}: ${elements[idx]}`;
|
|
192
|
-
const region = await this.
|
|
242
|
+
const region = await this.getRegionObjectFromBoundingBox(selector, boundingBoxRegion);
|
|
193
243
|
regionsArray.push(region);
|
|
194
244
|
} catch (e) {
|
|
195
245
|
log.warn(`Selenium Element with ${findBy}: ${elements[idx]} not found. Ignoring this ${findBy}.`);
|
|
@@ -198,8 +248,57 @@ export default class GenericProvider {
|
|
|
198
248
|
}
|
|
199
249
|
return regionsArray;
|
|
200
250
|
}
|
|
251
|
+
async updatePageShiftFactor(location, scaleFactor) {
|
|
252
|
+
const scrollFactors = await this.driver.executeScript({
|
|
253
|
+
script: 'return [parseInt(window.scrollX), parseInt(window.scrollY)];',
|
|
254
|
+
args: []
|
|
255
|
+
});
|
|
256
|
+
if (this.currentTag.osName === 'iOS' || this.currentTag.osName === 'OS X' && parseInt(this.currentTag.browserVersion) > 13 && this.currentTag.browserName.toLowerCase() === 'safari') {
|
|
257
|
+
this.pageYShiftFactor = this.statusBarHeight;
|
|
258
|
+
} else {
|
|
259
|
+
this.pageYShiftFactor = this.statusBarHeight - scrollFactors.value[1] * scaleFactor;
|
|
260
|
+
}
|
|
261
|
+
this.pageXShiftFactor = this.currentTag.osName === 'iOS' ? 0 : -(scrollFactors.value[0] * scaleFactor);
|
|
262
|
+
if (this.currentTag.osName === 'iOS') {
|
|
263
|
+
if (scrollFactors.value[0] !== this.initialScrollFactor.value[0] || scrollFactors.value[1] !== this.initialScrollFactor.value[1]) {
|
|
264
|
+
this.pageXShiftFactor = -1 * this.removeElementShiftFactor;
|
|
265
|
+
this.pageYShiftFactor = -1 * this.removeElementShiftFactor;
|
|
266
|
+
} else if (location.y === 0) {
|
|
267
|
+
this.pageYShiftFactor += -(scrollFactors.value[1] * scaleFactor);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
async getRegionObject(selector, elementId) {
|
|
272
|
+
const scaleFactor = await this.metaData.devicePixelRatio();
|
|
273
|
+
const rect = await this.driver.rect(elementId);
|
|
274
|
+
const location = {
|
|
275
|
+
x: rect.x,
|
|
276
|
+
y: rect.y
|
|
277
|
+
};
|
|
278
|
+
const size = {
|
|
279
|
+
height: rect.height,
|
|
280
|
+
width: rect.width
|
|
281
|
+
};
|
|
282
|
+
// Update pageShiftFactor Element is not visible in viewport
|
|
283
|
+
// In case of iOS if the element is not visible in viewport it gives 0 for x-y coordinate.
|
|
284
|
+
// In case of iOS if the element is partially visible it gives negative x-y coordinate.
|
|
285
|
+
// Subtracting ScrollY/ScrollX ensures if the element is visible in viewport or not.
|
|
286
|
+
await this.updatePageShiftFactor(location, scaleFactor);
|
|
287
|
+
const coOrdinates = {
|
|
288
|
+
top: Math.floor(location.y * scaleFactor) + Math.floor(this.pageYShiftFactor),
|
|
289
|
+
bottom: Math.ceil((location.y + size.height) * scaleFactor) + Math.ceil(this.pageYShiftFactor),
|
|
290
|
+
left: Math.floor(location.x * scaleFactor) + Math.floor(this.pageXShiftFactor),
|
|
291
|
+
right: Math.ceil((location.x + size.width) * scaleFactor) + Math.ceil(this.pageXShiftFactor)
|
|
292
|
+
};
|
|
293
|
+
const jsonObject = {
|
|
294
|
+
selector,
|
|
295
|
+
coOrdinates
|
|
296
|
+
};
|
|
297
|
+
return jsonObject;
|
|
298
|
+
}
|
|
201
299
|
async getSeleniumRegionsByElement(elements) {
|
|
202
300
|
const regionsArray = [];
|
|
301
|
+
await this.getInitialPosition();
|
|
203
302
|
for (let index = 0; index < elements.length; index++) {
|
|
204
303
|
try {
|
|
205
304
|
const selector = `element: ${index}`;
|
|
@@ -210,6 +309,7 @@ export default class GenericProvider {
|
|
|
210
309
|
log.debug(e.toString());
|
|
211
310
|
}
|
|
212
311
|
}
|
|
312
|
+
await this.scrollToInitialPosition(this.initialScrollFactor.value[0], this.initialScrollFactor.value[1]);
|
|
213
313
|
return regionsArray;
|
|
214
314
|
}
|
|
215
315
|
async getSeleniumRegionsByLocation(customLocations) {
|
|
@@ -239,12 +339,4 @@ export default class GenericProvider {
|
|
|
239
339
|
}
|
|
240
340
|
return elementsArray;
|
|
241
341
|
}
|
|
242
|
-
async getHeaderFooter(deviceName, osVersion, browserName) {
|
|
243
|
-
// passing 0 as key, since across different pages and tests, this config will remain same
|
|
244
|
-
const devicesConfig = await Cache.withCache(Cache.devicesConfig, 0, async () => {
|
|
245
|
-
return (await request(DEVICES_CONFIG_URL, httpsAgent())).body;
|
|
246
|
-
});
|
|
247
|
-
let deviceKey = `${deviceName}-${osVersion}`;
|
|
248
|
-
return devicesConfig[deviceKey] ? devicesConfig[deviceKey][browserName] ? [devicesConfig[deviceKey][browserName].header, devicesConfig[deviceKey][browserName].footer] : [0, 0] : [0, 0];
|
|
249
|
-
}
|
|
250
342
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@percy/webdriver-utils",
|
|
3
|
-
"version": "1.27.5-
|
|
3
|
+
"version": "1.27.5-beta.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"publishConfig": {
|
|
11
11
|
"access": "public",
|
|
12
|
-
"tag": "
|
|
12
|
+
"tag": "beta"
|
|
13
13
|
},
|
|
14
14
|
"engines": {
|
|
15
15
|
"node": ">=14"
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"test:coverage": "yarn test --coverage"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@percy/config": "1.27.5-
|
|
33
|
-
"@percy/sdk-utils": "1.27.5-
|
|
32
|
+
"@percy/config": "1.27.5-beta.1",
|
|
33
|
+
"@percy/sdk-utils": "1.27.5-beta.1"
|
|
34
34
|
},
|
|
35
|
-
"gitHead": "
|
|
35
|
+
"gitHead": "f5924b050d0c04f8ac63d610af291b32f51565f8"
|
|
36
36
|
}
|