Skip to content

Commit

Permalink
chore: add types to screenshots (#22768)
Browse files Browse the repository at this point in the history
* chore: add types to screenshots

* remove wrong reference to event property and opt for Event
  • Loading branch information
AtofStryker committed Jul 18, 2022
1 parent 0aebe4a commit 89acf9c
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 47 deletions.
101 changes: 63 additions & 38 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,7 +134,8 @@ 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
win.dispatchEvent(new win.Event('scroll'))

win.dispatchEvent(new Event('scroll'))

return () => {
doc.documentElement.style.overflow = originalOverflow
Expand All @@ -122,16 +149,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 +178,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 +214,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 +236,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 +252,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 +302,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 +354,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 +366,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 +395,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 +421,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 +442,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 +480,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

5 comments on commit 89acf9c

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 89acf9c Jul 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the linux x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/10.3.1/linux-x64/develop-89acf9c8a5e6220f645eb4b2a72a27b056d010e0/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 89acf9c Jul 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the linux arm64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/10.3.1/linux-arm64/develop-89acf9c8a5e6220f645eb4b2a72a27b056d010e0/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 89acf9c Jul 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the darwin arm64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/10.3.1/darwin-arm64/develop-89acf9c8a5e6220f645eb4b2a72a27b056d010e0/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 89acf9c Jul 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the darwin x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/10.3.1/darwin-x64/develop-89acf9c8a5e6220f645eb4b2a72a27b056d010e0/cypress.tgz

@cypress-bot
Copy link
Contributor

@cypress-bot cypress-bot bot commented on 89acf9c Jul 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Circle has built the win32 x64 version of the Test Runner.

Learn more about this pre-release platform-specific build at https://on.cypress.io/installing-cypress#Install-pre-release-version.

Run this command to install the pre-release locally:

npm install https://cdn.cypress.io/beta/npm/10.3.1/win32-x64/develop-89acf9c8a5e6220f645eb4b2a72a27b056d010e0/cypress.tgz

Please sign in to comment.