UNPKG

@applitools/screenshoter

Version:

Applitools universal screenshoter for web and native applications

186 lines (148 loc) 6.97 kB
const utils = require('@applitools/utils') const snippets = require('@applitools/snippets') const findImagePattern = require('./find-image-pattern') const {makeImage} = require('@applitools/image') async function makeTakeViewportScreenshot(options) { const {driver} = options const environment = await driver.getEnvironment() if (environment.isNative && !environment.isWeb) { return makeTakeNativeScreenshot(options) } else if ((environment.isIOS && !environment.isEmulation) || (environment.isNative && environment.isWeb)) { // safari on ios takes screenshot with browser and os interfaces return makeTakeMarkedScreenshot(options) } else if (environment.browserName === 'Firefox') { try { const browserVersion = Number.parseInt(environment.browserVersion, 10) if (browserVersion >= 48 && browserVersion <= 72) { // firefox between versions 48 and 72 takes current frame screenshot only return makeTakeMainContextScreenshot(options) } } catch (ignored) {} } else if (environment.browserName === 'Safari' && Number.parseInt(environment.browserVersion) === 11) { // safari 11 on macs takes full page screenshot return makeTakeSafari11Screenshot(options) } return makeTakeDefaultScreenshot(options) } function makeTakeDefaultScreenshot({driver, stabilization = {}, debug, logger}) { return async function takeScreenshot({name} = {}) { logger.verbose('Taking screenshot (default)...') const viewport = await driver.getViewport() const image = makeImage(await driver.takeScreenshot()) await image.debug({...debug, name, suffix: 'original'}) if (stabilization.scale) image.scale(stabilization.scale) else image.scale(1 / viewport.pixelRatio / viewport.viewportScale) if (stabilization.rotate) image.crop(stabilization.rotate) if (stabilization.crop) image.crop(stabilization.crop) return image } } function makeTakeMainContextScreenshot({driver, stabilization = {}, debug, logger}) { return async function takeScreenshot({name} = {}) { logger.verbose('Taking screenshot (with forced main context)...') const viewport = await driver.getViewport() const originalContext = driver.currentContext await driver.mainContext.focus() const image = makeImage(await driver.takeScreenshot()) await originalContext.focus() await image.debug({...debug, name, suffix: 'original'}) if (stabilization.scale) image.scale(stabilization.scale) else image.scale(1 / viewport.pixelRatio / viewport.viewportScale) if (stabilization.rotate) image.rotate(stabilization.rotate) if (stabilization.crop) image.crop(stabilization.crop) return image } } function makeTakeSafari11Screenshot({driver, stabilization = {}, debug, logger}) { return async function takeScreenshot({name} = {}) { logger.verbose('Taking safari 11 driver screenshot...') const viewport = await driver.getViewport() const image = makeImage(await driver.takeScreenshot()) await image.debug({...debug, name, suffix: 'original'}) if (stabilization.scale) image.scale(stabilization.scale) else image.scale(1 / viewport.pixelRatio / viewport.viewportScale) if (stabilization.rotate) image.rotate(stabilization.rotate) if (stabilization.crop) image.crop(stabilization.crop) else { const viewportLocation = await driver.mainContext.execute(snippets.getElementScrollOffset, []) image.crop(utils.geometry.region(viewportLocation, viewport.viewportSize)) } return image } } function makeTakeMarkedScreenshot({driver, stabilization = {}, debug, logger}) { let viewportRegion return async function takeScreenshot({name} = {}) { logger.verbose('Taking viewport screenshot (using markers)...') const viewport = await driver.getViewport() const image = makeImage(await driver.takeScreenshot()) await image.debug({...debug, name, suffix: 'original'}) if (stabilization.scale) image.scale(stabilization.scale) else image.scale(1 / viewport.pixelRatio / viewport.viewportScale) if (stabilization.rotate) image.rotate(stabilization.rotate) else if (viewport.orientation.startsWith('landscape') && image.width < image.height) image.rotate(-90) if (stabilization.crop) image.crop(stabilization.crop) else { if (!viewportRegion) viewportRegion = await getViewportRegion() if (viewportRegion) image.crop(viewportRegion) } await image.debug({...debug, name, suffix: 'viewport'}) return image } async function getViewportRegion() { const viewport = await driver.getViewport() // marker is -> bwb bwbb wbw bwbb wbww bbb const marker = await driver.mainContext.execute(snippets.addPageMarker, [ { mask: [1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1], size: utils.math.multiplier(viewport.viewportScale * viewport.pixelRatio, 0.05), }, ]) await utils.general.sleep(100) try { const image = makeImage(await driver.takeScreenshot()) if (stabilization.rotate) image.rotate(stabilization.rotate) else if (viewport.orientation.startsWith('landscape') && image.width < image.height) image.rotate(-90) await image.debug({...debug, name: 'marker'}) const markerLocation = findImagePattern(await image.toObject(), { ...marker, scale: viewport.viewportScale * viewport.pixelRatio, }) if (!markerLocation) return null return utils.geometry.region( utils.geometry.scale(markerLocation, 1 / viewport.pixelRatio / viewport.viewportScale), await driver.getViewportSize(), ) } finally { await driver.mainContext.execute(snippets.cleanupPageMarker) } } } function makeTakeNativeScreenshot({driver, stabilization = {}, debug, logger}) { return async function takeScreenshot({name, captureStatusBar, keepNavigationBar} = {}) { logger.verbose('Taking native driver screenshot...') const viewport = await driver.getViewport({keepNavigationBar}) const image = makeImage(await driver.takeScreenshot()) await image.debug({...debug, name, suffix: 'original'}) if (stabilization.scale) image.scale(stabilization.scale) else image.scale(1 / viewport.pixelRatio / viewport.viewportScale) if (stabilization.rotate) image.rotate(stabilization.rotate) else if (viewport.orientation.startsWith('landscape') && image.width < image.height) image.rotate(-90) if (stabilization.crop) image.crop(stabilization.crop) else { const cropRegion = {...viewport.viewportLocation, ...viewport.viewportSize} if (captureStatusBar) { cropRegion.y = 0 cropRegion.height += viewport.statusBarSize } image.crop(cropRegion) } await image.debug({ ...debug, name, suffix: `viewport${captureStatusBar ? '-with-statusbar' : ''}`, }) return image } } module.exports = makeTakeViewportScreenshot