function testMithril(mock) { m.deps(mock) //m test(function() {return m.version().constructor === String}) test(function() {return m("div").tag === "div"}) test(function() {return m(".foo").tag === "div"}) test(function() {return m(".foo").attrs.className === "foo"}) test(function() {return m("[title=bar]").tag === "div"}) test(function() {return m("[title=bar]").attrs.title === "bar"}) test(function() {return m("[title=\'bar\']").attrs.title === "bar"}) test(function() {return m("[title=\"bar\"]").attrs.title === "bar"}) test(function() {return m("div", "test").children[0] === "test"}) test(function() {return m("div", "test", "test2").children[1] === "test2"}) test(function() {return m("div", ["test"]).children[0] === "test"}) test(function() {return m("div", {title: "bar"}, "test").attrs.title === "bar"}) test(function() {return m("div", {title: "bar"}, "test").children[0] === "test"}) test(function() {return m("div", {title: "bar"}, ["test"]).children[0] === "test"}) test(function() {return m("div", {title: "bar"}, m("div")).children[0].tag === "div"}) test(function() {return m("div", {title: "bar"}, [m("div")]).children[0].tag === "div"}) test(function() {return m("div", {title: "bar"}, "test0", "test1", "test2", "test3").children[3] === "test3"}) // splat test(function() {return m("div", {title: "bar"}, m("div"), m("i"), m("span")).children[2].tag === "span"}) test(function() {return m("div", ["a", "b"]).children.length === 2}) test(function() {return m("div", [m("div")]).children[0].tag === "div"}) test(function() {return m("div", m("div")).children[0].tag === "div"}) //yes, this is expected behavior: see method signature test(function() {return m("div", [undefined]).tag === "div"}) test(function() {return m("div", [{foo: "bar"}])}) //as long as it doesn't throw errors, it's fine test(function() {return m("svg", [m("g")])}) test(function() {return m("svg", [m("a[href='http://google.com']")])}) test(function() {return m(".foo", {"class": "bar"}).attrs["class"] === "foo bar"}) test(function() {return m(".foo", {className: "bar"}).attrs.className === "foo bar"}) test(function() {return m(".foo", {className: ""}).attrs.className === "foo"}) test(function() {return m("div", {className: ""}).attrs.className === ""}) //https://github.com/lhorie/mithril.js/issues/382 and 512 test(function() {return m("div", {"class": ""}).attrs.className === undefined}) test(function() {return m("div", {className: ""}).attrs["class"] === undefined}) test(function() {return m("div", {"class": ""}).attrs["class"] === ""}) test(function() {return m("div", [1, 2, 3], 4).children.length === 2}) test(function() {return m("div", [1, 2, 3], 4).children[0].length === 3}) test(function() {return m("div", [1, 2, 3], 4).children[1] === 4}) test(function() {return m("div", [1, 2, 3]).children.length === 3}) test(function() {return m("div", [1, 2, 3], [4, 5, 6, 7]).children.length === 2}) test(function() {return m("div", [1, 2, 3], [4, 5, 6, 7]).children[0].length === 3}) test(function() {return m("div", [1, 2, 3], [4, 5, 6, 7]).children[1].length === 4}) test(function() {return m("div", [1], [2], [3]).children.length === 3}) test(function() { //class changes shouldn't trigger dom recreation var v1 = m(".foo", {"class": "", onclick: function() {}}) var v2 = m(".foo", {"class": "bar", onclick: function() {}}) return Object.keys(v1.attrs).join() === Object.keys(v2.attrs).join() }) test(function() { //m should proxy object first arg to m.component var component = { controller: function(args) { this.args = args }, view: function () { return m("div", "testing") } } var args = {age: 12} var c1 = m(component, args).controller() var c2 = m.component(component, args).controller() return c1.args === args && c1.args === c2.args }) //m.mount test(function() { var root = mock.document.createElement("div") var whatever = 1 var app = { view: function() { return [ whatever % 2 ? m('span', '% 2') : undefined, m('div', 'bugs'), m('a') ] } } m.mount(root, app) mock.requestAnimationFrame.$resolve() whatever++ m.redraw() mock.requestAnimationFrame.$resolve() whatever++ m.redraw() mock.requestAnimationFrame.$resolve() return root.childNodes.length }) test(function() { mock.requestAnimationFrame.$resolve() var root1 = mock.document.createElement("div") var mod1 = m.mount(root1, { controller: function() {this.value = "test1"}, view: function(ctrl) {return ctrl.value} }) var root2 = mock.document.createElement("div") var mod2 = m.mount(root2, { controller: function() {this.value = "test2"}, view: function(ctrl) {return ctrl.value} }) mock.requestAnimationFrame.$resolve() return (root1.childNodes[0].nodeValue === "test1" && root2.childNodes[0].nodeValue === "test2") && (mod1.value && mod1.value === "test1") && (mod2.value && mod2.value === "test2") }) test(function() { mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var unloaded = false m.mount(root, { controller: function() { this.value = "test1" this.onunload = function() { unloaded = true } }, view: function(ctrl) {return ctrl.value} }) mock.requestAnimationFrame.$resolve() m.mount(root, null) mock.requestAnimationFrame.$resolve() return unloaded }) test(function() { //component should pass args to both controller and view mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var slot1, slot2 var component = { controller: function(options) {slot1 = options.a}, view: function(ctrl, options) {slot2 = options.a} } m.mount(root, m.component(component, {a: 1})) mock.requestAnimationFrame.$resolve() return slot1 === 1 && slot2 === 1 }) test(function() { //component should work without controller mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var slot2 var component = { view: function(ctrl, options) {slot2 = options.a} } m.mount(root, m.component(component, {a: 1})) mock.requestAnimationFrame.$resolve() return slot2 === 1 }) test(function() { //component controller should only run once mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var count1 = 0, count2 = 0 var component = { view: function() { return sub } } var sub = { controller: function() { count1++ }, view: function() { count2++ return m("div", "test") } } m.mount(root, component) mock.requestAnimationFrame.$resolve() m.redraw(true) mock.requestAnimationFrame.$resolve() return count1 === 1 && count2 === 2 }) test(function() { //sub component controller should only run once mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var count1 = 0, count2 = 0, count3 = 0, count4 = 0 var component = { view: function() { return sub } } var sub = { controller: function() { count1++ }, view: function() { count2++ return subsub } } var subsub = { controller: function() { count3++ }, view: function() { count4++ return m("div", "test") } } m.mount(root, component) mock.requestAnimationFrame.$resolve() m.redraw(true) mock.requestAnimationFrame.$resolve() return count1 === 1 && count2 === 2 && count3 === 1 && count4 === 2 }) test(function() { //keys in components should work mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var list = [1, 2, 3] var component = { controller: function() {}, view: function() { return list.map(function(i) { return m.component(sub, {key: i}) }) } } var sub = { controller: function() {}, view: function() { return m("div") } } m.mount(root, component) var firstBefore = root.childNodes[0] mock.requestAnimationFrame.$resolve() list.reverse() m.redraw(true) mock.requestAnimationFrame.$resolve() var firstAfter = root.childNodes[2] return firstBefore === firstAfter }) test(function() { //keys in subcomponents should work mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var list = [1, 2, 3] var component = { controller: function() {}, view: function() { return list.map(function(i) { return m.component(sub, {key: i}) }) } } var sub = { view: function() { return subsub } } var subsub = { controller: function() {}, view: function() { return m("div") } } m.mount(root, component) var firstBefore = root.childNodes[0] mock.requestAnimationFrame.$resolve() list.reverse() m.redraw(true) mock.requestAnimationFrame.$resolve() var firstAfter = root.childNodes[2] return firstBefore === firstAfter }) test(function() { //keys in components should work even if component internally messes them up mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var list = [1, 2, 3] var component = { controller: function() {}, view: function() { return list.map(function(i) { return m.component(sub, {key: i}) }) } } var sub = { controller: function() {}, view: function() { return m("div", {key: 1}) } } m.mount(root, component) var firstBefore = root.childNodes[0] mock.requestAnimationFrame.$resolve() list.reverse() m.redraw(true) mock.requestAnimationFrame.$resolve() var firstAfter = root.childNodes[2] return firstBefore === firstAfter }) test(function() { //keys in subcomponents should work even if component internally messes them up mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var list = [1, 2, 3] var component = { controller: function() {}, view: function() { return list.map(function(i) { return m.component(sub, {key: i}) }) } } var sub = { controller: function() {}, view: function() { return subsub } } var subsub = { controller: function() {}, view: function() { return m("div", {key: 1}) } } m.mount(root, component) var firstBefore = root.childNodes[0] mock.requestAnimationFrame.$resolve() list.reverse() m.redraw(true) mock.requestAnimationFrame.$resolve() var firstAfter = root.childNodes[2] return firstBefore === firstAfter }) test(function() { //component identity should stay intact if components are descendants of keyed elements mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var list = [1, 2, 3] var component = { controller: function() {}, view: function() { return list.map(function(i) { return m("div", {key: i}, sub) }) } } var sub = { controller: function() {}, view: function() { return m("div") } } m.mount(root, component) var firstBefore = root.childNodes[0].childNodes[0] mock.requestAnimationFrame.$resolve() list.reverse() m.redraw(true) mock.requestAnimationFrame.$resolve() var firstAfter = root.childNodes[2].childNodes[0] return firstBefore === firstAfter }) test(function() { //subcomponent identity should stay intact if components are descendants of keyed elements mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var list = [1, 2, 3] var component = { controller: function() {}, view: function() { return list.map(function(i) { return m("div", {key: i}, sub) }) } } var sub = { controller: function() {}, view: function() { return subsub } } var subsub = { controller: function() {}, view: function() { return m("div") } } m.mount(root, component) var firstBefore = root.childNodes[0].childNodes[0] mock.requestAnimationFrame.$resolve() list.reverse() m.redraw(true) mock.requestAnimationFrame.$resolve() var firstAfter = root.childNodes[2].childNodes[0] return firstBefore === firstAfter }) test(function() { //component should call onunload when removed from template mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var list = [1, 2, 3] var unloaded var component = { controller: function() {}, view: function() { return list.map(function(i) { return m.component(sub, {key: i}) }) } } var sub = { controller: function(opts) { this.onunload = function() { unloaded = opts.key } }, view: function() { return m("div") } } m.mount(root, component) mock.requestAnimationFrame.$resolve() list.pop() m.redraw(true) mock.requestAnimationFrame.$resolve() return unloaded === 3 }) test(function() { //subcomponent should call onunload when removed from template mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var list = [1, 2, 3] var unloaded1, unloaded2 var component = { controller: function() {}, view: function() { return list.map(function(i) { return m.component(sub, {key: i}) }) } } var sub = { controller: function(opts) { this.onunload = function() { unloaded1 = opts.key } }, view: function(ctrl, opts) { return m.component(subsub, {key: opts.key}) } } var subsub = { controller: function(opts) { this.onunload = function() { unloaded2 = opts.key } }, view: function() { return m("div") } } m.mount(root, component) mock.requestAnimationFrame.$resolve() list.pop() m.redraw(true) mock.requestAnimationFrame.$resolve() return unloaded1 === 3 && unloaded2 === 3 }) test(function() { //calling m.redraw synchronously from controller constructor should not trigger extra redraws mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var count = 0 var component = { controller: function() {}, view: function() { return sub } } var sub = { controller: function() { m.redraw() }, view: function() { count++ return m("div") } } m.mount(root, component) mock.requestAnimationFrame.$resolve() return count === 1 }) test(function() { //calling m.redraw synchronously from controller constructor should not trigger extra redraws mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var count = 0 var component = { controller: function() {}, view: function() { return sub } } var sub = { controller: function() {}, view: function() { return subsub } } var subsub = { controller: function() { m.redraw() }, view: function() { count++ return m("div") } } m.mount(root, component) mock.requestAnimationFrame.$resolve() return count === 1 }) test(function() { //calling preventDefault from component's onunload should prevent route change mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var loaded = false var testEnabled = true var component = { controller: function() {}, view: function() { return sub } } var sub = { controller: function() { this.onunload = function(e) {if (testEnabled) e.preventDefault()} }, view: function() { return m("div") } } m.route(root, "/a", { "/a": component, "/b": {controller: function() {loaded = true}, view: function() {}} }) mock.requestAnimationFrame.$resolve() m.route("/b") mock.requestAnimationFrame.$resolve() testEnabled = false return loaded === false }) test(function() { //calling preventDefault from subcomponent's onunload should prevent route change mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var loaded = false var testEnabled = true var component = { controller: function() {}, view: function() { return sub } } var sub = { controller: function() {}, view: function() { return subsub } } var subsub = { controller: function() { this.onunload = function(e) {if (testEnabled) e.preventDefault()} }, view: function() { return m("div") } } m.route(root, "/a", { "/a": component, "/b": {controller: function() {loaded = true}, view: function() {}} }) mock.requestAnimationFrame.$resolve() m.route("/b") mock.requestAnimationFrame.$resolve() testEnabled = false return loaded === false }) test(function() { //calling preventDefault from non-curried component's onunload should prevent route change mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var loaded = false var testEnabled = true var component = { controller: function() {}, view: function() { return sub } } var sub = { controller: function() { this.onunload = function(e) {if (testEnabled) e.preventDefault()} }, view: function() { return m("div") } } m.route(root, "/a", { "/a": component, "/b": {controller: function() {loaded = true}, view: function() {}} }) mock.requestAnimationFrame.$resolve() m.route("/b") mock.requestAnimationFrame.$resolve() testEnabled = false return loaded === false }) test(function() { //calling preventDefault from non-curried subcomponent's onunload should prevent route change mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var loaded = false var testEnabled = true var component = { controller: function() {}, view: function() { return sub } } var sub = { controller: function() {}, view: function() { return subsub } } var subsub = { controller: function() { this.onunload = function(e) {if (testEnabled) e.preventDefault()} }, view: function() { return m("div") } } m.route(root, "/a", { "/a": component, "/b": {controller: function() {loaded = true}, view: function() {}} }) mock.requestAnimationFrame.$resolve() m.route("/b") mock.requestAnimationFrame.$resolve() testEnabled = false return loaded === false }) test(function() { // nested components under keyed components should render mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var count = 0 var App = { controller: function() {}, view: function() { return m('.outer', [ m('.inner', m.component(CommentList, { list: [1, 2, 3] })) ]) } } var CommentList = { controller: function() {}, view: function(ctrl, props) { return m('.list', props.list.map(function(i) { return m('.comment', [ m.component(Reply, {key: i}) ]) })) } } var Reply = { controller: function() {}, view: function() { count++ return m(".reply") } } m.mount(root, App) mock.requestAnimationFrame.$resolve() return count === 3 }) test(function() { // a route change should initialize a component's controller mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var countA = 0 var countB = 0 var subA = { controller: function(){ countA += 1 }, view: function() { return m("div") } } var subB = { controller: function() { countB += 1 }, view: function() { return m("div") } } m.route(root, "/a", { "/a": { view: function () { return m('.page-a', [ m('h1'), m.component(subA, { x: 11 }) ]) } }, "/b": { view: function() { return m('.page-b', [ m('h2'), m.component(subB, { y: 22 }) ]) } } }) mock.requestAnimationFrame.$resolve() m.route("/b") mock.requestAnimationFrame.$resolve() m.route("/a") mock.requestAnimationFrame.$resolve() return countA === 2 && countB === 1 }) test(function() { var root = mock.document.createElement("div") var component = {}, unloaded = false component.controller = function() { this.onunload = function() {unloaded = true} } component.view = function() {} m.mount(root, component) m.mount(root, {controller: function() {}, view: function() {}}) return unloaded === true }) test(function() { mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var initCount = 0 var component = {} component.view = function() { return m("div", {config: function(el, init) { if (!init) initCount++ }}) } m.mount(root, component) mock.requestAnimationFrame.$resolve() m.redraw() mock.requestAnimationFrame.$resolve() return initCount === 1 }) test(function() { var root = mock.document.createElement("div") var dom = mock.document.createElement("div") var show = true var component = { view: function() { return [ m(".foo", {key: 1, config: test, onclick: function() {show = !show}}), show ? m(".bar", {key: 2}) : null ] } } function test(el, init) { if (!init) { root.appendChild(dom) } } m.mount(root, component) mock.requestAnimationFrame.$resolve() show = false m.redraw() mock.requestAnimationFrame.$resolve() show = true m.redraw() mock.requestAnimationFrame.$resolve() return root.childNodes.length === 3 }) test(function() { var root = mock.document.createElement("div") var show = true var testcomponent = { controller: function() {}, view: function() { return m('div', 'component'); } } var app = { view: function() { return show ? [ m('h1', '1'), testcomponent ] : [ m('h1', '2') ]; } }; m.mount(root, app); mock.requestAnimationFrame.$resolve() show = false m.redraw() mock.requestAnimationFrame.$resolve() show = true m.redraw() mock.requestAnimationFrame.$resolve() return root.childNodes.length === 2 }) test(function() { // Components should not require a view mock.requestAnimationFrame.$resolve() mock.location.search = "?" var Component = { view: function () { return m('.comp') } } var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/foo", { "/foo": { view: function() { return [ Component ] } } }) mock.requestAnimationFrame.$resolve() return root.childNodes[0].nodeName === "DIV" }) test(function() { //https://github.com/lhorie/mithril.js/issues/551 var root = mock.document.createElement("div") var a = false, found = false, unloaded = false, redraws = 0 var Root = { view: function() { return Comp } } var Comp = { view: function() { redraws++ return m("div", {config: Comp.config}, [ m("div", {onclick: function() { a = !a m.redraw(true) found = root.childNodes[0].childNodes[1] }}, "asd"), a ? m("#a", "aaa") : null, "test" ]) }, config: function(el, init, ctx) { if (!init) ctx.onunload = function() { unloaded = true } } } m.mount(root, Root) var target = root.childNodes[0].childNodes[0] target.onclick({currentTarget: target}) mock.requestAnimationFrame.$resolve() return !unloaded && found.id === "a" && redraws === 3 }) test(function() { //https://github.com/lhorie/mithril.js/issues/551 var root = mock.document.createElement("div") var a = false, found = false, unloaded = false, redraws = 0 var Root = { view: function() { return Comp } } var Comp = { view: function() { redraws++ return m("div", {config: Comp.config}, [ m("div", {onclick: function() { a = !a m.redraw(true) found = root.childNodes[0].childNodes[1] m.redraw.strategy("none") }}, "asd"), a ? m("#a", "aaa") : null, "test" ]) }, config: function(el, init, ctx) { if (!init) ctx.onunload = function() { unloaded = true } } } m.mount(root, Root) var target = root.childNodes[0].childNodes[0] target.onclick({currentTarget: target}) mock.requestAnimationFrame.$resolve() return !unloaded && found.id === "a" && redraws === 2 }) test(function() { var root = mock.document.createElement("div") var redraws = 0 var Root = { view: function() { redraws++ return m("div", {onclick: function() {m.redraw(true)}}) } } m.mount(root, Root) var target = root.childNodes[0] target.onclick({currentTarget: target}) mock.requestAnimationFrame.$resolve() return redraws === 3 }) test(function() { //https://github.com/lhorie/mithril.js/issues/555 var root = mock.document.createElement("div") var MyComponent = { controller: function(args) { this.name = args.name; }, view: function(ctrl) { return m('div', ctrl.name); } } var FooPage = { view: function() { return m('div', [ m('a[href=/]', {config: m.route}, 'foo'), m('a[href=/bar]', {config: m.route}, 'bar'), m.component(MyComponent, {name: 'Jane'}) ]); } }; var BarPage = { view: function() { return m('div', [ m('a[href=/]', {config: m.route}, 'foo'), m('a[href=/bar]', {config: m.route}, 'bar'), m.component(MyComponent, {name: 'Bob'}) ]); } }; m.route(root, '/', { '/': FooPage, '/bar': BarPage }) mock.requestAnimationFrame.$resolve() m.route("/bar") mock.requestAnimationFrame.$resolve() return root.childNodes[0].childNodes[2].childNodes[0].nodeValue === "Bob" }) test(function() { var root = mock.document.createElement("div") var redraws = 0, data var Root = { view: function() { return Comp } } var Comp = { controller: function() { this.foo = m.request({method: "GET", url: "/foo"}) }, view: function(ctrl) { redraws++ data = ctrl.foo() return m("div") } } m.mount(root, Root) mock.requestAnimationFrame.$resolve() mock.XMLHttpRequest.$instances.pop().onreadystatechange() mock.requestAnimationFrame.$resolve() m.mount(root, null) mock.requestAnimationFrame.$resolve() return redraws === 1 && data.url === "/foo" }) test(function() { mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var redraws1 = 0, redraws2 = 0 var Root = { view: function() { return m("div", [ Comp1, Comp2 ]) } } var Comp1 = { controller: function() { this.foo = m.request({method: "GET", url: "/foo"}) }, view: function() { redraws1++ return m("div") } } var Comp2 = { controller: function() { this.bar = m.request({method: "GET", url: "/bar"}) }, view: function() { redraws2++ return m("div") } } m.mount(root, Root) mock.requestAnimationFrame.$resolve() mock.XMLHttpRequest.$instances.pop().onreadystatechange() mock.requestAnimationFrame.$resolve() mock.XMLHttpRequest.$instances.pop().onreadystatechange() mock.requestAnimationFrame.$resolve() m.mount(root, null) mock.requestAnimationFrame.$resolve() return redraws1 === 1 && redraws2 === 1 }) test(function() { var root = mock.document.createElement("div") var redraws1 = 0, redraws2 = 0 var Root1 = { view: function() { return Comp1 } } var Root2 = { view: function() { return Comp2 } } var Comp1 = { controller: function() { this.foo = m.request({method: "GET", url: "/foo"}) }, view: function() { redraws1++ return m("div") } } var Comp2 = { controller: function() { this.bar = m.request({method: "GET", url: "/bar"}) }, view: function() { redraws2++ return m("div") } } m.route(root, "/", { "/": Root1, "/root2": Root2 }) mock.requestAnimationFrame.$resolve() mock.XMLHttpRequest.$instances.pop().onreadystatechange() m.route("/root2") mock.requestAnimationFrame.$resolve() mock.XMLHttpRequest.$instances.pop().onreadystatechange() mock.requestAnimationFrame.$resolve() m.mount(root, null) mock.requestAnimationFrame.$resolve() return redraws1 === 1 && redraws2 === 1 }) test(function() { var root = mock.document.createElement("div") var cond = true var controller1 = null, controller2 = null var Root = { view: function() { return cond ? Comp1 : Comp2 } } var Comp1 = { view: function(ctrl) { controller1 = ctrl return m("div") } } var Comp2 = { view: function(ctrl) { controller2 = ctrl return m("div") } } m.mount(root, Root) mock.requestAnimationFrame.$resolve() cond = false m.redraw(true) mock.requestAnimationFrame.$resolve() return controller1 !== controller2 }) test(function() { var root = mock.document.createElement("div") var cond = true var unloaded = false var Root = { view: function() { return cond ? Comp1 : Comp2 } } var Comp1 = { view: function() { return m("div", {config: function(el, init, ctx) { ctx.onunload = function() {unloaded = true} }}) } } var Comp2 = { view: function() { return m("div") } } m.mount(root, Root) mock.requestAnimationFrame.$resolve() cond = false m.redraw(true) mock.requestAnimationFrame.$resolve() return unloaded }) test(function() { var root = mock.document.createElement("div") var cond = true var initialized = null var Root = { view: function() { return cond ? Comp1 : Comp2 } } var Comp1 = { view: function() { return m("div") } } var Comp2 = { view: function() { return m("div", {config: function(el, init) { initialized = init }}) } } m.mount(root, Root) mock.requestAnimationFrame.$resolve() cond = false m.redraw(true) mock.requestAnimationFrame.$resolve() return initialized === false }) test(function() { var root = mock.document.createElement("div") var el var FooPage = { view: function(ctrl) { return m('div', [ m('button', {onclick: function() { ctrl.bar = true; m.redraw(true); el = root.childNodes[0].childNodes[1] }}, 'click me'), ctrl.bar ? m.component(BarComponent) : '' ]); } }; var BarComponent = { view: function() { return m('#bar', 'test'); } }; m.mount(root, FooPage); root.childNodes[0].childNodes[0].onclick({}) return el.id === "bar" }) //m.withAttr test(function() { var value var handler = m.withAttr("test", function(data) {value = data}) handler({currentTarget: {test: "foo"}}) return value === "foo" }) //m.trust test(function() {return m.trust("test").valueOf() === "test"}) //m.render test(function() { var root = mock.document.createElement("div") m.render(root, "test") return root.childNodes[0].nodeValue === "test" }) test(function() { var root = mock.document.createElement("div") m.render(root, m("div", {"class": "a"})) var elementBefore = root.childNodes[0] m.render(root, m("div", {"class": "b"})) var elementAfter = root.childNodes[0] return elementBefore === elementAfter }) test(function() { var root = mock.document.createElement("div") m.render(root, m(".a")) var elementBefore = root.childNodes[0] m.render(root, m(".b")) var elementAfter = root.childNodes[0] return elementBefore === elementAfter }) test(function() { var root = mock.document.createElement("div") m.render(root, m("div", {id: "a"})) var elementBefore = root.childNodes[0] m.render(root, m("div", {title: "b"})) var elementAfter = root.childNodes[0] return elementBefore !== elementAfter }) test(function() { var root = mock.document.createElement("div") m.render(root, m("#a")) var elementBefore = root.childNodes[0] m.render(root, m("[title=b]")) var elementAfter = root.childNodes[0] return elementBefore !== elementAfter }) test(function() { var root = mock.document.createElement("div") m.render(root, m("#a")) var elementBefore = root.childNodes[0] m.render(root, "test") var elementAfter = root.childNodes[0] return elementBefore !== elementAfter }) test(function() { var root = mock.document.createElement("div") m.render(root, m("div", [undefined])) return root.childNodes[0].childNodes[0].nodeValue === "" }) test(function() { var root = mock.document.createElement("div") m.render(root, m("svg", [m("g")])) var g = root.childNodes[0].childNodes[0] return g.nodeName === "G" && g.namespaceURI === "http://www.w3.org/2000/svg" }) test(function() { var root = mock.document.createElement("div") m.render(root, m("svg", [m("a[href='http://google.com']")])) return root.childNodes[0].childNodes[0].nodeName === "A" }) test(function() { var root = mock.document.createElement("div") m.render(root, m("div.classname", [m("a", {href: "/first"})])) m.render(root, m("div", [m("a", {href: "/second"})])) return root.childNodes[0].childNodes.length === 1 }) test(function() { var root = mock.document.createElement("div") m.render(root, m("ul", [m("li")])) m.render(root, m("ul", [m("li"), undefined])) return root.childNodes[0].childNodes[1].nodeValue === "" }) test(function() { var root = mock.document.createElement("div") m.render(root, m("ul", [m("li"), m("li")])) m.render(root, m("ul", [m("li"), undefined])) return root.childNodes[0].childNodes[1].nodeValue === "" }) test(function() { var root = mock.document.createElement("div") m.render(root, m("ul", [m("li")])) m.render(root, m("ul", [undefined])) return root.childNodes[0].childNodes[0].nodeValue === "" }) test(function() { var root = mock.document.createElement("div") m.render(root, m("ul", [m("li")])) m.render(root, m("ul", [{}])) return root.childNodes[0].childNodes.length === 0 }) test(function() { var root = mock.document.createElement("div") m.render(root, m("ul", [m("li")])) m.render(root, m("ul", [{tag: "b", attrs: {}}])) return root.childNodes[0].childNodes[0].nodeName === "B" }) test(function() { var root = mock.document.createElement("div") m.render(root, m("ul", [m("li")])) m.render(root, m("ul", [{tag: new String("b"), attrs: {}}])) return root.childNodes[0].childNodes[0].nodeName === "B" }) test(function() { var root = mock.document.createElement("div") m.render(root, m("ul", [m("li", [m("a")])])) m.render(root, m("ul", [{subtree: "retain"}])) return root.childNodes[0].childNodes[0].childNodes[0].nodeName === "A" }) test(function() { //https://github.com/lhorie/mithril.js/issues/43 var root = mock.document.createElement("div") m.render(root, m("a", {config: m.route}, "test")) m.render(root, m("a", {config: m.route}, "test")) return root.childNodes[0].childNodes[0].nodeValue === "test" }) test(function() { //https://github.com/lhorie/mithril.js/issues/44 (1) var root = mock.document.createElement("div") m.render(root, m("#foo", [null, m("#bar")])) m.render(root, m("#foo", ["test", m("#bar")])) return root.childNodes[0].childNodes[0].nodeValue === "test" }) test(function() { //https://github.com/lhorie/mithril.js/issues/44 (2) var root = mock.document.createElement("div") m.render(root, m("#foo", [null, m("#bar")])) m.render(root, m("#foo", [m("div"), m("#bar")])) return root.childNodes[0].childNodes[0].nodeName === "DIV" }) test(function() { //https://github.com/lhorie/mithril.js/issues/44 (3) var root = mock.document.createElement("div") m.render(root, m("#foo", ["test", m("#bar")])) m.render(root, m("#foo", [m("div"), m("#bar")])) return root.childNodes[0].childNodes[0].nodeName === "DIV" }) test(function() { //https://github.com/lhorie/mithril.js/issues/44 (4) var root = mock.document.createElement("div") m.render(root, m("#foo", [m("div"), m("#bar")])) m.render(root, m("#foo", ["test", m("#bar")])) return root.childNodes[0].childNodes[0].nodeValue === "test" }) test(function() { //https://github.com/lhorie/mithril.js/issues/44 (5) var root = mock.document.createElement("div") m.render(root, m("#foo", [m("#bar")])) m.render(root, m("#foo", [m("#bar"), [m("#baz")]])) return root.childNodes[0].childNodes[1].id === "baz" }) test(function() { //https://github.com/lhorie/mithril.js/issues/48 var root = mock.document m.render(root, m("html", [m("#foo")])) var result = root.childNodes[0].childNodes[0].id === "foo" root.childNodes = [mock.document.createElement("html")] return result }) test(function() { //https://github.com/lhorie/mithril.js/issues/49 var root = mock.document.createElement("div") m.render(root, m("a", "test")) m.render(root, m("a.foo", "test")) return root.childNodes[0].childNodes[0].nodeValue === "test" }) test(function() { //https://github.com/lhorie/mithril.js/issues/49 var root = mock.document.createElement("div") m.render(root, m("a.foo", "test")) m.render(root, m("a", "test")) return root.childNodes[0].childNodes[0].nodeValue === "test" }) test(function() { //https://github.com/lhorie/mithril.js/issues/49 var root = mock.document.createElement("div") m.render(root, m("a.foo", "test")) m.render(root, m("a", "test1")) return root.childNodes[0].childNodes[0].nodeValue === "test1" }) test(function() { //https://github.com/lhorie/mithril.js/issues/49 var root = mock.document.createElement("div") m.render(root, m("a", "test")) m.render(root, m("a", "test1")) return root.childNodes[0].childNodes[0].nodeValue === "test1" }) test(function() { //https://github.com/lhorie/mithril.js/issues/50 var root = mock.document.createElement("div") m.render(root, m("#foo", [[m("div", "a"), m("div", "b")], m("#bar")])) return root.childNodes[0].childNodes[1].childNodes[0].nodeValue === "b" }) test(function() { //https://github.com/lhorie/mithril.js/issues/50 var root = mock.document.createElement("div") m.render(root, m("#foo", [[m("div", "a"), m("div", "b")], m("#bar")])) m.render(root, m("#foo", [[m("div", "a"), m("div", "b"), m("div", "c")], m("#bar")])) return root.childNodes[0].childNodes[2].childNodes[0].nodeValue === "c" }) test(function() { //https://github.com/lhorie/mithril.js/issues/50 var root = mock.document.createElement("div") m.render(root, m("#foo", [[m("div", "a"), m("div", "b")], [m("div", "c"), m("div", "d")], m("#bar")])) return root.childNodes[0].childNodes[3].childNodes[0].nodeValue === "d" && root.childNodes[0].childNodes[4].id === "bar" }) test(function() { //https://github.com/lhorie/mithril.js/issues/50 var root = mock.document.createElement("div") m.render(root, m("#foo", [[m("div", "a"), m("div", "b")], "test"])) return root.childNodes[0].childNodes[1].childNodes[0].nodeValue === "b" && root.childNodes[0].childNodes[2].nodeValue === "test" }) test(function() { //https://github.com/lhorie/mithril.js/issues/50 var root = mock.document.createElement("div") m.render(root, m("#foo", [["a", "b"], "test"])) return root.childNodes[0].childNodes[1].nodeValue === "b" && root.childNodes[0].childNodes[2].nodeValue === "test" }) test(function() { //https://github.com/lhorie/mithril.js/issues/51 var root = mock.document.createElement("div") m.render(root, m("main", [m("button"), m("article", [m("section"), m("nav")])])) m.render(root, m("main", [m("button"), m("article", [m("span"), m("nav")])])) return root.childNodes[0].childNodes[1].childNodes[0].nodeName === "SPAN" }) test(function() { //https://github.com/lhorie/mithril.js/issues/51 var root = mock.document.createElement("div") m.render(root, m("main", [m("button"), m("article", [m("section"), m("nav")])])) m.render(root, m("main", [m("button"), m("article", ["test", m("nav")])])) return root.childNodes[0].childNodes[1].childNodes[0].nodeValue === "test" }) test(function() { //https://github.com/lhorie/mithril.js/issues/51 var root = mock.document.createElement("div") m.render(root, m("main", [m("button"), m("article", [m("section"), m("nav")])])) m.render(root, m("main", [m("button"), m("article", [m.trust("test"), m("nav")])])) return root.childNodes[0].childNodes[1].childNodes[0].nodeValue === "test" }) test(function() { //https://github.com/lhorie/mithril.js/issues/55 var root = mock.document.createElement("div") m.render(root, m("#a")) var elementBefore = root.childNodes[0] m.render(root, m("#b")) var elementAfter = root.childNodes[0] return elementBefore !== elementAfter }) test(function() { //https://github.com/lhorie/mithril.js/issues/56 var root = mock.document.createElement("div") m.render(root, [null, "foo"]) m.render(root, ["bar"]) return root.childNodes.length === 1 }) test(function() { //https://github.com/lhorie/mithril.js/issues/56 var root = mock.document.createElement("div") m.render(root, m("div", "foo")) return root.childNodes.length === 1 }) test(function() { var root = mock.document.createElement("div") m.render(root, m("div", [m("button"), m("ul")])) var valueBefore = root.childNodes[0].childNodes[0].nodeName m.render(root, m("div", [undefined, m("ul")])) var valueAfter = root.childNodes[0].childNodes[0].nodeValue return valueBefore === "BUTTON" && valueAfter === "" }) test(function() { var root = mock.document.createElement("div") m.render(root, m("div", [m("ul"), undefined])) var valueBefore1 = root.childNodes[0].childNodes[0].nodeName var valueBefore2 = root.childNodes[0].childNodes[1].nodeValue m.render(root, m("div", [undefined, m("ul")])) var valueAfter1 = root.childNodes[0].childNodes[0].nodeValue var valueAfter2 = root.childNodes[0].childNodes[1].nodeName return valueBefore1 === "UL" && valueAfter1 === "" && valueBefore2 === "" && valueAfter2 === "UL" }) test(function() { //https://github.com/lhorie/mithril.js/issues/79 var root = mock.document.createElement("div") m.render(root, m("div", {style: {background: "red"}})) var valueBefore = root.childNodes[0].style.background m.render(root, m("div", {style: {}})) var valueAfter = root.childNodes[0].style.background return valueBefore === "red" && valueAfter === "" }) test(function() { var root = mock.document.createElement("div") m.render(root, m("div[style='background:red']")) return root.childNodes[0].style === "background:red" }) test(function() { var root = mock.document.createElement("div") m.render(root, m("div", {style: {background: "red"}})) var valueBefore = root.childNodes[0].style.background m.render(root, m("div", {})) var valueAfter = root.childNodes[0].style.background return valueBefore === "red" && valueAfter === undefined }) test(function() { //https://github.com/lhorie/mithril.js/issues/87 var root = mock.document.createElement("div") m.render(root, m("div", [[m("a"), m("a")], m("button")])) m.render(root, m("div", [[m("a")], m("button")])) return root.childNodes[0].childNodes.length === 2 && root.childNodes[0].childNodes[1].nodeName === "BUTTON" }) test(function() { //https://github.com/lhorie/mithril.js/issues/87 var root = mock.document.createElement("div") m.render(root, m("div", [m("a"), m("b"), m("button")])) m.render(root, m("div", [m("a"), m("button")])) return root.childNodes[0].childNodes.length === 2 && root.childNodes[0].childNodes[1].nodeName === "BUTTON" }) test(function() { //https://github.com/lhorie/mithril.js/issues/99 var root = mock.document.createElement("div") m.render(root, m("div", [m("img"), m("h1")])) m.render(root, m("div", [m("a")])) return root.childNodes[0].childNodes.length === 1 && root.childNodes[0].childNodes[0].nodeName === "A" }) test(function() { //https://github.com/lhorie/mithril.js/issues/120 var root = mock.document.createElement("div") m.render(root, m("div", ["a", "b", "c", "d"])) m.render(root, m("div", [["d", "e"]])) var children = root.childNodes[0].childNodes return children.length === 2 && children[0].nodeValue === "d" && children[1].nodeValue === "e" }) test(function() { //https://github.com/lhorie/mithril.js/issues/120 var root = mock.document.createElement("div") m.render(root, m("div", [["a", "b", "c", "d"]])) m.render(root, m("div", ["d", "e"])) var children = root.childNodes[0].childNodes return children.length === 2 && children[0].nodeValue === "d" && children[1].nodeValue === "e" }) test(function() { //https://github.com/lhorie/mithril.js/issues/120 var root = mock.document.createElement("div") m.render(root, m("div", ["x", [["a"], "b", "c", "d"]])) m.render(root, m("div", ["d", ["e"]])) var children = root.childNodes[0].childNodes return children.length === 2 && children[0].nodeValue === "d" && children[1].nodeValue === "e" }) test(function() { //https://github.com/lhorie/mithril.js/issues/120 var root = mock.document.createElement("div") m.render(root, m("div", ["b"])) m.render(root, m("div", [["e"]])) var children = root.childNodes[0].childNodes return children.length === 1 && children[0].nodeValue === "e" }) test(function() { //https://github.com/lhorie/mithril.js/issues/120 var root = mock.document.createElement("div") m.render(root, m("div", ["a", ["b"]])) m.render(root, m("div", ["d", [["e"]]])) var children = root.childNodes[0].childNodes return children.length === 2 && children[0].nodeValue === "d" && children[1].nodeValue === "e" }) test(function() { //https://github.com/lhorie/mithril.js/issues/120 var root = mock.document.createElement("div") m.render(root, m("div", ["a", [["b"]]])) m.render(root, m("div", ["d", ["e"]])) var children = root.childNodes[0].childNodes return children.length === 2 && children[0].nodeValue === "d" && children[1].nodeValue === "e" }) test(function() { //https://github.com/lhorie/mithril.js/issues/120 var root = mock.document.createElement("div") m.render(root, m("div", ["a", [["b"], "c"]])) m.render(root, m("div", ["d", [[["e"]], "x"]])) var children = root.childNodes[0].childNodes return children.length === 3 && children[0].nodeValue === "d" && children[1].nodeValue === "e" }) test(function() { var root = mock.document.createElement("div") var success = false m.render(root, m("div", {config: function(elem, isInitialized, ctx) {ctx.data = 1}})) m.render(root, m("div", {config: function(elem, isInitialized, ctx) {success = ctx.data === 1}})) return success }) test(function() { var root = mock.document.createElement("div") var index = 0; var success = true; var statefulConfig = function(elem, isInitialized, ctx) {ctx.data = index++} var node = m("div", {config: statefulConfig}); m.render(root, [node, node]); index = 0; var checkConfig = function(elem, isInitialized, ctx) { success = success && (ctx.data === index++) } node = m("div", {config: checkConfig}); m.render(root, [node, node]); return success; }) test(function() { var root = mock.document.createElement("div") var parent m.render(root, m("div", m("a", { config: function(el) {parent = el.parentNode.parentNode} }))); return parent === root }) test(function() { var root = mock.document.createElement("div") var count = 0 m.render(root, m("div", m("a", { config: function() { var island = mock.document.createElement("div") count++ if (count > 2) throw new Error("too much recursion...") m.render(island, m("div")) } }))); return count === 1 }) test(function() { //https://github.com/lhorie/mithril.js/issues/129 var root = mock.document.createElement("div") m.render(root, m("div", [["foo", "bar"], ["foo", "bar"], ["foo", "bar"]])); m.render(root, m("div", ["asdf", "asdf2", "asdf3"])); return true }) test(function() { //https://github.com/lhorie/mithril.js/issues/98 //insert at beginning var root = mock.document.createElement("div") m.render(root, [m("a", {key: 1}, 1), m("a", {key: 2}, 2), m("a", {key: 3}, 3)]) var firstBefore = root.childNodes[0] m.render(root, [m("a", {key: 4}, 4), m("a", {key: 1}, 1), m("a", {key: 2}, 2), m("a", {key: 3}, 3)]) var firstAfter = root.childNodes[1] return firstBefore === firstAfter && root.childNodes[0].childNodes[0].nodeValue === "4" && root.childNodes.length === 4 }) test(function() { //https://github.com/lhorie/mithril.js/issues/98 var root = mock.document.createElement("div") m.render(root, [m("a", {key: 1}, 1), m("a", {key: 2}, 2), m("a", {key: 3}, 3)]) var firstBefore = root.childNodes[0] m.render(root, [m("a", {key: 4}, 4), m("a", {key: 1}, 1), m("a", {key: 2}, 2)]) var firstAfter = root.childNodes[1] return firstBefore === firstAfter && root.childNodes[0].childNodes[0].nodeValue === "4" && root.childNodes.length === 3 }) test(function() { //https://github.com/lhorie/mithril.js/issues/98 var root = mock.document.createElement("div") m.render(root, [m("a", {key: 1}, 1), m("a", {key: 2}, 2), m("a", {key: 3}, 3)]) var firstBefore = root.childNodes[1] m.render(root, [m("a", {key: 2}, 2), m("a", {key: 3}, 3), m("a", {key: 4}, 4)]) var firstAfter = root.childNodes[0] return firstBefore === firstAfter && root.childNodes[0].childNodes[0].nodeValue === "2" && root.childNodes.length === 3 }) test(function() { //https://github.com/lhorie/mithril.js/issues/98 var root = mock.document.createElement("div") m.render(root, [m("a", {key: 1}, 1), m("a", {key: 2}, 2), m("a", {key: 3}, 3), m("a", {key: 4}, 4), m("a", {key: 5}, 5)]) var firstBefore = root.childNodes[0] var secondBefore = root.childNodes[1] var fourthBefore = root.childNodes[3] m.render(root, [m("a", {key: 4}, 4), m("a", {key: 10}, 10), m("a", {key: 1}, 1), m("a", {key: 2}, 2)]) var firstAfter = root.childNodes[2] var secondAfter = root.childNodes[3] var fourthAfter = root.childNodes[0] return firstBefore === firstAfter && secondBefore === secondAfter && fourthBefore === fourthAfter && root.childNodes[1].childNodes[0].nodeValue === "10" && root.childNodes.length === 4 }) test(function() { //https://github.com/lhorie/mithril.js/issues/98 var root = mock.document.createElement("div") m.render(root, [m("a", {key: 1}, 1), m("a", {key: 2}, 2), m("a", {key: 3}, 3), m("a", {key: 4}, 4), m("a", {key: 5}, 5)]) var firstBefore = root.childNodes[0] var secondBefore = root.childNodes[1] var fourthBefore = root.childNodes[3] m.render(root, [m("a", {key: 4}, 4), m("a", {key: 10}, 10), m("a", {key: 2}, 2), m("a", {key: 1}, 1), m("a", {key: 6}, 6), m("a", {key: 7}, 7)]) var firstAfter = root.childNodes[3] var secondAfter = root.childNodes[2] var fourthAfter = root.childNodes[0] return firstBefore === firstAfter && secondBefore === secondAfter && fourthBefore === fourthAfter && root.childNodes[1].childNodes[0].nodeValue === "10" && root.childNodes[4].childNodes[0].nodeValue === "6" && root.childNodes[5].childNodes[0].nodeValue === "7" && root.childNodes.length === 6 }) test(function() { //https://github.com/lhorie/mithril.js/issues/149 var root = mock.document.createElement("div") m.render(root, [m("a", {key: 1}), m("a", {key: 2}), m("a"), m("a", {key: 4}), m("a", {key: 5})]) var firstBefore = root.childNodes[0] var secondBefore = root.childNodes[1] var thirdBefore = root.childNodes[2] var fourthBefore = root.childNodes[3] var fifthBefore = root.childNodes[4] m.render(root, [m("a", {key: 4}), m("a", {key: 5}), m("a"), m("a", {key: 1}), m("a", {key: 2})]) var firstAfter = root.childNodes[3] var secondAfter = root.childNodes[4] var thirdAfter = root.childNodes[2] var fourthAfter = root.childNodes[0] var fifthAfter = root.childNodes[1] return firstBefore === firstAfter && secondBefore === secondAfter && thirdBefore === thirdAfter && fourthBefore === fourthAfter && fifthBefore === fifthAfter }) test(function() { //https://github.com/lhorie/mithril.js/issues/246 //insert at beginning with non-keyed in the middle var root = mock.document.createElement("div") m.render(root, [m("a", {key: 1}, 1)]) var firstBefore = root.childNodes[0] m.render(root, [m("a", {key: 2}, 2), m("br"), m("a", {key: 1}, 1)]) var firstAfter = root.childNodes[2] return firstBefore === firstAfter && root.childNodes[0].childNodes[0].nodeValue === "2" && root.childNodes.length === 3 }) test(function() { //https://github.com/lhorie/mithril.js/issues/134 var root = mock.document.createElement("div") m.render(root, m("div", {contenteditable: true}, "test")) mock.document.activeElement = root.childNodes[0] m.render(root, m("div", {contenteditable: true}, "test1")) m.render(root, m("div", {contenteditable: false}, "test2")) return root.childNodes[0].childNodes[0].nodeValue === "test2" }) test(function() { //https://github.com/lhorie/mithril.js/issues/136 var root = mock.document.createElement("div") m.render(root, m("textarea", ["test"])) m.render(root, m("textarea", ["test1"])) return root.childNodes[0].value === "test1" }) test(function() { var root = mock.document.createElement("div") var unloaded = 0 m.render(root, [ m("div", { key: 1, config: function(el, init, ctx) { ctx.onunload = function() { unloaded++ } } }) ]) m.render(root, [ m("div", {key: 2}), m("div", { key: 1, config: function(el, init, ctx) { ctx.onunload = function() { unloaded++ } } }) ]) return unloaded === 0 }) test(function() { var root = mock.document.createElement("div") var unloadedParent = 0 var unloadedChild = 0 var configParent = function(el, init, ctx) { ctx.onunload = function() { unloadedParent++ } } var configChild = function(el, init, ctx) { ctx.onunload = function() { unloadedChild++ } } m.render(root, m("div", {config: configParent}, m("a", {config: configChild}))) m.render(root, m("main", {config: configParent}, m("a", {config: configChild}))) return unloadedParent === 1 && unloadedChild === 0 }) test(function() { var root = mock.document.createElement("div") var unloadedParent = 0 var unloadedChild = 0 var configParent = function(el, init, ctx) { ctx.onunload = function() { unloadedParent++ } } var configChild = function(el, init, ctx) { ctx.onunload = function() { unloadedChild++ } } m.render(root, m("div", {config: configParent}, m("a", {config: configChild}))) m.render(root, m("main", {config: configParent}, m("b", {config: configChild}))) return unloadedParent === 1 && unloadedChild === 1 }) test(function() { //https://github.com/lhorie/mithril.js/issues/150 var root = mock.document.createElement("div") m.render(root, [m("a"), m("div")]) m.render(root, [[], m("div")]) return root.childNodes.length === 1 && root.childNodes[0].nodeName === "DIV" }) test(function() { //https://github.com/lhorie/mithril.js/issues/156 var root = mock.document.createElement("div") m.render(root, m("div", [ ["a", "b", "c", "d"].map(function() { return [m("div"), " "] }), m("span") ])) return root.childNodes[0].childNodes[8].nodeName === "SPAN" }) test(function() { //https://github.com/lhorie/mithril.js/issues/157 var root = mock.document.createElement("div") m.render(root, m("ul", [m("li", {key: 0}, 0), m("li", {key: 2}, 2), m("li", {key: 4}, 4)])) m.render(root, m("ul", [m("li", {key: 0}, 0), m("li", {key: 1}, 1), m("li", {key: 2}, 2), m("li", {key: 3}, 3), m("li", {key: 4}, 4), m("li", {key: 5}, 5)])) return root.childNodes[0].childNodes.map(function(n) {return n.childNodes[0].nodeValue}).join("") === "012345" }) test(function() { //https://github.com/lhorie/mithril.js/issues/157 var root = mock.document.createElement("div") m.render(root, m("input", {value: "a"})) m.render(root, m("input", {value: "aa"})) return root.childNodes[0].childNodes.length === 0 }) test(function() { //https://github.com/lhorie/mithril.js/issues/157 var root = mock.document.createElement("div") m.render(root, m("br", {"class": "a"})) m.render(root, m("br", {"class": "aa"})) return root.childNodes[0].childNodes.length === 0 }) test(function() { //https://github.com/lhorie/mithril.js/issues/194 var root = mock.document.createElement("div") m.render(root, m("ul", [m("li", {key: 0}, 0), m("li", {key: 1}, 1), m("li", {key: 2}, 2), m("li", {key: 3}, 3), m("li", {key: 4}, 4), m("li", {key: 5}, 5)])) m.render(root, m("ul", [m("li", {key: 0}, 0), m("li", {key: 1}, 1), m("li", {key: 2}, 2), m("li", {key: 4}, 4), m("li", {key: 5}, 5)])) return root.childNodes[0].childNodes.map(function(n) {return n.childNodes[0].nodeValue}).join("") === "01245" }) test(function() { //https://github.com/lhorie/mithril.js/issues/194 var root = mock.document.createElement("div") m.render(root, m("ul", [m("li", {key: 0}, 0), m("li", {key: 1}, 1), m("li", {key: 2}, 2), m("li", {key: 3}, 3), m("li", {key: 4}, 4), m("li", {key: 5}, 5)])) m.render(root, m("ul", [m("li", {key: 1}, 1), m("li", {key: 2}, 2), m("li", {key: 3}, 3), m("li", {key: 4}, 4), m("li", {key: 5}, 5), m("li", {key: 6}, 6)])) m.render(root, m("ul", [m("li", {key: 12}, 12), m("li", {key: 13}, 13), m("li", {key: 14}, 14), m("li", {key: 15}, 15), m("li", {key: 16}, 16), m("li", {key: 17}, 17)])) return root.childNodes[0].childNodes.map(function(n) {return n.childNodes[0].nodeValue}).join(",") === "12,13,14,15,16,17" }) test(function() { //https://github.com/lhorie/mithril.js/issues/206 var root = mock.document.createElement("div") m.render(root, m("div", undefined)) m.render(root, m("div", [m("div")])) return root.childNodes[0].childNodes.length === 1 }) test(function() { // https://github.com/lhorie/mithril.js/issues/206 var root = mock.document.createElement("div") m.render(root, m("div", null)) m.render(root, m("div", [m("div")])) return root.childNodes[0].childNodes.length === 1 }) test(function() { //https://github.com/lhorie/mithril.js/issues/200 var root = mock.document.createElement("div") var unloaded1 = false function unloadable1(element, isInit, context) { context.onunload = function() { unloaded1 = true } } m.render(root, [ m("div", {config: unloadable1}) ]) m.render(root, [ ]) var unloaded2 = false function unloadable2(element, isInit, context) { context.onunload = function() { unloaded2 = true } } m.render(root, [ m("div", {config: unloadable2}) ]) m.render(root, [ ]) return unloaded1 === true && unloaded2 === true }) test(function() { var root = mock.document.createElement("div") m.render(root, [m("div.blue")]) m.render(root, [m("div.green", [m("div")]), m("div.blue")]) return root.childNodes.length === 2 }) test(function() { //https://github.com/lhorie/mithril.js/issues/277 var root = mock.document.createElement("div") function Field() { this.tag = "div"; this.attrs = {}; this.children = "hello"; } m.render(root, new Field()) return root.childNodes.length === 1 }) test(function() { var root = mock.document.createElement("div") m.render(root, {foo: 123}) return root.childNodes.length === 0 }) test(function() { //https://github.com/lhorie/mithril.js/issues/299 var root = mock.document.createElement("div") m.render(root, m("div", [m("div", {key: 1}, 1), m("div", {key: 2}, 2), m("div", {key: 3}, 3), m("div", {key: 4}, 4), m("div", {key: 5}, 5), null, null, null, null, null, null, null, null, null, null])) m.render(root, m("div", [null, null, m("div", {key: 3}, 3), null, null, m("div", {key: 6}, 6), null, null, m("div", {key: 9}, 9), null, null, m("div", {key: 12}, 12), null, null, m("div", {key: 15}, 15)])) m.render(root, m("div", [m("div", {key: 1}, 1), m("div", {key: 2}, 2), m("div", {key: 3}, 3), m("div", {key: 4}, 4), m("div", {key: 5}, 5), null, null, null, null, null, null, null, null, null, null])) return root.childNodes[0].childNodes.map(function(c) {return c.childNodes ? c.childNodes[0].nodeValue : c.nodeValue}).slice(0, 5).join("") === "12345" }) test(function() { //https://github.com/lhorie/mithril.js/issues/377 var root = mock.document.createElement("div") m.render(root, m("div", [m("div", 1), m("div", 2), [m("div", {key: 3}, 3), m("div", {key: 4}, 4), m("div", {key:5}, 5)], [m("div", {key: 6}, 6)]])) m.render(root, m("div", [m("div", 1), null, [m("div", {key: 3}, 3), m("div", {key: 4}, 4), m("div", {key:5}, 5)], [m("div", {key: 6}, 6)]])) return root.childNodes[0].childNodes.map(function(c) {return c.childNodes ? c.childNodes[0].nodeValue : c.nodeValue}).join("") === "13456" }) test(function() { var root = mock.document.createElement("div") m.render(root, m("div", [console.log()])) // don't throw in Firefox return true }) test(function() { var root = mock.document.createElement("div") m.render(root, [ m("#div-1", {key: 1}), m("#div-2", {key: 2}), m("#div-3", {key: 3}) ]) root.appendChild(root.childNodes[1]) m.render(root, [ m("#div-1", {key: 1}), m("#div-3", {key: 3}), m("#div-2", {key: 2}) ]) return root.childNodes.map(function(node) {return node.id}).join() === "div-1,div-3,div-2" }) test(function() { var root = mock.document.createElement("div") m.render(root, m("div", function() {})) return root.childNodes[0].childNodes.length === 0 }) test(function() { var root = mock.document.createElement("div") m.render(root, m("div", "foo", m("a"))) m.render(root, m("div", "test")) return root.childNodes[0].childNodes.length === 1 }) test(function() { //if an element is preceded by a conditional, it should not lose its identity var root = mock.document.createElement("div") m.render(root, m("div", [m("a"), m("input[autofocus]")])) var before = root.childNodes[0].childNodes[1] m.render(root, m("div", [undefined, m("input[autofocus]")])) var after = root.childNodes[0].childNodes[1] return before === after }) test(function() { //unkeyed element should maintain identity if mixed w/ keyed elements and identity can be inferred var root = mock.document.createElement("div") m.render(root, m("div", [m("a", {key: 1}), m("a", {key: 2}), m("a", {key: 3}), m("i")])) var before = root.childNodes[0].childNodes[3] m.render(root, m("div", [m("b", {key: 3}), m("b", {key: 4}), m("i"), m("b", {key: 1})])) var after = root.childNodes[0].childNodes[2] return before === after }) test(function() { //unkeyed element should maintain identity if mixed w/ keyed elements and text nodes and identity can be inferred var root = mock.document.createElement("div") m.render(root, m("div", [m("a", {key: 1}), m("a", {key: 2}), "foo", m("a", {key: 3}), m("i")])) var before = root.childNodes[0].childNodes[4] m.render(root, m("div", [m("a", {key: 3}), m("a", {key: 4}), "bar", m("i"), m("a", {key: 1})])) var after = root.childNodes[0].childNodes[3] return before === after }) test(function() { var root = mock.document.createElement("div") m.render(root, m("div", [m("a", {key: 1}), m("a", {key: 2}), null, m("a", {key: 3}), m("i")])) var before = root.childNodes[0].childNodes[4] m.render(root, m("div", [m("a", {key: 3}), m("a", {key: 4}), null, m("i"), m("a", {key: 1})])) var after = root.childNodes[0].childNodes[3] return before === after }) test(function() { var root = mock.document.createElement("div") m.render(root, m("div", [m("a", {key: 1}), m("a", {key: 2}), undefined, m("a", {key: 3}), m("i")])) var before = root.childNodes[0].childNodes[4] m.render(root, m("div", [m("a", {key: 3}), m("a", {key: 4}), undefined, m("i"), m("a", {key: 1})])) var after = root.childNodes[0].childNodes[3] return before === after }) test(function() { var root = mock.document.createElement("div") m.render(root, m("div", [m("a", {key: 1}), m("a", {key: 2}), m.trust("a"), m("a", {key: 3}), m("i")])) var before = root.childNodes[0].childNodes[4] m.render(root, m("div", [m("a", {key: 3}), m("a", {key: 4}), m.trust("a"), m("i"), m("a", {key: 1})])) var after = root.childNodes[0].childNodes[3] return before === after }) test(function() { var root = mock.document.createElement("div") var vdom = m("div.a", {"class": undefined}) m.render(root, vdom) return root.childNodes[0]["class"] === "a" }) test(function() { var root = mock.document.createElement("div") m.render(root, m(".a", [1])) m.render(root, m(".a", [])) return root.childNodes[0].childNodes.length === 0 }) //end m.render //m.redraw test(function() { mock.requestAnimationFrame.$resolve() //setup var controller var root = mock.document.createElement("div") m.mount(root, { controller: function() {controller = this}, view: function(ctrl) {return ctrl.value} }) mock.requestAnimationFrame.$resolve() var valueBefore = root.childNodes[0].nodeValue controller.value = "foo" m.redraw() mock.requestAnimationFrame.$resolve() return valueBefore === "" && root.childNodes[0].nodeValue === "foo" }) test(function() { mock.requestAnimationFrame.$resolve() //setup var count = 0 var root = mock.document.createElement("div") m.mount(root, { controller: function() {}, view: function() { count++ } }) mock.requestAnimationFrame.$resolve() //teardown m.redraw() //should run synchronously m.redraw() //rest should run asynchronously since they're spamming m.redraw() m.redraw() mock.requestAnimationFrame.$resolve() //teardown return count === 3 }) test(function() { mock.requestAnimationFrame.$resolve() //setup var count = 0 var root = mock.document.createElement("div") m.mount(root, { controller: function() {}, view: function() { count++ } }) mock.requestAnimationFrame.$resolve() //teardown m.redraw(true) //should run synchronously m.redraw(true) //forced to run synchronously m.redraw(true) m.redraw(true) mock.requestAnimationFrame.$resolve() //teardown return count === 5 }) //m.route test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/test1", { "/test1": {controller: function() {}, view: function() {return "foo"}} }) mock.requestAnimationFrame.$resolve() var result = mock.location.search === "?/test1" && root.childNodes[0].nodeValue === "foo" m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.pathname = "/" var root = mock.document.createElement("div") m.route.mode = "pathname" m.route(root, "/test2", { "/test2": { controller: function() {}, view: function() { return [ "foo", m("a", { href: "/test2", config: m.route }, "Test2") ] } } }) mock.requestAnimationFrame.$resolve() var result = mock.location.pathname === "/test2" && root.childNodes[0].nodeValue === "foo" && root.childNodes[1].href === "/test2" m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.hash = "#" var root = mock.document.createElement("div") m.route.mode = "hash" m.route(root, "/test3", { "/test3": {controller: function() {}, view: function() {return "foo"}} }) mock.requestAnimationFrame.$resolve() var result = mock.location.hash === "#/test3" && root.childNodes[0].nodeValue === "foo" m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/test4/foo", { "/test4/:test": {controller: function() {}, view: function() {return m.route.param("test")}} }) mock.requestAnimationFrame.$resolve() var result = mock.location.search === "?/test4/foo" && root.childNodes[0].nodeValue === "foo" m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var component = {controller: function() {}, view: function() {return m.route.param("test")}} var root = mock.document.createElement("div") m.route.mode = "search" 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() var result = mock.location.search === "?/" && paramValueBefore === "foo" && paramValueAfter === undefined m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var component = {controller: function() {}, view: function() {return m.route.param("a1")}} var root = mock.document.createElement("div") m.route.mode = "search" 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() var result = mock.location.search === "?/" && paramValueBefore === "foo" && paramValueAfter === undefined m.mount(root, null) //teardown return result }) test(function() { //https://github.com/lhorie/mithril.js/issues/61 mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var component = {controller: function() {}, view: function() {return m.route.param("a1")}} var root = mock.document.createElement("div") m.route.mode = "search" 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() var result = routeValueBefore === "/test7/foo" && routeValueAfter === "/" m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/test8/foo/SEP/bar/baz", { "/test8/:test/SEP/:path...": { controller: function() {}, view: function() { return m.route.param("test") + "_" + m.route.param("path") } } }) mock.requestAnimationFrame.$resolve() var result = mock.location.search === "?/test8/foo/SEP/bar/baz" && root.childNodes[0].nodeValue === "foo_bar/baz" m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/test9/foo/bar/SEP/baz", { "/test9/:test.../SEP/:path": { controller: function() {}, view: function() { return m.route.param("test") + "_" + m.route.param("path") } } }) mock.requestAnimationFrame.$resolve() var result = mock.location.search === "?/test9/foo/bar/SEP/baz" && root.childNodes[0].nodeValue === "foo/bar_baz" m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/test10/foo%20bar", { "/test10/:test": { controller: function() {}, view: function() { return m.route.param("test") } } }) mock.requestAnimationFrame.$resolve() var result = root.childNodes[0].nodeValue === "foo bar" m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/", { "/": {controller: function() {}, view: function() {return "foo"}}, "/test11": {controller: function() {}, view: function() {return "bar"}} }) mock.requestAnimationFrame.$resolve() m.route("/test11/") mock.requestAnimationFrame.$resolve() var result = mock.location.search === "?/test11/" && root.childNodes[0].nodeValue === "bar" m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/", { "/": {controller: function() {}, view: function() {}}, "/test12": {controller: function() {}, view: function() {}} }) mock.requestAnimationFrame.$resolve() m.route("/test12?a=foo&b=bar") mock.requestAnimationFrame.$resolve() var result = mock.location.search === "?/test12?a=foo&b=bar" && m.route.param("a") === "foo" && m.route.param("b") === "bar" m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/", { "/": {controller: function() {}, view: function() {return "bar"}}, "/test13/:test": {controller: function() {}, view: function() {return m.route.param("test")}} }) mock.requestAnimationFrame.$resolve() m.route("/test13/foo?test=bar") mock.requestAnimationFrame.$resolve() var result = mock.location.search === "?/test13/foo?test=bar" && root.childNodes[0].nodeValue === "foo" m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/", { "/": {controller: function() {}, view: function() {return "bar"}}, "/test14": {controller: function() {}, view: function() {return "foo"}} }) mock.requestAnimationFrame.$resolve() m.route("/test14?test&test2=") mock.requestAnimationFrame.$resolve() var result = mock.location.search === "?/test14?test&test2=" && m.route.param("test") == null && m.route.param("test2") === "" m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/", { "/": {controller: function() {}, view: function() {}}, "/test12": {controller: function() {}, view: function() {}} }) mock.requestAnimationFrame.$resolve() m.route("/test12", {a: "foo", b: "bar"}) mock.requestAnimationFrame.$resolve() var result = mock.location.search === "?/test12?a=foo&b=bar" && m.route.param("a") === "foo" && m.route.param("b") === "bar" m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") var route1, route2 m.route.mode = "search" m.route(root, "/", { "/": {controller: function() {route1 = m.route()}, view: function() {}}, "/test13": {controller: function() {route2 = m.route()}, view: function() {}} }) mock.requestAnimationFrame.$resolve() m.route("/test13") mock.requestAnimationFrame.$resolve() var result = route1 === "/" && route2 === "/test13" m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") var unloaded = 0 m.route.mode = "search" m.route(root, "/", { "/": { controller: function() {}, view: function() { return m("div", { config: function(el, init, ctx) { ctx.onunload = function() { unloaded++ } } }) } }, "/test14": {controller: function() {}, view: function() {}} }) mock.requestAnimationFrame.$resolve() m.route("/test14") mock.requestAnimationFrame.$resolve() var result = unloaded === 1 m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") var unloaded = 0 m.route.mode = "search" m.route(root, "/", { "/": { controller: function() {}, view: function() { return [ m("div"), m("div", { config: function(el, init, ctx) { ctx.onunload = function() { unloaded++ } } }) ] } }, "/test15": { controller: function() {}, view: function() { return [m("div")] } } }) mock.requestAnimationFrame.$resolve() m.route("/test15") mock.requestAnimationFrame.$resolve() var result = unloaded === 1 m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") var unloaded = 0 m.route.mode = "search" m.route(root, "/", { "/": { controller: function() {}, view: function() { return m("div", { config: function(el, init, ctx) { ctx.onunload = function() { unloaded++ } } }) } }, "/test16": { controller: function() {}, view: function() { return m("a") } } }) mock.requestAnimationFrame.$resolve() m.route("/test16") mock.requestAnimationFrame.$resolve() var result = unloaded === 1 m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") var unloaded = 0 m.route.mode = "search" m.route(root, "/", { "/": { controller: function() {}, view: function() { return [ m("div", { config: function(el, init, ctx) { ctx.onunload = function() { unloaded++ } } }) ] } }, "/test17": { controller: function() {}, view: function() { return m("a") } } }) mock.requestAnimationFrame.$resolve() m.route("/test17") mock.requestAnimationFrame.$resolve() var result = unloaded === 1 m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") var unloaded = 0 m.route.mode = "search" m.route(root, "/", { "/": { controller: function() {}, view: function() { return m("div", { config: function(el, init, ctx) { ctx.onunload = function() { unloaded++ } } }) } }, "/test18": { controller: function() {}, view: function() { return [m("a")] } } }) mock.requestAnimationFrame.$resolve() m.route("/test18") mock.requestAnimationFrame.$resolve() var result = unloaded === 1 m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") var unloaded = 0 m.route.mode = "search" m.route(root, "/", { "/": { controller: function() {}, view: function() { return [ m("div", { key: 1, config: function(el, init, ctx) { ctx.onunload = function() { unloaded++ } } }) ] } }, "/test20": { controller: function() {}, view: function() { return [ m("div", { key: 2, config: function(el, init, ctx) { ctx.onunload = function() { unloaded++ } } }) ] } } }) mock.requestAnimationFrame.$resolve() m.route("/test20") mock.requestAnimationFrame.$resolve() var result = unloaded === 1 m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") var unloaded = 0 m.route.mode = "search" m.route(root, "/", { "/": { controller: function() {}, view: function() { return [ m("div", { key: 1, config: function(el, init, ctx) { ctx.onunload = function() { unloaded++ } } }) ] } }, "/test21": { controller: function() {}, view: function() { return [ m("div", { config: function(el, init, ctx) { ctx.onunload = function() { unloaded++ } } }) ] } } }) mock.requestAnimationFrame.$resolve() m.route("/test21") mock.requestAnimationFrame.$resolve() var result = unloaded === 1 m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/foo", { "/foo": { controller: function() {}, view: function() { return m("div", "foo"); } }, "/bar": { controller: function() {}, view: function() { return m("div", "bar"); } } }) mock.requestAnimationFrame.$resolve() var foo = root.childNodes[0].childNodes[0].nodeValue; m.route("/bar") mock.requestAnimationFrame.$resolve() var bar = root.childNodes[0].childNodes[0].nodeValue; var result = (foo === "foo" && bar === "bar") m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") var unloaded = 0 var config = function(el, init, ctx) { ctx.onunload = function() { unloaded++ } } m.route.mode = "search" m.route(root, "/foo1", { "/foo1": { controller: function() {}, view: function() { return m("div", m("a", {config: config}, "foo")); } }, "/bar1": { controller: function() {}, view: function() { return m("main", m("a", {config: config}, "foo")); } } }) mock.requestAnimationFrame.$resolve() m.route("/bar1") mock.requestAnimationFrame.$resolve() var result = unloaded === 1 m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") var strategy m.route.mode = "search" m.route(root, "/foo1", { "/foo1": { controller: function() { strategy = m.redraw.strategy() m.redraw.strategy("none") }, view: function() { return m("div"); } } }) mock.requestAnimationFrame.$resolve() var result = strategy === "all" && root.childNodes.length === 0 m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") var strategy, count = 0 var config = function(el, init) {if (!init) count++} m.route.mode = "search" m.route(root, "/foo1", { "/foo1": { controller: function() {}, view: function() { return m("div", {config: config}); } }, "/bar1": { controller: function() { strategy = m.redraw.strategy() m.redraw.strategy("redraw") }, view: function() { return m("div", {config: config}); } } }) mock.requestAnimationFrame.$resolve() m.route("/bar1") mock.requestAnimationFrame.$resolve() var result = strategy === "all" && count === 1 m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") var strategy m.route.mode = "search" m.route(root, "/foo1", { "/foo1": { controller: function() {this.number = 1}, view: function(ctrl) { return m("div", {onclick: function() { strategy = m.redraw.strategy() ctrl.number++ m.redraw.strategy("none") }}, ctrl.number); } } }) root.childNodes[0].onclick({}) mock.requestAnimationFrame.$resolve() var result = strategy === "diff" && root.childNodes[0].childNodes[0].nodeValue === "1" m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") var count = 0 var config = function(el, init ) {if (!init) count++} m.route.mode = "search" m.route(root, "/foo1", { "/foo1": { controller: function() {}, view: function() { return m("div", {config: config, onclick: function() { m.redraw.strategy("all") }}); } } }) root.childNodes[0].onclick({}) mock.requestAnimationFrame.$resolve() var result = count === 2 m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") var value m.route(root, "/foo+bar", { "/:arg": { controller: function() {value = m.route.param("arg")}, view: function() { return "" } } }) var result = value === "foo+bar" m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/", { "/": {controller: function() {}, view: function() {return "foo"}}, "/test22": {controller: function() {}, view: function() {return "bar"}} }) mock.requestAnimationFrame.$resolve() m.route(String("/test22/")) mock.requestAnimationFrame.$resolve() var result = mock.location.search === "?/test22/" && root.childNodes[0].nodeValue === "bar" m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") m.route.mode = "search" m.route(root, "/", { "/": {controller: function() {}, view: function() {return "foo"}}, "/test23": {controller: function() {}, view: function() {return "bar"}} }) mock.requestAnimationFrame.$resolve() m.route(new String("/test23/")) mock.requestAnimationFrame.$resolve() var result = mock.location.search === "?/test23/" && root.childNodes[0].nodeValue === "bar" m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") var value m.route(root, String("/foo+bar"), { "/:arg": { controller: function() {value = m.route.param("arg")}, view: function() { return "" } } }) var result = value === "foo+bar" m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() //setup mock.location.search = "?" var root = mock.document.createElement("div") var value m.route(root, new String("/foo+bar"), { "/:arg": { controller: function() {value = m.route.param("arg")}, view: function() { return "" } } }) var result = value === "foo+bar" m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var a = {} a.controller = function() {m.route("/b")} a.view = function() {return "a"} var b = {} b.controller = function() {} b.view = function() {return "b"} m.route(root, "/a", { "/a": a, "/b": b }) mock.requestAnimationFrame.$resolve() var result = root.childNodes[0].nodeValue === "b" m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var a = {} a.controller = function() { m.route("/b?foo=1", {foo: 2}) } a.view = function() {return "a"} var b = {} b.controller = function() {} b.view = function() {return "b"} m.route(root, "/", { "/": a, "/b": b }) mock.requestAnimationFrame.$resolve() var result = mock.location.search === "?/b?foo=2" m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() mock.location.search = "?" mock.history.$$length = 0 var root = mock.document.createElement("div") var a = {} a.controller = function() {} a.view = function() {return "a"} var b = {} b.controller = function() {} b.view = function() {return "b"} m.route(root, "/a", { "/a": a, "/b": b }) mock.requestAnimationFrame.$resolve() m.route("/b") mock.requestAnimationFrame.$resolve() var result = mock.history.$$length === 1 m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() mock.location.search = "?" mock.history.$$length = 0 var root = mock.document.createElement("div") var a = {} a.controller = function() {} a.view = function() {return "a"} var b = {} b.controller = function() {} b.view = function() {return "b"} m.route(root, "/a", { "/a": a, "/b": b }) mock.requestAnimationFrame.$resolve() m.route("/a") mock.requestAnimationFrame.$resolve() var result = mock.history.$$length === 0 m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var initCount = 0 var a = {} a.controller = function() {} a.view = function() { return m("a", {config: function(el, init) { if (!init) initCount++ }}) } var b = {} b.controller = function() {} b.view = a.view m.route(root, "/a", { "/a": a, "/b": b }) mock.requestAnimationFrame.$resolve() m.route("/b") mock.requestAnimationFrame.$resolve() var result = initCount === 2 m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var initCount = 0 var a = {} a.controller = function() {} a.view = function() { return m("a", {config: function(el, init, ctx) { ctx.retain = false if (!init) initCount++ }}) } var b = {} b.controller = function() {} b.view = a.view m.route(root, "/a", { "/a": a, "/b": b }) mock.requestAnimationFrame.$resolve() m.route("/b") mock.requestAnimationFrame.$resolve() var result = initCount === 2 m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var initCount = 0 var a = {} a.controller = function() {} a.view = function() { return m("a", {config: function(el, init, ctx) { ctx.retain = true if (!init) initCount++ }}) } var b = {} b.controller = function() {} b.view = a.view m.route(root, "/a", { "/a": a, "/b": b }) mock.requestAnimationFrame.$resolve() m.route("/b") mock.requestAnimationFrame.$resolve() var result = initCount === 1 m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var initCount = 0 var a = {} a.controller = function() {m.redraw.strategy("diff")} a.view = function() { return m("a", {config: function(el, init) { if (!init) initCount++ }}) } var b = {} b.controller = function() {m.redraw.strategy("diff")} b.view = a.view m.route(root, "/a", { "/a": a, "/b": b }) mock.requestAnimationFrame.$resolve() m.route("/b") mock.requestAnimationFrame.$resolve() var result = initCount === 1 m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var initCount = 0 var a = {} a.controller = function() {m.redraw.strategy("diff")} a.view = function() { return m("a", {config: function(el, init, ctx) { ctx.retain = true if (!init) initCount++ }}) } var b = {} b.controller = function() {m.redraw.strategy("diff")} b.view = a.view m.route(root, "/a", { "/a": a, "/b": b }) mock.requestAnimationFrame.$resolve() m.route("/b") mock.requestAnimationFrame.$resolve() var result = initCount === 1 m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var initCount = 0 var a = {} a.controller = function() {m.redraw.strategy("diff")} a.view = function() { return m("a", {config: function(el, init, ctx) { ctx.retain = false if (!init) initCount++ }}) } var b = {} b.controller = function() {m.redraw.strategy("diff")} b.view = a.view m.route(root, "/a", { "/a": a, "/b": b }) mock.requestAnimationFrame.$resolve() m.route("/b") mock.requestAnimationFrame.$resolve() var result = initCount === 2 m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var initCount = 0 var a = {} a.controller = function() {} a.view = function() { return m("div", m("a", {config: function(el, init, ctx) { ctx.retain = true if (!init) initCount++ }})) } var b = {} b.controller = function() {} b.view = function() { return m("section", m("a", {config: function(el, init, ctx) { ctx.retain = true if (!init) initCount++ }})) } m.route(root, "/a", { "/a": a, "/b": b }) mock.requestAnimationFrame.$resolve() m.route("/b") mock.requestAnimationFrame.$resolve() var result = initCount === 1 m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var initCount = 0 var a = {} a.controller = function() {} a.view = function() { return m("div", m("a", {config: function(el, init, ctx) { ctx.retain = false if (!init) initCount++ }})) } var b = {} b.controller = function() {} b.view = function() { return m("section", m("a", {config: function(el, init, ctx) { ctx.retain = false if (!init) initCount++ }})) } m.route(root, "/a", { "/a": a, "/b": b }) mock.requestAnimationFrame.$resolve() m.route("/b") mock.requestAnimationFrame.$resolve() var result = initCount === 2 m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var initCount = 0 var a = {} a.controller = function() {} a.view = function() { return m("div", m("a", {config: function(el, init) { if (!init) initCount++ }})) } var b = {} b.controller = function() {} b.view = function() { return m("section", m("a", {config: function(el, init) { if (!init) initCount++ }})) } m.route(root, "/a", { "/a": a, "/b": b }) mock.requestAnimationFrame.$resolve() m.route("/b") mock.requestAnimationFrame.$resolve() var result = initCount === 2 m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var initCount = 0 var a = {} a.controller = function() {m.redraw.strategy("diff")} a.view = function() { return m("div", m("a", {config: function(el, init, ctx) { ctx.retain = true if (!init) initCount++ }})) } var b = {} b.controller = function() {m.redraw.strategy("diff")} b.view = function() { return m("section", m("a", {config: function(el, init, ctx) { ctx.retain = true if (!init) initCount++ }})) } m.route(root, "/a", { "/a": a, "/b": b }) mock.requestAnimationFrame.$resolve() m.route("/b") mock.requestAnimationFrame.$resolve() var result = initCount === 1 m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var initCount = 0 var a = {} a.controller = function() {m.redraw.strategy("diff")} a.view = function() { return m("div", m("a", {config: function(el, init, ctx) { ctx.retain = false if (!init) initCount++ }})) } var b = {} b.controller = function() {m.redraw.strategy("diff")} b.view = function() { return m("section", m("a", {config: function(el, init, ctx) { ctx.retain = false if (!init) initCount++ }})) } m.route(root, "/a", { "/a": a, "/b": b }) mock.requestAnimationFrame.$resolve() m.route("/b") mock.requestAnimationFrame.$resolve() var result = initCount === 2 m.mount(root, null) //teardown return result }) test(function() { mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var initCount = 0 var a = {} a.controller = function() {m.redraw.strategy("diff")} a.view = function() { return m("div", m("a", {config: function(el, init) { if (!init) initCount++ }})) } var b = {} b.controller = function() {m.redraw.strategy("diff")} b.view = function() { return m("section", m("a", {config: function(el, init) { if (!init) initCount++ }})) } m.route(root, "/a", { "/a": a, "/b": b }) mock.requestAnimationFrame.$resolve() m.route("/b") mock.requestAnimationFrame.$resolve() var result = initCount === 1 m.mount(root, null) //teardown return result }) test(function() { //retain flag should work inside component mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var initCount = 0 var a = {} a.controller = function() {} a.view = function() { return m("div", m("a", {config: function(el, init, ctx) { ctx.retain = true if (!init) initCount++ }})) } var b = {} b.controller = function() {m.redraw.strategy("diff")} b.view = function() { return m("section", m("a", {config: function(el, init, ctx) { ctx.retain = true if (!init) initCount++ }})) } m.route(root, "/a", { "/a": {view: function() {return m("div", a)}}, "/b": {view: function() {return m("div", b)}} }) mock.requestAnimationFrame.$resolve() m.route("/b") mock.requestAnimationFrame.$resolve() var result = initCount === 1 m.mount(root, null) //teardown return result }) test(function() { // https://github.com/lhorie/mithril.js/pull/571 mock.requestAnimationFrame.$resolve() mock.location.search = "?" var root = mock.document.createElement("div") var a = {} a.controller = function() {} a.view = function() { return m("div", {config: function(elm) { elm.childNodes[0].modified = true }}, m("div")) } var b = {} b.controller = function() {} b.view = function() { return m("div", m("div")) } m.route(root, "/a", { "/a": a, "/b": b }) mock.requestAnimationFrame.$resolve() m.route("/b") mock.requestAnimationFrame.$resolve() var result = !root.childNodes[0].childNodes[0].modified; m.mount(root, null) //teardown return result }); //end m.route //m.route.parseQueryString test(function() { var args = m.route.parseQueryString("foo=bar&hello%5B%5D=world&hello%5B%5D=mars&hello%5B%5D=pluto") return args["hello[]"] instanceof Array && args["hello[]"].indexOf("world") > -1 && args["hello[]"].indexOf("mars") > -1 && args["hello[]"].indexOf("pluto") > -1 }) test(function() { var args = m.route.parseQueryString("foo=bar&hello=world&hello=mars&bam=&yup") return args.foo === "bar" && args.hello[0] === "world" && args.hello[1] === "mars" && args.bam === "" && args.yup == null }) test(function() { var args = m.route.parseQueryString("") return Object.keys(args).length === 0 }) //m.route.buildQueryString test(function() { var string = m.route.buildQueryString({ foo: "bar", hello: ["world", "mars", "mars"], world: { test: 3 }, bam: "", yup: null, removed: undefined }) return string === "foo=bar&hello=world&hello=mars&world%5Btest%5D=3&bam=&yup" }) test(function() { var string = m.route.buildQueryString({}); return string === "" }) //m.prop test(function() { var prop = m.prop("test") return prop() === "test" }) test(function() { var prop = m.prop("test") prop("foo") return prop() === "foo" }) test(function() { var prop = m.prop("test") return JSON.stringify(prop) === '"test"' }) test(function() { var obj = {prop: m.prop("test")} return JSON.stringify(obj) === '{"prop":"test"}' }) test(function() { var defer = m.deferred() var prop = m.prop(defer.promise) defer.resolve("test") return prop() === "test" }) test(function() { var defer = m.deferred() var prop = m.prop(defer.promise).then(function () { return "test2" }) defer.resolve("test") return prop() === "test2" }) test(function() { var prop = m.prop(null) return prop() === null }) //m.request test(function() { var prop = m.request({method: "GET", url: "test"}) mock.XMLHttpRequest.$instances.pop().onreadystatechange() return prop().method === "GET" && prop().url === "test" }) test(function() { var prop = m.request({method: "GET", url: "test"}).then(function() {return "foo"}) mock.XMLHttpRequest.$instances.pop().onreadystatechange() return prop() === "foo" }) test(function() { var prop = m.request({method: "POST", url: "http://domain.com:80", data: {}}).then(function(value) {return value}) mock.XMLHttpRequest.$instances.pop().onreadystatechange() return prop().url === "http://domain.com:80" }) test(function() { var prop = m.request({method: "POST", url: "http://domain.com:80/:test1", data: {test1: "foo"}}).then(function(value) {return value}) mock.XMLHttpRequest.$instances.pop().onreadystatechange() return prop().url === "http://domain.com:80/foo" }) test(function() { var error = m.prop("no error") var prop = m.request({method: "GET", url: "test", deserialize: function() {throw new Error("error occurred")}}).then(null, error) mock.XMLHttpRequest.$instances.pop().onreadystatechange() return prop().message === "error occurred" && error().message === "error occurred" }) test(function() { var error = m.prop("no error") var prop = m.request({method: "GET", url: "test", deserialize: function() {throw new Error("error occurred")}})["catch"](error) mock.XMLHttpRequest.$instances.pop().onreadystatechange() return prop().message === "error occurred" && error().message === "error occurred" }) test(function() { var error = m.prop("no error"), exception var prop = m.request({method: "GET", url: "test", deserialize: function() {throw new TypeError("error occurred")}}).then(null, error) try {mock.XMLHttpRequest.$instances.pop().onreadystatechange()} catch (e) {exception = e} return prop() === undefined && error() === "no error" && exception.message === "error occurred" }) test(function() { var error = m.prop("no error") m.request({method: "POST", url: "test", data: {foo: 1}}).then(null, error) var xhr = mock.XMLHttpRequest.$instances.pop() xhr.onreadystatechange() return xhr.$headers["Content-Type"] === "application/json; charset=utf-8" }) test(function() { var error = m.prop("no error") m.request({method: "POST", url: "test"}).then(null, error) var xhr = mock.XMLHttpRequest.$instances.pop() xhr.onreadystatechange() return xhr.$headers["Content-Type"] === undefined }) test(function() { var prop = m.request({method: "POST", url: "test", initialValue: "foo"}).then(function(data) { return data; }) var initialValue = prop(); mock.XMLHttpRequest.$instances.pop().onreadystatechange() return initialValue === "foo" }) test(function() { var prop = m.request({method: "POST", url: "test", initialValue: "foo"}) var initialValue = prop(); mock.XMLHttpRequest.$instances.pop().onreadystatechange() return initialValue === "foo" }) test(function() { var prop = m.request({method: "POST", url: "test", initialValue: "foo"}).then(function() {return "bar"}) mock.XMLHttpRequest.$instances.pop().onreadystatechange() return prop() === "bar" }) test(function() { var prop = m.request({method: "GET", url: "test", data: {foo: 1}}) mock.XMLHttpRequest.$instances.pop().onreadystatechange() return prop().url === "test?foo=1" }) test(function() { var prop = m.request({method: "POST", url: "test", data: {foo: 1}}) mock.XMLHttpRequest.$instances.pop().onreadystatechange() return prop().url === "test" }) test(function() { var prop = m.request({method: "GET", url: "test", data: {foo: [1, 2]}}) mock.XMLHttpRequest.$instances.pop().onreadystatechange() return prop().url === "test?foo=1&foo=2" }) test(function() { var value var prop1 = m.request({method: "GET", url: "test", initialValue: 123}) var val1 = prop1() var prop2 = prop1.then(function() {return 1}) var val2 = prop2() var prop3 = prop1.then(function(v) {value = v}) var val3 = prop3() mock.XMLHttpRequest.$instances.pop().onreadystatechange() return val1 === 123 && val2 === 123 && val3 === 123 && value.method === "GET" && value.url === "test" }) // m.request over jsonp test(function(){ // script tags cannot be appended directly on the document var body = mock.document.createElement("body") mock.document.body = body mock.document.appendChild(body) var error = m.prop("no error") var data m.request({url: "/test", dataType: "jsonp"}).then(function(received) {data = received}, error) var callbackKey = Object.keys(mock).filter(function(globalKey){ return globalKey.indexOf("mithril_callback") > -1 }).pop() var scriptTag = [].slice.call(mock.document.getElementsByTagName("script")).filter(function(script){ return script.src.indexOf(callbackKey) > -1 }).pop() mock[callbackKey]({foo: "bar"}) mock.document.removeChild(body) return scriptTag.src.indexOf("/test?callback=mithril_callback") > -1 && data.foo === "bar" }) test(function(){ // script tags cannot be appended directly on the document var body = mock.document.createElement("body") mock.document.body = body mock.document.appendChild(body) var error = m.prop("no error") var data m.request({url: "/test", dataType: "jsonp", callbackKey: "jsonpCallback"}).then(function(received) {data = received}, error) var callbackKey = Object.keys(mock).filter(function(globalKey){ return globalKey.indexOf("mithril_callback") > -1 }).pop() var scriptTag = [].slice.call(mock.document.getElementsByTagName("script")).filter(function(script){ return script.src.indexOf(callbackKey) > -1 }).pop(); mock[callbackKey]({foo: "bar1"}) mock.document.removeChild(body) return scriptTag.src.indexOf("/test?jsonpCallback=mithril_callback") > -1 && data.foo === "bar1" }) test(function(){ var body = mock.document.createElement("body") mock.document.body = body mock.document.appendChild(body) var req = m.request({url: "/test", dataType: "jsonp"}) var callbackKey = Object.keys(mock).filter(function(globalKey){ return globalKey.indexOf("mithril_callback") > -1 }).pop() ;[].slice.call(mock.document.getElementsByTagName("script")).filter(function(script){ return script.src.indexOf(callbackKey) > -1 }).pop(); mock[callbackKey]({foo: "bar1"}) var out = {foo: "bar1"} mock.document.removeChild(body) return JSON.stringify(out) === JSON.stringify(req()) }) test(function(){ var body = mock.document.createElement("body") mock.document.body = body mock.document.appendChild(body) m.request({url: "/test", dataType: "jsonp", data: {foo: "bar"}}) var callbackKey = Object.keys(mock).filter(function(globalKey){ return globalKey.indexOf("mithril_callback") > -1 }).pop() var scriptTag = [].slice.call(mock.document.getElementsByTagName("script")).filter(function(script){ return script.src.indexOf(callbackKey) > -1 }).pop(); mock[callbackKey]({foo: "bar"}) return scriptTag.src.indexOf("foo=bar") > -1 }) test(function(){ var body = mock.document.createElement("body"); mock.document.body = body; mock.document.appendChild(body); m.request({url: "/test", dataType: "jsonp", method: "GET", data: {foo: "bar"}}); var callbackKey = Object.keys(mock).filter(function(globalKey){ return globalKey.indexOf("mithril_callback") > -1 }).pop() var scriptTag = [].slice.call(mock.document.getElementsByTagName("script")).filter(function(script){ return script.src.indexOf(callbackKey) > -1 }).pop(); mock[callbackKey]({foo: "bar"}) mock.document.removeChild(body); return scriptTag.src.match(/foo=bar/g).length === 1; }) //m.deferred test(function() { var value var deferred = m.deferred() deferred.promise.then(function(data) {value = data}) deferred.resolve("test") return value === "test" }) test(function() { var value var deferred = m.deferred() deferred.promise.then(function() {return "foo"}).then(function(data) {value = data}) deferred.resolve("test") return value === "foo" }) test(function() { var value var deferred = m.deferred() deferred.promise.then(null, function(data) {value = data}) deferred.reject("test") return value === "test" }) test(function() { var value var deferred = m.deferred() deferred.promise["catch"](function(data) {value = data}) deferred.reject("test") return value === "test" }) test(function() { var value var deferred = m.deferred() deferred.promise.then(null, function() {return "foo"}).then(function(data) {value = data}) deferred.reject("test") return value === "foo" }) test(function() { var value var deferred = m.deferred() deferred.promise["catch"](function() {return "foo"}).then(function(data) {value = data}) deferred.reject("test") return value === "foo" }) test(function() { var value1, value2 var deferred = m.deferred() deferred.promise.then(function() {throw new Error()}).then(function() {value1 = 1}, function(data) {value2 = data}) deferred.resolve("test") return value1 === undefined && value2 instanceof Error }) test(function() { //Let unchecked exceptions bubble up in order to allow meaningful error messages in common cases like null reference exceptions due to typos //An unchecked exception is defined as an object that is a subclass of Error (but not a direct instance of Error itself) - basically anything that can be thrown without an explicit `throw` keyword and that we'd never want to programmatically manipulate. In other words, an unchecked error is one where we only care about its line number and where the only reasonable way to deal with it is to change the buggy source code that caused the error to be thrown in the first place. //By contrast, a checked exception is defined as anything that is explicitly thrown via the `throw` keyword and that can be programmatically handled, for example to display a validation error message on the UI. If an exception is a subclass of Error for whatever reason, but it is meant to be handled as a checked exception (i.e. follow the rejection rules for A+), it can be rethrown as an instance of Error //This test tests two implementation details that differ from the Promises/A+ spec: //1) A+ requires the `then` callback to be called in a different event loop from the resolve call, i.e. it must be asynchronous (this requires a setImmediate polyfill, which cannot be implemented in a reasonable way for Mithril's purpose - the possible polyfills are either too big or too slow) //2) A+ swallows exceptions in a unrethrowable way, i.e. it's not possible to see default error messages on the console for runtime errors thrown from within a promise chain var value1, value2, value3 var deferred = m.deferred() try { deferred.promise .then(function() {foo.bar.baz}) //throws ReferenceError .then(function() {value1 = 1}, function(data) {value2 = data}) deferred.resolve("test") } catch (e) {value3 = e} return value1 === undefined && value2 === undefined && (value3 instanceof ReferenceError || value3 instanceof TypeError) }) test(function() { var deferred1 = m.deferred() var deferred2 = m.deferred() var value1, value2 deferred1.promise.then(function(data) { value1 = data return deferred2.promise }).then(function(data) { value2 = data }) deferred1.resolve(1) deferred2.resolve(2) return value1 === 1 && value2 === 2 }) test(function() { //https://github.com/lhorie/mithril.js/issues/80 var deferred = m.deferred(), value deferred.resolve(1) deferred.promise.then(function(data) { value = data }) return value === 1 }) test(function() { //https://github.com/lhorie/mithril.js/issues/80 var deferred = m.deferred(), value deferred.reject(1) deferred.promise.then(null, function(data) { value = data }) return value === 1 }) test(function() { //https://github.com/lhorie/mithril.js/issues/80 var deferred = m.deferred(), value deferred.resolve(1) deferred.resolve(2) deferred.promise.then(function(data) { value = data }) return value === 1 }) test(function() { //https://github.com/lhorie/mithril.js/issues/80 var deferred = m.deferred(), value deferred.promise.then(function(data) { value = data }) deferred.resolve(1) deferred.resolve(2) return value === 1 }) test(function() { //https://github.com/lhorie/mithril.js/issues/80 var deferred = m.deferred(), value1, value2 deferred.promise.then(function(data) { value1 = data }, function(data) { value2 = data }) deferred.resolve(1) deferred.reject(2) return value1 === 1 && value2 === undefined }) test(function() { //https://github.com/lhorie/mithril.js/issues/80 var deferred = m.deferred(), value1, value2 deferred.promise.then(function(data) { value1 = data }, function(data) { value2 = data }) deferred.reject(1) deferred.resolve(2) return value1 === undefined && value2 === 1 }) test(function() { //https://github.com/lhorie/mithril.js/issues/80 var deferred = m.deferred(), value deferred.promise.then(null, function(data) { value = data }) deferred.reject(1) deferred.reject(2) return value === 1 }) test(function() { //https://github.com/lhorie/mithril.js/issues/85 var deferred = m.deferred(), value deferred.resolve() deferred.promise.then(function() { value = 1 }) return value === 1 }) test(function() { //https://github.com/lhorie/mithril.js/issues/85 var deferred = m.deferred(), value deferred.reject() deferred.promise.then(null, function() { value = 1 }) return value === 1 }) test(function() { var deferred = m.deferred() deferred.resolve(1) return deferred.promise() === 1 }) test(function() { var deferred = m.deferred() var promise = deferred.promise.then(function(data) {return data + 1}) deferred.resolve(1) return promise() === 2 }) test(function() { var deferred = m.deferred() deferred.reject(1) return deferred.promise() === undefined }) //m.sync test(function() { var value var deferred1 = m.deferred() var deferred2 = m.deferred() m.sync([deferred1.promise, deferred2.promise]).then(function(data) {value = data}) deferred1.resolve("test") deferred2.resolve("foo") return value[0] === "test" && value[1] === "foo" }) test(function() { var value var deferred1 = m.deferred() var deferred2 = m.deferred() m.sync([deferred1.promise, deferred2.promise]).then(function(data) {value = data}) deferred2.resolve("foo") deferred1.resolve("test") return value[0] === "test" && value[1] === "foo" }) test(function() { var value var deferred = m.deferred() m.sync([deferred.promise])["catch"](function(data) {value = data}) deferred.reject("fail") return value[0] === "fail" }) test(function() { var value = 1 m.sync([]).then(function() {value = 2}) return value === 2 }) test(function() { var success m.sync([]).then(function(value) {success = value instanceof Array}) return success }) //m.startComputation/m.endComputation test(function() { mock.requestAnimationFrame.$resolve() var root = mock.document.createElement("div") var controller = m.mount(root, { controller: function() {}, view: function(ctrl) {return ctrl.value} }) mock.requestAnimationFrame.$resolve() m.startComputation() controller.value = "foo" m.endComputation() mock.requestAnimationFrame.$resolve() return root.childNodes[0].nodeValue === "foo" }) // config context test(function() { var root = mock.document.createElement("div") var success = false; m.render(root, m("div", {config: function(elem, isInitialized, ctx) {ctx.data=1}})); m.render(root, m("div", {config: function(elem, isInitialized, ctx) {success = ctx.data===1}})); return success; }) // more complex config context test(function() { var root = mock.document.createElement("div") var idx = 0; var success = true; var statefulConfig = function(elem, isInitialized, ctx) {ctx.data=idx++} var node = m("div", {config: statefulConfig}); m.render(root, [node, node]); idx = 0; var checkConfig = function(elem, isInitialized, ctx) { success = success && (ctx.data === idx++) } node = m("div", {config: checkConfig}); m.render(root, [node, node]); return success; }) //console.log presence test(function() { return m.deps.factory.toString().indexOf("console") < 0 }) test(function() { return m.deps.factory.toString().indexOf("document.write") < 0 }) } //mock testMithril(mock.window); test.print(function(value) {console.log(value)})