Skip to content

Commit

Permalink
chore: add types to screenshots
Browse files Browse the repository at this point in the history
  • Loading branch information
AtofStryker committed Jul 13, 2022
1 parent e16820b commit 5143ee5
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 46 deletions.
101 changes: 64 additions & 37 deletions packages/driver/src/cy/commands/screenshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,50 @@ import $dom from '../../dom'
import $errUtils from '../../cypress/error_utils'
import $utils from '../../cypress/utils'
import type { Log } from '../../cypress/log'
import type { StateFunc } from '../../cypress/state'

const getViewportHeight = (state) => {
interface InternalScreenshotOptions extends Partial<Cypress.Loggable & Cypress.Timeoutable & Cypress.ScreenshotOptions> {
_log?: Log
}

type Scroll = {
y: number
clip?: Cypress.ScreenshotOptions['clip']
afterScroll?: () => Cypress.Dimensions
}

type TakeScreenshotOptions = {
name?: string
subject?: JQuery<HTMLElement>
simple?: boolean
testFailure?: boolean
runnable: (Mocha.Test | Mocha.Hook) & {
id: string
}
log?: Log
timeout?: number
}

type AutomationOptions = TakeScreenshotOptions & Omit<Cypress.ScreenshotOptions, 'onBeforeScreenshot'| 'onAfterScreenshot' | 'disableTimersAndAnimations' | 'scale' | 'padding'> & Partial<Cypress.ScreenshotOptions>

const getViewportHeight = (state: StateFunc) => {
// TODO this doesn't seem correct
return Math.min(state('viewportHeight'), window.innerHeight)
}

const getViewportWidth = (state) => {
const getViewportWidth = (state: StateFunc) => {
return Math.min(state('viewportWidth'), window.innerWidth)
}

const automateScreenshot = (state, options: TakeScreenshotOptions = {}) => {
const automateScreenshot = (state: StateFunc, options: TakeScreenshotOptions) => {
const { runnable, timeout } = options

const titles: string[] = []

// if this a hook then push both the current test title
// and our own hook title
if (runnable.type === 'hook') {
let ct = runnable.ctx.currentTest
let ct = runnable.ctx?.currentTest

if (runnable.ctx && ct) {
titles.push(ct.title, runnable.title)
Expand Down Expand Up @@ -56,6 +81,7 @@ const automateScreenshot = (state, options: TakeScreenshotOptions = {}) => {
titles,
testId: runnable.id,
takenPaths: state('screenshotPaths'),
// @ts-ignore
testAttemptIndex: $utils.getTestFromRunnable(runnable)._currentRetry,
}, _.omit(options, 'runnable', 'timeout', 'log', 'subject'))

Expand Down Expand Up @@ -84,7 +110,7 @@ const automateScreenshot = (state, options: TakeScreenshotOptions = {}) => {
})
}

const scrollOverrides = (win, doc) => {
const scrollOverrides = (win: Window, doc: Document) => {
const originalOverflow = doc.documentElement.style.overflow
const originalBodyOverflowY = doc.body.style.overflowY
const originalX = win.scrollX
Expand All @@ -108,6 +134,9 @@ const scrollOverrides = (win, doc) => {
// since we scroll down the page in takeScrollingScreenshots
// and don't want the page size to change once we start
// https://github.com/cypress-io/cypress/issues/6099

// Window.Event is private and also deprecated. See https://developer.mozilla.org/en-US/docs/Web/API/Window/event.
// @ts-ignore
win.dispatchEvent(new win.Event('scroll'))

return () => {
Expand All @@ -122,16 +151,16 @@ const scrollOverrides = (win, doc) => {
}
}

const validateNumScreenshots = (numScreenshots, automationOptions) => {
const validateNumScreenshots = (numScreenshots: number, automationOptions: AutomationOptions) => {
if (numScreenshots < 1) {
$errUtils.throwErrByPath('screenshot.invalid_height', {
log: automationOptions.log,
})
}
}

const takeScrollingScreenshots = (scrolls, win, state, automationOptions) => {
const scrollAndTake = ({ y, clip, afterScroll }, index) => {
const takeScrollingScreenshots = (scrolls: Scroll[], win: Window, state: StateFunc, automationOptions: AutomationOptions) => {
const scrollAndTake = ({ y, clip, afterScroll }: Scroll, index) => {
win.scrollTo(0, y)
if (afterScroll) {
clip = afterScroll()
Expand All @@ -151,7 +180,7 @@ const takeScrollingScreenshots = (scrolls, win, state, automationOptions) => {
.then(_.last)
}

const takeFullPageScreenshot = (state, automationOptions) => {
const takeFullPageScreenshot = (state: StateFunc, automationOptions: AutomationOptions) => {
const win = state('window')
const doc = state('document')

Expand Down Expand Up @@ -187,11 +216,12 @@ const takeFullPageScreenshot = (state, automationOptions) => {
.finally(resetScrollOverrides)
}

const applyPaddingToElementPositioning = (elPosition, automationOptions) => {
const applyPaddingToElementPositioning = (elPosition: Cypress.ElementPositioning, automationOptions: AutomationOptions) => {
if (!automationOptions.padding) {
return elPosition
}

// @ts-ignore
const [paddingTop, paddingRight, paddingBottom, paddingLeft] = automationOptions.padding

return {
Expand All @@ -208,7 +238,7 @@ const applyPaddingToElementPositioning = (elPosition, automationOptions) => {
}
}

const takeElementScreenshot = ($el, state, automationOptions) => {
const takeElementScreenshot = ($el: JQuery<HTMLElement>, state: StateFunc, automationOptions: AutomationOptions) => {
const win = state('window')
const doc = state('document')

Expand All @@ -224,7 +254,7 @@ const takeElementScreenshot = ($el, state, automationOptions) => {

validateNumScreenshots(numScreenshots, automationOptions)

const scrolls = _.map(_.times(numScreenshots), (index) => {
const scrolls: Scroll[] = _.map(_.times(numScreenshots), (index) => {
const y = elPosition.fromElWindow.top + (viewportHeight * index)

const afterScroll = () => {
Expand Down Expand Up @@ -274,30 +304,30 @@ const takeElementScreenshot = ($el, state, automationOptions) => {
}

// "app only" means we're hiding the runner UI
const isAppOnly = ({ capture }) => {
const isAppOnly = ({ capture }: { capture: Cypress.ScreenshotOptions['capture']}) => {
return (capture === 'viewport') || (capture === 'fullPage')
}

const getShouldScale = ({ capture, scale }) => {
const getShouldScale = ({ capture, scale }: {
capture: Cypress.ScreenshotOptions['capture']
scale: Cypress.ScreenshotOptions['scale']
}) => {
return isAppOnly({ capture }) ? scale : true
}

const getBlackout = ({ capture, blackout }) => {
const getBlackout = ({ capture, blackout }: {
capture: Cypress.ScreenshotOptions['capture']
blackout: Cypress.ScreenshotOptions['blackout']
}) => {
return isAppOnly({ capture }) ? blackout : []
}

// TODO: anys should be removed.
type TakeScreenshotOptions = {
name?: string
subject?: any
simple?: boolean
testFailure?: boolean
runnable?: any
log?: any
timeout?: number
}

const takeScreenshot = (Cypress, state, screenshotConfig, options: TakeScreenshotOptions = {}) => {
const takeScreenshot = (
Cypress: Cypress.Cypress,
state: StateFunc,
screenshotConfig: Partial<Cypress.ScreenshotOptions> & Pick<Cypress.ScreenshotOptions, 'capture' | 'scale' | 'blackout' | 'overwrite'>,
options: TakeScreenshotOptions,
) => {
const {
capture,
padding,
Expand Down Expand Up @@ -326,7 +356,8 @@ const takeScreenshot = (Cypress, state, screenshotConfig, options: TakeScreensho
const getOptions = (isOpen) => {
return {
id: runnable.id,
testAttemptIndex: $utils.getTestFromRunnable(runnable)._currentRetry,
// @ts-ignore
testAttemptIndex: $utils.getTestFromRunnable(runnable)?._currentRetry,
isOpen,
appOnly: isAppOnly(screenshotConfig),
scale: getShouldScale(screenshotConfig),
Expand All @@ -337,7 +368,7 @@ const takeScreenshot = (Cypress, state, screenshotConfig, options: TakeScreensho
}
}

const before = ($body, $container) => {
const before = ($body: JQuery<HTMLBodyElement>, $container: JQuery<HTMLElement>) => {
return Promise.try(() => {
if (disableTimersAndAnimations) {
return cy.pauseTimers(true)
Expand Down Expand Up @@ -366,7 +397,7 @@ const takeScreenshot = (Cypress, state, screenshotConfig, options: TakeScreensho
})
}

const after = ($body) => {
const after = ($body: JQuery<HTMLBodyElement>) => {
// could fail if iframe is cross-origin, so fail gracefully
try {
if (disableTimersAndAnimations) {
Expand All @@ -392,7 +423,7 @@ const takeScreenshot = (Cypress, state, screenshotConfig, options: TakeScreensho
})
}

const automationOptions = _.extend({}, options, {
const automationOptions: AutomationOptions = _.extend({}, options, {
capture,
clip: {
x: 0,
Expand All @@ -413,13 +444,13 @@ const takeScreenshot = (Cypress, state, screenshotConfig, options: TakeScreensho
})

// use the subject as $el or yield the wrapped documentElement
const $el = $dom.isElement(subject)
const $el: JQuery<HTMLElement> = $dom.isElement(subject)
? subject
: $dom.wrap(state('document').documentElement)

// get the current body of the AUT to accurately calculate screenshot blackouts
// as well as properly enable/disable CSS animations while screenshotting is happening
const $body = Cypress.$('body')
const $body: JQuery<HTMLBodyElement> = Cypress.$('body')

return before($body, $el)
.then(() => {
Expand Down Expand Up @@ -451,10 +482,6 @@ const takeScreenshot = (Cypress, state, screenshotConfig, options: TakeScreensho
.finally(() => after($body))
}

interface InternalScreenshotOptions extends Partial<Cypress.Loggable & Cypress.Timeoutable & Cypress.ScreenshotOptions> {
_log?: Log
}

export default function (Commands, Cypress, cy, state, config) {
// failure screenshot when not interactive
Cypress.on('runnable:after:run:async', (test, runnable) => {
Expand Down
1 change: 1 addition & 0 deletions packages/driver/src/cypress/log.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ const defaults = function (state: StateFunc, config, obj) {

const t = $utils.getTestFromRunnable(runnable)

// @ts-ignore
return t._currentRetry || 0
}

Expand Down
2 changes: 1 addition & 1 deletion packages/driver/src/cypress/screenshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import _ from 'lodash'
import $utils from './utils'
import $errUtils from './error_utils'

const _reset = () => {
const _reset = (): Pick<Cypress.ScreenshotDefaultsOptions, 'capture' | 'scale' | 'disableTimersAndAnimations' | 'screenshotOnRunFailure' | 'blackout' | 'overwrite' | 'onBeforeScreenshot' | 'onAfterScreenshot'> => {
return {
capture: 'fullPage',
scale: false,
Expand Down
4 changes: 2 additions & 2 deletions packages/driver/src/cypress/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,8 +312,8 @@ export default {
return Math.sqrt((deltaX * deltaX) + (deltaY * deltaY))
},

getTestFromRunnable (r) {
return r.ctx.currentTest || r
getTestFromRunnable (r: Mocha.Runnable) {
return r.ctx?.currentTest || r
},

memoize (func, cacheInstance = new Map()) {
Expand Down
4 changes: 2 additions & 2 deletions packages/driver/src/dom/animation.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import $ from 'jquery'

function addCssAnimationDisabler ($body) {
function addCssAnimationDisabler ($body: JQuery<HTMLBodyElement>) {
$(`
<style id="__cypress-animation-disabler">
*, *:before, *:after {
Expand All @@ -11,7 +11,7 @@ function addCssAnimationDisabler ($body) {
`).appendTo($body)
}

function removeCssAnimationDisabler ($body) {
function removeCssAnimationDisabler ($body: JQuery<HTMLBodyElement>) {
$body.find('#__cypress-animation-disabler').remove()
}

Expand Down
8 changes: 4 additions & 4 deletions packages/driver/src/dom/blackout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const styles = (styleString) => {
return styleString.replace(/\s*\n\s*/g, '')
}

function addBlackoutForElement ($body, $el) {
function addBlackoutForElement ($body: JQuery<HTMLBodyElement>, $el: JQuery<HTMLElement>) {
const dimensions = $dimensions.getElementDimensions($el)
const width = dimensions.widthWithBorder
const height = dimensions.heightWithBorder
Expand All @@ -32,8 +32,8 @@ function addBlackoutForElement ($body, $el) {
$(`<div class="__cypress-blackout" style="${style}">`).appendTo($body)
}

function addBlackouts ($body, $container, selector) {
let $el
function addBlackouts ($body: JQuery<HTMLBodyElement>, $container: JQuery<HTMLElement>, selector: string) {
let $el: JQuery<HTMLElement>

try {
// only scope blacked out elements to to screenshotted element, not necessarily the whole body
Expand All @@ -49,7 +49,7 @@ function addBlackouts ($body, $container, selector) {
})
}

function removeBlackouts ($body) {
function removeBlackouts ($body: JQuery<HTMLBodyElement>) {
$body.find('.__cypress-blackout').remove()
}

Expand Down

0 comments on commit 5143ee5

Please sign in to comment.