mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
1225 lines
26 KiB
JavaScript
1225 lines
26 KiB
JavaScript
"use strict"
|
|
|
|
var o = require("../../ospec/ospec")
|
|
var callAsync = require("../../test-utils/callAsync")
|
|
var browserMock = require("../../test-utils/browserMock")
|
|
|
|
var m = require("../../render/hyperscript")
|
|
var callAsync = require("../../test-utils/callAsync")
|
|
var coreRenderer = require("../../render/render")
|
|
var apiRedraw = require("../../api/redraw")
|
|
var apiRouter = require("../../api/router")
|
|
var Promise = require("../../promise/promise")
|
|
|
|
o.spec("route", function() {
|
|
void [{protocol: "http:", hostname: "localhost"}, {protocol: "file:", hostname: "/"}].forEach(function(env) {
|
|
void ["#", "?", "", "#!", "?!", "/foo"].forEach(function(prefix) {
|
|
o.spec("using prefix `" + prefix + "` starting on " + env.protocol + "//" + env.hostname, function() {
|
|
var FRAME_BUDGET = Math.floor(1000 / 60)
|
|
var $window, root, redrawService, route
|
|
|
|
o.beforeEach(function() {
|
|
$window = browserMock(env)
|
|
|
|
root = $window.document.body
|
|
|
|
redrawService = apiRedraw($window)
|
|
route = apiRouter($window, redrawService)
|
|
route.prefix(prefix)
|
|
})
|
|
|
|
o("throws on invalid `root` DOM node", function() {
|
|
var threw = false
|
|
try {
|
|
route(null, '/', {'/':{view: function() {}}})
|
|
} catch (e) {
|
|
threw = true
|
|
}
|
|
o(threw).equals(true)
|
|
})
|
|
|
|
o("renders into `root`", function() {
|
|
$window.location.href = prefix + "/"
|
|
route(root, "/", {
|
|
"/" : {
|
|
view: function() {
|
|
return m("div")
|
|
}
|
|
}
|
|
})
|
|
|
|
o(root.firstChild.nodeName).equals("DIV")
|
|
})
|
|
|
|
o("routed mount points can redraw synchronously (#1275)", function() {
|
|
var view = o.spy()
|
|
|
|
$window.location.href = prefix + "/"
|
|
route(root, "/", {"/":{view:view}})
|
|
|
|
o(view.callCount).equals(1)
|
|
|
|
redrawService.redraw()
|
|
|
|
o(view.callCount).equals(2)
|
|
|
|
})
|
|
|
|
o("default route doesn't break back button", function(done) {
|
|
$window.location.href = "http://old.com"
|
|
$window.location.href = "http://new.com"
|
|
|
|
route(root, "/a", {
|
|
"/a" : {
|
|
view: function() {
|
|
return m("div")
|
|
}
|
|
}
|
|
})
|
|
|
|
callAsync(function() {
|
|
o(root.firstChild.nodeName).equals("DIV")
|
|
|
|
o(route.get()).equals("/a")
|
|
|
|
$window.history.back()
|
|
|
|
o($window.location.pathname).equals("/")
|
|
o($window.location.hostname).equals("old.com")
|
|
|
|
done()
|
|
})
|
|
})
|
|
|
|
o("default route does not inherit params", function(done) {
|
|
$window.location.href = "/invalid?foo=bar"
|
|
route(root, "/a", {
|
|
"/a" : {
|
|
oninit: init,
|
|
view: function() {
|
|
return m("div")
|
|
}
|
|
}
|
|
})
|
|
|
|
function init(vnode) {
|
|
o(vnode.attrs.foo).equals(undefined)
|
|
|
|
done()
|
|
}
|
|
})
|
|
|
|
o("redraws when render function is executed", function() {
|
|
var onupdate = o.spy()
|
|
var oninit = o.spy()
|
|
|
|
$window.location.href = prefix + "/"
|
|
route(root, "/", {
|
|
"/" : {
|
|
view: function() {
|
|
return m("div", {
|
|
oninit: oninit,
|
|
onupdate: onupdate
|
|
})
|
|
}
|
|
}
|
|
})
|
|
|
|
o(oninit.callCount).equals(1)
|
|
|
|
redrawService.redraw()
|
|
|
|
o(onupdate.callCount).equals(1)
|
|
})
|
|
|
|
o("redraws on events", function(done) {
|
|
var onupdate = o.spy()
|
|
var oninit = o.spy()
|
|
var onclick = o.spy()
|
|
var e = $window.document.createEvent("MouseEvents")
|
|
|
|
e.initEvent("click", true, true)
|
|
|
|
$window.location.href = prefix + "/"
|
|
route(root, "/", {
|
|
"/" : {
|
|
view: function() {
|
|
return m("div", {
|
|
oninit: oninit,
|
|
onupdate: onupdate,
|
|
onclick: onclick,
|
|
})
|
|
}
|
|
}
|
|
})
|
|
|
|
root.firstChild.dispatchEvent(e)
|
|
|
|
o(oninit.callCount).equals(1)
|
|
|
|
o(onclick.callCount).equals(1)
|
|
o(onclick.this).equals(root.firstChild)
|
|
o(onclick.args[0].type).equals("click")
|
|
o(onclick.args[0].target).equals(root.firstChild)
|
|
|
|
// Wrapped to give time for the rate-limited redraw to fire
|
|
callAsync(function() {
|
|
o(onupdate.callCount).equals(1)
|
|
|
|
done()
|
|
})
|
|
})
|
|
|
|
o("event handlers can skip redraw", function(done) {
|
|
var onupdate = o.spy()
|
|
var oninit = o.spy()
|
|
var onclick = o.spy()
|
|
var e = $window.document.createEvent("MouseEvents")
|
|
|
|
e.initEvent("click", true, true)
|
|
|
|
$window.location.href = prefix + "/"
|
|
route(root, "/", {
|
|
"/" : {
|
|
view: function() {
|
|
return m("div", {
|
|
oninit: oninit,
|
|
onupdate: onupdate,
|
|
onclick: function(e) {
|
|
e.redraw = false
|
|
},
|
|
})
|
|
}
|
|
}
|
|
})
|
|
|
|
root.firstChild.dispatchEvent(e)
|
|
|
|
o(oninit.callCount).equals(1)
|
|
|
|
// Wrapped to ensure no redraw fired
|
|
callAsync(function() {
|
|
o(onupdate.callCount).equals(0)
|
|
|
|
done()
|
|
})
|
|
})
|
|
|
|
o("changes location on route.link", function() {
|
|
var e = $window.document.createEvent("MouseEvents")
|
|
|
|
e.initEvent("click", true, true)
|
|
|
|
$window.location.href = prefix + "/"
|
|
route(root, "/", {
|
|
"/" : {
|
|
view: function() {
|
|
return m("a", {
|
|
href: "/test",
|
|
oncreate: route.link
|
|
})
|
|
}
|
|
},
|
|
"/test" : {
|
|
view : function() {
|
|
return m("div")
|
|
}
|
|
}
|
|
})
|
|
|
|
var slash = prefix[0] === "/" ? "" : "/"
|
|
|
|
o($window.location.href).equals(env.protocol + "//" + (env.hostname === "/" ? "" : env.hostname) + slash + (prefix ? prefix + "/" : ""))
|
|
|
|
root.firstChild.dispatchEvent(e)
|
|
|
|
o($window.location.href).equals(env.protocol + "//" + (env.hostname === "/" ? "" : env.hostname) + slash + (prefix ? prefix + "/" : "") + "test")
|
|
})
|
|
|
|
o("accepts RouteResolver with onmatch that returns Component", function(done) {
|
|
var matchCount = 0
|
|
var renderCount = 0
|
|
var Component = {
|
|
view: function() {
|
|
return m("span")
|
|
}
|
|
}
|
|
|
|
var resolver = {
|
|
onmatch: function(args, requestedPath) {
|
|
matchCount++
|
|
|
|
o(args.id).equals("abc")
|
|
o(requestedPath).equals("/abc")
|
|
o(this).equals(resolver)
|
|
return Component
|
|
},
|
|
render: function(vnode) {
|
|
renderCount++
|
|
|
|
o(vnode.attrs.id).equals("abc")
|
|
o(this).equals(resolver)
|
|
|
|
return vnode
|
|
},
|
|
}
|
|
|
|
$window.location.href = prefix + "/abc"
|
|
route(root, "/abc", {
|
|
"/:id" : resolver
|
|
})
|
|
|
|
callAsync(function() {
|
|
o(matchCount).equals(1)
|
|
o(renderCount).equals(1)
|
|
o(root.firstChild.nodeName).equals("SPAN")
|
|
done()
|
|
})
|
|
})
|
|
|
|
o("accepts RouteResolver with onmatch that returns Promise<Component>", function(done) {
|
|
var matchCount = 0
|
|
var renderCount = 0
|
|
var Component = {
|
|
view: function() {
|
|
return m("span")
|
|
}
|
|
}
|
|
|
|
var resolver = {
|
|
onmatch: function(args, requestedPath) {
|
|
matchCount++
|
|
|
|
o(args.id).equals("abc")
|
|
o(requestedPath).equals("/abc")
|
|
o(this).equals(resolver)
|
|
return Promise.resolve(Component)
|
|
},
|
|
render: function(vnode) {
|
|
renderCount++
|
|
|
|
o(vnode.attrs.id).equals("abc")
|
|
o(this).equals(resolver)
|
|
|
|
return vnode
|
|
},
|
|
}
|
|
|
|
$window.location.href = prefix + "/abc"
|
|
route(root, "/abc", {
|
|
"/:id" : resolver
|
|
})
|
|
|
|
callAsync(function() {
|
|
o(matchCount).equals(1)
|
|
o(renderCount).equals(1)
|
|
o(root.firstChild.nodeName).equals("SPAN")
|
|
done()
|
|
})
|
|
})
|
|
|
|
o("accepts RouteResolver with onmatch that returns Promise<undefined>", function(done) {
|
|
var matchCount = 0
|
|
var renderCount = 0
|
|
var Component = {
|
|
view: function() {
|
|
return m("span")
|
|
}
|
|
}
|
|
|
|
var resolver = {
|
|
onmatch: function(args, requestedPath) {
|
|
matchCount++
|
|
|
|
o(args.id).equals("abc")
|
|
o(requestedPath).equals("/abc")
|
|
o(this).equals(resolver)
|
|
return Promise.resolve()
|
|
},
|
|
render: function(vnode) {
|
|
renderCount++
|
|
|
|
o(vnode.attrs.id).equals("abc")
|
|
o(this).equals(resolver)
|
|
|
|
return vnode
|
|
},
|
|
}
|
|
|
|
$window.location.href = prefix + "/abc"
|
|
route(root, "/abc", {
|
|
"/:id" : resolver
|
|
})
|
|
|
|
callAsync(function() {
|
|
o(matchCount).equals(1)
|
|
o(renderCount).equals(1)
|
|
o(root.firstChild.nodeName).equals("DIV")
|
|
done()
|
|
})
|
|
})
|
|
|
|
o("accepts RouteResolver with onmatch that returns Promise<any>", function(done) {
|
|
var matchCount = 0
|
|
var renderCount = 0
|
|
var Component = {
|
|
view: function() {
|
|
return m("span")
|
|
}
|
|
}
|
|
|
|
var resolver = {
|
|
onmatch: function(args, requestedPath) {
|
|
matchCount++
|
|
|
|
o(args.id).equals("abc")
|
|
o(requestedPath).equals("/abc")
|
|
o(this).equals(resolver)
|
|
return Promise.resolve([])
|
|
},
|
|
render: function(vnode) {
|
|
renderCount++
|
|
|
|
o(vnode.attrs.id).equals("abc")
|
|
o(this).equals(resolver)
|
|
|
|
return vnode
|
|
},
|
|
}
|
|
|
|
$window.location.href = prefix + "/abc"
|
|
route(root, "/abc", {
|
|
"/:id" : resolver
|
|
})
|
|
|
|
callAsync(function() {
|
|
o(matchCount).equals(1)
|
|
o(renderCount).equals(1)
|
|
o(root.firstChild.nodeName).equals("DIV")
|
|
done()
|
|
})
|
|
})
|
|
|
|
o("accepts RouteResolver with onmatch that returns rejected Promise", function(done) {
|
|
var matchCount = 0
|
|
var renderCount = 0
|
|
var spy = o.spy()
|
|
var Component = {
|
|
view: function() {
|
|
return m("span")
|
|
}
|
|
}
|
|
|
|
var resolver = {
|
|
onmatch: function(args, requestedPath) {
|
|
matchCount++
|
|
return Promise.reject(new Error("error"))
|
|
},
|
|
render: function(vnode) {
|
|
renderCount++
|
|
return vnode
|
|
},
|
|
}
|
|
|
|
$window.location.href = prefix + "/test/1"
|
|
route(root, "/default", {
|
|
"/default" : {view: spy},
|
|
"/test/:id" : resolver
|
|
})
|
|
|
|
callAsync(function() {
|
|
callAsync(function() {
|
|
o(matchCount).equals(1)
|
|
o(renderCount).equals(0)
|
|
o(spy.callCount).equals(1)
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
|
|
o("accepts RouteResolver without `render` method as payload", function(done) {
|
|
var matchCount = 0
|
|
var Component = {
|
|
view: function() {
|
|
return m("div")
|
|
}
|
|
}
|
|
|
|
$window.location.href = prefix + "/abc"
|
|
route(root, "/abc", {
|
|
"/:id" : {
|
|
onmatch: function(args, requestedPath) {
|
|
matchCount++
|
|
|
|
o(args.id).equals("abc")
|
|
o(requestedPath).equals("/abc")
|
|
|
|
return Component
|
|
},
|
|
},
|
|
})
|
|
|
|
callAsync(function() {
|
|
o(matchCount).equals(1)
|
|
o(root.firstChild.nodeName).equals("DIV")
|
|
done()
|
|
})
|
|
})
|
|
|
|
o("changing `vnode.key` in `render` resets the component", function(done, timeout){
|
|
var oninit = o.spy()
|
|
var Component = {
|
|
oninit: oninit,
|
|
view: function() {
|
|
return m("div")
|
|
}
|
|
}
|
|
$window.location.href = prefix + "/abc"
|
|
route(root, "/abc", {
|
|
"/:id": {render: function(vnode) {
|
|
return m(Component, {key: vnode.attrs.id})
|
|
}}
|
|
})
|
|
callAsync(function() {
|
|
o(oninit.callCount).equals(1)
|
|
route.set("/def")
|
|
callAsync(function() {
|
|
o(oninit.callCount).equals(2)
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
|
|
o("accepts RouteResolver without `onmatch` method as payload", function() {
|
|
var renderCount = 0
|
|
var Component = {
|
|
view: function() {
|
|
return m("div")
|
|
}
|
|
}
|
|
|
|
$window.location.href = prefix + "/abc"
|
|
route(root, "/abc", {
|
|
"/:id" : {
|
|
render: function(vnode) {
|
|
renderCount++
|
|
|
|
o(vnode.attrs.id).equals("abc")
|
|
|
|
return m(Component)
|
|
},
|
|
},
|
|
})
|
|
|
|
o(root.firstChild.nodeName).equals("DIV")
|
|
})
|
|
|
|
o("RouteResolver `render` does not have component semantics", function(done) {
|
|
var renderCount = 0
|
|
var A = {
|
|
view: function() {
|
|
return m("div")
|
|
}
|
|
}
|
|
|
|
$window.location.href = prefix + "/a"
|
|
route(root, "/a", {
|
|
"/a" : {
|
|
render: function(vnode) {
|
|
return m("div")
|
|
},
|
|
},
|
|
"/b" : {
|
|
render: function(vnode) {
|
|
return m("div")
|
|
},
|
|
},
|
|
})
|
|
|
|
var dom = root.firstChild
|
|
o(root.firstChild.nodeName).equals("DIV")
|
|
|
|
route.set("/b")
|
|
|
|
callAsync(function() {
|
|
o(root.firstChild).equals(dom)
|
|
|
|
done()
|
|
})
|
|
})
|
|
|
|
o("calls onmatch and view correct number of times", function(done) {
|
|
var matchCount = 0
|
|
var renderCount = 0
|
|
var Component = {
|
|
view: function() {
|
|
return m("div")
|
|
}
|
|
}
|
|
|
|
$window.location.href = prefix + "/"
|
|
route(root, "/", {
|
|
"/" : {
|
|
onmatch: function() {
|
|
matchCount++
|
|
return Component
|
|
},
|
|
render: function(vnode) {
|
|
renderCount++
|
|
return vnode
|
|
},
|
|
},
|
|
})
|
|
|
|
callAsync(function() {
|
|
o(matchCount).equals(1)
|
|
o(renderCount).equals(1)
|
|
|
|
redrawService.redraw()
|
|
|
|
o(matchCount).equals(1)
|
|
o(renderCount).equals(2)
|
|
|
|
done()
|
|
})
|
|
})
|
|
|
|
o("calls onmatch and view correct number of times when not onmatch returns undefined", function(done) {
|
|
var matchCount = 0
|
|
var renderCount = 0
|
|
var Component = {
|
|
view: function() {
|
|
return m("div")
|
|
}
|
|
}
|
|
|
|
$window.location.href = prefix + "/"
|
|
route(root, "/", {
|
|
"/" : {
|
|
onmatch: function() {
|
|
matchCount++
|
|
},
|
|
render: function(vnode) {
|
|
renderCount++
|
|
return {tag: Component}
|
|
},
|
|
},
|
|
})
|
|
|
|
callAsync(function() {
|
|
o(matchCount).equals(1)
|
|
o(renderCount).equals(1)
|
|
|
|
redrawService.redraw()
|
|
|
|
o(matchCount).equals(1)
|
|
o(renderCount).equals(2)
|
|
|
|
done()
|
|
})
|
|
})
|
|
|
|
o("onmatch can redirect to another route", function(done) {
|
|
var redirected = false
|
|
var render = o.spy()
|
|
|
|
$window.location.href = prefix + "/a"
|
|
route(root, "/a", {
|
|
"/a" : {
|
|
onmatch: function() {
|
|
route.set("/b")
|
|
},
|
|
render: render
|
|
},
|
|
"/b" : {
|
|
view: function() {
|
|
redirected = true
|
|
}
|
|
}
|
|
})
|
|
|
|
callAsync(function() {
|
|
o(render.callCount).equals(0)
|
|
o(redirected).equals(true)
|
|
|
|
done()
|
|
})
|
|
})
|
|
|
|
o("onmatch can redirect to another route that has RouteResolver w/ only onmatch", function(done) {
|
|
var redirected = false
|
|
var render = o.spy()
|
|
var view = o.spy(function() {return m("div")})
|
|
|
|
$window.location.href = prefix + "/a"
|
|
route(root, "/a", {
|
|
"/a" : {
|
|
onmatch: function() {
|
|
route.set("/b")
|
|
},
|
|
render: render
|
|
},
|
|
"/b" : {
|
|
onmatch: function() {
|
|
redirected = true
|
|
return {view: view}
|
|
}
|
|
}
|
|
})
|
|
|
|
callAsync(function() {
|
|
callAsync(function() {
|
|
o(render.callCount).equals(0)
|
|
o(redirected).equals(true)
|
|
o(view.callCount).equals(1)
|
|
o(root.childNodes.length).equals(1)
|
|
o(root.firstChild.nodeName).equals("DIV")
|
|
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
|
|
o("onmatch can redirect to another route that has RouteResolver w/ only render", function(done) {
|
|
var redirected = false
|
|
var render = o.spy()
|
|
|
|
$window.location.href = prefix + "/a"
|
|
route(root, "/a", {
|
|
"/a" : {
|
|
onmatch: function() {
|
|
route.set("/b")
|
|
},
|
|
render: render
|
|
},
|
|
"/b" : {
|
|
render: function(vnode){
|
|
redirected = true
|
|
}
|
|
}
|
|
})
|
|
|
|
callAsync(function() {
|
|
o(render.callCount).equals(0)
|
|
o(redirected).equals(true)
|
|
|
|
done()
|
|
})
|
|
})
|
|
|
|
o("onmatch can redirect to another route that has RouteResolver whose onmatch resolves asynchronously", function(done) {
|
|
var redirected = false
|
|
var render = o.spy()
|
|
var view = o.spy()
|
|
|
|
$window.location.href = prefix + "/a"
|
|
route(root, "/a", {
|
|
"/a" : {
|
|
onmatch: function() {
|
|
route.set("/b")
|
|
},
|
|
render: render
|
|
},
|
|
"/b" : {
|
|
onmatch: function() {
|
|
redirected = true
|
|
return new Promise(function(fulfill){
|
|
callAsync(function(){
|
|
fulfill({view: view})
|
|
})
|
|
})
|
|
}
|
|
}
|
|
})
|
|
|
|
callAsync(function() {
|
|
callAsync(function() {
|
|
callAsync(function() {
|
|
o(render.callCount).equals(0)
|
|
o(redirected).equals(true)
|
|
o(view.callCount).equals(1)
|
|
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
o("onmatch can redirect to another route asynchronously", function(done) {
|
|
var redirected = false
|
|
var render = o.spy()
|
|
var view = o.spy()
|
|
|
|
$window.location.href = prefix + "/a"
|
|
route(root, "/a", {
|
|
"/a" : {
|
|
onmatch: function() {
|
|
callAsync(function() {route.set("/b")})
|
|
return new Promise(function() {})
|
|
},
|
|
render: render
|
|
},
|
|
"/b" : {
|
|
onmatch: function() {
|
|
redirected = true
|
|
return {view: view}
|
|
}
|
|
}
|
|
})
|
|
|
|
callAsync(function() {
|
|
callAsync(function() {
|
|
callAsync(function() {
|
|
o(render.callCount).equals(0)
|
|
o(redirected).equals(true)
|
|
o(view.callCount).equals(1)
|
|
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
o("onmatch can redirect w/ window.history.back()", function(done) {
|
|
|
|
var render = o.spy()
|
|
var component = {view: o.spy()}
|
|
|
|
$window.location.href = prefix + "/a"
|
|
route(root, "/a", {
|
|
"/a" : {
|
|
onmatch: function() {
|
|
return component
|
|
},
|
|
render: function(vnode) {
|
|
return vnode
|
|
}
|
|
},
|
|
"/b" : {
|
|
onmatch: function() {
|
|
$window.history.back()
|
|
return new Promise(function() {})
|
|
},
|
|
render: render
|
|
}
|
|
})
|
|
|
|
callAsync(function() {
|
|
route.set('/b')
|
|
callAsync(function() {
|
|
callAsync(function() {
|
|
callAsync(function() {
|
|
o(render.callCount).equals(0)
|
|
o(component.view.callCount).equals(2)
|
|
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
o("onmatch can redirect to a non-existent route that defaults to a RouteResolver w/ onmatch", function(done) {
|
|
var redirected = false
|
|
var render = o.spy()
|
|
|
|
$window.location.href = prefix + "/a"
|
|
route(root, "/b", {
|
|
"/a" : {
|
|
onmatch: function() {
|
|
route.set("/c")
|
|
},
|
|
render: render
|
|
},
|
|
"/b" : {
|
|
onmatch: function(vnode){
|
|
redirected = true
|
|
return {view: function() {}}
|
|
}
|
|
}
|
|
})
|
|
|
|
callAsync(function() {
|
|
callAsync(function() {
|
|
o(render.callCount).equals(0)
|
|
o(redirected).equals(true)
|
|
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
|
|
o("onmatch can redirect to a non-existent route that defaults to a RouteResolver w/ render", function(done) {
|
|
var redirected = false
|
|
var render = o.spy()
|
|
|
|
$window.location.href = prefix + "/a"
|
|
route(root, "/b", {
|
|
"/a" : {
|
|
onmatch: function() {
|
|
route.set("/c")
|
|
},
|
|
render: render
|
|
},
|
|
"/b" : {
|
|
render: function(vnode){
|
|
redirected = true
|
|
}
|
|
}
|
|
})
|
|
|
|
callAsync(function() {
|
|
callAsync(function() {
|
|
o(render.callCount).equals(0)
|
|
o(redirected).equals(true)
|
|
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
|
|
o("onmatch can redirect to a non-existent route that defaults to a component", function(done) {
|
|
var redirected = false
|
|
var render = o.spy()
|
|
|
|
$window.location.href = prefix + "/a"
|
|
route(root, "/b", {
|
|
"/a" : {
|
|
onmatch: function() {
|
|
route.set("/c")
|
|
},
|
|
render: render
|
|
},
|
|
"/b" : {
|
|
view: function(vnode){
|
|
redirected = true
|
|
}
|
|
}
|
|
})
|
|
|
|
callAsync(function() {
|
|
callAsync(function() {
|
|
o(render.callCount).equals(0)
|
|
o(redirected).equals(true)
|
|
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
|
|
o("the previous view redraws while onmatch resolution is pending (#1268)", function(done) {
|
|
var view = o.spy()
|
|
var onmatch = o.spy(function() {
|
|
return new Promise(function() {})
|
|
})
|
|
|
|
$window.location.href = prefix + "/a"
|
|
route(root, "/", {
|
|
"/a": {view: view},
|
|
"/b": {onmatch: onmatch}
|
|
})
|
|
|
|
o(view.callCount).equals(1)
|
|
o(onmatch.callCount).equals(0)
|
|
|
|
route.set("/b")
|
|
|
|
callAsync(function() {
|
|
o(view.callCount).equals(1)
|
|
o(onmatch.callCount).equals(1)
|
|
|
|
redrawService.redraw()
|
|
|
|
o(view.callCount).equals(2)
|
|
o(onmatch.callCount).equals(1)
|
|
|
|
done()
|
|
})
|
|
})
|
|
|
|
o("when two async routes are racing, the last one set cancels the finalization of the first", function(done) {
|
|
var renderA = o.spy()
|
|
var renderB = o.spy()
|
|
var onmatchA = o.spy(function(){
|
|
return new Promise(function(fulfill) {
|
|
setTimeout(function(){
|
|
fulfill()
|
|
}, 10)
|
|
})
|
|
})
|
|
|
|
$window.location.href = prefix + "/a"
|
|
route(root, "/a", {
|
|
"/a": {
|
|
onmatch: onmatchA,
|
|
render: renderA
|
|
},
|
|
"/b": {
|
|
onmatch: function(){
|
|
var p = new Promise(function(fulfill) {
|
|
o(onmatchA.callCount).equals(1)
|
|
o(renderA.callCount).equals(0)
|
|
o(renderB.callCount).equals(0)
|
|
|
|
setTimeout(function(){
|
|
o(onmatchA.callCount).equals(1)
|
|
o(renderA.callCount).equals(0)
|
|
o(renderB.callCount).equals(0)
|
|
|
|
fulfill()
|
|
|
|
p.then(function(){
|
|
o(onmatchA.callCount).equals(1)
|
|
o(renderA.callCount).equals(0)
|
|
o(renderB.callCount).equals(1)
|
|
|
|
done()
|
|
})
|
|
}, 20)
|
|
})
|
|
return p
|
|
},
|
|
render: renderB
|
|
}
|
|
})
|
|
|
|
callAsync(function() {
|
|
o(onmatchA.callCount).equals(1)
|
|
o(renderA.callCount).equals(0)
|
|
o(renderB.callCount).equals(0)
|
|
route.set("/b")
|
|
o(onmatchA.callCount).equals(1)
|
|
o(renderA.callCount).equals(0)
|
|
o(renderB.callCount).equals(0)
|
|
})
|
|
})
|
|
|
|
o("m.route.set(m.route.get()) re-runs the resolution logic (#1180)", function(done){
|
|
var onmatch = o.spy()
|
|
var render = o.spy(function() {return m("div")})
|
|
|
|
$window.location.href = prefix + "/"
|
|
route(root, '/', {
|
|
"/": {
|
|
onmatch: onmatch,
|
|
render: render
|
|
}
|
|
})
|
|
|
|
callAsync(function() {
|
|
o(onmatch.callCount).equals(1)
|
|
o(render.callCount).equals(1)
|
|
|
|
route.set(route.get())
|
|
|
|
callAsync(function() {
|
|
callAsync(function() {
|
|
o(onmatch.callCount).equals(2)
|
|
o(render.callCount).equals(2)
|
|
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
o("m.route.get() returns the last fully resolved route (#1276)", function(done){
|
|
$window.location.href = prefix + "/"
|
|
|
|
route(root, "/", {
|
|
"/": {view: function() {}},
|
|
"/2": {
|
|
onmatch: function() {
|
|
return new Promise(function() {})
|
|
}
|
|
}
|
|
})
|
|
|
|
|
|
o(route.get()).equals("/")
|
|
|
|
route.set("/2")
|
|
|
|
callAsync(function() {
|
|
o(route.get()).equals("/")
|
|
done()
|
|
})
|
|
})
|
|
|
|
o("routing with RouteResolver works more than once", function(done) {
|
|
$window.location.href = prefix + "/a"
|
|
route(root, '/a', {
|
|
'/a': {
|
|
render: function() {
|
|
return m("a", "a")
|
|
}
|
|
},
|
|
'/b': {
|
|
render: function() {
|
|
return m("b", "b")
|
|
}
|
|
}
|
|
})
|
|
|
|
route.set('/b')
|
|
|
|
callAsync(function() {
|
|
route.set('/a')
|
|
|
|
callAsync(function() {
|
|
o(root.firstChild.nodeName).equals("A")
|
|
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
|
|
o("calling route.set invalidates pending onmatch resolution", function(done) {
|
|
var rendered = false
|
|
var resolved
|
|
$window.location.href = prefix + "/a"
|
|
route(root, "/a", {
|
|
"/a": {
|
|
onmatch: function() {
|
|
return new Promise(function(resolve) {
|
|
callAsync(function() {
|
|
callAsync(function() {
|
|
resolve({view: function() {rendered = true}})
|
|
})
|
|
})
|
|
})
|
|
},
|
|
render: function(vnode) {
|
|
rendered = true
|
|
resolved = "a"
|
|
}
|
|
},
|
|
"/b": {
|
|
view: function() {
|
|
resolved = "b"
|
|
}
|
|
}
|
|
})
|
|
|
|
route.set("/b")
|
|
|
|
callAsync(function() {
|
|
o(rendered).equals(false)
|
|
o(resolved).equals("b")
|
|
|
|
callAsync(function() {
|
|
o(rendered).equals(false)
|
|
o(resolved).equals("b")
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
|
|
o("route changes activate onbeforeremove", function(done) {
|
|
var spy = o.spy()
|
|
|
|
$window.location.href = prefix + "/a"
|
|
route(root, "/a", {
|
|
"/a": {
|
|
onbeforeremove: spy,
|
|
view: function() {}
|
|
},
|
|
"/b": {
|
|
view: function() {}
|
|
}
|
|
})
|
|
|
|
route.set("/b")
|
|
|
|
callAsync(function() {
|
|
o(spy.callCount).equals(1)
|
|
|
|
done()
|
|
})
|
|
})
|
|
|
|
o("asynchronous route.set in onmatch works", function(done) {
|
|
var rendered = false, resolved
|
|
route(root, "/a", {
|
|
"/a": {
|
|
onmatch: function() {
|
|
return Promise.resolve().then(function() {
|
|
route.set("/b")
|
|
})
|
|
},
|
|
render: function(vnode) {
|
|
rendered = true
|
|
resolved = "a"
|
|
}
|
|
},
|
|
"/b": {
|
|
view: function() {
|
|
resolved = "b"
|
|
}
|
|
},
|
|
})
|
|
|
|
callAsync(function() { // tick for popstate for /a
|
|
callAsync(function() { // tick for promise in onmatch
|
|
callAsync(function() { // tick for onpopstate for /b
|
|
o(rendered).equals(false)
|
|
o(resolved).equals("b")
|
|
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
o("throttles", function(done, timeout) {
|
|
timeout(200)
|
|
|
|
var i = 0
|
|
$window.location.href = prefix + "/"
|
|
route(root, "/", {
|
|
"/": {view: function(v) {i++}}
|
|
})
|
|
var before = i
|
|
|
|
redrawService.redraw()
|
|
redrawService.redraw()
|
|
redrawService.redraw()
|
|
redrawService.redraw()
|
|
var after = i
|
|
|
|
setTimeout(function() {
|
|
o(before).equals(1) // routes synchronously
|
|
o(after).equals(2) // redraws synchronously
|
|
o(i).equals(3) // throttles rest
|
|
done()
|
|
}, FRAME_BUDGET * 2)
|
|
})
|
|
|
|
o("m.route.param is available outside of route handlers", function(done) {
|
|
$window.location.href = prefix + "/"
|
|
|
|
route(root, "/1", {
|
|
"/:id" : {
|
|
view : function() {
|
|
o(route.param("id")).equals("1")
|
|
|
|
return m("div")
|
|
}
|
|
}
|
|
})
|
|
|
|
o(route.param("id")).equals(undefined);
|
|
o(route.param()).deepEquals(undefined);
|
|
|
|
callAsync(function() {
|
|
o(route.param("id")).equals("1")
|
|
o(route.param()).deepEquals({id:"1"})
|
|
|
|
done()
|
|
})
|
|
})
|
|
})
|
|
})
|
|
})
|
|
})
|