1240 lines
26 KiB
JavaScript
1240 lines
26 KiB
JavaScript
describe("m.route()", function () {
|
|
"use strict"
|
|
|
|
// Use this instead of m.route() unless you have to call m.route and do
|
|
// something else in the same frame.
|
|
function route() {
|
|
var res = m.route.apply(null, arguments)
|
|
mock.requestAnimationFrame.$resolve()
|
|
return res
|
|
}
|
|
|
|
var mode = (function () {
|
|
var types = {
|
|
search: "?",
|
|
hash: "#",
|
|
pathname: "/"
|
|
}
|
|
|
|
return function (type) {
|
|
if (!{}.hasOwnProperty.call(types, type)) {
|
|
throw new RangeError("bad mode type")
|
|
}
|
|
mock.location[type] = types[type]
|
|
m.route.mode = type
|
|
}
|
|
})()
|
|
|
|
// Little helper utility
|
|
function noop() {}
|
|
|
|
// Use this if all you need to do is render a view (i.e. a pure component).
|
|
function pure(view) {
|
|
return {
|
|
controller: noop,
|
|
view: view
|
|
}
|
|
}
|
|
|
|
// Use these instead of `it` and `xit` in this set of tests if you need a
|
|
// root element.
|
|
var dit = makeIt(it)
|
|
var xdit = makeIt(xit)
|
|
|
|
// Wraps the `it` function for dependency injection that doesn't require
|
|
// `this`
|
|
/* eslint-disable no-invalid-this */
|
|
function makeIt(it) {
|
|
return function (name, callback) {
|
|
return it(name, function () {
|
|
var args = [this.root]
|
|
for (var i = 0; i < arguments.length; i++) {
|
|
args.push(arguments[i])
|
|
}
|
|
callback.apply(null, args)
|
|
})
|
|
}
|
|
}
|
|
|
|
beforeEach(function () {
|
|
mock.requestAnimationFrame.$resolve()
|
|
this.root = mock.document.createElement("div")
|
|
})
|
|
|
|
afterEach(function () {
|
|
m.mount(this.root, null)
|
|
})
|
|
/* eslint-enable no-invalid-this */
|
|
|
|
it("exists", function () {
|
|
expect(m.route).to.be.a("function")
|
|
})
|
|
|
|
dit("routes to the right location by default", function (root) {
|
|
mode("search")
|
|
|
|
route(root, "/test1", {
|
|
"/test1": pure(function () { return "foo" })
|
|
})
|
|
|
|
expect(mock.location.search).to.equal("?/test1")
|
|
expect(root.childNodes[0].nodeValue).to.equal("foo")
|
|
})
|
|
|
|
dit("gets the right right location when routed to it", function (root) {
|
|
mode("search")
|
|
|
|
var route1, route2
|
|
route(root, "/", {
|
|
"/": {
|
|
controller: function () { route1 = m.route() },
|
|
view: noop
|
|
},
|
|
"/test13": {
|
|
controller: function () { route2 = m.route() },
|
|
view: noop
|
|
}
|
|
})
|
|
|
|
m.route("/test13")
|
|
|
|
expect(route1).to.equal("/")
|
|
expect(route2).to.equal("/test13")
|
|
})
|
|
|
|
// FIXME: this causes others to fail
|
|
xdit("skips route change if component ctrl.onunload calls preventDefault", function (root) { // eslint-disable-line
|
|
mode("search")
|
|
var spy = sinon.spy()
|
|
|
|
var sub = {
|
|
controller: function () {
|
|
this.onunload = function (e) { e.preventDefault() }
|
|
},
|
|
view: function () {
|
|
return m("div")
|
|
}
|
|
}
|
|
|
|
route(root, "/a", {
|
|
"/a": pure(function () { return sub }),
|
|
|
|
"/b": {
|
|
controller: spy,
|
|
view: noop
|
|
}
|
|
})
|
|
|
|
route("/b")
|
|
|
|
expect(spy).to.not.have.been.called
|
|
})
|
|
|
|
// FIXME: this causes others to fail
|
|
xdit("skips route change if subcomponent ctrl.onunload calls preventDefault", function (root) { // eslint-disable-line
|
|
mode("search")
|
|
|
|
var spy = sinon.spy()
|
|
|
|
var subsub = {
|
|
controller: function () {
|
|
this.onunload = function (e) { e.preventDefault() }
|
|
},
|
|
view: function () {
|
|
return m("div")
|
|
}
|
|
}
|
|
|
|
var sub = pure(function () { return subsub })
|
|
|
|
route(root, "/a", {
|
|
"/a": pure(function () { return sub }),
|
|
|
|
"/b": {
|
|
controller: spy,
|
|
view: noop
|
|
}
|
|
})
|
|
|
|
route("/b")
|
|
|
|
expect(spy).to.not.have.been.called
|
|
})
|
|
|
|
// FIXME: this causes others to fail
|
|
xdit("skips route change if non-curried component ctrl.onunload calls preventDefault", function (root) { // eslint-disable-line
|
|
mode("search")
|
|
|
|
var spy = sinon.spy()
|
|
|
|
var sub = {
|
|
controller: function () {
|
|
this.onunload = function (e) { e.preventDefault() }
|
|
},
|
|
view: function () {
|
|
return m("div")
|
|
}
|
|
}
|
|
|
|
route(root, "/a", {
|
|
"/a": pure(function () { return sub }),
|
|
|
|
"/b": {
|
|
controller: spy,
|
|
view: noop
|
|
}
|
|
})
|
|
|
|
route("/b")
|
|
|
|
expect(spy).to.not.have.been.called
|
|
})
|
|
|
|
// FIXME: this causes others to fail
|
|
xdit("skips route change if non-curried subcomponent ctrl.onunload calls preventDefault", function (root) { // eslint-disable-line
|
|
mode("search")
|
|
|
|
var spy = sinon.spy()
|
|
|
|
var subsub = {
|
|
controller: function () {
|
|
this.onunload = function (e) { e.preventDefault() }
|
|
},
|
|
view: function () {
|
|
return m("div")
|
|
}
|
|
}
|
|
|
|
var sub = pure(function () { return subsub })
|
|
|
|
route(root, "/a", {
|
|
"/a": pure(function () { return sub }),
|
|
|
|
"/b": {
|
|
controller: spy,
|
|
view: noop
|
|
}
|
|
})
|
|
|
|
route("/b")
|
|
|
|
expect(spy).to.not.have.been.called
|
|
})
|
|
|
|
dit("initializes a component's constructor on route change", function (root) { // eslint-disable-line
|
|
mode("search")
|
|
|
|
var ctrl1 = sinon.spy()
|
|
var ctrl2 = sinon.spy()
|
|
|
|
var sub1 = {
|
|
controller: ctrl1,
|
|
view: function () { return m("div") }
|
|
}
|
|
|
|
var sub2 = {
|
|
controller: ctrl2,
|
|
view: function () { return m("div") }
|
|
}
|
|
|
|
route(root, "/a", {
|
|
"/a": pure(function () {
|
|
return m(".page-a", [
|
|
m("h1"), m.component(sub1, {x: 11})
|
|
])
|
|
}),
|
|
|
|
"/b": pure(function () {
|
|
return m(".page-b", [
|
|
m("h2"), m.component(sub2, {y: 22})
|
|
])
|
|
})
|
|
})
|
|
|
|
route("/b")
|
|
route("/a")
|
|
|
|
expect(ctrl1).to.have.been.calledTwice
|
|
expect(ctrl2).to.have.been.calledOnce
|
|
})
|
|
|
|
dit("doesn't require components to have a view", function (root) {
|
|
mode("search")
|
|
|
|
var Component = pure(function () { return m(".comp") })
|
|
|
|
route(root, "/foo", {
|
|
"/foo": pure(function () { return [Component] })
|
|
})
|
|
|
|
expect(root.childNodes[0].nodeName).to.equal("DIV")
|
|
})
|
|
|
|
// https://github.com/lhorie/mithril.js/issues/555
|
|
dit("reinstantiates the controller when redraw strategy is `all`", function (root) { // eslint-disable-line
|
|
var MyComponent = {
|
|
controller: function (args) {
|
|
this.name = args.name
|
|
},
|
|
|
|
view: function (ctrl) {
|
|
return m("div", ctrl.name)
|
|
}
|
|
}
|
|
|
|
route(root, "/", {
|
|
"/": pure(function () {
|
|
return m("div", [
|
|
m("a[href=/]", {config: m.route}, "foo"),
|
|
m("a[href=/bar]", {config: m.route}, "bar"),
|
|
m.component(MyComponent, {name: "Jane"})
|
|
])
|
|
}),
|
|
|
|
"/bar": pure(function () {
|
|
return m("div", [
|
|
m("a[href=/]", {config: m.route}, "foo"),
|
|
m("a[href=/bar]", {config: m.route}, "bar"),
|
|
m.component(MyComponent, {name: "Bob"})
|
|
])
|
|
})
|
|
})
|
|
|
|
route("/bar")
|
|
|
|
expect(root.childNodes[0].childNodes[2].childNodes[0].nodeValue)
|
|
.to.equal("Bob")
|
|
})
|
|
|
|
dit("sets the correct href with config: m.route", function (root) {
|
|
mode("pathname")
|
|
|
|
route(root, "/test2", {
|
|
"/test2": pure(function () {
|
|
return [
|
|
"foo",
|
|
m("a", {href: "/test2", config: m.route}, "Test2")
|
|
]
|
|
})
|
|
})
|
|
|
|
expect(mock.location.pathname).to.equal("/test2")
|
|
expect(root.childNodes[0].nodeValue).to.equal("foo")
|
|
expect(root.childNodes[1].href).to.equal("/test2")
|
|
})
|
|
|
|
dit("can use a hash", function (root) {
|
|
mode("hash")
|
|
|
|
route(root, "/test3", {
|
|
"/test3": pure(function () { return "foo" })
|
|
})
|
|
|
|
expect(mock.location.hash).to.equal("#/test3")
|
|
expect(root.childNodes[0].nodeValue).to.equal("foo")
|
|
})
|
|
|
|
dit("can use a query", function (root) {
|
|
mode("search")
|
|
|
|
route(root, "/test4/foo", {
|
|
"/test4/:test": pure(function () { return m.route.param("test") })
|
|
})
|
|
|
|
expect(mock.location.search).to.equal("?/test4/foo")
|
|
expect(root.childNodes[0].nodeValue).to.equal("foo")
|
|
})
|
|
|
|
context("m.route.param()", function () {
|
|
it("exists", function () {
|
|
expect(m.route.param).to.be.a("function")
|
|
})
|
|
|
|
dit("can get params (1)", function (root) {
|
|
mode("search")
|
|
|
|
var component = pure(function () { return m.route.param("test") })
|
|
|
|
m.route(root, "/test5/foo", {
|
|
"/": component,
|
|
"/test5/:test": component
|
|
})
|
|
|
|
var paramValueBefore = m.route.param("test")
|
|
|
|
mock.requestAnimationFrame.$resolve()
|
|
m.route("/")
|
|
|
|
var paramValueAfter = m.route.param("test")
|
|
|
|
mock.requestAnimationFrame.$resolve()
|
|
|
|
expect(mock.location.search).to.equal("?/")
|
|
expect(paramValueBefore).to.equal("foo")
|
|
expect(paramValueAfter).to.not.exist
|
|
})
|
|
|
|
dit("can deal with params (2)", function (root) {
|
|
mode("search")
|
|
|
|
var component = pure(function () { return m.route.param("a1") })
|
|
|
|
m.route(root, "/test6/foo", {
|
|
"/": component,
|
|
"/test6/:a1": component
|
|
})
|
|
|
|
var paramValueBefore = m.route.param("a1")
|
|
|
|
mock.requestAnimationFrame.$resolve()
|
|
m.route("/")
|
|
|
|
var paramValueAfter = m.route.param("a1")
|
|
|
|
mock.requestAnimationFrame.$resolve()
|
|
|
|
expect(mock.location.search).to.equal("?/")
|
|
expect(paramValueBefore).to.equal("foo")
|
|
expect(paramValueAfter).to.not.exist
|
|
})
|
|
|
|
// https://github.com/lhorie/mithril.js/issues/61
|
|
dit("can get the route via m.route()", function (root) {
|
|
mode("search")
|
|
|
|
var component = pure(function () { return m.route.param("a1") })
|
|
|
|
m.route(root, "/test7/foo", {
|
|
"/": component,
|
|
"/test7/:a1": component
|
|
})
|
|
|
|
var routeValueBefore = m.route()
|
|
|
|
mock.requestAnimationFrame.$resolve()
|
|
m.route("/")
|
|
|
|
var routeValueAfter = m.route()
|
|
|
|
mock.requestAnimationFrame.$resolve()
|
|
|
|
expect(routeValueBefore).to.equal("/test7/foo")
|
|
expect(routeValueAfter).to.equal("/")
|
|
})
|
|
|
|
dit("can deal with rest paths at the end", function (root) {
|
|
mode("search")
|
|
|
|
route(root, "/test8/foo/SEP/bar/baz", {
|
|
"/test8/:test/SEP/:path...": pure(function () {
|
|
return m.route.param("test") + "_" + m.route.param("path")
|
|
})
|
|
})
|
|
|
|
expect(mock.location.search).to.equal("?/test8/foo/SEP/bar/baz")
|
|
expect(root.childNodes[0].nodeValue).to.equal("foo_bar/baz")
|
|
})
|
|
|
|
dit("can deal with rest paths in the middle", function (root) {
|
|
mode("search")
|
|
|
|
route(root, "/test9/foo/bar/SEP/baz", {
|
|
"/test9/:test.../SEP/:path": pure(function () {
|
|
return m.route.param("test") + "_" + m.route.param("path")
|
|
})
|
|
})
|
|
|
|
expect(mock.location.search).to.equal("?/test9/foo/bar/SEP/baz")
|
|
expect(root.childNodes[0].nodeValue).to.equal("foo/bar_baz")
|
|
})
|
|
|
|
dit("unescapes urls for m.route.param()", function (root) {
|
|
mode("search")
|
|
|
|
route(root, "/test10/foo%20bar", {
|
|
"/test10/:test": pure(function () {
|
|
return m.route.param("test")
|
|
})
|
|
})
|
|
|
|
expect(root.childNodes[0].nodeValue).to.equal("foo bar")
|
|
})
|
|
|
|
dit("renders the correct path", function (root) {
|
|
mode("search")
|
|
|
|
route(root, "/", {
|
|
"/": pure(function () { return "foo" }),
|
|
"/test11": pure(function () { return "bar" })
|
|
})
|
|
|
|
route("/test11/")
|
|
|
|
expect(mock.location.search).to.equal("?/test11/")
|
|
expect(root.childNodes[0].nodeValue).to.equal("bar")
|
|
})
|
|
|
|
dit("reads params by parsing query string", function (root) {
|
|
mode("search")
|
|
|
|
route(root, "/", {
|
|
"/": pure(noop),
|
|
"/test12": pure(noop)
|
|
})
|
|
|
|
route("/test12?a=foo&b=bar")
|
|
|
|
expect(mock.location.search).to.equal("?/test12?a=foo&b=bar")
|
|
expect(m.route.param("a")).to.equal("foo")
|
|
expect(m.route.param("b")).to.equal("bar")
|
|
})
|
|
|
|
dit("prefers local params to global params", function (root) {
|
|
mode("search")
|
|
|
|
route(root, "/", {
|
|
"/": pure(function () { return "bar" }),
|
|
"/test13/:test": pure(function () {
|
|
return m.route.param("test")
|
|
})
|
|
})
|
|
|
|
route("/test13/foo?test=bar")
|
|
|
|
expect(mock.location.search).to.equal("?/test13/foo?test=bar")
|
|
expect(root.childNodes[0].nodeValue).to.equal("foo")
|
|
})
|
|
|
|
dit("reads global params", function (root) {
|
|
mode("search")
|
|
|
|
route(root, "/", {
|
|
"/": pure(function () { return "bar" }),
|
|
"/test14": pure(function () { return "foo" })
|
|
})
|
|
|
|
route("/test14?test&test2=")
|
|
|
|
expect(mock.location.search).to.equal("?/test14?test&test2=")
|
|
expect(m.route.param("test")).to.not.exist
|
|
expect(m.route.param("test2")).to.equal("")
|
|
})
|
|
|
|
dit("parses params when using m.route(path, params)", function (root) {
|
|
mode("search")
|
|
|
|
route(root, "/", {
|
|
"/": pure(noop),
|
|
"/test12": pure(noop)
|
|
})
|
|
|
|
route("/test12", {a: "foo", b: "bar"})
|
|
|
|
expect(mock.location.search).to.equal("?/test12?a=foo&b=bar")
|
|
expect(m.route.param("a")).to.equal("foo")
|
|
expect(m.route.param("b")).to.equal("bar")
|
|
})
|
|
|
|
dit("gets params object by using m.route.param()", function (root) {
|
|
mode("search")
|
|
|
|
route(root, "/", {
|
|
"/": pure(noop),
|
|
"/test12": pure(noop)
|
|
})
|
|
|
|
route("/test12", {a: "foo", b: "bar"})
|
|
|
|
var params = m.route.param()
|
|
|
|
expect(params.a).to.equal("foo")
|
|
expect(params.b).to.equal("bar")
|
|
})
|
|
})
|
|
|
|
dit("only calls onunload once when routed away (1)", function (root) {
|
|
mode("search")
|
|
|
|
var onunload = sinon.spy()
|
|
|
|
route(root, "/", {
|
|
"/": pure(function () {
|
|
return m("div", {
|
|
config: function (el, init, ctx) {
|
|
ctx.onunload = onunload
|
|
}
|
|
})
|
|
}),
|
|
"/test14": pure(noop)
|
|
})
|
|
|
|
route("/test14")
|
|
|
|
expect(onunload).to.be.calledOnce
|
|
})
|
|
|
|
dit("only calls onunload once when routed away (2)", function (root) {
|
|
mode("search")
|
|
|
|
var onunload = sinon.spy()
|
|
|
|
route(root, "/", {
|
|
"/": pure(function () {
|
|
return [
|
|
m("div"),
|
|
m("div", {
|
|
config: function (el, init, ctx) {
|
|
ctx.onunload = onunload
|
|
}
|
|
})
|
|
]
|
|
}),
|
|
"/test15": pure(function () { return [m("div")] })
|
|
})
|
|
|
|
route("/test15")
|
|
|
|
expect(onunload).to.be.calledOnce
|
|
})
|
|
|
|
dit("only calls onunload once when routed away (3)", function (root) {
|
|
mode("search")
|
|
|
|
var onunload = sinon.spy()
|
|
|
|
route(root, "/", {
|
|
"/": pure(function () {
|
|
return m("div", {
|
|
config: function (el, init, ctx) {
|
|
ctx.onunload = onunload
|
|
}
|
|
})
|
|
}),
|
|
"/test16": pure(function () { return m("a") })
|
|
})
|
|
|
|
route("/test16")
|
|
|
|
expect(onunload).to.be.calledOnce
|
|
})
|
|
|
|
dit("only calls onunload once when routed away (4)", function (root) {
|
|
mode("search")
|
|
|
|
var onunload = sinon.spy()
|
|
|
|
route(root, "/", {
|
|
"/": pure(function () {
|
|
return [
|
|
m("div", {
|
|
config: function (el, init, ctx) {
|
|
ctx.onunload = onunload
|
|
}
|
|
})
|
|
]
|
|
}),
|
|
"/test17": pure(function () { return m("a") })
|
|
})
|
|
|
|
route("/test17")
|
|
|
|
expect(onunload).to.be.calledOnce
|
|
})
|
|
|
|
dit("only calls onunload once when routed away (5)", function (root) {
|
|
mode("search")
|
|
|
|
var onunload = sinon.spy()
|
|
|
|
route(root, "/", {
|
|
"/": pure(function () {
|
|
return m("div", {
|
|
config: function (el, init, ctx) {
|
|
ctx.onunload = onunload
|
|
}
|
|
})
|
|
}),
|
|
"/test18": pure(function () { return [m("a")] })
|
|
})
|
|
|
|
route("/test18")
|
|
|
|
expect(onunload).to.be.calledOnce
|
|
})
|
|
|
|
dit("only calls onunload once when routed away (6)", function (root) {
|
|
mode("search")
|
|
|
|
var onunload = sinon.spy()
|
|
|
|
route(root, "/", {
|
|
"/": pure(function () {
|
|
return [
|
|
m("div", {
|
|
key: 1,
|
|
config: function (el, init, ctx) {
|
|
ctx.onunload = onunload
|
|
}
|
|
})
|
|
]
|
|
}),
|
|
"/test20": pure(function () {
|
|
return [
|
|
m("div", {
|
|
key: 2,
|
|
config: function (el, init, ctx) {
|
|
ctx.onunload = onunload
|
|
}
|
|
})
|
|
]
|
|
})
|
|
})
|
|
|
|
route("/test20")
|
|
|
|
expect(onunload).to.be.calledOnce
|
|
})
|
|
|
|
dit("only calls onunload once when routed away (7)", function (root) {
|
|
mode("search")
|
|
|
|
var onunload = sinon.spy()
|
|
|
|
route(root, "/", {
|
|
"/": pure(function () {
|
|
return [
|
|
m("div", {
|
|
key: 1,
|
|
config: function (el, init, ctx) {
|
|
ctx.onunload = onunload
|
|
}
|
|
})
|
|
]
|
|
}),
|
|
"/test21": pure(function () {
|
|
return [
|
|
m("div", {
|
|
config: function (el, init, ctx) {
|
|
ctx.onunload = onunload
|
|
}
|
|
})
|
|
]
|
|
})
|
|
})
|
|
|
|
route("/test21")
|
|
|
|
expect(onunload).to.be.calledOnce
|
|
})
|
|
|
|
dit("renders the right virtual node when routed to it", function (root) {
|
|
mode("search")
|
|
|
|
route(root, "/foo", {
|
|
"/foo": pure(function () { return m("div", "foo") }),
|
|
"/bar": pure(function () { return m("div", "bar") })
|
|
})
|
|
var foo = root.childNodes[0].childNodes[0].nodeValue
|
|
|
|
route("/bar")
|
|
var bar = root.childNodes[0].childNodes[0].nodeValue
|
|
|
|
expect(foo).to.equal("foo")
|
|
expect(bar).to.equal("bar")
|
|
})
|
|
|
|
dit("keeps identity with unchanged nodes", function (root) {
|
|
mode("search")
|
|
|
|
var onunload = sinon.spy()
|
|
function config(el, init, ctx) {
|
|
ctx.onunload = onunload
|
|
}
|
|
|
|
route(root, "/foo1", {
|
|
"/foo1": pure(function () {
|
|
return m("div", m("a", {config: config}, "foo"))
|
|
}),
|
|
"/bar1": pure(function () {
|
|
return m("main", m("a", {config: config}, "foo"))
|
|
})
|
|
})
|
|
|
|
route("/bar1")
|
|
|
|
expect(onunload).to.be.calledOnce
|
|
})
|
|
|
|
dit("allows illegal URL characters in paths", function (root) {
|
|
mode("search")
|
|
|
|
var value
|
|
m.route(root, "/foo+bar", {
|
|
"/:arg": {
|
|
controller: function () { value = m.route.param("arg") },
|
|
view: function () {
|
|
return ""
|
|
}
|
|
}
|
|
})
|
|
expect(value).to.equal("foo+bar")
|
|
})
|
|
|
|
dit("allows trailing slashes in paths", function (root) {
|
|
mode("search")
|
|
|
|
route(root, "/", {
|
|
"/": pure(function () { return "foo" }),
|
|
"/test22": pure(function () { return "bar" })
|
|
})
|
|
|
|
m.route("/test22/")
|
|
|
|
expect(mock.location.search).to.equal("?/test22/")
|
|
expect(root.childNodes[0].nodeValue).to.equal("bar")
|
|
})
|
|
|
|
dit("reads non-primitive String objects in route changes", function (root) {
|
|
mode("search")
|
|
|
|
route(root, "/", {
|
|
"/": pure(function () { return "foo" }),
|
|
"/test23": pure(function () { return "bar" })
|
|
})
|
|
|
|
route(new String("/test23/")) // eslint-disable-line no-new-wrappers
|
|
|
|
expect(mock.location.search).to.equal("?/test23/")
|
|
expect(root.childNodes[0].nodeValue).to.equal("bar")
|
|
})
|
|
|
|
dit("reads primitive Strings in default routes", function (root) {
|
|
mode("search")
|
|
|
|
var value
|
|
m.route(root, "/foo+bar", {
|
|
"/:arg": {
|
|
controller: function () { value = m.route.param("arg") },
|
|
view: function () {
|
|
return ""
|
|
}
|
|
}
|
|
})
|
|
expect(value).to.equal("foo+bar")
|
|
})
|
|
|
|
dit("reads non-primitive Strings in default routes", function (root) {
|
|
mode("search")
|
|
|
|
var value
|
|
m.route(root, new String("/foo+bar"), { // eslint-disable-line
|
|
"/:arg": {
|
|
controller: function () { value = m.route.param("arg") },
|
|
view: function () {
|
|
return ""
|
|
}
|
|
}
|
|
})
|
|
|
|
expect(value).to.equal("foo+bar")
|
|
})
|
|
|
|
dit("can redirect to another route while loading default", function (root) { // eslint-disable-line
|
|
mode("search")
|
|
|
|
route(root, "/a", {
|
|
"/a": {
|
|
controller: function () { m.route("/b") },
|
|
view: function () { return "a" }
|
|
},
|
|
|
|
"/b": pure(function () { return "b" })
|
|
})
|
|
|
|
expect(root.childNodes[0].nodeValue).to.equal("b")
|
|
})
|
|
|
|
dit("can redirect to another route with params while loading default", function (root) { // eslint-disable-line
|
|
mode("search")
|
|
|
|
route(root, "/", {
|
|
"/": {
|
|
controller: function () {
|
|
m.route("/b?foo=1", {foo: 2})
|
|
},
|
|
view: function () { return "a" }
|
|
},
|
|
"/b": pure(function () { return "b" })
|
|
})
|
|
|
|
expect(mock.location.search).to.equal("?/b?foo=2")
|
|
})
|
|
|
|
dit("modifies history when changing route", function (root) {
|
|
mode("search")
|
|
mock.history.$$length = 0
|
|
|
|
route(root, "/a", {
|
|
"/a": pure(function () { return "a" }),
|
|
"/b": pure(function () { return "b" })
|
|
})
|
|
|
|
route("/b")
|
|
|
|
expect(mock.history.$$length).to.equal(1)
|
|
})
|
|
|
|
dit("doesn't modify history when redirecting to same route", function (root) { // eslint-disable-line
|
|
mode("search")
|
|
mock.history.$$length = 0
|
|
|
|
route(root, "/a", {
|
|
"/a": pure(function () { return "a" }),
|
|
"/b": pure(function () { return "b" })
|
|
})
|
|
|
|
route("/a")
|
|
|
|
expect(mock.history.$$length).to.equal(0)
|
|
})
|
|
|
|
context("m.route.strategy() === \"all\", identical views", function () {
|
|
context("parent nodes", function () {
|
|
dit("renders routes independently", function (root) {
|
|
mode("search")
|
|
var initCount = 0
|
|
|
|
var a = pure(function () {
|
|
return m("a", {
|
|
config: function (el, init) {
|
|
if (!init) initCount++
|
|
}
|
|
})
|
|
})
|
|
|
|
route(root, "/a", {
|
|
"/a": a,
|
|
"/b": pure(a.view)
|
|
})
|
|
|
|
route("/b")
|
|
|
|
expect(initCount).to.equal(2)
|
|
})
|
|
|
|
dit("renders routes independently with `context.retain === false`", function (root) { // eslint-disable-line
|
|
mode("search")
|
|
var initCount = 0
|
|
|
|
var a = pure(function () {
|
|
return m("a", {
|
|
config: function (el, init, ctx) {
|
|
ctx.retain = false
|
|
if (!init) initCount++
|
|
}
|
|
})
|
|
})
|
|
|
|
route(root, "/a", {
|
|
"/a": a,
|
|
"/b": pure(a.view)
|
|
})
|
|
|
|
route("/b")
|
|
|
|
expect(initCount).to.equal(2)
|
|
})
|
|
|
|
dit("renders routes independently with `context.retain === true`", function (root) { // eslint-disable-line
|
|
mode("search")
|
|
var initCount = 0
|
|
|
|
var a = pure(function () {
|
|
return m("a", {
|
|
config: function (el, init, ctx) {
|
|
ctx.retain = true
|
|
if (!init) initCount++
|
|
}
|
|
})
|
|
})
|
|
|
|
route(root, "/a", {
|
|
"/a": a,
|
|
"/b": pure(a.view)
|
|
})
|
|
|
|
route("/b")
|
|
|
|
expect(initCount).to.equal(1)
|
|
})
|
|
})
|
|
|
|
context("child nodes", function () {
|
|
dit("reinitialize unchanged child nodes without `context.retain`", function (root) { // eslint-disable-line
|
|
mode("search")
|
|
var initCount = 0
|
|
|
|
function config(el, init) {
|
|
if (!init) initCount++
|
|
}
|
|
|
|
route(root, "/a", {
|
|
"/a": pure(function () {
|
|
return m("div", m("a", {config: config}))
|
|
}),
|
|
"/b": pure(function () {
|
|
return m("section", m("a", {config: config}))
|
|
})
|
|
})
|
|
|
|
route("/b")
|
|
|
|
expect(initCount).to.equal(2)
|
|
})
|
|
|
|
dit("doesn't reinitialize unchanged child nodes with `context.retain === true`", function (root) { // eslint-disable-line
|
|
mode("search")
|
|
var initCount = 0
|
|
function config(el, init, ctx) {
|
|
ctx.retain = true
|
|
if (!init) initCount++
|
|
}
|
|
|
|
route(root, "/a", {
|
|
"/a": pure(function () {
|
|
return m("div", m("a", {config: config}))
|
|
}),
|
|
"/b": pure(function () {
|
|
return m("section", m("a", {config: config}))
|
|
})
|
|
})
|
|
|
|
route("/b")
|
|
|
|
expect(initCount).to.equal(1)
|
|
})
|
|
|
|
dit("reinitializes unchanged child nodes with `context.retain === false`", function (root) { // eslint-disable-line
|
|
mode("search")
|
|
var initCount = 0
|
|
function config(el, init, ctx) {
|
|
ctx.retain = false
|
|
if (!init) initCount++
|
|
}
|
|
|
|
route(root, "/a", {
|
|
"/a": pure(function () {
|
|
return m("div", m("a", {config: config}))
|
|
}),
|
|
"/b": pure(function () {
|
|
return m("section", m("a", {config: config}))
|
|
})
|
|
})
|
|
|
|
route("/b")
|
|
|
|
expect(initCount).to.equal(2)
|
|
})
|
|
})
|
|
})
|
|
|
|
context("m.route.strategy() === \"diff\"", function () {
|
|
function diff(view) {
|
|
return {
|
|
controller: function () { m.redraw.strategy("diff") },
|
|
view: view
|
|
}
|
|
}
|
|
|
|
context("parent nodes", function () {
|
|
dit("renders routes independently", function (root) {
|
|
mode("search")
|
|
var initCount = 0
|
|
|
|
var a = diff(function () {
|
|
return m("a", {
|
|
config: function (el, init) {
|
|
if (!init) initCount++
|
|
}
|
|
})
|
|
})
|
|
|
|
route(root, "/a", {
|
|
"/a": a,
|
|
"/b": diff(a.view)
|
|
})
|
|
|
|
route("/b")
|
|
|
|
expect(initCount).to.equal(1)
|
|
})
|
|
|
|
dit("renders routes independently with `context.retain === false`", function (root) { // eslint-disable-line
|
|
mode("search")
|
|
var initCount = 0
|
|
|
|
var a = diff(function () {
|
|
return m("a", {
|
|
config: function (el, init, ctx) {
|
|
ctx.retain = true
|
|
if (!init) initCount++
|
|
}
|
|
})
|
|
})
|
|
|
|
route(root, "/a", {
|
|
"/a": a,
|
|
"/b": diff(a.view)
|
|
})
|
|
|
|
route("/b")
|
|
|
|
expect(initCount).to.equal(1)
|
|
})
|
|
|
|
dit("renders routes independently with `context.retain === true`", function (root) { // eslint-disable-line
|
|
mode("search")
|
|
var initCount = 0
|
|
|
|
var a = diff(function () {
|
|
return m("a", {
|
|
config: function (el, init, ctx) {
|
|
ctx.retain = false
|
|
if (!init) initCount++
|
|
}
|
|
})
|
|
})
|
|
|
|
route(root, "/a", {
|
|
"/a": a,
|
|
"/b": diff(a.view)
|
|
})
|
|
|
|
route("/b")
|
|
|
|
expect(initCount).to.equal(2)
|
|
})
|
|
})
|
|
|
|
context("child nodes", function () {
|
|
dit("reinitialize unchanged child nodes without `context.retain`", function (root) { // eslint-disable-line
|
|
mode("search")
|
|
var initCount = 0
|
|
|
|
function config(el, init) {
|
|
if (!init) initCount++
|
|
}
|
|
|
|
route(root, "/a", {
|
|
"/a": diff(function () {
|
|
return m("div", m("a", {config: config}))
|
|
}),
|
|
"/b": diff(function () {
|
|
return m("section", m("a", {config: config}))
|
|
})
|
|
})
|
|
|
|
route("/b")
|
|
|
|
expect(initCount).to.equal(1)
|
|
})
|
|
|
|
dit("doesn't reinitialize unchanged child nodes with `context.retain === true`", function (root) { // eslint-disable-line
|
|
mode("search")
|
|
var initCount = 0
|
|
|
|
function config(el, init, ctx) {
|
|
ctx.retain = true
|
|
if (!init) initCount++
|
|
}
|
|
|
|
route(root, "/a", {
|
|
"/a": diff(function () {
|
|
return m("div", m("a", {config: config}))
|
|
}),
|
|
"/b": diff(function () {
|
|
return m("section", m("a", {config: config}))
|
|
})
|
|
})
|
|
|
|
route("/b")
|
|
|
|
expect(initCount).to.equal(1)
|
|
})
|
|
|
|
dit("reinitializes unchanged child nodes with `context.retain === false`", function (root) { // eslint-disable-line
|
|
mode("search")
|
|
var initCount = 0
|
|
|
|
function config(el, init, ctx) {
|
|
ctx.retain = false
|
|
if (!init) initCount++
|
|
}
|
|
|
|
route(root, "/a", {
|
|
"/a": diff(function () {
|
|
return m("div", m("a", {config: config}))
|
|
}),
|
|
"/b": diff(function () {
|
|
return m("section", m("a", {config: config}))
|
|
})
|
|
})
|
|
|
|
m.route("/b")
|
|
|
|
expect(initCount).to.equal(2)
|
|
})
|
|
})
|
|
})
|
|
|
|
dit("honors retain flag inside child components during route change", function (root) { // eslint-disable-line
|
|
mode("search")
|
|
var initCount = 0
|
|
|
|
function config(el, init, ctx) {
|
|
ctx.retain = true
|
|
if (!init) initCount++
|
|
}
|
|
|
|
var a = pure(function () {
|
|
return m("div", m("a", {config: config}))
|
|
})
|
|
|
|
var b = {
|
|
controller: function () { m.redraw.strategy("diff") },
|
|
view: function () {
|
|
return m("section", m("a", {config: config}))
|
|
}
|
|
}
|
|
|
|
route(root, "/a", {
|
|
"/a": pure(function () { return m("div", a) }),
|
|
"/b": pure(function () { return m("div", b) })
|
|
})
|
|
|
|
route("/b")
|
|
|
|
expect(initCount).to.equal(1)
|
|
})
|
|
|
|
// https://github.com/lhorie/mithril.js/pull/571
|
|
dit("clears nodes with config on route change", function (root) {
|
|
mode("search")
|
|
|
|
route(root, "/a", {
|
|
"/a": pure(function () {
|
|
return m("div", {
|
|
config: function (el) {
|
|
el.childNodes[0].modified = true
|
|
}
|
|
}, m("div"))
|
|
}),
|
|
"/b": pure(function () { return m("div", m("div")) })
|
|
})
|
|
|
|
route("/b")
|
|
|
|
expect(root.childNodes[0].childNodes[0])
|
|
.to.not.have.property("modified")
|
|
})
|
|
})
|