UNPKG

@applitools/screenshoter

Version:

Applitools universal screenshoter for web and native applications

155 lines (130 loc) 5.53 kB
const {makeLogger} = require('@applitools/logger') const getTarget = require('./get-target') const scrollIntoViewport = require('./scroll-into-viewport') const takeStitchedScreenshot = require('./take-stitched-screenshot') const takeSimpleScreenshot = require('./take-simple-screenshot') const extractCoordinatesForSelectorsAndElements = require('./extract-coordinates-for-selectors-and-elements') async function takeScreenshot({ driver, frames = [], region, regionsToCalculate = [], fully, scrollingMode, hideScrollbars, hideCaret, captureStatusBar, keepNavigationBar, overlap, framed, wait, stabilization, hooks, debug, logger, lazyLoad, webview, }) { debug = debug || (process.env.APPLITOOLS_DEBUG_SCREENSHOTS_DIR ? {path: process.env.APPLITOOLS_DEBUG_SCREENSHOTS_DIR} : debug) logger = logger ? logger.extend({label: 'screenshoter'}) : makeLogger({label: 'screenshoter'}) // screenshot of a window/app was requested (fully or viewport) const window = !region && (!frames || frames.length === 0) const originalEnvironment = await driver.getEnvironment() // world should be switched to webview if webview screenshot or the window screenshot is requested // in case of window screenshot we will be switching to native app view let activeWorld if (originalEnvironment.isNative && (webview || (window && originalEnvironment.isWeb))) { if (webview === true) { const worlds = await driver.getWorlds() webview = worlds && worlds.find(name => name.includes('WEBVIEW')) } activeWorld = await driver.getCurrentWorld() if (activeWorld !== webview) await driver.switchWorld(webview) else activeWorld = undefined } const environment = await driver.getEnvironment() // framed screenshots could be taken only when screenshot of window/app fully was requested framed = framed && fully && window // screenshots with status bar could be taken only when screenshot of app or framed app fully was requested captureStatusBar = captureStatusBar && environment.isNative && window && (!fully || framed) scrollingMode = !environment.isWeb ? 'scroll' : scrollingMode const activeContext = driver.currentContext const context = frames.length > 0 ? await activeContext.context(frames.reduce((parent, frame) => ({...frame, parent}), null)) : activeContext // traverse from main context to target context to hide scrollbars and preserve context state (scroll/translate position) for (const nextContext of context.path) { const scrollingElement = await nextContext.getScrollingElement() // unlike web apps, native apps do not always have scrolling element if (scrollingElement) { if (environment.isWeb && hideScrollbars) await scrollingElement.hideScrollbars() // this is unwanted but necessary side effect, because it is not possible to extract initial scroll position if (!environment.isWeb && !window) await scrollingElement.scrollTo({x: 0, y: 0}, {force: true}) await scrollingElement.preserveState() } } // blur active element in target context const activeElement = environment.isWeb && hideCaret ? await context.blurElement() : null const target = await getTarget({window, context, region, fully, scrollingMode, logger}) if (target.scroller) { await target.scroller.preserveState() if (environment.isWeb && hideScrollbars) await target.scroller.hideScrollbars() } if (!window && environment.isWeb) await scrollIntoViewport({...target, logger}) if (fully && !target.region && target.scroller) await target.scroller.moveTo({x: 0, y: 0}) const screenshot = fully && target.scroller ? await takeStitchedScreenshot({ ...target, captureStatusBar, overlap, framed, wait, stabilization, debug, logger, lazyLoad, }) : await takeSimpleScreenshot({...target, captureStatusBar, keepNavigationBar, wait, stabilization, debug, logger}) const viewport = await driver.getViewport() screenshot.image.scale(viewport.viewportScale) const calculatedRegions = await extractCoordinatesForSelectorsAndElements({ regionsToCalculate, screenshot, context, logger, }) if (hooks && hooks.afterScreenshot) { await hooks.afterScreenshot({driver, scroller: target.scroller, screenshot}) } return { ...screenshot, element: target.element, scrollingElement: target.scroller && target.scroller.element, calculatedRegions, async restoreState() { if (target.scroller) { await target.scroller.restoreScrollbars() await target.scroller.restoreState() } // if there was active element and we have blurred it, then restore focus if (activeElement) await context.focusElement(activeElement) // traverse from target context to the main context to restore scrollbars and context states for (const prevContext of context.path.reverse()) { const scrollingElement = await prevContext.getScrollingElement() if (scrollingElement) { if (environment.isWeb && hideScrollbars) await scrollingElement.restoreScrollbars() await scrollingElement.restoreState() } } // restore focus on original active context await activeContext.focus() // return driver to previous app world if switched if (activeWorld) await driver.switchWorld(activeWorld) }, } } module.exports = takeScreenshot