@percy/webdriver-utils
Advanced tools
Comparing version 1.27.6-alpha.0 to 1.27.6-beta.0
@@ -74,2 +74,27 @@ import utils from '@percy/sdk-utils'; | ||
} | ||
async findElementBoundingBox(using, value) { | ||
if (using === 'xpath') { | ||
return await this.findElementXpath(value); | ||
} else if (using === 'css selector') { | ||
return await this.findElementSelector(value); | ||
} | ||
} | ||
async findElementXpath(xpath) { | ||
xpath = xpath.replace(/'/g, '"'); | ||
const command = { | ||
script: `return document.evaluate('${xpath}', document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.getBoundingClientRect();`, | ||
args: [] | ||
}; | ||
const response = await this.executeScript(command); | ||
return response.value; | ||
} | ||
async findElementSelector(selector) { | ||
selector = selector.replace('\\', '\\\\'); | ||
const command = { | ||
script: `return document.querySelector('${selector}').getBoundingClientRect();`, | ||
args: [] | ||
}; | ||
const response = await this.executeScript(command); | ||
return response.value; | ||
} | ||
} |
@@ -24,2 +24,10 @@ import utils from '@percy/sdk-utils'; | ||
this.footer = 0; | ||
this.statusBarHeight = 0; | ||
this.pageXShiftFactor = 0; | ||
this.pageYShiftFactor = 0; | ||
this.currentTag = null; | ||
this.removeElementShiftFactor = 50000; | ||
this.initialScrollFactor = { | ||
value: [0, 0] | ||
}; | ||
} | ||
@@ -49,2 +57,18 @@ addDefaultOptions() { | ||
} | ||
async getInitialPosition() { | ||
if (this.currentTag.osName === 'iOS') { | ||
this.initialScrollFactor = await this.driver.executeScript({ | ||
script: 'return [parseInt(window.scrollX), parseInt(window.scrollY)];', | ||
args: [] | ||
}); | ||
} | ||
} | ||
async scrollToInitialPosition(x, y) { | ||
if (this.currentTag.osName === 'iOS') { | ||
await this.driver.executeScript({ | ||
script: `window.scrollTo(${x}, ${y})`, | ||
args: [] | ||
}); | ||
} | ||
} | ||
async screenshot(name, { | ||
@@ -68,2 +92,4 @@ ignoreRegionXpaths = [], | ||
log.debug(`[${name}] : Tiles ${JSON.stringify(tiles)}`); | ||
this.currentTag = tag; | ||
this.statusBarHeight = tiles.tiles[0].statusBarHeight; | ||
const ignoreRegions = await this.findRegions(ignoreRegionXpaths, ignoreRegionSelectors, ignoreRegionElements, customIgnoreRegions); | ||
@@ -150,25 +176,58 @@ const considerRegions = await this.findRegions(considerRegionXpaths, considerRegionSelectors, considerRegionElements, customConsiderRegions); | ||
} | ||
async doTransformations() { | ||
const hideScrollbarStyle = ` | ||
/* Hide scrollbar for Chrome, Safari and Opera */ | ||
::-webkit-scrollbar { | ||
display: none !important; | ||
} | ||
/* Hide scrollbar for IE, Edge and Firefox */ | ||
body, html { | ||
-ms-overflow-style: none !important; /* IE and Edge */ | ||
scrollbar-width: none !important; /* Firefox */ | ||
}`.replace(/\n/g, ''); | ||
const jsScript = ` | ||
const e = document.createElement('style'); | ||
e.setAttribute('class', 'poa-injected'); | ||
e.innerHTML = '${hideScrollbarStyle}' | ||
document.head.appendChild(e);`; | ||
await this.driver.executeScript({ | ||
script: jsScript, | ||
args: [] | ||
}); | ||
} | ||
async undoTransformations(data) { | ||
const jsScript = ` | ||
const n = document.querySelectorAll('${data}'); | ||
n.forEach((e) => {e.remove()});`; | ||
await this.driver.executeScript({ | ||
script: jsScript, | ||
args: [] | ||
}); | ||
} | ||
async findRegions(xpaths, selectors, elements, customLocations) { | ||
const xpathRegions = await this.getSeleniumRegionsBy('xpath', xpaths); | ||
const selectorRegions = await this.getSeleniumRegionsBy('css selector', selectors); | ||
const elementRegions = await this.getSeleniumRegionsByElement(elements); | ||
const customRegions = await this.getSeleniumRegionsByLocation(customLocations); | ||
return [...xpathRegions, ...selectorRegions, ...elementRegions, ...customRegions]; | ||
let isRegionPassed = [xpaths, selectors, elements, customLocations].some(regions => regions.length > 0); | ||
if (isRegionPassed) { | ||
await this.doTransformations(); | ||
const xpathRegions = await this.getSeleniumRegionsBy('xpath', xpaths); | ||
const selectorRegions = await this.getSeleniumRegionsBy('css selector', selectors); | ||
const elementRegions = await this.getSeleniumRegionsByElement(elements); | ||
const customRegions = await this.getSeleniumRegionsByLocation(customLocations); | ||
await this.undoTransformations('.poa-injected'); | ||
return [...xpathRegions, ...selectorRegions, ...elementRegions, ...customRegions]; | ||
} else { | ||
return []; | ||
} | ||
} | ||
async getRegionObject(selector, elementId) { | ||
const scaleFactor = parseInt(await this.metaData.devicePixelRatio()); | ||
const rect = await this.driver.rect(elementId); | ||
const location = { | ||
x: rect.x, | ||
y: rect.y | ||
}; | ||
const size = { | ||
height: rect.height, | ||
width: rect.width | ||
}; | ||
async getRegionObjectFromBoundingBox(selector, element) { | ||
const scaleFactor = await this.metaData.devicePixelRatio(); | ||
let headerAdjustment = 0; | ||
if (this.currentTag.osName === 'iOS') { | ||
headerAdjustment = this.statusBarHeight; | ||
} | ||
const coOrdinates = { | ||
top: Math.floor(location.y * scaleFactor), | ||
bottom: Math.ceil((location.y + size.height) * scaleFactor), | ||
left: Math.floor(location.x * scaleFactor), | ||
right: Math.ceil((location.x + size.width) * scaleFactor) | ||
top: Math.floor(element.y * scaleFactor) + Math.floor(headerAdjustment), | ||
bottom: Math.ceil((element.y + element.height) * scaleFactor) + Math.ceil(headerAdjustment), | ||
left: Math.floor(element.x * scaleFactor), | ||
right: Math.ceil((element.x + element.width) * scaleFactor) | ||
}; | ||
@@ -185,5 +244,5 @@ const jsonObject = { | ||
try { | ||
const element = await this.driver.findElement(findBy, elements[idx]); | ||
const boundingBoxRegion = await this.driver.findElementBoundingBox(findBy, elements[idx]); | ||
const selector = `${findBy}: ${elements[idx]}`; | ||
const region = await this.getRegionObject(selector, element[Object.keys(element)[0]]); | ||
const region = await this.getRegionObjectFromBoundingBox(selector, boundingBoxRegion); | ||
regionsArray.push(region); | ||
@@ -197,4 +256,53 @@ } catch (e) { | ||
} | ||
async updatePageShiftFactor(location, scaleFactor) { | ||
const scrollFactors = await this.driver.executeScript({ | ||
script: 'return [parseInt(window.scrollX), parseInt(window.scrollY)];', | ||
args: [] | ||
}); | ||
if (this.currentTag.osName === 'iOS' || this.currentTag.osName === 'OS X' && parseInt(this.currentTag.browserVersion) > 13 && this.currentTag.browserName.toLowerCase() === 'safari') { | ||
this.pageYShiftFactor = this.statusBarHeight; | ||
} else { | ||
this.pageYShiftFactor = this.statusBarHeight - scrollFactors.value[1] * scaleFactor; | ||
} | ||
this.pageXShiftFactor = this.currentTag.osName === 'iOS' ? 0 : -(scrollFactors.value[0] * scaleFactor); | ||
if (this.currentTag.osName === 'iOS') { | ||
if (scrollFactors.value[0] !== this.initialScrollFactor.value[0] || scrollFactors.value[1] !== this.initialScrollFactor.value[1]) { | ||
this.pageXShiftFactor = -1 * this.removeElementShiftFactor; | ||
this.pageYShiftFactor = -1 * this.removeElementShiftFactor; | ||
} else if (location.y === 0) { | ||
this.pageYShiftFactor += -(scrollFactors.value[1] * scaleFactor); | ||
} | ||
} | ||
} | ||
async getRegionObject(selector, elementId) { | ||
const scaleFactor = await this.metaData.devicePixelRatio(); | ||
const rect = await this.driver.rect(elementId); | ||
const location = { | ||
x: rect.x, | ||
y: rect.y | ||
}; | ||
const size = { | ||
height: rect.height, | ||
width: rect.width | ||
}; | ||
// Update pageShiftFactor Element is not visible in viewport | ||
// In case of iOS if the element is not visible in viewport it gives 0 for x-y coordinate. | ||
// In case of iOS if the element is partially visible it gives negative x-y coordinate. | ||
// Subtracting ScrollY/ScrollX ensures if the element is visible in viewport or not. | ||
await this.updatePageShiftFactor(location, scaleFactor); | ||
const coOrdinates = { | ||
top: Math.floor(location.y * scaleFactor) + Math.floor(this.pageYShiftFactor), | ||
bottom: Math.ceil((location.y + size.height) * scaleFactor) + Math.ceil(this.pageYShiftFactor), | ||
left: Math.floor(location.x * scaleFactor) + Math.floor(this.pageXShiftFactor), | ||
right: Math.ceil((location.x + size.width) * scaleFactor) + Math.ceil(this.pageXShiftFactor) | ||
}; | ||
const jsonObject = { | ||
selector, | ||
coOrdinates | ||
}; | ||
return jsonObject; | ||
} | ||
async getSeleniumRegionsByElement(elements) { | ||
const regionsArray = []; | ||
await this.getInitialPosition(); | ||
for (let index = 0; index < elements.length; index++) { | ||
@@ -210,2 +318,3 @@ try { | ||
} | ||
await this.scrollToInitialPosition(this.initialScrollFactor.value[0], this.initialScrollFactor.value[1]); | ||
return regionsArray; | ||
@@ -212,0 +321,0 @@ } |
{ | ||
"name": "@percy/webdriver-utils", | ||
"version": "1.27.6-alpha.0", | ||
"version": "1.27.6-beta.0", | ||
"license": "MIT", | ||
@@ -12,3 +12,3 @@ "repository": { | ||
"access": "public", | ||
"tag": "alpha" | ||
"tag": "beta" | ||
}, | ||
@@ -33,6 +33,6 @@ "engines": { | ||
"dependencies": { | ||
"@percy/config": "1.27.6-alpha.0", | ||
"@percy/sdk-utils": "1.27.6-alpha.0" | ||
"@percy/config": "1.27.6-beta.0", | ||
"@percy/sdk-utils": "1.27.6-beta.0" | ||
}, | ||
"gitHead": "415a083dc13e9453990b042a41d6676f6618df0c" | ||
"gitHead": "264fe038aa6a6ef6ed4d94b53f4f8905218c266e" | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
40179
977
2
14
+ Added@percy/config@1.27.6-beta.0(transitive)
+ Added@percy/logger@1.27.6-beta.0(transitive)
+ Added@percy/sdk-utils@1.27.6-beta.0(transitive)
- Removed@percy/config@1.27.6-alpha.0(transitive)
- Removed@percy/logger@1.27.6-alpha.0(transitive)
- Removed@percy/sdk-utils@1.27.6-alpha.0(transitive)
Updated@percy/config@1.27.6-beta.0