Merge pull request #1466 from pygy/rewrite-router-test-redirection-async-onmatch

[rewrite] (WIP) A few more tests for the router + mock fixes
This commit is contained in:
Leo Horie 2016-12-07 12:04:12 -05:00 committed by GitHub
commit a3a1516584
5 changed files with 285 additions and 124 deletions

View file

@ -627,7 +627,7 @@ o.spec("route", function() {
render: render render: render
}, },
"/b" : { "/b" : {
view: function(vnode){ view: function() {
redirected = true redirected = true
} }
} }
@ -644,6 +644,7 @@ o.spec("route", function() {
o("onmatch can redirect to another route that has RouteResolver w/ only onmatch", function(done) { o("onmatch can redirect to another route that has RouteResolver w/ only onmatch", function(done) {
var redirected = false var redirected = false
var render = o.spy() var render = o.spy()
var view = o.spy(function() {return m("div")})
$window.location.href = prefix + "/a" $window.location.href = prefix + "/a"
route(root, "/a", { route(root, "/a", {
@ -656,16 +657,21 @@ o.spec("route", function() {
"/b" : { "/b" : {
onmatch: function() { onmatch: function() {
redirected = true redirected = true
return {view: function() {}} return {view: view}
} }
} }
}) })
callAsync(function() { callAsync(function() {
o(render.callCount).equals(0) callAsync(function() {
o(redirected).equals(true) 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() done()
})
}) })
}) })
@ -696,6 +702,118 @@ o.spec("route", function() {
}) })
}) })
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) { o("onmatch can redirect to a non-existent route that defaults to a RouteResolver w/ onmatch", function(done) {
var redirected = false var redirected = false
var render = o.spy() var render = o.spy()

View file

@ -5,14 +5,14 @@ var domMock = require("./domMock")
var xhrMock = require("./xhrMock") var xhrMock = require("./xhrMock")
module.exports = function(env) { module.exports = function(env) {
var $window = {} env = env || {}
var $window = env.window = {}
var dom = domMock() var dom = domMock()
var xhr = xhrMock() var xhr = xhrMock()
var ps = pushStateMock(env)
for (var key in dom) if (!$window[key]) $window[key] = dom[key] for (var key in dom) if (!$window[key]) $window[key] = dom[key]
for (var key in xhr) if (!$window[key]) $window[key] = xhr[key] for (var key in xhr) if (!$window[key]) $window[key] = xhr[key]
for (var key in ps) if (!$window[key]) $window[key] = ps[key] pushStateMock(env)
return $window return $window
} }

View file

@ -5,6 +5,7 @@ var parseURL = require("../test-utils/parseURL")
module.exports = function(options) { module.exports = function(options) {
if (options == null) options = {} if (options == null) options = {}
var $window = options.window || {}
var protocol = options.protocol || "http:" var protocol = options.protocol || "http:"
var hostname = options.hostname || "localhost" var hostname = options.hostname || "localhost"
var port = "" var port = ""
@ -32,7 +33,7 @@ module.exports = function(options) {
} }
return isNew return isNew
} }
function prefix(prefix, value) { function prefix(prefix, value) {
if (value === "") return "" if (value === "") return ""
return (value.charAt(0) !== prefix ? prefix : "") + value return (value.charAt(0) !== prefix ? prefix : "") + value
@ -46,125 +47,125 @@ module.exports = function(options) {
function unload() { function unload() {
if (typeof $window.onunload === "function") $window.onunload({type: "unload"}) if (typeof $window.onunload === "function") $window.onunload({type: "unload"})
} }
var $window = {
location: {
get protocol() {
return protocol
},
get hostname() {
return hostname
},
get port() {
return port
},
get pathname() {
return pathname
},
get search() {
return search
},
get hash() {
return hash
},
get origin() {
if (protocol === "file:") return "null"
return protocol + "//" + hostname + prefix(":", port)
},
get host() {
if (protocol === "file:") return ""
return hostname + prefix(":", port)
},
get href() {
return getURL()
},
set protocol(value) { $window.location = {
throw new Error("Protocol is read-only") get protocol() {
}, return protocol
set hostname(value) { },
unload() get hostname() {
past.push({url: getURL(), isNew: true}) return hostname
future = [] },
hostname = value get port() {
}, return port
set port(value) { },
if (protocol === "file:") throw new Error("Port is read-only under `file://` protocol") get pathname() {
unload() return pathname
past.push({url: getURL(), isNew: true}) },
future = [] get search() {
port = value return search
}, },
set pathname(value) { get hash() {
if (protocol === "file:") throw new Error("Pathname is read-only under `file://` protocol") return hash
unload() },
past.push({url: getURL(), isNew: true}) get origin() {
future = [] if (protocol === "file:") return "null"
pathname = prefix("/", value) return protocol + "//" + hostname + prefix(":", port)
}, },
set search(value) { get host() {
unload() if (protocol === "file:") return ""
past.push({url: getURL(), isNew: true}) return hostname + prefix(":", port)
future = [] },
search = prefix("?", value) get href() {
}, return getURL()
set hash(value) { },
var oldHash = hash
past.push({url: getURL(), isNew: false})
future = []
hash = prefix("#", value)
if (oldHash != hash) hashchange()
},
set origin(value) { set protocol(value) {
//origin is writable but ignored throw new Error("Protocol is read-only")
},
set host(value) {
//host is writable but ignored in Chrome
},
set href(value) {
var url = getURL()
var isNew = setURL(value)
if (isNew) {
setURL(url)
unload()
setURL(value)
}
past.push({url: url, isNew: isNew})
future = []
},
}, },
history: { set hostname(value) {
pushState: function(data, title, url) { unload()
past.push({url: getURL(), isNew: false}) past.push({url: getURL(), isNew: true})
future = [] future = []
setURL(url) hostname = value
}, },
replaceState: function(data, title, url) { set port(value) {
future = [] if (protocol === "file:") throw new Error("Port is read-only under `file://` protocol")
setURL(url) unload()
}, past.push({url: getURL(), isNew: true})
back: function() { future = []
var entry = past.pop() port = value
if (entry != null) { },
if (entry.isNew) unload() set pathname(value) {
future.push({url: getURL(), isNew: false}) if (protocol === "file:") throw new Error("Pathname is read-only under `file://` protocol")
setURL(entry.url) unload()
if (!entry.isNew) popstate() past.push({url: getURL(), isNew: true})
} future = []
}, pathname = prefix("/", value)
forward: function() { },
var entry = future.pop() set search(value) {
if (entry != null) { unload()
if (entry.isNew) unload() past.push({url: getURL(), isNew: true})
past.push({url: getURL(), isNew: false}) future = []
setURL(entry.url) search = prefix("?", value)
if (!entry.isNew) popstate() },
} set hash(value) {
}, var oldHash = hash
past.push({url: getURL(), isNew: false})
future = []
hash = prefix("#", value)
if (oldHash != hash) hashchange()
},
set origin(value) {
//origin is writable but ignored
},
set host(value) {
//host is writable but ignored in Chrome
},
set href(value) {
var url = getURL()
var isNew = setURL(value)
if (isNew) {
setURL(url)
unload()
setURL(value)
}
past.push({url: url, isNew: isNew})
future = []
}, },
onpopstate: null,
onhashchange: null,
onunload: null,
} }
$window.history = {
pushState: function(data, title, url) {
past.push({url: getURL(), isNew: false})
future = []
setURL(url)
},
replaceState: function(data, title, url) {
future = []
setURL(url)
},
back: function() {
var entry = past.pop()
if (entry != null) {
if (entry.isNew) unload()
future.push({url: getURL(), isNew: false})
setURL(entry.url)
if (!entry.isNew) popstate()
}
},
forward: function() {
var entry = future.pop()
if (entry != null) {
if (entry.isNew) unload()
past.push({url: getURL(), isNew: false})
setURL(entry.url)
if (!entry.isNew) popstate()
}
},
}
$window.onpopstate = null,
$window.onhashchange = null,
$window.onunload = null
return $window return $window
} }

View file

@ -13,11 +13,13 @@
<script src="../../test-utils/pushStateMock.js"></script> <script src="../../test-utils/pushStateMock.js"></script>
<script src="../../test-utils/xhrMock.js"></script> <script src="../../test-utils/xhrMock.js"></script>
<script src="../../test-utils/domMock.js"></script> <script src="../../test-utils/domMock.js"></script>
<script src="../../test-utils/browserMock.js"></script>
<script src="test-callAsync.js"></script> <script src="test-callAsync.js"></script>
<script src="test-parseURL.js"></script> <script src="test-parseURL.js"></script>
<script src="test-pushStateMock.js"></script> <script src="test-pushStateMock.js"></script>
<script src="test-xhrMock.js"></script> <script src="test-xhrMock.js"></script>
<script src="test-domMock.js"></script> <script src="test-domMock.js"></script>
<script src="test-browserMock.js"></script>
<script>require("../../ospec/ospec").run()</script> <script>require("../../ospec/ospec").run()</script>
</body> </body>

View file

@ -0,0 +1,40 @@
"use strict"
var o = require("../../ospec/ospec")
var browserMock = require("../../test-utils/browserMock")
var callAsync = require("../../test-utils/callAsync")
o.spec("browserMock", function() {
var $window
o.beforeEach(function() {
$window = browserMock()
})
o("Mocks DOM, pushState and XHR", function() {
o($window.location).notEquals(undefined)
o($window.document).notEquals(undefined)
o($window.XMLHttpRequest).notEquals(undefined)
})
o("$window.onhashchange can be reached from the pushStateMock functions", function(done) {
$window.onhashchange = o.spy()
$window.location.hash = '#a'
callAsync(function(){
o($window.onhashchange.callCount).equals(1)
done()
})
})
o("$window.onpopstate can be reached from the pushStateMock functions", function() {
$window.onpopstate = o.spy()
$window.history.pushState(null, null, "#a")
$window.history.back()
o($window.onpopstate.callCount).equals(1)
})
o("$window.onunload can be reached from the pushStateMock functions", function() {
$window.onunload = o.spy()
$window.location.href = '/a'
o($window.onunload.callCount).equals(1)
})
})