mithril-vndb/archive/v0.1.11/mithril-tests.js
2014-05-01 21:31:56 -04:00

1209 lines
No EOL
41 KiB
JavaScript

Mithril = m = new function app(window) {
var selectorCache = {}
var type = {}.toString
var parser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[.+?\])/g, attrParser = /\[(.+?)(?:=("|'|)(.+?)\2)?\]/
function m() {
var args = arguments
var hasAttrs = type.call(args[1]) == "[object Object]"
var attrs = hasAttrs ? args[1] : {}
var classAttrName = "class" in attrs ? "class" : "className"
var cell = selectorCache[args[0]]
if (cell === undefined) {
selectorCache[args[0]] = cell = {tag: "div", attrs: {}}
var match, classes = []
while (match = parser.exec(args[0])) {
if (match[1] == "") cell.tag = match[2]
else if (match[1] == "#") cell.attrs.id = match[2]
else if (match[1] == ".") classes.push(match[2])
else if (match[3][0] == "[") {
var pair = attrParser.exec(match[3])
cell.attrs[pair[1]] = pair[3] || true
}
}
if (classes.length > 0) cell.attrs[classAttrName] = classes.join(" ")
}
cell = clone(cell)
cell.attrs = clone(cell.attrs)
cell.children = hasAttrs ? args[2] : args[1]
for (var attrName in attrs) {
if (attrName == classAttrName) cell.attrs[attrName] = (cell.attrs[attrName] || "") + " " + attrs[attrName]
else cell.attrs[attrName] = attrs[attrName]
}
return cell
}
function build(parentElement, parentTag, data, cached, shouldReattach, index, namespace) {
if (data === null || data === undefined) {
if (cached) clear(cached.nodes)
return
}
if (data.subtree === "retain") return
var cachedType = type.call(cached), dataType = type.call(data)
if (cachedType != dataType) {
if (cached !== null && cached !== undefined) clear(cached.nodes)
cached = new data.constructor
cached.nodes = []
}
if (dataType == "[object Array]") {
var nodes = [], intact = cached.length === data.length, subArrayCount = 0
for (var i = 0, cacheCount = 0; i < data.length; i++) {
var item = build(parentElement, null, data[i], cached[cacheCount], shouldReattach, index + subArrayCount || subArrayCount, namespace)
if (item === undefined) continue
if (!item.nodes.intact) intact = false
subArrayCount += item instanceof Array ? item.length : 1
cached[cacheCount++] = item
}
if (!intact) {
for (var i = 0; i < data.length; i++) if (cached[i] !== undefined) nodes = nodes.concat(cached[i].nodes)
for (var i = nodes.length, node; node = cached.nodes[i]; i++) if (node.parentNode !== null) node.parentNode.removeChild(node)
for (var i = cached.nodes.length, node; node = nodes[i]; i++) if (node.parentNode === null) parentElement.appendChild(node)
if (data.length < cached.length) cached.length = data.length
cached.nodes = nodes
}
}
else if (dataType == "[object Object]") {
if (data.tag != cached.tag || Object.keys(data.attrs).join() != Object.keys(cached.attrs).join() || data.attrs.id != cached.attrs.id) clear(cached.nodes)
if (typeof data.tag != "string") return
var node, isNew = cached.nodes.length === 0
if (data.tag === "svg") namespace = "http://www.w3.org/2000/svg"
if (isNew) {
node = namespace === undefined ? window.document.createElement(data.tag) : window.document.createElementNS(namespace, data.tag)
cached = {
tag: data.tag,
attrs: setAttributes(node, data.tag, data.attrs, {}, namespace),
children: build(node, data.tag, data.children, cached.children, true, 0, namespace),
nodes: [node]
}
parentElement.insertBefore(node, parentElement.childNodes[index] || null)
}
else {
node = cached.nodes[0]
setAttributes(node, data.tag, data.attrs, cached.attrs, namespace)
cached.children = build(node, data.tag, data.children, cached.children, false, 0, namespace)
cached.nodes.intact = true
if (shouldReattach === true) parentElement.insertBefore(node, parentElement.childNodes[index] || null)
}
if (type.call(data.attrs["config"]) == "[object Function]") data.attrs["config"](node, !isNew)
}
else {
var node
if (cached.nodes.length === 0) {
if (data.$trusted) {
node = injectHTML(parentElement, index, data)
}
else {
node = window.document.createTextNode(data)
parentElement.insertBefore(node, parentElement.childNodes[index] || null)
}
cached = "string number boolean".indexOf(typeof data) > -1 ? new data.constructor(data) : data
cached.nodes = [node]
}
else if (cached.valueOf() !== data.valueOf() || shouldReattach === true) {
if (data.$trusted) {
var current = cached.nodes[0], nodes = [current]
if (current) {
while (current = current.nextSibling) nodes.push(current)
clear(nodes)
node = injectHTML(parentElement, index, data)
}
else parentElement.innerHTML = data
}
else {
node = cached.nodes[0]
if (parentTag === "textarea") parentElement.value = data
else parentElement.insertBefore(node, parentElement.childNodes[index] || null)
node.nodeValue = data
}
cached = new data.constructor(data)
cached.nodes = [node]
}
else cached.nodes.intact = true
}
return cached
}
function setAttributes(node, tag, dataAttrs, cachedAttrs, namespace) {
for (var attrName in dataAttrs) {
var dataAttr = dataAttrs[attrName]
var cachedAttr = cachedAttrs[attrName]
if (!(attrName in cachedAttrs) || (cachedAttr !== dataAttr) || node === window.document.activeElement) {
cachedAttrs[attrName] = dataAttr
if (attrName === "config") continue
else if (typeof dataAttr == "function" && attrName.indexOf("on") == 0) {
node[attrName] = autoredraw(dataAttr, node)
}
else if (attrName === "style") {
for (var rule in dataAttr) {
if (cachedAttr === undefined || cachedAttr[rule] !== dataAttr[rule]) node.style[rule] = dataAttr[rule]
}
}
else if (namespace !== undefined) {
if (attrName === "href") node.setAttributeNS("http://www.w3.org/1999/xlink", "href", dataAttr)
else if (attrName === "className") node.setAttribute("class", dataAttr)
else node.setAttribute(attrName, dataAttr)
}
else if (attrName === "value" && tag === "input") {
if (node.value !== dataAttr) node.value = dataAttr
}
else if (attrName in node) node[attrName] = dataAttr
else node.setAttribute(attrName, dataAttr)
}
}
return cachedAttrs
}
function clear(nodes) {
for (var i = 0; i < nodes.length; i++) nodes[i].parentNode.removeChild(nodes[i])
nodes.length = 0
}
function injectHTML(parentElement, index, data) {
var nextSibling = parentElement.childNodes[index]
if (nextSibling) nextSibling.insertAdjacentHTML("beforebegin", data)
else parentElement.insertAdjacentHTML("beforeend", data)
return nextSibling ? nextSibling.previousSibling : parentElement.firstChild
}
function clone(object) {
var result = {}
for (var prop in object) result[prop] = object[prop]
return result
}
function autoredraw(callback, object) {
return function(e) {
m.startComputation()
var output = callback.call(object, e)
m.endComputation()
return output
}
}
var html
var documentNode = {
insertAdjacentHTML: function(_, data) {
window.document.write(data)
window.document.close()
},
appendChild: function(node) {
if (html === undefined) html = window.document.createElement("html")
if (node.nodeName == "HTML") html = node
else html.appendChild(node)
if (window.document.documentElement !== html) {
window.document.replaceChild(html, window.document.documentElement)
}
},
insertBefore: function(node, reference) {
this.appendChild(node)
},
childNodes: []
}
var nodeCache = [], cellCache = {}
m.render = function(root, cell) {
var index = nodeCache.indexOf(root)
var id = index < 0 ? nodeCache.push(root) - 1 : index
var node = root == window.document || root == window.document.documentElement ? documentNode : root
cellCache[id] = build(node, null, cell, cellCache[id], false, 0)
}
m.trust = function(value) {
value = new String(value)
value.$trusted = true
return value
}
var roots = [], modules = [], controllers = [], now = 0, lastRedraw = 0, lastRedrawId = 0, computePostRedrawHook = null
m.module = function(root, module) {
m.startComputation()
var index = roots.indexOf(root)
if (index < 0) index = roots.length
roots[index] = root
modules[index] = module
controllers[index] = new module.controller
m.endComputation()
}
m.redraw = function() {
now = window.performance && window.performance.now ? window.performance.now() : new window.Date().getTime()
if (now - lastRedraw > 16) redraw()
else {
var cancel = window.cancelAnimationFrame || window.clearTimeout
var defer = window.requestAnimationFrame || window.setTimeout
cancel(lastRedrawId)
lastRedrawId = defer(redraw, 0)
}
}
function redraw() {
for (var i = 0; i < roots.length; i++) {
m.render(roots[i], modules[i].view(controllers[i]))
}
if (computePostRedrawHook) {
computePostRedrawHook()
computePostRedrawHook = null
}
lastRedraw = now
}
var pendingRequests = 0
m.startComputation = function() {pendingRequests++}
m.endComputation = function() {
pendingRequests = Math.max(pendingRequests - 1, 0)
if (pendingRequests == 0) m.redraw()
}
m.withAttr = function(prop, withAttrCallback) {
return function(e) {withAttrCallback(prop in e.currentTarget ? e.currentTarget[prop] : e.currentTarget.getAttribute(prop))}
}
//routing
var modes = {pathname: "", hash: "#", search: "?"}
var redirect = function() {}, routeParams = {}, currentRoute
m.route = function() {
if (arguments.length === 0) return currentRoute
else if (arguments.length === 3) {
currentRoute = window.location[m.route.mode].slice(modes[m.route.mode].length)
var root = arguments[0], defaultRoute = arguments[1], router = arguments[2]
redirect = function(source) {
var path = source.slice(modes[m.route.mode].length)
if (!routeByValue(root, router, path)) {
m.route(defaultRoute, true)
}
}
var listener = m.route.mode == "hash" ? "onhashchange" : "onpopstate"
window[listener] = function() {
redirect(window.location[m.route.mode])
}
computePostRedrawHook = scrollToHash
window[listener]()
}
else if (arguments[0].addEventListener) {
var element = arguments[0]
var isInitialized = arguments[1]
element.href = modes[m.route.mode] + element.pathname
if (!isInitialized) {
element.removeEventListener("click", routeUnobtrusive)
element.addEventListener("click", routeUnobtrusive)
}
}
else if (typeof arguments[0] == "string") {
currentRoute = arguments[0]
var shouldReplaceHistoryEntry = arguments[1] === true
if (window.history.pushState) {
computePostRedrawHook = function() {
window.history[shouldReplaceHistoryEntry ? "replaceState" : "pushState"](null, window.document.title, modes[m.route.mode] + currentRoute)
scrollToHash()
}
redirect(modes[m.route.mode] + currentRoute)
}
else window.location[m.route.mode] = currentRoute
}
}
m.route.param = function(key) {return routeParams[key]}
m.route.mode = "search"
function routeByValue(root, router, path) {
routeParams = {}
for (var route in router) {
if (route == path) return !void m.module(root, router[route])
var matcher = new RegExp("^" + route.replace(/:[^\/]+/g, "([^\\/]+)") + "$")
if (matcher.test(path)) {
return !void path.replace(matcher, function() {
var keys = route.match(/:[^\/]+/g)
var values = [].slice.call(arguments, 1, -2)
for (var i = 0; i < keys.length; i++) routeParams[keys[i].slice(1)] = values[i]
m.module(root, router[route])
})
}
}
}
function routeUnobtrusive(e) {
if (e.ctrlKey || e.metaKey || e.which == 2) return
e.preventDefault()
m.route(e.currentTarget[m.route.mode].slice(modes[m.route.mode].length))
}
function scrollToHash() {
if (m.route.mode != "hash" && window.location.hash) window.location.hash = window.location.hash
}
//model
m.prop = function(store) {
var prop = function() {
if (arguments.length) store = arguments[0]
return store
}
prop.toJSON = function() {
return store
}
return prop
}
m.deferred = function() {
var resolvers = [], rejecters = []
var object = {
resolve: function(value) {
for (var i = 0; i < resolvers.length; i++) resolvers[i](value)
},
reject: function(value) {
for (var i = 0; i < rejecters.length; i++) rejecters[i](value)
},
promise: m.prop()
}
object.promise.resolvers = resolvers
object.promise.then = function(success, error) {
var next = m.deferred()
if (!success) success = identity
if (!error) error = identity
function push(list, method, callback) {
list.push(function(value) {
try {
var result = callback(value)
if (result && typeof result.then == "function") result.then(next[method], error)
else next[method](result !== undefined ? result : value)
}
catch (e) {
if (e instanceof Error && e.constructor !== Error) throw e
else next.reject(e)
}
})
}
push(resolvers, "resolve", success)
push(rejecters, "reject", error)
return next.promise
}
return object
}
m.sync = function(args) {
var method = "resolve"
function synchronizer(resolved) {
return function(value) {
results.push(value)
if (!resolved) method = "reject"
if (results.length == args.length) {
deferred.promise(results)
deferred[method](results)
}
return value
}
}
var deferred = m.deferred()
var results = []
for (var i = 0; i < args.length; i++) {
args[i].then(synchronizer(true), synchronizer(false))
}
return deferred.promise
}
function identity(value) {return value}
function ajax(options) {
var xhr = window.XDomainRequest ? new window.XDomainRequest : new window.XMLHttpRequest
xhr.open(options.method, options.url, true, options.user, options.password)
xhr.onload = typeof options.onload == "function" ? options.onload : function() {}
xhr.onerror = typeof options.onerror == "function" ? options.onerror : function() {}
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 0) {
xhr.onerror({type: "error", target: xhr})
}
}
if (typeof options.config == "function") options.config(xhr, options)
xhr.send(options.data)
return xhr
}
function querystring(object, prefix) {
var str = []
for(var prop in object) {
var key = prefix ? prefix + "[" + prop + "]" : prop, value = object[prop]
str.push(typeof value == "object" ? querystring(value, key) : encodeURIComponent(key) + "=" + encodeURIComponent(value))
}
return str.join("&")
}
function bindData(xhrOptions, data, serialize) {
if (data && Object.keys(data).length > 0) {
if (xhrOptions.method == "GET") {
xhrOptions.url = xhrOptions.url + (xhrOptions.url.indexOf("?") < 0 ? "?" : "&") + querystring(data)
}
else xhrOptions.data = serialize(data)
}
return xhrOptions
}
function parameterizeUrl(url, data) {
var tokens = url.match(/:[a-z]\w+/gi)
if (tokens && data) {
for (var i = 0; i < tokens.length; i++) {
var key = tokens[i].slice(1)
url = url.replace(tokens[i], data[key])
delete data[key]
}
}
return url
}
m.request = function(xhrOptions) {
if (xhrOptions.background !== true) m.startComputation()
var deferred = m.deferred()
var serialize = xhrOptions.serialize || JSON.stringify
var deserialize = xhrOptions.deserialize || JSON.parse
var extract = xhrOptions.extract || function(xhr, xhrOptions) {
return xhr.responseText.length === 0 && deserialize === JSON.parse ? null : xhr.responseText
}
xhrOptions.url = parameterizeUrl(xhrOptions.url, xhrOptions.data)
xhrOptions = bindData(xhrOptions, xhrOptions.data, serialize)
xhrOptions.onload = xhrOptions.onerror = function(e) {
var unwrap = (e.type == "load" ? xhrOptions.unwrapSuccess : xhrOptions.unwrapError) || identity
var response = unwrap(deserialize(extract(e.target, xhrOptions)))
if (response instanceof Array && xhrOptions.type) {
for (var i = 0; i < response.length; i++) response[i] = new xhrOptions.type(response[i])
}
else if (xhrOptions.type) response = new xhrOptions.type(response)
deferred.promise(response)
deferred[e.type == "load" ? "resolve" : "reject"](response)
if (xhrOptions.background !== true) m.endComputation()
}
ajax(xhrOptions)
deferred.promise.then = propBinder(deferred.promise)
return deferred.promise
}
function propBinder(promise) {
var bind = promise.then
return function(success, error) {
var next = bind(function(value) {return next(success(value))}, function(value) {return next(error(value))})
next.then = propBinder(next)
return next
}
}
//testing API
m.deps = function(mock) {return window = mock}
return m
}(this)
if (typeof module != "undefined" && module !== null) module.exports = m
if (typeof define == "function" && define.amd) define(function() {return m})
function test(condition) {
try {if (!condition()) throw new Error}
catch (e) {console.error(e);test.failures.push(condition)}
test.total++
}
test.total = 0
test.failures = []
test.print = function(print) {
for (var i = 0; i < test.failures.length; i++) {
print(test.failures[i].toString())
}
print("tests: " + test.total + "\nfailures: " + test.failures.length)
if (test.failures.length > 0) {
throw new Error(test.failures.length + " tests did not pass")
}
}
var mock = {}
mock.window = new function() {
var window = {}
window.document = {}
window.document.childNodes = []
window.document.createElement = function(tag) {
return {
childNodes: [],
nodeName: tag.toUpperCase(),
appendChild: window.document.appendChild,
removeChild: window.document.removeChild,
replaceChild: window.document.replaceChild,
insertBefore: function(node, reference) {
node.parentNode = this
var referenceIndex = this.childNodes.indexOf(reference)
if (referenceIndex < 0) this.childNodes.push(node)
else {
var index = this.childNodes.indexOf(node)
this.childNodes.splice(referenceIndex, index < 0 ? 0 : 1, node)
}
},
insertAdjacentHTML: function(position, html) {
//todo: accept markup
if (position == "beforebegin") {
this.parentNode.insertBefore(window.document.createTextNode(html), this)
}
else if (position == "beforeend") {
this.appendChild(window.document.createTextNode(html))
}
},
setAttribute: function(name, value) {
this[name] = value.toString()
},
setAttributeNS: function(namespace, name, value) {
this.namespaceURI = namespace
this[name] = value.toString()
},
getAttribute: function(name, value) {
return this[name]
}
}
}
window.document.createElementNS = function(namespace, tag) {
var element = window.document.createElement(tag)
element.namespaceURI = namespace
return element
}
window.document.createTextNode = function(text) {
return {nodeValue: text.toString()}
}
window.document.documentElement = window.document.createElement("html")
window.document.replaceChild = function(newChild, oldChild) {
var index = this.childNodes.indexOf(oldChild)
if (index > -1) this.childNodes.splice(index, 1, newChild)
else this.childNodes.push(newChild)
newChild.parentNode = this
oldChild.parentNode = null
}
window.document.appendChild = function(child) {
var index = this.childNodes.indexOf(child)
if (index > -1) this.childNodes.splice(index, 1)
this.childNodes.push(child)
child.parentNode = this
}
window.document.removeChild = function(child) {
var index = this.childNodes.indexOf(child)
this.childNodes.splice(index, 1)
child.parentNode = null
}
window.performance = new function () {
var timestamp = 50
this.$elapse = function(amount) {timestamp += amount}
this.now = function() {return timestamp}
}
window.cancelAnimationFrame = function() {}
window.requestAnimationFrame = function(callback) {window.requestAnimationFrame.$callback = callback}
window.requestAnimationFrame.$resolve = function() {
if (window.requestAnimationFrame.$callback) window.requestAnimationFrame.$callback()
window.requestAnimationFrame.$callback = null
window.performance.$elapse(20)
}
window.XMLHttpRequest = new function() {
var request = function() {
this.open = function(method, url) {
this.method = method
this.url = url
}
this.send = function() {
this.responseText = JSON.stringify(this)
request.$events.push({type: "load", target: this})
}
}
request.$events = []
return request
}
window.location = {search: "", pathname: "", hash: ""},
window.history = {}
window.history.pushState = function(data, title, url) {
window.location.pathname = window.location.search = window.location.hash = url
},
window.history.replaceState = function(data, title, url) {
window.location.pathname = window.location.search = window.location.hash = url
}
return window
}
function testMithril(mock) {
m.deps(mock)
//m
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 === "test"})
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 === "test"})
test(function() {return m("div", {title: "bar"}, ["test"]).children[0] === "test"})
test(function() {return m("div", {title: "bar"}, m("div")).children.tag === "div"})
test(function() {return m("div", {title: "bar"}, [m("div")]).children[0].tag === "div"})
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")).attrs.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']")])})
//m.module
test(function() {
mock.performance.$elapse(50)
var root1 = mock.document.createElement("div")
m.module(root1, {
controller: function() {this.value = "test1"},
view: function(ctrl) {return ctrl.value}
})
var root2 = mock.document.createElement("div")
m.module(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"
})
//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.length === 0
})
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.length === 1
})
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.length === 1
})
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.length === 0
})
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("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/29
var root = mock.document.createElement("div")
var list = [false, false]
m.render(root, list.reverse().map(function(flag, index) {
return m("input[type=checkbox]", {onclick: m.withAttr("checked", function(value) {list[index] = value}), checked: flag})
}))
mock.document.activeElement = root.childNodes[0]
root.childNodes[0].checked = true
root.childNodes[0].onclick({currentTarget: {checked: true}})
m.render(root, list.reverse().map(function(flag, index) {
return m("input[type=checkbox]", {onclick: m.withAttr("checked", function(value) {list[index] = value}), checked: flag})
}))
mock.document.activeElement = null
return root.childNodes[0].checked === false && root.childNodes[1].checked === true
})
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
})
//end m.render
//m.redraw
test(function() {
mock.performance.$elapse(50) //setup
var controller
var root = mock.document.createElement("div")
m.module(root, {
controller: function() {controller = this},
view: function(ctrl) {return ctrl.value}
})
controller.value = "foo"
m.redraw()
var lengthBefore = root.childNodes.length
mock.performance.$elapse(50)
m.redraw()
mock.performance.$elapse(50) //teardown
return lengthBefore === 0 && root.childNodes[0].nodeValue === "foo"
})
test(function() {
mock.performance.$elapse(50) //setup
var count = 0
var root = mock.document.createElement("div")
m.module(root, {
controller: function() {},
view: function(ctrl) {
count++
}
})
m.redraw()
m.redraw()
m.redraw()
mock.performance.$elapse(50)
m.redraw()
mock.performance.$elapse(50) //teardown
return count === 2
})
//m.route
test(function() {
mock.performance.$elapse(50) //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.performance.$elapse(50) //teardown
return mock.location.search == "?/test1" && root.childNodes[0].nodeValue === "foo"
})
test(function() {
mock.performance.$elapse(50) //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"}}
})
mock.performance.$elapse(50) //teardown
return mock.location.pathname == "/test2" && root.childNodes[0].nodeValue === "foo"
})
test(function() {
mock.performance.$elapse(50) //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.performance.$elapse(50) //teardown
return mock.location.hash == "#/test3" && root.childNodes[0].nodeValue === "foo"
})
test(function() {
mock.performance.$elapse(50) //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.performance.$elapse(50) //teardown
return mock.location.search == "?/test4/foo" && root.childNodes[0].nodeValue === "foo"
})
test(function() {
mock.performance.$elapse(50) //setup
mock.location.search = "?"
var module = {controller: function() {}, view: function() {return m.route.param("test")}}
var root = mock.document.createElement("div")
m.route.mode = "search"
m.route(root, "/test5/foo", {
"/": module,
"/test5/:test": module
})
var paramValueBefore = m.route.param("test")
mock.performance.$elapse(50)
m.route("/")
var paramValueAfter = m.route.param("test")
mock.performance.$elapse(50) //teardown
return mock.location.search == "?/" && paramValueBefore === "foo" && paramValueAfter === undefined
})
test(function() {
mock.performance.$elapse(50) //setup
mock.location.search = "?"
var module = {controller: function() {}, view: function() {return m.route.param("a1")}}
var root = mock.document.createElement("div")
m.route.mode = "search"
m.route(root, "/test6/foo", {
"/": module,
"/test6/:a1": module
})
var paramValueBefore = m.route.param("a1")
mock.performance.$elapse(50)
m.route("/")
var paramValueAfter = m.route.param("a1")
mock.performance.$elapse(50) //teardown
return mock.location.search == "?/" && paramValueBefore === "foo" && paramValueAfter === undefined
})
test(function() {
//https://github.com/lhorie/mithril.js/issues/61
mock.performance.$elapse(50) //setup
mock.location.search = "?"
var module = {controller: function() {}, view: function() {return m.route.param("a1")}}
var root = mock.document.createElement("div")
m.route.mode = "search"
m.route(root, "/test7/foo", {
"/": module,
"/test7/:a1": module
})
var routeValueBefore = m.route()
mock.performance.$elapse(50)
m.route("/")
var routeValueAfter = m.route()
mock.performance.$elapse(50) //teardown
return routeValueBefore === "/test7/foo" && routeValueAfter === "/"
})
//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"}'
})
//m.request
test(function() {
var prop = m.request({method: "GET", url: "test"})
var e = mock.XMLHttpRequest.$events.pop()
e.target.onload(e)
return prop().method === "GET" && prop().url === "test"
})
test(function() {
var prop = m.request({method: "GET", url: "test"}).then(function(value) {return "foo"})
var e = mock.XMLHttpRequest.$events.pop()
e.target.onload(e)
return prop() === "foo"
})
test(function() {
var prop = m.request({method: "POST", url: "http://domain.com:80", data: {}}).then(function(value) {return value})
var e = mock.XMLHttpRequest.$events.pop()
e.target.onload(e)
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})
var e = mock.XMLHttpRequest.$events.pop()
e.target.onload(e)
return prop().url === "http://domain.com:80/foo"
})
//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(data) {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.then(null, function(data) {return "foo"}).then(null, function(data) {value = data})
deferred.reject("test")
return value === "foo"
})
test(function() {
var value1, value2
var deferred = m.deferred()
deferred.promise.then(function(data) {throw new Error}).then(function(data) {value1 = 1}, function(data) {value2 = data})
deferred.resolve("test")
return value1 === undefined && value2 instanceof Error
})
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
})
//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"
})
//m.startComputation/m.endComputation
test(function() {
mock.performance.$elapse(50)
var controller
var root = mock.document.createElement("div")
m.module(root, {
controller: function() {controller = this},
view: function(ctrl) {return ctrl.value}
})
mock.performance.$elapse(50)
m.startComputation()
controller.value = "foo"
m.endComputation()
return root.childNodes[0].nodeValue === "foo"
})
}
//mocks
testMithril(mock.window)
test.print(console.log)