tests for components
This commit is contained in:
parent
67cdda7249
commit
2ac027a2af
2 changed files with 247 additions and 7 deletions
17
mithril.js
17
mithril.js
|
|
@ -234,8 +234,7 @@ var m = (function app(window, undefined) {
|
||||||
if (data.controller) {
|
if (data.controller) {
|
||||||
var module = data
|
var module = data
|
||||||
var controller = cached.controller || new (module.controller || function() {})
|
var controller = cached.controller || new (module.controller || function() {})
|
||||||
var args = module.controller.$$args ? [controller].concat(module.controller.$$args) : controller
|
data = module.view(controller)
|
||||||
data = module.view.apply(module, args)
|
|
||||||
if (!data.tag) throw new Error(module.view.toString() + "\n\nThis template must return a virtual element, not an array, string, etc.")
|
if (!data.tag) throw new Error(module.view.toString() + "\n\nThis template must return a virtual element, not an array, string, etc.")
|
||||||
}
|
}
|
||||||
if (!data.attrs) data.attrs = {};
|
if (!data.attrs) data.attrs = {};
|
||||||
|
|
@ -509,11 +508,15 @@ var m = (function app(window, undefined) {
|
||||||
var controller = function() {
|
var controller = function() {
|
||||||
return module.controller.apply(this, args) || this
|
return module.controller.apply(this, args) || this
|
||||||
}
|
}
|
||||||
controller.$$args = args //private, do not use
|
var view = function(ctrl) {
|
||||||
return {
|
if (arguments.length > 1) args = args.concat([].slice.call(arguments, 1))
|
||||||
controller: controller,
|
var template = module.view.apply(module, args ? [ctrl].concat(args) : [ctrl])
|
||||||
view: module.view,
|
if (args[0] && args[0].key != null) template.attrs.key = args[0].key
|
||||||
|
return template
|
||||||
}
|
}
|
||||||
|
var output = {controller: controller, view: view}
|
||||||
|
if (args[0] && args[0].key != null) output.attrs = {key: args[0].key}
|
||||||
|
return output
|
||||||
}
|
}
|
||||||
m.module = function(root, module) {
|
m.module = function(root, module) {
|
||||||
if (!root) throw new Error("Please ensure the DOM element exists before rendering a template into it.");
|
if (!root) throw new Error("Please ensure the DOM element exists before rendering a template into it.");
|
||||||
|
|
@ -533,7 +536,7 @@ var m = (function app(window, undefined) {
|
||||||
roots[index] = root;
|
roots[index] = root;
|
||||||
if (arguments.length > 2) module = submodule(module, [].slice.call(arguments, 2))
|
if (arguments.length > 2) module = submodule(module, [].slice.call(arguments, 2))
|
||||||
var currentModule = topModule = module = module || {};
|
var currentModule = topModule = module = module || {};
|
||||||
var constructor = module.controller || m.prop()
|
var constructor = module.controller || function() {}
|
||||||
var controller = new constructor;
|
var controller = new constructor;
|
||||||
//controllers may call m.module recursively (via m.route redirects, for example)
|
//controllers may call m.module recursively (via m.route redirects, for example)
|
||||||
//this conditional ensures only the last recursive m.module call is applied
|
//this conditional ensures only the last recursive m.module call is applied
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,243 @@ function testMithril(mock) {
|
||||||
|
|
||||||
return unloaded
|
return unloaded
|
||||||
})
|
})
|
||||||
|
test(function() {
|
||||||
|
//module should pass args to both controller and view
|
||||||
|
mock.requestAnimationFrame.$resolve()
|
||||||
|
|
||||||
|
var root = mock.document.createElement("div")
|
||||||
|
var slot1, slot2
|
||||||
|
var module = {
|
||||||
|
controller: function(options) {slot1 = options.a},
|
||||||
|
view: function(ctrl, options) {slot2 = options.a}
|
||||||
|
}
|
||||||
|
m.module(root, module, {a: 1})
|
||||||
|
|
||||||
|
mock.requestAnimationFrame.$resolve()
|
||||||
|
|
||||||
|
return slot1 == 1 && slot2 == 1
|
||||||
|
})
|
||||||
|
test(function() {
|
||||||
|
//arguments should update in component's view
|
||||||
|
mock.requestAnimationFrame.$resolve()
|
||||||
|
|
||||||
|
var root = mock.document.createElement("div")
|
||||||
|
var args = {a: 1}
|
||||||
|
var slot1, slot2
|
||||||
|
var module = {
|
||||||
|
controller: function() {},
|
||||||
|
view: function(ctrl, options) {
|
||||||
|
return m.module(sub, args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var sub = {
|
||||||
|
controller: function(options) {slot1 = options.a},
|
||||||
|
view: function(ctrl, options) {
|
||||||
|
slot2 = options.a
|
||||||
|
return m("div")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.module(root, module)
|
||||||
|
|
||||||
|
mock.requestAnimationFrame.$resolve()
|
||||||
|
|
||||||
|
args.a = 2
|
||||||
|
m.redraw(true)
|
||||||
|
|
||||||
|
mock.requestAnimationFrame.$resolve()
|
||||||
|
|
||||||
|
return slot1 == 1 && slot2 == 2
|
||||||
|
})
|
||||||
|
test(function() {
|
||||||
|
//module(mod, args) should also pass args to both controller and view
|
||||||
|
mock.requestAnimationFrame.$resolve()
|
||||||
|
|
||||||
|
var root = mock.document.createElement("div")
|
||||||
|
var slot1, slot2
|
||||||
|
var module = {
|
||||||
|
controller: function(options) {slot1 = options.a},
|
||||||
|
view: function(ctrl, options) {slot2 = options.a}
|
||||||
|
}
|
||||||
|
var moduleWithArgs = m.module(module, {a: 1})
|
||||||
|
m.module(root, moduleWithArgs)
|
||||||
|
|
||||||
|
mock.requestAnimationFrame.$resolve()
|
||||||
|
|
||||||
|
return slot1 == 1 && 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 module = {
|
||||||
|
view: function(ctrl) {
|
||||||
|
return m.module(sub)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var sub = {
|
||||||
|
controller: function() {
|
||||||
|
count1++
|
||||||
|
},
|
||||||
|
view: function(ctrl) {
|
||||||
|
count2++
|
||||||
|
return m("div", "test")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.module(root, module)
|
||||||
|
|
||||||
|
mock.requestAnimationFrame.$resolve()
|
||||||
|
|
||||||
|
m.redraw(true)
|
||||||
|
|
||||||
|
mock.requestAnimationFrame.$resolve()
|
||||||
|
|
||||||
|
return count1 == 1 && count2 == 2
|
||||||
|
})
|
||||||
|
test(function() {
|
||||||
|
//keys in components should work
|
||||||
|
mock.requestAnimationFrame.$resolve()
|
||||||
|
|
||||||
|
var root = mock.document.createElement("div")
|
||||||
|
var list = [1, 2, 3]
|
||||||
|
var module = {
|
||||||
|
controller: function() {},
|
||||||
|
view: function(ctrl) {
|
||||||
|
return list.map(function(i) {
|
||||||
|
return m.module(sub, {key: i})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var sub = {
|
||||||
|
controller: function() {},
|
||||||
|
view: function() {
|
||||||
|
return m("div")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.module(root, module)
|
||||||
|
|
||||||
|
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 module = {
|
||||||
|
controller: function() {},
|
||||||
|
view: function(ctrl) {
|
||||||
|
return list.map(function(i) {
|
||||||
|
return m.module(sub, {key: i})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var sub = {
|
||||||
|
controller: function() {},
|
||||||
|
view: function() {
|
||||||
|
return m("div", {key: 1})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.module(root, module)
|
||||||
|
|
||||||
|
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 module = {
|
||||||
|
controller: function() {},
|
||||||
|
view: function(ctrl) {
|
||||||
|
return list.map(function(i) {
|
||||||
|
return m("div", {key: i}, m.module(sub))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var sub = {
|
||||||
|
controller: function() {},
|
||||||
|
view: function() {
|
||||||
|
return m("div")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.module(root, module)
|
||||||
|
|
||||||
|
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 module = {
|
||||||
|
controller: function() {},
|
||||||
|
view: function(ctrl) {
|
||||||
|
return list.map(function(i) {
|
||||||
|
return m.module(sub, {key: i})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var sub = {
|
||||||
|
controller: function(opts) {
|
||||||
|
this.onunload = function() {
|
||||||
|
unloaded = opts.key
|
||||||
|
}
|
||||||
|
},
|
||||||
|
view: function() {
|
||||||
|
return m("div")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m.module(root, module)
|
||||||
|
|
||||||
|
var firstBefore = root.childNodes[0]
|
||||||
|
|
||||||
|
mock.requestAnimationFrame.$resolve()
|
||||||
|
|
||||||
|
list.pop()
|
||||||
|
m.redraw(true)
|
||||||
|
|
||||||
|
mock.requestAnimationFrame.$resolve()
|
||||||
|
|
||||||
|
return unloaded === 3
|
||||||
|
})
|
||||||
|
|
||||||
//m.withAttr
|
//m.withAttr
|
||||||
test(function() {
|
test(function() {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue