fix double redraw when events fire simultaneously

This commit is contained in:
Leo Horie 2014-07-10 08:23:42 -04:00
parent 0354a4e251
commit ccde633e92
5 changed files with 99 additions and 102 deletions

View file

@ -1,5 +1,14 @@
## Change Log ## Change Log
[v0.1.18](/mithril/archive/v0.1.19) - maintenance
### Bug Fixes:
- fix double redraw when events fire simultaneously
- prevent routes from reverting to original route in some cases
---
[v0.1.18](/mithril/archive/v0.1.18) - maintenance [v0.1.18](/mithril/archive/v0.1.18) - maintenance
### Bug Fixes: ### Bug Fixes:

View file

@ -376,8 +376,6 @@ m.module(document, todo);
Mithril's auto-redrawing system keeps track of controller stability, and only redraws the view once it detects that the controller has finished running all of its code, including asynchronous AJAX payloads. Mithril's auto-redrawing system keeps track of controller stability, and only redraws the view once it detects that the controller has finished running all of its code, including asynchronous AJAX payloads.
Also note that this mechanism itself is not asynchronous if it doesn't need to be: Mithril does not need to wait for the next browser repaint frame to redraw - it doesn't even need to wait for the document ready event on the first redraw - it will redraw immediately upon script completion, if able to.
--- ---
### Summary ### Summary

View file

@ -1,7 +1,7 @@
Mithril = m = new function app(window) { Mithril = m = new function app(window) {
var type = {}.toString var type = {}.toString
var parser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[.+?\])/g, attrParser = /\[(.+?)(?:=("|'|)(.*?)\2)?\]/ var parser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[.+?\])/g, attrParser = /\[(.+?)(?:=("|'|)(.*?)\2)?\]/
function m() { function m() {
var args = arguments var args = arguments
var hasAttrs = type.call(args[1]) == "[object Object]" && !("tag" in args[1]) && !("subtree" in args[1]) var hasAttrs = type.call(args[1]) == "[object Object]" && !("tag" in args[1]) && !("subtree" in args[1])
@ -197,6 +197,7 @@ Mithril = m = new function app(window) {
return cached return cached
} }
function setAttributes(node, tag, dataAttrs, cachedAttrs, namespace) { function setAttributes(node, tag, dataAttrs, cachedAttrs, namespace) {
var groups = {}
for (var attrName in dataAttrs) { for (var attrName in dataAttrs) {
var dataAttr = dataAttrs[attrName] var dataAttr = dataAttrs[attrName]
var cachedAttr = cachedAttrs[attrName] var cachedAttr = cachedAttrs[attrName]
@ -267,7 +268,7 @@ Mithril = m = new function app(window) {
} }
return nodes return nodes
} }
function autoredraw(callback, object) { function autoredraw(callback, object, group) {
return function(e) { return function(e) {
e = e || event e = e || event
m.startComputation() m.startComputation()
@ -316,7 +317,7 @@ Mithril = m = new function app(window) {
return value return value
} }
var roots = [], modules = [], controllers = [], now = 0, lastRedraw = 0, lastRedrawId = 0, computePostRedrawHook = null var roots = [], modules = [], controllers = [], lastRedrawId = 0, computePostRedrawHook = null
m.module = function(root, module) { m.module = function(root, module) {
var index = roots.indexOf(root) var index = roots.indexOf(root)
if (index < 0) index = roots.length if (index < 0) index = roots.length
@ -336,14 +337,10 @@ Mithril = m = new function app(window) {
} }
} }
m.redraw = function() { m.redraw = function() {
now = window.performance && window.performance.now ? window.performance.now() : new window.Date().getTime() var cancel = window.cancelAnimationFrame || window.clearTimeout
if (now - lastRedraw > 16) redraw() var defer = window.requestAnimationFrame || window.setTimeout
else { cancel(lastRedrawId)
var cancel = window.cancelAnimationFrame || window.clearTimeout lastRedrawId = defer(redraw, 0)
var defer = window.requestAnimationFrame || window.setTimeout
cancel(lastRedrawId)
lastRedrawId = defer(redraw, 0)
}
} }
function redraw() { function redraw() {
for (var i = 0; i < roots.length; i++) { for (var i = 0; i < roots.length; i++) {
@ -353,7 +350,6 @@ Mithril = m = new function app(window) {
computePostRedrawHook() computePostRedrawHook()
computePostRedrawHook = null computePostRedrawHook = null
} }
lastRedraw = now
} }
var pendingRequests = 0 var pendingRequests = 0
@ -391,7 +387,6 @@ Mithril = m = new function app(window) {
} }
computePostRedrawHook = setScroll computePostRedrawHook = setScroll
window[listener]() window[listener]()
currentRoute = normalizeRoute(window.location[m.route.mode])
} }
else if (arguments[0].addEventListener) { else if (arguments[0].addEventListener) {
var element = arguments[0] var element = arguments[0]
@ -410,7 +405,7 @@ Mithril = m = new function app(window) {
if (querystring) currentRoute += (currentRoute.indexOf("?") === -1 ? "?" : "&") + querystring if (querystring) currentRoute += (currentRoute.indexOf("?") === -1 ? "?" : "&") + querystring
var shouldReplaceHistoryEntry = (arguments.length == 3 ? arguments[2] : arguments[1]) === true var shouldReplaceHistoryEntry = (arguments.length == 3 ? arguments[2] : arguments[1]) === true
if (window.history.pushState) { if (window.history.pushState) {
computePostRedrawHook = function() { computePostRedrawHook = function() {
window.history[shouldReplaceHistoryEntry ? "replaceState" : "pushState"](null, window.document.title, modes[m.route.mode] + currentRoute) window.history[shouldReplaceHistoryEntry ? "replaceState" : "pushState"](null, window.document.title, modes[m.route.mode] + currentRoute)
@ -585,7 +580,7 @@ Mithril = m = new function app(window) {
var maybeXhr = options.config(xhr, options) var maybeXhr = options.config(xhr, options)
if (maybeXhr !== undefined) xhr = maybeXhr if (maybeXhr !== undefined) xhr = maybeXhr
} }
xhr.send(options.data) xhr.send(options.method == "GET" ? "" : options.data)
return xhr return xhr
} }
function bindData(xhrOptions, data, serialize) { function bindData(xhrOptions, data, serialize) {

View file

@ -28,7 +28,7 @@ function testMithril(mock) {
//m.module //m.module
test(function() { test(function() {
mock.performance.$elapse(50) mock.requestAnimationFrame.$resolve()
var root1 = mock.document.createElement("div") var root1 = mock.document.createElement("div")
m.module(root1, { m.module(root1, {
@ -671,23 +671,22 @@ function testMithril(mock) {
//m.redraw //m.redraw
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
var controller var controller
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
m.module(root, { m.module(root, {
controller: function() {controller = this}, controller: function() {controller = this},
view: function(ctrl) {return ctrl.value} view: function(ctrl) {return ctrl.value}
}) })
mock.requestAnimationFrame.$resolve()
var valueBefore = root.childNodes[0].nodeValue
controller.value = "foo" controller.value = "foo"
m.redraw() m.redraw()
var valueBefore = root.childNodes[0].nodeValue mock.requestAnimationFrame.$resolve()
mock.performance.$elapse(50)
m.redraw()
mock.performance.$elapse(50) //teardown
return valueBefore === "" && root.childNodes[0].nodeValue === "foo" return valueBefore === "" && root.childNodes[0].nodeValue === "foo"
}) })
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
var count = 0 var count = 0
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
m.module(root, { m.module(root, {
@ -696,18 +695,18 @@ function testMithril(mock) {
count++ count++
} }
}) })
mock.requestAnimationFrame.$resolve() //teardown
m.redraw() m.redraw()
m.redraw() m.redraw()
m.redraw() m.redraw()
mock.performance.$elapse(50)
m.redraw() m.redraw()
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return count === 2 return count === 2
}) })
//m.route //m.route
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.search = "?" mock.location.search = "?"
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
@ -715,11 +714,11 @@ function testMithril(mock) {
m.route(root, "/test1", { m.route(root, "/test1", {
"/test1": {controller: function() {}, view: function() {return "foo"}} "/test1": {controller: function() {}, view: function() {return "foo"}}
}) })
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return mock.location.search == "?/test1" && root.childNodes[0].nodeValue === "foo" return mock.location.search == "?/test1" && root.childNodes[0].nodeValue === "foo"
}) })
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.pathname = "/" mock.location.pathname = "/"
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
@ -727,11 +726,11 @@ function testMithril(mock) {
m.route(root, "/test2", { m.route(root, "/test2", {
"/test2": {controller: function() {}, view: function() {return "foo"}} "/test2": {controller: function() {}, view: function() {return "foo"}}
}) })
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return mock.location.pathname == "/test2" && root.childNodes[0].nodeValue === "foo" return mock.location.pathname == "/test2" && root.childNodes[0].nodeValue === "foo"
}) })
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.hash = "#" mock.location.hash = "#"
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
@ -739,11 +738,11 @@ function testMithril(mock) {
m.route(root, "/test3", { m.route(root, "/test3", {
"/test3": {controller: function() {}, view: function() {return "foo"}} "/test3": {controller: function() {}, view: function() {return "foo"}}
}) })
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return mock.location.hash == "#/test3" && root.childNodes[0].nodeValue === "foo" return mock.location.hash == "#/test3" && root.childNodes[0].nodeValue === "foo"
}) })
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.search = "?" mock.location.search = "?"
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
@ -751,11 +750,11 @@ function testMithril(mock) {
m.route(root, "/test4/foo", { m.route(root, "/test4/foo", {
"/test4/:test": {controller: function() {}, view: function() {return m.route.param("test")}} "/test4/:test": {controller: function() {}, view: function() {return m.route.param("test")}}
}) })
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return mock.location.search == "?/test4/foo" && root.childNodes[0].nodeValue === "foo" return mock.location.search == "?/test4/foo" && root.childNodes[0].nodeValue === "foo"
}) })
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.search = "?" mock.location.search = "?"
var module = {controller: function() {}, view: function() {return m.route.param("test")}} var module = {controller: function() {}, view: function() {return m.route.param("test")}}
@ -767,14 +766,14 @@ function testMithril(mock) {
"/test5/:test": module "/test5/:test": module
}) })
var paramValueBefore = m.route.param("test") var paramValueBefore = m.route.param("test")
mock.performance.$elapse(50) mock.requestAnimationFrame.$resolve()
m.route("/") m.route("/")
var paramValueAfter = m.route.param("test") var paramValueAfter = m.route.param("test")
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return mock.location.search == "?/" && paramValueBefore === "foo" && paramValueAfter === undefined return mock.location.search == "?/" && paramValueBefore === "foo" && paramValueAfter === undefined
}) })
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.search = "?" mock.location.search = "?"
var module = {controller: function() {}, view: function() {return m.route.param("a1")}} var module = {controller: function() {}, view: function() {return m.route.param("a1")}}
@ -786,15 +785,15 @@ function testMithril(mock) {
"/test6/:a1": module "/test6/:a1": module
}) })
var paramValueBefore = m.route.param("a1") var paramValueBefore = m.route.param("a1")
mock.performance.$elapse(50) mock.requestAnimationFrame.$resolve()
m.route("/") m.route("/")
var paramValueAfter = m.route.param("a1") var paramValueAfter = m.route.param("a1")
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return mock.location.search == "?/" && paramValueBefore === "foo" && paramValueAfter === undefined return mock.location.search == "?/" && paramValueBefore === "foo" && paramValueAfter === undefined
}) })
test(function() { test(function() {
//https://github.com/lhorie/mithril.js/issues/61 //https://github.com/lhorie/mithril.js/issues/61
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.search = "?" mock.location.search = "?"
var module = {controller: function() {}, view: function() {return m.route.param("a1")}} var module = {controller: function() {}, view: function() {return m.route.param("a1")}}
@ -806,14 +805,14 @@ function testMithril(mock) {
"/test7/:a1": module "/test7/:a1": module
}) })
var routeValueBefore = m.route() var routeValueBefore = m.route()
mock.performance.$elapse(50) mock.requestAnimationFrame.$resolve()
m.route("/") m.route("/")
var routeValueAfter = m.route() var routeValueAfter = m.route()
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return routeValueBefore === "/test7/foo" && routeValueAfter === "/" return routeValueBefore === "/test7/foo" && routeValueAfter === "/"
}) })
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.search = "?" mock.location.search = "?"
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
@ -826,11 +825,11 @@ function testMithril(mock) {
} }
} }
}) })
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return mock.location.search == "?/test8/foo/SEP/bar/baz" && root.childNodes[0].nodeValue === "foo_bar/baz" return mock.location.search == "?/test8/foo/SEP/bar/baz" && root.childNodes[0].nodeValue === "foo_bar/baz"
}) })
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.search = "?" mock.location.search = "?"
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
@ -843,11 +842,11 @@ function testMithril(mock) {
} }
} }
}) })
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return mock.location.search == "?/test9/foo/bar/SEP/baz" && root.childNodes[0].nodeValue === "foo/bar_baz" return mock.location.search == "?/test9/foo/bar/SEP/baz" && root.childNodes[0].nodeValue === "foo/bar_baz"
}) })
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.search = "?" mock.location.search = "?"
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
@ -860,11 +859,11 @@ function testMithril(mock) {
} }
} }
}) })
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return root.childNodes[0].nodeValue === "foo bar" return root.childNodes[0].nodeValue === "foo bar"
}) })
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.search = "?" mock.location.search = "?"
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
@ -873,13 +872,13 @@ function testMithril(mock) {
"/": {controller: function() {}, view: function() {return "foo"}}, "/": {controller: function() {}, view: function() {return "foo"}},
"/test11": {controller: function() {}, view: function() {return "bar"}} "/test11": {controller: function() {}, view: function() {return "bar"}}
}) })
mock.performance.$elapse(50) mock.requestAnimationFrame.$resolve()
m.route("/test11/") m.route("/test11/")
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return mock.location.search == "?/test11/" && root.childNodes[0].nodeValue === "bar" return mock.location.search == "?/test11/" && root.childNodes[0].nodeValue === "bar"
}) })
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.search = "?" mock.location.search = "?"
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
@ -888,13 +887,13 @@ function testMithril(mock) {
"/": {controller: function() {}, view: function() {}}, "/": {controller: function() {}, view: function() {}},
"/test12": {controller: function() {}, view: function() {}} "/test12": {controller: function() {}, view: function() {}}
}) })
mock.performance.$elapse(50) mock.requestAnimationFrame.$resolve()
m.route("/test12?a=foo&b=bar") m.route("/test12?a=foo&b=bar")
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return mock.location.search == "?/test12?a=foo&b=bar" && m.route.param("a") == "foo" && m.route.param("b") == "bar" return mock.location.search == "?/test12?a=foo&b=bar" && m.route.param("a") == "foo" && m.route.param("b") == "bar"
}) })
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.search = "?" mock.location.search = "?"
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
@ -903,13 +902,13 @@ function testMithril(mock) {
"/": {controller: function() {}, view: function() {return "bar"}}, "/": {controller: function() {}, view: function() {return "bar"}},
"/test13/:test": {controller: function() {}, view: function() {return m.route.param("test")}} "/test13/:test": {controller: function() {}, view: function() {return m.route.param("test")}}
}) })
mock.performance.$elapse(50) mock.requestAnimationFrame.$resolve()
m.route("/test13/foo?test=bar") m.route("/test13/foo?test=bar")
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return mock.location.search == "?/test13/foo?test=bar" && root.childNodes[0].nodeValue === "foo" return mock.location.search == "?/test13/foo?test=bar" && root.childNodes[0].nodeValue === "foo"
}) })
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.search = "?" mock.location.search = "?"
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
@ -918,13 +917,13 @@ function testMithril(mock) {
"/": {controller: function() {}, view: function() {return "bar"}}, "/": {controller: function() {}, view: function() {return "bar"}},
"/test14": {controller: function() {}, view: function() {return "foo"}} "/test14": {controller: function() {}, view: function() {return "foo"}}
}) })
mock.performance.$elapse(50) mock.requestAnimationFrame.$resolve()
m.route("/test14?test&test2=") m.route("/test14?test&test2=")
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return mock.location.search == "?/test14?test&test2=" && m.route.param("test") === true && m.route.param("test2") === "" return mock.location.search == "?/test14?test&test2=" && m.route.param("test") === true && m.route.param("test2") === ""
}) })
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.search = "?" mock.location.search = "?"
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
@ -933,13 +932,13 @@ function testMithril(mock) {
"/": {controller: function() {}, view: function() {}}, "/": {controller: function() {}, view: function() {}},
"/test12": {controller: function() {}, view: function() {}} "/test12": {controller: function() {}, view: function() {}}
}) })
mock.performance.$elapse(50) mock.requestAnimationFrame.$resolve()
m.route("/test12", {a: "foo", b: "bar"}) m.route("/test12", {a: "foo", b: "bar"})
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return mock.location.search == "?/test12?a=foo&b=bar" && m.route.param("a") == "foo" && m.route.param("b") == "bar" return mock.location.search == "?/test12?a=foo&b=bar" && m.route.param("a") == "foo" && m.route.param("b") == "bar"
}) })
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.search = "?" mock.location.search = "?"
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
@ -949,13 +948,13 @@ function testMithril(mock) {
"/": {controller: function() {route1 = m.route()}, view: function() {}}, "/": {controller: function() {route1 = m.route()}, view: function() {}},
"/test13": {controller: function() {route2 = m.route()}, view: function() {}} "/test13": {controller: function() {route2 = m.route()}, view: function() {}}
}) })
mock.performance.$elapse(50) mock.requestAnimationFrame.$resolve()
m.route("/test13") m.route("/test13")
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return route1 == "/" && route2 == "/test13" return route1 == "/" && route2 == "/test13"
}) })
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.search = "?" mock.location.search = "?"
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
@ -976,13 +975,13 @@ function testMithril(mock) {
}, },
"/test14": {controller: function() {}, view: function() {}} "/test14": {controller: function() {}, view: function() {}}
}) })
mock.performance.$elapse(50) mock.requestAnimationFrame.$resolve()
m.route("/test14") m.route("/test14")
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return unloaded == 1 return unloaded == 1
}) })
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.search = "?" mock.location.search = "?"
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
@ -1011,13 +1010,13 @@ function testMithril(mock) {
} }
} }
}) })
mock.performance.$elapse(50) mock.requestAnimationFrame.$resolve()
m.route("/test15") m.route("/test15")
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return unloaded == 1 return unloaded == 1
}) })
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.search = "?" mock.location.search = "?"
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
@ -1043,13 +1042,13 @@ function testMithril(mock) {
} }
} }
}) })
mock.performance.$elapse(50) mock.requestAnimationFrame.$resolve()
m.route("/test16") m.route("/test16")
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return unloaded == 1 return unloaded == 1
}) })
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.search = "?" mock.location.search = "?"
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
@ -1077,13 +1076,13 @@ function testMithril(mock) {
} }
} }
}) })
mock.performance.$elapse(50) mock.requestAnimationFrame.$resolve()
m.route("/test17") m.route("/test17")
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return unloaded == 1 return unloaded == 1
}) })
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.search = "?" mock.location.search = "?"
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
@ -1109,13 +1108,13 @@ function testMithril(mock) {
} }
} }
}) })
mock.performance.$elapse(50) mock.requestAnimationFrame.$resolve()
m.route("/test18") m.route("/test18")
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return unloaded == 1 return unloaded == 1
}) })
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.search = "?" mock.location.search = "?"
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
@ -1153,13 +1152,13 @@ function testMithril(mock) {
} }
} }
}) })
mock.performance.$elapse(50) mock.requestAnimationFrame.$resolve()
m.route("/test20") m.route("/test20")
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return unloaded == 1 return unloaded == 1
}) })
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.search = "?" mock.location.search = "?"
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
@ -1196,13 +1195,13 @@ function testMithril(mock) {
} }
} }
}) })
mock.performance.$elapse(50) mock.requestAnimationFrame.$resolve()
m.route("/test21") m.route("/test21")
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return unloaded == 1 return unloaded == 1
}) })
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.search = "?" mock.location.search = "?"
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
@ -1221,15 +1220,15 @@ function testMithril(mock) {
} }
}, },
}) })
mock.performance.$elapse(50) mock.requestAnimationFrame.$resolve()
var foo = root.childNodes[0].childNodes[0].nodeValue; var foo = root.childNodes[0].childNodes[0].nodeValue;
m.route("/bar") m.route("/bar")
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
var bar = root.childNodes[0].childNodes[0].nodeValue; var bar = root.childNodes[0].childNodes[0].nodeValue;
return (foo === "foo" && bar === "bar") return (foo === "foo" && bar === "bar")
}) })
test(function() { test(function() {
mock.performance.$elapse(50) //setup mock.requestAnimationFrame.$resolve() //setup
mock.location.search = "?" mock.location.search = "?"
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
@ -1254,9 +1253,9 @@ function testMithril(mock) {
} }
}, },
}) })
mock.performance.$elapse(50) mock.requestAnimationFrame.$resolve()
m.route("/bar1") m.route("/bar1")
mock.performance.$elapse(50) //teardown mock.requestAnimationFrame.$resolve() //teardown
return unloaded == 1 return unloaded == 1
}) })
//end m.route //end m.route
@ -1502,7 +1501,7 @@ function testMithril(mock) {
//m.startComputation/m.endComputation //m.startComputation/m.endComputation
test(function() { test(function() {
mock.performance.$elapse(50) mock.requestAnimationFrame.$resolve()
var controller var controller
var root = mock.document.createElement("div") var root = mock.document.createElement("div")
@ -1511,11 +1510,13 @@ function testMithril(mock) {
view: function(ctrl) {return ctrl.value} view: function(ctrl) {return ctrl.value}
}) })
mock.performance.$elapse(50) mock.requestAnimationFrame.$resolve()
m.startComputation() m.startComputation()
controller.value = "foo" controller.value = "foo"
m.endComputation() m.endComputation()
mock.requestAnimationFrame.$resolve()
return root.childNodes[0].nodeValue === "foo" return root.childNodes[0].nodeValue === "foo"
}) })

View file

@ -71,17 +71,11 @@ mock.window = new function() {
child.parentNode = null child.parentNode = null
} }
window.scrollTo = function() {} window.scrollTo = function() {}
window.performance = new function () {
var timestamp = 50
this.$elapse = function(amount) {timestamp += amount}
this.now = function() {return timestamp}
}
window.cancelAnimationFrame = function() {} window.cancelAnimationFrame = function() {}
window.requestAnimationFrame = function(callback) {window.requestAnimationFrame.$callback = callback} window.requestAnimationFrame = function(callback) {window.requestAnimationFrame.$callback = callback}
window.requestAnimationFrame.$resolve = function() { window.requestAnimationFrame.$resolve = function() {
if (window.requestAnimationFrame.$callback) window.requestAnimationFrame.$callback() if (window.requestAnimationFrame.$callback) window.requestAnimationFrame.$callback()
window.requestAnimationFrame.$callback = null window.requestAnimationFrame.$callback = null
window.performance.$elapse(20)
} }
window.XMLHttpRequest = new function() { window.XMLHttpRequest = new function() {
var request = function() { var request = function() {