Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Yield details object from cy.screenshot() #1733

Merged
merged 1 commit into from
May 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 46 additions & 19 deletions packages/driver/src/cy/commands/screenshot.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -172,20 +172,27 @@ takeElementScreenshot = ($el, state, automationOptions) ->
takeScrollingScreenshots(scrolls, win, automationOptions)
.finally(resetScrollOverrides)

isAppOnly = ({ capture }) ->
capture is "app" or capture is "fullpage"

getShouldScale = ({ capture, scaleAppCaptures }) ->
if isAppOnly({ capture }) then scaleAppCaptures else true

getShouldWait = ({ capture, waitForCommandSynchronization }) ->
if isAppOnly({ capture }) then false else waitForCommandSynchronization

getBlackout = ({ capture, blackout }) ->
if isAppOnly({ capture }) then blackout else []

takeScreenshot = (Cypress, state, screenshotConfig, options = {}) ->
{
blackout
capture
clip
disableTimersAndAnimations
scaleAppCaptures
waitForCommandSynchronization
} = screenshotConfig

{ subject, runnable } = options

appOnly = capture is "app" or capture is "fullpage"

send = (event, props) ->
new Promise (resolve) ->
Cypress.action("cy:#{event}", props, resolve)
Expand All @@ -194,11 +201,11 @@ takeScreenshot = (Cypress, state, screenshotConfig, options = {}) ->
{
id: runnable.id
isOpen: isOpen
appOnly: appOnly
scale: if appOnly then scaleAppCaptures else true
waitForCommandSynchronization: if appOnly then false else waitForCommandSynchronization
appOnly: isAppOnly(screenshotConfig)
scale: getShouldScale(screenshotConfig)
waitForCommandSynchronization: getShouldWait(screenshotConfig)
disableTimersAndAnimations: disableTimersAndAnimations
blackout: if appOnly then blackout else []
blackout: getBlackout(screenshotConfig)
}

before = ->
Expand Down Expand Up @@ -280,12 +287,19 @@ module.exports = (Commands, Cypress, cy, state, config) ->
screenshotConfig = Screenshot.validate(screenshotConfig, "cy.screenshot", options._log)
screenshotConfig = _.extend(Screenshot.getConfig(), screenshotConfig)

if options.log
consoleProps = {
options: userOptions
config: screenshotConfig
}
## set this regardless of options.log b/c its used by the
## yielded value below
consoleProps = _.omit(screenshotConfig, "scaleAppCaptures", "screenshotOnRunFailure")
consoleProps = _.extend(consoleProps, {
scaled: getShouldScale(screenshotConfig)
blackout: getBlackout(screenshotConfig)
waitForCommandSynchronization: getShouldWait(screenshotConfig)
})

if name
consoleProps.name = name

if options.log
options._log = Cypress.log({
message: name
consoleProps: ->
Expand All @@ -301,17 +315,30 @@ module.exports = (Commands, Cypress, cy, state, config) ->
if subject
screenshotConfig.capture = "app"

startTime = Date.now()

takeScreenshot(Cypress, state, screenshotConfig, {
subject: subject
runnable: runnable
name: name
log: options._log
timeout: options.timeout
})
.then ({ path, size }) ->
_.extend(consoleProps, {
"Saved": path
"Size": size
.then (props) ->
duration = Date.now() - startTime

yieldValue = _.extend({}, consoleProps, props, { duration })

{ width, height } = props.dimensions

_.extend(consoleProps, yieldValue, {
duration: "#{duration}ms"
dimensions: "#{width}px x #{height}px"
})
.return(null)

if subject
consoleProps.subject = subject
yieldValue.el = subject

return yieldValue
})
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,21 @@ describe "src/cy/commands/screenshot", ->
beforeEach ->
cy.stub(Cypress, "automation").callThrough()

@serverResult = {
path: "/path/to/screenshot"
size: "12 B"
dimensions: { width: 20, height: 20 }
multipart: false
pixelRatio: 1
takenAt: new Date().toISOString()
}

@screenshotConfig = {
capture: "app"
screenshotOnRunFailure: true
disableTimersAndAnimations: true
waitForCommandSynchronization: true
scaleAppCaptures: true
fullPage: false
blackout: [".foo"]
}

Expand Down Expand Up @@ -73,7 +81,7 @@ describe "src/cy/commands/screenshot", ->
@screenshotConfig.scaleAppCaptures = false
cy.stub(Screenshot, "getConfig").returns(@screenshotConfig)

Cypress.automation.withArgs("take:screenshot").resolves({})
Cypress.automation.withArgs("take:screenshot").resolves(@serverResult)

cy.stub(Cypress, "action").log(false)
.callThrough()
Expand All @@ -94,7 +102,7 @@ describe "src/cy/commands/screenshot", ->
Cypress.config("isInteractive", false)
cy.stub(Screenshot, "getConfig").returns(@screenshotConfig)

Cypress.automation.withArgs("take:screenshot").resolves({})
Cypress.automation.withArgs("take:screenshot").resolves(@serverResult)

test = {
id: "123"
Expand Down Expand Up @@ -123,7 +131,7 @@ describe "src/cy/commands/screenshot", ->
Cypress.config("isInteractive", false)
cy.stub(Screenshot, "getConfig").returns(@screenshotConfig)

Cypress.automation.withArgs("take:screenshot").resolves({})
Cypress.automation.withArgs("take:screenshot").resolves(@serverResult)

test = {
id: "123"
Expand Down Expand Up @@ -153,16 +161,11 @@ describe "src/cy/commands/screenshot", ->
beforeEach ->
cy.stub(Screenshot, "getConfig").returns(@screenshotConfig)

it "nulls out current subject", ->
Cypress.automation.withArgs("take:screenshot").resolves({path: "foo/bar.png", size: "100 kB"})

cy.screenshot().should("be.null")

it "sets name to undefined when not passed name", ->
runnable = cy.state("runnable")
runnable.title = "foo bar"

Cypress.automation.withArgs("take:screenshot").resolves({path: "foo/bar.png", size: "100 kB"})
Cypress.automation.withArgs("take:screenshot").resolves(@serverResult)

cy.screenshot().then ->
expect(Cypress.automation.withArgs("take:screenshot").args[0][1].name).to.be.undefined
Expand All @@ -171,13 +174,13 @@ describe "src/cy/commands/screenshot", ->
runnable = cy.state("runnable")
runnable.title = "foo bar"

Cypress.automation.withArgs("take:screenshot").resolves({path: "foo/bar.png", size: "100 kB"})
Cypress.automation.withArgs("take:screenshot").resolves(@serverResult)

cy.screenshot("my/file").then ->
expect(Cypress.automation.withArgs("take:screenshot").args[0][1].name).to.equal("my/file")

it "calls beforeScreenshot callback with document", ->
Cypress.automation.withArgs("take:screenshot").resolves({})
Cypress.automation.withArgs("take:screenshot").resolves(@serverResult)
cy.stub(Screenshot, "callBeforeScreenshot")
cy.spy(Cypress, "action").log(false)

Expand All @@ -187,7 +190,7 @@ describe "src/cy/commands/screenshot", ->
expect(Screenshot.callBeforeScreenshot).to.be.calledWith(cy.state("document"))

it "calls afterScreenshot callback with document", ->
Cypress.automation.withArgs("take:screenshot").resolves({})
Cypress.automation.withArgs("take:screenshot").resolves(@serverResult)
cy.stub(Screenshot, "callAfterScreenshot")
cy.spy(Cypress, "action").log(false)

Expand All @@ -197,7 +200,7 @@ describe "src/cy/commands/screenshot", ->
expect(Screenshot.callAfterScreenshot).to.be.calledWith(cy.state("document"))

it "pauses then unpauses timers if disableTimersAndAnimations is true", ->
Cypress.automation.withArgs("take:screenshot").resolves({})
Cypress.automation.withArgs("take:screenshot").resolves(@serverResult)
cy.spy(Cypress, "action").log(false)
cy.spy(cy, "pauseTimers")

Expand All @@ -209,7 +212,7 @@ describe "src/cy/commands/screenshot", ->

it "does not pause timers if disableTimersAndAnimations is false", ->
@screenshotConfig.disableTimersAndAnimations = false
Cypress.automation.withArgs("take:screenshot").resolves({})
Cypress.automation.withArgs("take:screenshot").resolves(@serverResult)
cy.spy(Cypress, "action").log(false)

cy
Expand All @@ -218,7 +221,7 @@ describe "src/cy/commands/screenshot", ->
expect(Cypress.action.withArgs("cy:pause:timers")).not.to.be.called

it "sends clip as userClip if specified", ->
Cypress.automation.withArgs("take:screenshot").resolves({})
Cypress.automation.withArgs("take:screenshot").resolves(@serverResult)
cy.spy(Cypress, "action").log(false)
clip = { width: 100, height: 100, x: 0, y: 0 }

Expand All @@ -228,7 +231,7 @@ describe "src/cy/commands/screenshot", ->
expect(Cypress.automation.withArgs("take:screenshot").args[0][1].userClip).to.equal(clip)

it "sends viewport dimensions of main browser window", ->
Cypress.automation.withArgs("take:screenshot").resolves({})
Cypress.automation.withArgs("take:screenshot").resolves(@serverResult)
cy.spy(Cypress, "action").log(false)

cy
Expand All @@ -239,9 +242,29 @@ describe "src/cy/commands/screenshot", ->
height: $(window.parent).height()
})

it "yields an object with details", ->
Cypress.automation.withArgs("take:screenshot").resolves(@serverResult)

expected = _.extend({}, @serverResult, @screenshotConfig, {
name: "name"
scaled: true
waitForCommandSynchronization: false
})
expected = _.omit(expected, "blackout", "dimensions", "screenshotOnRunFailure", "scaleAppCaptures")

cy
.screenshot("name")
.then (result) =>
actual = _.omit(result, "blackout", "dimensions", "duration")
expect(actual).to.eql(expected)
expect(result.blackout).to.eql(@screenshotConfig.blackout)
expect(result.dimensions).to.eql(@serverResult.dimensions)
expect(result.duration).to.be.a("number")
expect(result.duration).to.be.gt(0)

describe "before/after events", ->
beforeEach ->
Cypress.automation.withArgs("take:screenshot").resolves({})
Cypress.automation.withArgs("take:screenshot").resolves(@serverResult)
cy.spy(Cypress, "action").log(false)

it "sends before:screenshot", ->
Expand Down Expand Up @@ -313,7 +336,7 @@ describe "src/cy/commands/screenshot", ->

describe "capture: fullpage", ->
beforeEach ->
Cypress.automation.withArgs("take:screenshot").resolves({})
Cypress.automation.withArgs("take:screenshot").resolves(@serverResult)
cy.spy(Cypress, "action").log(false)
cy.viewport(600, 200)
cy.visit("/fixtures/screenshots.html")
Expand Down Expand Up @@ -375,7 +398,7 @@ describe "src/cy/commands/screenshot", ->

describe "element capture", ->
beforeEach ->
Cypress.automation.withArgs("take:screenshot").resolves({})
Cypress.automation.withArgs("take:screenshot").resolves(@serverResult)
cy.spy(Cypress, "action").log(false)
cy.viewport(600, 200)
cy.visit("/fixtures/screenshots.html")
Expand Down Expand Up @@ -437,16 +460,24 @@ describe "src/cy/commands/screenshot", ->
expect(take.args[0][1].clip).to.eql({ x: 40, y: 0, width: 200, height: 100 })

it "coerces capture option into 'app'", ->
Cypress.automation.withArgs("take:screenshot").resolves({})
Cypress.automation.withArgs("take:screenshot").resolves(@serverResult)

cy.get(".short-element").screenshot({ capture: "runner" })
.then ->
expect(Cypress.action.withArgs("cy:before:screenshot").args[0][1].appOnly).to.be.true
expect(Cypress.automation.withArgs("take:screenshot").args[0][1].capture).to.equal("app")

it "yields an object with el set to subject", ->
cy.get(".short-element").then ($el) ->
cy
.get(".short-element")
.screenshot()
.then ({ el }) =>
expect(el[0]).to.equal($el[0])

describe "timeout", ->
beforeEach ->
Cypress.automation.withArgs("take:screenshot").resolves({path: "foo/bar.png", size: "100 kB"})
Cypress.automation.withArgs("take:screenshot").resolves(@serverResult)

it "sets timeout to Cypress.config(responseTimeout)", ->
Cypress.config("responseTimeout", 2500)
Expand Down Expand Up @@ -583,7 +614,7 @@ describe "src/cy/commands/screenshot", ->

describe ".log", ->
beforeEach ->
Cypress.automation.withArgs("take:screenshot").resolves({path: "foo/bar.png", size: "100 kB"})
Cypress.automation.withArgs("take:screenshot").resolves(@serverResult)

cy.on "log:added", (attrs, log) =>
if attrs.name is "screenshot"
Expand All @@ -610,7 +641,20 @@ describe "src/cy/commands/screenshot", ->
expect(lastLog.get("snapshots")[0]).to.be.an("object")

it "#consoleProps", ->
cy.screenshot().then ->
c = @lastLog.invoke("consoleProps")
expect(c["Saved"]).to.deep.eq "foo/bar.png"
expect(c["Size"]).to.eq "100 kB"
Cypress.automation.withArgs("take:screenshot").resolves(@serverResult)

expected = _.extend({}, @serverResult, @screenshotConfig, {
Command: "screenshot"
scaled: true
waitForCommandSynchronization: false
})
expected = _.omit(expected, "blackout", "dimensions", "screenshotOnRunFailure", "scaleAppCaptures")

cy.screenshot().then =>
consoleProps = @lastLog.invoke("consoleProps")
actual = _.omit(consoleProps, "blackout", "dimensions", "duration")
{ width, height } = @serverResult.dimensions
expect(actual).to.eql(expected)
expect(consoleProps.blackout).to.eql(@screenshotConfig.blackout)
expect(consoleProps.dimensions).to.eql("#{width}px x #{height}px")
expect(consoleProps.duration).to.match(/^\d+ms$/)
6 changes: 3 additions & 3 deletions packages/server/lib/automation/screenshot.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ module.exports = (screenshotsFolder) ->
log("capture %o", data)

screenshots.capture(data, automate)
.then (imageOrBuffer) ->
if imageOrBuffer
screenshots.save(data, imageOrBuffer, screenshotsFolder)
.then (details) ->
if details
screenshots.save(data, details, screenshotsFolder)
.catch (err) ->
screenshots.clearMultipartState()
throw err
Expand Down
4 changes: 2 additions & 2 deletions packages/server/lib/modes/run.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -436,8 +436,8 @@ module.exports = {
testId: data.testId
takenAt: resp.takenAt
path: resp.path
height: resp.height
width: resp.width
height: resp.dimensions.height
width: resp.dimensions.width
}

runSpecs: (options = {}) ->
Expand Down
Loading