@applitools/screenshoter
Version:
Applitools universal screenshoter for web and native applications
167 lines (145 loc) • 5.3 kB
JavaScript
const utils = require('@applitools/utils')
function makeScroller({logger, element, scrollingMode = 'mixed'}) {
if (!element) return null
const defaultElement = element
return {
element,
moveTo,
getInnerOffset,
getContentSize,
getClientRegion,
getScrollOffset,
getTranslateOffset,
getShiftOffset,
scrollTo,
translateTo,
shiftTo,
preserveState,
restoreState,
hideScrollbars,
restoreScrollbars,
}
async function moveTo(offset, element = defaultElement) {
if (scrollingMode === 'scroll') return scrollTo(offset, element)
if (scrollingMode === 'css') return translateTo(offset, element)
if (scrollingMode === 'mixed') return shiftTo(offset, element)
if (scrollingMode === 'mixed+') return shiftTo(offset, element, {formerlyCssScrollingMode: true})
}
async function getInnerOffset(element = defaultElement) {
if (scrollingMode === 'scroll') return getScrollOffset(element)
if (scrollingMode === 'css') return getTranslateOffset(element)
if (scrollingMode === 'mixed') return getShiftOffset(element)
if (scrollingMode === 'mixed+') return getShiftOffset(element)
}
async function getContentSize(options) {
const size = await element.getContentSize(options)
return size
}
async function getClientRegion() {
const region = await element.getClientRegion()
// const location = await element.context.getLocationInPage()
return region
}
async function getScrollOffset(element = defaultElement) {
try {
const offset = await element.getScrollOffset()
return offset
} catch (err) {
// Sometimes it is expected e.g. on Appium, otherwise, take care
logger.verbose(`Failed to extract current scroll offset!`, err)
return {x: 0, y: 0}
}
}
async function getTranslateOffset(element = defaultElement) {
try {
const offset = await element.getTranslateOffset()
return offset
} catch (err) {
// Sometimes it is expected e.g. on Appium, otherwise, take care
logger.verbose(`Failed to extract current translate offset!`, err)
return {x: 0, y: 0}
}
}
async function getShiftOffset(element = defaultElement) {
try {
const scrollOffset = await element.getScrollOffset()
const translateOffset = await element.getTranslateOffset()
return utils.geometry.offset(scrollOffset, translateOffset)
} catch (err) {
// Sometimes it is expected e.g. on Appium, otherwise, take care
logger.verbose(`Failed to set current scroll offset!.`, err)
return {x: 0, y: 0}
}
}
async function scrollTo(offset, element = defaultElement) {
try {
const scrollOffset = await element.scrollTo(offset)
return scrollOffset
} catch (err) {
// Sometimes it is expected e.g. on Appium, otherwise, take care
logger.verbose(`Failed to set current scroll offset!.`, err)
return {x: 0, y: 0}
}
}
async function translateTo(offset, element = defaultElement) {
try {
await element.scrollTo({x: 0, y: 0})
const translateOffset = await element.translateTo(offset)
return translateOffset
} catch (err) {
// Sometimes it is expected e.g. on Appium, otherwise, take care
logger.verbose(`Failed to set current scroll offset!.`, err)
return {x: 0, y: 0}
}
}
async function shiftTo(offset, element = defaultElement, {formerlyCssScrollingMode} = {}) {
try {
const scrollOffset = await element.scrollTo(offset)
if (utils.geometry.equals(scrollOffset, offset) && !formerlyCssScrollingMode) return scrollOffset
// there is a "bug" in iOS that will not move a root element if it already scrolled, so it should be translated all the way
const environment = await element.driver.getEnvironment()
if (environment.isIOS && (await element.isRoot())) {
const translateOffset = await element.translateTo(offset)
return translateOffset
}
const remainingOffset = utils.geometry.offsetNegative(offset, scrollOffset)
const translateOffset = await element.translateTo(remainingOffset)
return utils.geometry.offset(scrollOffset, translateOffset)
} catch (err) {
// Sometimes it is expected e.g. on Appium, otherwise, take care
logger.verbose(`Failed to set current scroll offset!.`, err)
return {x: 0, y: 0}
}
}
async function preserveState(element = defaultElement) {
try {
return element.preserveState()
} catch (err) {
logger.verbose(`Failed to get current transforms!.`, err)
return {}
}
}
async function restoreState(state, element = defaultElement) {
try {
await element.restoreState(state)
} catch (err) {
logger.verbose(`Failed to restore state!.`, err)
}
}
async function hideScrollbars(element = defaultElement) {
try {
return element.hideScrollbars()
} catch (err) {
logger.verbose(`Failed to get current transforms!.`, err)
return {}
}
}
async function restoreScrollbars(state, element = defaultElement) {
try {
await element.restoreScrollbars(state)
} catch (err) {
logger.verbose(`Failed to restore state!.`, err)
}
}
}
module.exports = makeScroller