Skip to content

Commit

Permalink
enable passing string arguments to timers (#2025)
Browse files Browse the repository at this point in the history
fixes #1854
  • Loading branch information
brian-mann authored Jun 25, 2018
1 parent df0ec8e commit 55b352a
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 29 deletions.
63 changes: 34 additions & 29 deletions packages/driver/src/cypress/cy.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,18 @@ setRemoteIframeProps = ($autIframe, state) ->
create = (specWindow, Cypress, Cookies, state, config, log) ->
stopped = false
commandFns = {}
timersPaused = false

## TODO: move this to its own module
timerQueues = {}
timerQueues.reset = ->
_.extend(timerQueues, {
setTimeout: []
setInterval: []
requestAnimationFrame: []
})

timerQueues.reset()

isStopped = -> stopped

Expand Down Expand Up @@ -143,42 +155,34 @@ create = (specWindow, Cypress, Cookies, state, config, log) ->
return ret
})

timersPaused = false
timerQueues = {
setTimeout: []
setInterval: []
requestAnimationFrame: []
}

wrapNativeMethods = (contentWindow) ->
try
contentWindow.document.hasFocus = ->
top.document.hasFocus()

runTimerQueue = (queue) ->
_.each timerQueues[queue], ([fn, args, context]) ->
fn.apply(context, args)
_.each timerQueues[queue], ([contentWindow, args]) ->
contentWindow[queue].apply(contentWindow, args)

timerQueues[queue] = []

wrapTimers = (contentWindow) ->
originalSetTimeout = contentWindow.setTimeout
originalSetInterval = contentWindow.setInterval
originalRequestAnimationFrame = contentWindow.requestAnimationFrame

wrap = (fn, queue) -> (args...) ->
if timersPaused
timerQueues[queue].push([fn, args, this])
else
fn.apply(this, args)

contentWindow.setTimeout = (fn, args...) ->
originalSetTimeout(wrap(fn, "setTimeout"), args...)

contentWindow.setInterval = (fn, args...) ->
originalSetInterval(wrap(fn, "setInterval"), args...)
originals = {
setTimeout: contentWindow.setTimeout
setInterval: contentWindow.setInterval
requestAnimationFrame: contentWindow.requestAnimationFrame
}

wrapFn = (fnName) ->
return (args...) ->
if timersPaused
timerQueues[fnName].push([contentWindow, args])
else
originals[fnName].apply(contentWindow, args)

contentWindow.requestAnimationFrame = (fn, args...) ->
originalRequestAnimationFrame(wrap(fn, "requestAnimationFrame"), args...)
contentWindow.setTimeout = wrapFn("setTimeout")
contentWindow.setInterval = wrapFn("setInterval")
contentWindow.requestAnimationFrame = wrapFn("requestAnimationFrame")

enqueue = (obj) ->
## if we have a nestedIndex it means we're processing
Expand Down Expand Up @@ -633,7 +637,7 @@ create = (specWindow, Cypress, Cookies, state, config, log) ->

## jquery sync methods
getRemotejQueryInstance: jquery.getRemotejQueryInstance

## focused sync methods
getFocused: focused.getFocused

Expand Down Expand Up @@ -740,6 +744,7 @@ create = (specWindow, Cypress, Cookies, state, config, log) ->
state(backup)

queue.reset()
timerQueues.reset()

cy.removeAllListeners()

Expand Down Expand Up @@ -912,7 +917,7 @@ create = (specWindow, Cypress, Cookies, state, config, log) ->
contentWindowListeners(contentWindow)

wrapNativeMethods(contentWindow)

wrapTimers(contentWindow)

pauseTimers: (pause) ->
Expand Down
13 changes: 13 additions & 0 deletions packages/driver/test/cypress/integration/issues/1854_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
describe('issue #1854', () => {
it('does not error when using setTimeouts referencing string globals', () => {
cy.visit('/fixtures/generic.html')
cy.window().then((win) => {
win.foo = (arg) => {
win.bar = arg
}

win.setTimeout('foo(true)', 100)
})
cy.window().its('bar').should('be.true')
})
})

0 comments on commit 55b352a

Please sign in to comment.