clean slate
This commit is contained in:
parent
5d2b6ea2b7
commit
13fdb60f66
377 changed files with 0 additions and 71900 deletions
|
|
@ -1,18 +0,0 @@
|
|||
{
|
||||
"extends": "../.eslintrc",
|
||||
"env": {
|
||||
"mocha": true
|
||||
},
|
||||
"globals": {
|
||||
"sinon": false,
|
||||
"expect": false,
|
||||
"mock": false,
|
||||
"dom": false,
|
||||
"m": false
|
||||
},
|
||||
"rules": {
|
||||
"max-statements": 0,
|
||||
"no-unused-expressions": 0,
|
||||
"no-warning-comments": 0
|
||||
}
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>Mithril test suite</title>
|
||||
<div id="mocha"></div>
|
||||
|
||||
<!-- Dependencies -->
|
||||
<script src="../node_modules/chai/chai.js"></script>
|
||||
<script src="../node_modules/sinon/pkg/sinon.js" charset="utf-8"></script>
|
||||
<script src="../node_modules/sinon-chai/lib/sinon-chai.js" charset="utf-8"></script>
|
||||
<link rel="stylesheet" href="../node_modules/mocha/mocha.css">
|
||||
<script src="../node_modules/mocha/mocha.js"></script>
|
||||
|
||||
<script src="../test-deps/dom.js"></script>
|
||||
<script src="../test-deps/mock.js"></script>
|
||||
<script src="../mithril.js"></script>
|
||||
<script>
|
||||
mocha.setup("bdd")
|
||||
var expect = chai.expect
|
||||
// Temporary workaround for https://github.com/mochajs/mocha/issues/1348
|
||||
chai.config.truncateThreshold = 0
|
||||
</script>
|
||||
|
||||
<!-- Tests go here -->
|
||||
<script src="./mithril.js"></script>
|
||||
<script src="./mithril.mount.js"></script>
|
||||
<script src="./mithril.render.js"></script>
|
||||
<script src="./mithril.withAttr.js"></script>
|
||||
<script src="./mithril.trust.js"></script>
|
||||
<script src="./mithril.redraw.js"></script>
|
||||
<script src="./mithril.route.js"></script>
|
||||
<script src="./mithril.route.parseQueryString.js"></script>
|
||||
<script src="./mithril.route.buildQueryString.js"></script>
|
||||
<script src="./mithril.prop.js"></script>
|
||||
<script src="./mithril.request.js"></script>
|
||||
<script src="./mithril.deferred.js"></script>
|
||||
<script src="./mithril.sync.js"></script>
|
||||
<script src="./mithril.startComputation.js"></script>
|
||||
|
||||
<!-- Set options and run this thing -->
|
||||
<script>
|
||||
m.deps(mock)
|
||||
mocha.checkLeaks()
|
||||
mocha.globals(["m", "mochaResults"])
|
||||
|
||||
// For Saucelabs reporting
|
||||
var runner = mocha.run()
|
||||
|
||||
var failedTests = []
|
||||
|
||||
runner.on("end", function() {
|
||||
window.mochaResults = runner.stats
|
||||
window.mochaResults.reports = failedTests
|
||||
})
|
||||
|
||||
runner.on("fail", function (test, err) {
|
||||
function flattenTitles(test) {
|
||||
var titles = []
|
||||
while (test.parent.title) {
|
||||
titles.push(test.parent.title)
|
||||
test = test.parent
|
||||
}
|
||||
return titles.reverse()
|
||||
}
|
||||
|
||||
failedTests.push({
|
||||
name: test.title,
|
||||
result: false,
|
||||
message: err.message,
|
||||
stack: err.stack,
|
||||
titles: flattenTitles(test),
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
<!doctype html>
|
||||
<title>Input cursor test</title>
|
||||
<h2>Things to check:</h2>
|
||||
<ul>
|
||||
<li>
|
||||
Typing in the fields below should not move the cursor to the end of the
|
||||
input. Especially in Chrome.
|
||||
</li>
|
||||
<li>All inputs should update with the same value.</li>
|
||||
<li>
|
||||
Typing in an input should not prevent it from being updated by other
|
||||
inputs.
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div id="test"></div>
|
||||
<script src="../mithril.js"></script>
|
||||
|
||||
<script>
|
||||
function test(sel) {
|
||||
return m("li", [
|
||||
m("p", m("code", "m(" + JSON.stringify(sel) + ")")),
|
||||
m.apply(null, arguments)
|
||||
])
|
||||
}
|
||||
|
||||
m.module(document.getElementById("test"), {
|
||||
controller: function() {
|
||||
this.title = m.prop("hello world");
|
||||
},
|
||||
|
||||
view: function (ctrl) {
|
||||
return m("body", [
|
||||
m("h1", ["Title: ", ctrl.title()]),
|
||||
m("ul", [
|
||||
test("input[list=data]", {
|
||||
onkeyup: m.withAttr("value", ctrl.title),
|
||||
value: ctrl.title()
|
||||
}),
|
||||
|
||||
test("datalist#data", [
|
||||
m("option", "John"),
|
||||
m("option", "Bob"),
|
||||
m("option", "Mary")
|
||||
]),
|
||||
|
||||
test("textarea", {
|
||||
onkeyup: m.withAttr("value", ctrl.title),
|
||||
value: ctrl.title()
|
||||
}),
|
||||
|
||||
m("li", [
|
||||
m("p", "untrusted ",
|
||||
m("code", "m(\"div[contenteditable]\")")),
|
||||
m("div[contenteditable]", {
|
||||
style: {border: "1px solid #888"},
|
||||
onkeyup: m.withAttr("innerHTML", ctrl.title)
|
||||
}, ctrl.title()),
|
||||
]),
|
||||
|
||||
m("li", [
|
||||
m("p", "trusted ",
|
||||
m("code", "m(\"div[contenteditable]\")")),
|
||||
m("div[contenteditable]", {
|
||||
style: {border: "1px solid #888"},
|
||||
onkeyup: m.withAttr("innerHTML", ctrl.title)
|
||||
}, m.trust(ctrl.title())),
|
||||
])
|
||||
])
|
||||
]);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
<!doctype html>
|
||||
<!--<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.0.3/es5-shim.min.js"></script>-->
|
||||
<script src="test.js"></script>
|
||||
<script src="mock.js"></script>
|
||||
<script src="../mithril.js"></script>
|
||||
|
||||
<p>Open the console to see the test report</p>
|
||||
<script src="./isolation-test.js"></script>
|
||||
|
|
@ -1,159 +0,0 @@
|
|||
/* global m, test, mock */
|
||||
(function () {
|
||||
"use strict"
|
||||
|
||||
m.deps(mock.window)
|
||||
|
||||
test(function () { // eslint-disable-line max-statements
|
||||
var root = mock.document.createElement("div")
|
||||
var retain = false
|
||||
var flag = true
|
||||
var loaded1 = null
|
||||
var loaded2 = null
|
||||
var loaded1a = null
|
||||
var loaded2a = null
|
||||
|
||||
var Comp1 = {
|
||||
controller: function () {
|
||||
loaded1 = true
|
||||
this.onunload = function () {
|
||||
loaded1 = false
|
||||
}
|
||||
},
|
||||
view: function () {
|
||||
if (retain) {
|
||||
return {subtree: "retain"}
|
||||
} else {
|
||||
return m("a", {
|
||||
config: function (el, init, ctx) {
|
||||
if (!init) {
|
||||
loaded1a = true
|
||||
ctx.onunload = function () {
|
||||
loaded1a = false
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var Comp2 = {
|
||||
controller: function () {
|
||||
loaded2 = true
|
||||
this.onunload = function () {
|
||||
loaded2 = false
|
||||
}
|
||||
},
|
||||
view: function () {
|
||||
if (retain) {
|
||||
return {subtree: "retain"}
|
||||
} else {
|
||||
return m("b", {
|
||||
config: function (el, init, ctx) {
|
||||
if (!init) {
|
||||
loaded2a = true
|
||||
ctx.onunload = function () {
|
||||
loaded2a = false
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var Root = {
|
||||
view: function () {
|
||||
return flag ? Comp1 : Comp2
|
||||
}
|
||||
}
|
||||
|
||||
m.mount(root, Root)
|
||||
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
// loaded 1
|
||||
var result1 = loaded1 === true &&
|
||||
loaded2 === null &&
|
||||
loaded1a === true &&
|
||||
loaded2a === null
|
||||
|
||||
retain = true
|
||||
m.redraw(true)
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
// retained
|
||||
var result2 = loaded1 === true &&
|
||||
loaded2 === null &&
|
||||
loaded1a === true &&
|
||||
loaded2a === null
|
||||
|
||||
flag = false
|
||||
m.redraw(true)
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
// loaded 2 while retained: both controllers are alive at the same time
|
||||
// because dom element is retained
|
||||
var result3 = loaded1 === true &&
|
||||
loaded2 === true &&
|
||||
loaded1a === true &&
|
||||
loaded2a === null
|
||||
|
||||
retain = false
|
||||
m.redraw(true)
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
// unretained, i.e. 2 is now dynamic
|
||||
var result4 = loaded1 === false &&
|
||||
loaded2 === true &&
|
||||
loaded1a === false &&
|
||||
loaded2a === true
|
||||
|
||||
flag = true
|
||||
m.redraw(true)
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
// loaded 1 while dynamic
|
||||
var result5 = loaded1 === true &&
|
||||
loaded2 === false &&
|
||||
loaded1a === true &&
|
||||
loaded2a === false
|
||||
|
||||
return result1 && result2 && result3 && result4 && result5
|
||||
})
|
||||
|
||||
/*
|
||||
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()
|
||||
|
||||
return redraws == 1 && data.url == "/foo"
|
||||
})
|
||||
*/
|
||||
|
||||
test.print(function (value) {
|
||||
console.log(value) // eslint-disable-line no-console
|
||||
})
|
||||
})()
|
||||
|
|
@ -1,311 +0,0 @@
|
|||
describe("m.deferred()", function () {
|
||||
"use strict"
|
||||
|
||||
// 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 implementation deviates from the Promises/A+ spec in two ways:
|
||||
//
|
||||
// 1) A+ requires the `then` callback to be called asynchronously (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). This implementation calls the `then`
|
||||
// callback synchronously.
|
||||
// 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. This throws such checked exceptions.
|
||||
|
||||
it("exists", function () {
|
||||
expect(m.deferred).to.be.a("function")
|
||||
})
|
||||
|
||||
it("resolves values", function () {
|
||||
var value = m.prop()
|
||||
var deferred = m.deferred()
|
||||
|
||||
deferred.promise.then(value)
|
||||
deferred.resolve("test")
|
||||
|
||||
expect(value()).to.equal("test")
|
||||
})
|
||||
|
||||
it("resolves values returned in `then` method", function () {
|
||||
var value = m.prop()
|
||||
var deferred = m.deferred()
|
||||
|
||||
deferred.promise
|
||||
.then(function () { return "foo" })
|
||||
.then(value)
|
||||
deferred.resolve("test")
|
||||
|
||||
expect(value()).to.equal("foo")
|
||||
})
|
||||
|
||||
it("passes rejections through second `then` handler", function () {
|
||||
var obj = {}
|
||||
var value1 = m.prop(obj)
|
||||
var value2 = m.prop(obj)
|
||||
var deferred = m.deferred()
|
||||
|
||||
deferred.promise.then(value1, value2)
|
||||
deferred.reject("test")
|
||||
|
||||
expect(value1()).to.equal(obj)
|
||||
expect(value2()).to.equal("test")
|
||||
})
|
||||
|
||||
it("passes rejections through `catch`", function () {
|
||||
var value = m.prop()
|
||||
var deferred = m.deferred()
|
||||
|
||||
deferred.promise.catch(value)
|
||||
deferred.reject("test")
|
||||
|
||||
expect(value()).to.equal("test")
|
||||
})
|
||||
|
||||
it("can resolve from a `then` rejection handler", function () {
|
||||
var value = m.prop()
|
||||
var deferred = m.deferred()
|
||||
|
||||
deferred.promise
|
||||
.then(null, function () { return "foo" })
|
||||
.then(value)
|
||||
deferred.reject("test")
|
||||
|
||||
expect(value()).to.equal("foo")
|
||||
})
|
||||
|
||||
it("can resolve from a `catch`", function () {
|
||||
var value = m.prop()
|
||||
var deferred = m.deferred()
|
||||
|
||||
deferred.promise
|
||||
.catch(function () { return "foo" })
|
||||
.then(value)
|
||||
deferred.reject("test")
|
||||
|
||||
expect(value()).to.equal("foo")
|
||||
})
|
||||
|
||||
it("can reject by throwing an `Error`", function () {
|
||||
var value1 = m.prop()
|
||||
var value2 = m.prop()
|
||||
var deferred = m.deferred()
|
||||
|
||||
deferred.promise
|
||||
.then(function () { throw new Error() })
|
||||
.then(value1, value2)
|
||||
deferred.resolve("test")
|
||||
|
||||
expect(value1()).to.not.exist
|
||||
expect(value2()).to.be.an("error")
|
||||
})
|
||||
|
||||
it("synchronously throws subclasses of Errors on creation", function () {
|
||||
expect(function () {
|
||||
m.deferred().reject(new TypeError())
|
||||
}).to.throw()
|
||||
})
|
||||
|
||||
it("synchronously throws subclasses of Errors thrown from its `then` fufill handler", function () { // eslint-disable-line
|
||||
expect(function () {
|
||||
var deferred = m.deferred()
|
||||
deferred.promise.then(function () { throw new TypeError() })
|
||||
deferred.resolve()
|
||||
}).to.throw()
|
||||
})
|
||||
|
||||
it("synchronously throws subclasses of Errors thrown from its `then` rejection handler", function () { // eslint-disable-line
|
||||
expect(function () {
|
||||
var deferred = m.deferred()
|
||||
deferred.promise.then(null, function () { throw new TypeError() })
|
||||
deferred.reject("test")
|
||||
}).to.throw()
|
||||
})
|
||||
|
||||
it("synchronously throws subclasses of Errors thrown from its `catch` method", function () { // eslint-disable-line
|
||||
expect(function () {
|
||||
var deferred = m.deferred()
|
||||
deferred.promise.catch(function () { throw new TypeError() })
|
||||
deferred.reject("test")
|
||||
}).to.throw()
|
||||
})
|
||||
|
||||
it("unwraps other thenables, and returns the correct values in the chain", function () { // eslint-disable-line
|
||||
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)
|
||||
expect(value1).to.equal(1)
|
||||
expect(value2).to.equal(2)
|
||||
})
|
||||
|
||||
// https://github.com/lhorie/mithril.js/issues/80
|
||||
it("propogates returns with `then` after being resolved", function () {
|
||||
var deferred = m.deferred()
|
||||
var value = m.prop()
|
||||
deferred.resolve(1)
|
||||
deferred.promise.then(value)
|
||||
expect(value()).to.equal(1)
|
||||
})
|
||||
|
||||
// https://github.com/lhorie/mithril.js/issues/80
|
||||
it("propogates errors with `then` after being rejected", function () {
|
||||
var deferred = m.deferred()
|
||||
var value = m.prop()
|
||||
deferred.reject(1)
|
||||
deferred.promise.then(null, value)
|
||||
expect(value()).to.equal(1)
|
||||
})
|
||||
|
||||
// https://github.com/lhorie/mithril.js/issues/80
|
||||
it("can only be resolved once before being chained", function () {
|
||||
var deferred = m.deferred()
|
||||
var value = m.prop()
|
||||
deferred.resolve(1)
|
||||
deferred.resolve(2)
|
||||
deferred.promise.then(value)
|
||||
expect(value()).to.equal(1)
|
||||
})
|
||||
|
||||
// https://github.com/lhorie/mithril.js/issues/80
|
||||
it("can only be resolved once after being chained", function () {
|
||||
var deferred = m.deferred()
|
||||
var value = m.prop()
|
||||
deferred.promise.then(value)
|
||||
deferred.resolve(1)
|
||||
deferred.resolve(2)
|
||||
expect(value()).to.equal(1)
|
||||
})
|
||||
|
||||
// https://github.com/lhorie/mithril.js/issues/80
|
||||
it("can't be rejected after being resolved", function () {
|
||||
var deferred = m.deferred()
|
||||
var value1 = m.prop()
|
||||
var value2 = m.prop()
|
||||
deferred.promise.then(value1, value2)
|
||||
deferred.resolve(1)
|
||||
deferred.reject(2)
|
||||
expect(value1()).to.equal(1)
|
||||
expect(value2()).to.not.exist
|
||||
})
|
||||
|
||||
// https://github.com/lhorie/mithril.js/issues/80
|
||||
it("can't be resolved after being rejected", function () {
|
||||
var deferred = m.deferred()
|
||||
var value1 = m.prop()
|
||||
var value2 = m.prop()
|
||||
deferred.promise.then(value1, value2)
|
||||
deferred.reject(1)
|
||||
deferred.resolve(2)
|
||||
expect(value1()).to.not.exist
|
||||
expect(value2()).to.equal(1)
|
||||
})
|
||||
|
||||
// https://github.com/lhorie/mithril.js/issues/80
|
||||
it("can only be rejected once before being chained", function () {
|
||||
var deferred = m.deferred()
|
||||
var value = m.prop()
|
||||
deferred.reject(1)
|
||||
deferred.reject(2)
|
||||
deferred.promise.then(null, value)
|
||||
expect(value()).to.equal(1)
|
||||
})
|
||||
|
||||
// https://github.com/lhorie/mithril.js/issues/80
|
||||
it("can only be rejected once after being chained", function () {
|
||||
var deferred = m.deferred()
|
||||
var value = m.prop()
|
||||
deferred.promise.then(null, value)
|
||||
deferred.reject(1)
|
||||
deferred.reject(2)
|
||||
expect(value()).to.equal(1)
|
||||
})
|
||||
|
||||
// https://github.com/lhorie/mithril.js/issues/85
|
||||
it("calls resolution handler when resolved with `undefined`", function () {
|
||||
var deferred = m.deferred()
|
||||
var value
|
||||
deferred.resolve()
|
||||
deferred.promise.then(function () {
|
||||
value = 1
|
||||
})
|
||||
expect(value).to.equal(1)
|
||||
})
|
||||
|
||||
// https://github.com/lhorie/mithril.js/issues/85
|
||||
it("calls rejection handler when rejected with `undefined`", function () {
|
||||
var deferred = m.deferred()
|
||||
var value
|
||||
deferred.reject()
|
||||
deferred.promise.then(null, function () {
|
||||
value = 1
|
||||
})
|
||||
expect(value).to.equal(1)
|
||||
})
|
||||
|
||||
it("immediately resolves promise with `resolve` method", function () {
|
||||
var deferred = m.deferred()
|
||||
deferred.resolve(1)
|
||||
expect(deferred.promise()).to.equal(1)
|
||||
})
|
||||
|
||||
it("gets chained promise value when called", function () {
|
||||
var deferred = m.deferred()
|
||||
var promise = deferred.promise.then(function (data) { return data + 1 })
|
||||
deferred.resolve(1)
|
||||
expect(promise()).to.equal(2)
|
||||
})
|
||||
|
||||
it("returns `undefined` from call if it's rejected", function () {
|
||||
var deferred = m.deferred()
|
||||
deferred.reject(1)
|
||||
expect(deferred.promise()).to.be.undefined
|
||||
})
|
||||
|
||||
it("resolves to value of returned promise", function () {
|
||||
var prmA = m.deferred()
|
||||
var prmB = m.deferred()
|
||||
|
||||
prmA.resolve("A")
|
||||
prmB.resolve("B")
|
||||
|
||||
prmA.promise.then(function () {
|
||||
return prmB.promise
|
||||
}).then(function (B) {
|
||||
expect(B).to.equal("B")
|
||||
})
|
||||
})
|
||||
|
||||
it("yields immutable promises", function () {
|
||||
var d = m.deferred()
|
||||
d.resolve(5)
|
||||
d.resolve(6)
|
||||
d.promise.then(function (v) {
|
||||
expect(v).to.equal(5)
|
||||
})
|
||||
})
|
||||
})
|
||||
220
test/mithril.js
220
test/mithril.js
|
|
@ -1,220 +0,0 @@
|
|||
describe("m.version()", function () {
|
||||
"use strict"
|
||||
|
||||
it("exists", function () {
|
||||
expect(m.version).to.be.a("function")
|
||||
})
|
||||
|
||||
it("is a string", function () {
|
||||
expect(m.version()).to.be.a("string")
|
||||
})
|
||||
})
|
||||
|
||||
describe("m()", function () {
|
||||
"use strict"
|
||||
|
||||
it("exists", function () {
|
||||
expect(m).to.be.a("function")
|
||||
})
|
||||
|
||||
it("sets correct tag name", function () {
|
||||
expect(m("div")).to.have.property("tag", "div")
|
||||
})
|
||||
|
||||
it("sets correct tag name with only a class", function () {
|
||||
expect(m(".foo")).to.have.property("tag", "div")
|
||||
})
|
||||
|
||||
it("sets correct class name", function () {
|
||||
expect(m(".foo")).to.have.deep.property("attrs.className", "foo")
|
||||
})
|
||||
|
||||
it("sets correct tag name with only an attr", function () {
|
||||
expect(m("[title=bar]")).to.have.property("tag", "div")
|
||||
})
|
||||
|
||||
it("sets correct unquoted attr", function () {
|
||||
expect(m("[title=bar]")).to.have.deep.property("attrs.title", "bar")
|
||||
})
|
||||
|
||||
it("sets attr without a value as an empty string", function () {
|
||||
expect(m("[empty]")).to.have.deep.property("attrs.empty", "")
|
||||
})
|
||||
|
||||
it("sets correct single quoted attr", function () {
|
||||
expect(m("[title=\'bar\']")).to.have.deep.property("attrs.title", "bar")
|
||||
})
|
||||
|
||||
it("sets correct double quoted attr", function () {
|
||||
expect(m("[title=\"bar\"]")).to.have.deep.property("attrs.title", "bar")
|
||||
})
|
||||
|
||||
it("sets correct children with 1 string arg", function () {
|
||||
expect(m("div", "test"))
|
||||
.to.have.property("children")
|
||||
.that.eqls(["test"])
|
||||
})
|
||||
|
||||
it("sets correct children with multiple string args", function () {
|
||||
expect(m("div", "test", "test2"))
|
||||
.to.have.property("children")
|
||||
.that.eqls(["test", "test2"])
|
||||
})
|
||||
|
||||
it("sets correct children with string array", function () {
|
||||
expect(m("div", ["test"]))
|
||||
.to.have.property("children")
|
||||
.that.eqls(["test"])
|
||||
})
|
||||
|
||||
it("sets correct attrs with object", function () {
|
||||
expect(m("div", {title: "bar"}, "test"))
|
||||
.to.have.deep.property("attrs.title", "bar")
|
||||
})
|
||||
|
||||
it("sets correct children with attrs object", function () {
|
||||
expect(m("div", {title: "bar"}, "test"))
|
||||
.to.have.property("children")
|
||||
.that.eqls(["test"])
|
||||
})
|
||||
|
||||
it("sets correct children with nested node", function () {
|
||||
expect(m("div", {title: "bar"}, m("div")))
|
||||
.to.have.property("children")
|
||||
.that.eqls([m("div")])
|
||||
})
|
||||
|
||||
it("sets correct children with string rest arg", function () {
|
||||
expect(m("div", {title: "bar"}, "test0", "test1", "test2", "test3"))
|
||||
.to.have.property("children")
|
||||
.that.eqls(["test0", "test1", "test2", "test3"])
|
||||
})
|
||||
|
||||
it("sets correct children with node rest arg", function () {
|
||||
expect(m("div", {title: "bar"}, m("div"), m("i"), m("span")))
|
||||
.to.have.property("children")
|
||||
.that.eqls([m("div"), m("i"), m("span")])
|
||||
})
|
||||
|
||||
it("sets correct children with string array & no attrs", function () {
|
||||
expect(m("div", ["a", "b"]))
|
||||
.to.have.property("children")
|
||||
.that.eqls(["a", "b"])
|
||||
})
|
||||
|
||||
it("sets correct children with node array & no attrs", function () {
|
||||
expect(m("div", [m("div"), m("i")]))
|
||||
.to.have.property("children")
|
||||
.that.eqls([m("div"), m("i")])
|
||||
})
|
||||
|
||||
it("sets correct children with 2nd arg as node", function () {
|
||||
expect(m("div", m("div"))).to.have.property("children")
|
||||
.that.eqls([m("div")])
|
||||
})
|
||||
|
||||
it("sets correct tag with undefined array entry", function () {
|
||||
expect(m("div", [undefined])).to.have.property("tag", "div")
|
||||
})
|
||||
|
||||
it("loosely accepts invalid objects", function () {
|
||||
expect(function () { m("div", [{foo: "bar"}]) }).to.not.throw()
|
||||
})
|
||||
|
||||
it("accepts svg nodes", function () {
|
||||
expect(m("svg", [m("g")]))
|
||||
.to.have.property("children")
|
||||
.that.eqls([m("g")])
|
||||
})
|
||||
|
||||
it("accepts HTML children in svg element", function () {
|
||||
expect(m("svg", [m("a[href='http://google.com']")]))
|
||||
.to.have.property("children")
|
||||
.that.eqls([m("a[href='http://google.com']")])
|
||||
})
|
||||
|
||||
it("uses className if given", function () {
|
||||
expect(m(".foo", {className: ""}))
|
||||
.to.have.deep.property("attrs.className", "foo")
|
||||
})
|
||||
|
||||
it("accepts a class and class attr", function () {
|
||||
var node = m(".foo", {class: "bar"})
|
||||
expect(node).to.have.deep.property("attrs.class")
|
||||
expect(node.attrs.class).to.include("foo").and.include("bar")
|
||||
})
|
||||
|
||||
it("accepts a class and className attr", function () {
|
||||
var node = m(".foo", {className: "bar"})
|
||||
expect(node).to.have.deep.property("attrs.className")
|
||||
expect(node.attrs.className).to.include("foo").and.include("bar")
|
||||
})
|
||||
|
||||
// https://github.com/lhorie/mithril.js/issues/382 and 512
|
||||
it("sets an empty className attr if it's an empty string", function () {
|
||||
expect(m("div", {className: ""}))
|
||||
.to.have.deep.property("attrs.className", "")
|
||||
})
|
||||
|
||||
it("does not set className attr if class is given", function () {
|
||||
expect(m("div", {class: ""})).to.not.have.property("attrs.className")
|
||||
})
|
||||
|
||||
it("does not set class attr if className is given", function () {
|
||||
expect(m("div", {className: ""})).to.not.have.property("attrs.class")
|
||||
})
|
||||
|
||||
it("sets an empty class attr if it's an empty string", function () {
|
||||
expect(m("div", {class: ""})).to.have.deep.property("attrs.class", "")
|
||||
})
|
||||
|
||||
it("does not flatten 1 nested array", function () {
|
||||
expect(m("div", [1, 2, 3], 4))
|
||||
.to.have.property("children")
|
||||
.that.eqls([[1, 2, 3], 4])
|
||||
})
|
||||
|
||||
it("does not flatten 2 nested arrays", function () {
|
||||
expect(m("div", [1, 2, 3], [4, 5, 6, 7]))
|
||||
.to.have.property("children")
|
||||
.that.eqls([[1, 2, 3], [4, 5, 6, 7]])
|
||||
})
|
||||
|
||||
it("does not flatten 3 nested arrays", function () {
|
||||
expect(m("div", [1], [2], [3]))
|
||||
.to.have.property("children")
|
||||
.that.eqls([[1], [2], [3]])
|
||||
})
|
||||
|
||||
it("doesn't recreate the DOM when classes are different", function () {
|
||||
var v1 = m(".foo", {class: "", onclick: function () {}})
|
||||
var v2 = m(".foo", {class: "bar", onclick: function () {}})
|
||||
|
||||
expect(v1)
|
||||
.to.have.property("attrs")
|
||||
.that.contains.all.keys("class", "onclick")
|
||||
|
||||
expect(v2)
|
||||
.to.have.property("attrs")
|
||||
.that.contains.all.keys("class", "onclick")
|
||||
})
|
||||
|
||||
it("proxies an object first arg to m.component()", function () {
|
||||
var spy = sinon.spy()
|
||||
|
||||
var component = {
|
||||
controller: spy,
|
||||
view: function () {
|
||||
return m("div", "testing")
|
||||
}
|
||||
}
|
||||
|
||||
var args = {age: 12}
|
||||
|
||||
m(component, args).controller()
|
||||
expect(spy.firstCall).to.have.been.calledWith(args)
|
||||
|
||||
m.component(component, args).controller()
|
||||
expect(spy.secondCall).to.have.been.calledWith(args)
|
||||
})
|
||||
})
|
||||
|
|
@ -1,798 +0,0 @@
|
|||
describe("m.mount()", function () {
|
||||
"use strict"
|
||||
|
||||
// This is a frequent idiom
|
||||
function refresh(force) {
|
||||
m.redraw(!!force)
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
}
|
||||
|
||||
function clear(root) {
|
||||
m.mount(root, null)
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
}
|
||||
|
||||
function mount(root, mod) {
|
||||
var res = m.mount(root, mod)
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
return res
|
||||
}
|
||||
|
||||
// This is extremely frequent in the tests
|
||||
function pure(view) {
|
||||
return {
|
||||
controller: function () {},
|
||||
view: view
|
||||
}
|
||||
}
|
||||
|
||||
it("exists", function () {
|
||||
expect(m.mount).to.be.a("function")
|
||||
})
|
||||
|
||||
it("mounts onto the root", function () {
|
||||
var root = mock.document.createElement("div")
|
||||
var whatever = 1
|
||||
|
||||
var app = pure(function () {
|
||||
return [
|
||||
whatever % 2 ? m("span", "% 2") : undefined,
|
||||
m("div", "bugs"),
|
||||
m("a")
|
||||
]
|
||||
})
|
||||
|
||||
mount(root, app)
|
||||
|
||||
whatever++
|
||||
refresh()
|
||||
|
||||
whatever++
|
||||
refresh()
|
||||
|
||||
expect(root.childNodes).to.have.length.above(0)
|
||||
})
|
||||
|
||||
it("reloads components correctly", function () {
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
var root1 = mock.document.createElement("div")
|
||||
var controller1 = sinon.spy(function () { this.value = "test1" }) // eslint-disable-line
|
||||
var view1 = sinon.stub().returns("test1")
|
||||
|
||||
var mod1 = m.mount(root1, {
|
||||
controller: controller1,
|
||||
view: view1
|
||||
})
|
||||
|
||||
var controller2 = sinon.spy(function () { this.value = "test2" }) // eslint-disable-line
|
||||
var view2 = sinon.stub().returns("test2")
|
||||
var root2 = mock.document.createElement("div")
|
||||
|
||||
var mod2 = mount(root2, {
|
||||
controller: controller2,
|
||||
view: view2
|
||||
})
|
||||
|
||||
expect(controller1).to.have.been.called
|
||||
expect(view1).to.have.been.called
|
||||
expect(controller2).to.have.been.called
|
||||
expect(view2).to.have.been.called
|
||||
|
||||
expect(root1.childNodes[0].nodeValue).to.equal("test1")
|
||||
expect(root2.childNodes[0].nodeValue).to.equal("test2")
|
||||
expect(mod1).to.have.property("value", "test1")
|
||||
expect(mod2).to.have.property("value", "test2")
|
||||
})
|
||||
|
||||
it("triggers an unload when the element is removed", function () {
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
var root = mock.document.createElement("div")
|
||||
var spy = sinon.spy()
|
||||
|
||||
mount(root, {
|
||||
controller: function () {
|
||||
this.onunload = spy
|
||||
},
|
||||
view: function () {}
|
||||
})
|
||||
|
||||
clear(root)
|
||||
|
||||
expect(spy).to.have.been.called
|
||||
})
|
||||
|
||||
it("passes the args to both component & view", function () {
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
var root = mock.document.createElement("div")
|
||||
var ctrlSpy = sinon.spy()
|
||||
var viewSpy = sinon.stub().returns(m("div"))
|
||||
|
||||
var component = {
|
||||
controller: ctrlSpy,
|
||||
view: viewSpy
|
||||
}
|
||||
|
||||
var arg = {}
|
||||
|
||||
mount(root, m.component(component, arg))
|
||||
|
||||
expect(ctrlSpy).to.have.been.calledWith(arg)
|
||||
expect(viewSpy.firstCall.args[1]).to.equal(arg)
|
||||
})
|
||||
|
||||
it("mounts a component without a controller", function () {
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
var root = mock.document.createElement("div")
|
||||
var arg = {}
|
||||
var spy = sinon.spy()
|
||||
|
||||
var component = pure(spy)
|
||||
|
||||
mount(root, m.component(component, arg))
|
||||
|
||||
expect(spy.firstCall.args[1]).to.equal(arg)
|
||||
})
|
||||
|
||||
it("only runs a component controller once", function () {
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
var root = mock.document.createElement("div")
|
||||
var ctrlSpy = sinon.spy()
|
||||
var viewSpy = sinon.stub().returns(m("div"))
|
||||
|
||||
var sub = {
|
||||
controller: ctrlSpy,
|
||||
view: viewSpy
|
||||
}
|
||||
|
||||
mount(root, pure(function () { return sub }))
|
||||
|
||||
refresh(true)
|
||||
|
||||
expect(ctrlSpy).to.have.been.calledOnce
|
||||
expect(viewSpy).to.have.been.calledTwice
|
||||
})
|
||||
|
||||
it("only runs a subcomponent controller once", function () {
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
var root = mock.document.createElement("div")
|
||||
var ctrl1 = sinon.spy()
|
||||
var view1 = sinon.stub().returns(m("div"))
|
||||
|
||||
var subsub = {
|
||||
controller: ctrl1,
|
||||
view: view1
|
||||
}
|
||||
|
||||
var ctrl2 = sinon.spy()
|
||||
var view2 = sinon.stub().returns(subsub)
|
||||
|
||||
var sub = {
|
||||
controller: ctrl2,
|
||||
view: view2
|
||||
}
|
||||
|
||||
mount(root, pure(function () { return sub }))
|
||||
|
||||
refresh(true)
|
||||
|
||||
expect(ctrl1).to.have.been.calledOnce
|
||||
expect(ctrl2).to.have.been.calledOnce
|
||||
expect(view1).to.have.been.calledTwice
|
||||
expect(view2).to.have.been.calledTwice
|
||||
})
|
||||
|
||||
it("addresses keys in components", function () {
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
var root = mock.document.createElement("div")
|
||||
var list = [1, 2, 3]
|
||||
|
||||
var sub = pure(function () { return m("div") })
|
||||
|
||||
m.mount(root, pure(function () {
|
||||
return list.map(function (i) {
|
||||
return m.component(sub, {key: i})
|
||||
})
|
||||
}))
|
||||
|
||||
var firstBefore = root.childNodes[0]
|
||||
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
list.reverse()
|
||||
refresh(true)
|
||||
|
||||
expect(root.childNodes[2]).to.equal(firstBefore)
|
||||
})
|
||||
|
||||
it("addresses keys in subcomponents correctly", function () {
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
var root = mock.document.createElement("div")
|
||||
var list = [1, 2, 3]
|
||||
|
||||
var subsub = pure(function () { return m("div") })
|
||||
|
||||
var sub = pure(function () { return subsub })
|
||||
|
||||
m.mount(root, pure(function () {
|
||||
return list.map(function (i) {
|
||||
return m.component(sub, {key: i})
|
||||
})
|
||||
}))
|
||||
|
||||
var firstBefore = root.childNodes[0]
|
||||
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
list.reverse()
|
||||
refresh(true)
|
||||
|
||||
expect(root.childNodes[2]).to.equal(firstBefore)
|
||||
})
|
||||
|
||||
it("is error resistant with keys in components", function () {
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
var root = mock.document.createElement("div")
|
||||
var list = [1, 2, 3]
|
||||
|
||||
var sub = pure(function () { return m("div", {key: 1}) })
|
||||
|
||||
m.mount(root, pure(function () {
|
||||
return list.map(function (i) {
|
||||
return m.component(sub, {key: i})
|
||||
})
|
||||
}))
|
||||
|
||||
var firstBefore = root.childNodes[0]
|
||||
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
list.reverse()
|
||||
refresh(true)
|
||||
|
||||
expect(root.childNodes[2]).to.equal(firstBefore)
|
||||
})
|
||||
|
||||
it("is error resistant with keys in subcomponents", function () {
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
var root = mock.document.createElement("div")
|
||||
var list = [1, 2, 3]
|
||||
|
||||
var subsub = pure(function () { return m("div", {key: 1}) })
|
||||
|
||||
var sub = pure(function () { return subsub })
|
||||
|
||||
m.mount(root, pure(function () {
|
||||
return list.map(function (i) {
|
||||
return m.component(sub, {key: i})
|
||||
})
|
||||
}))
|
||||
|
||||
var firstBefore = root.childNodes[0]
|
||||
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
list.reverse()
|
||||
refresh(true)
|
||||
|
||||
expect(root.childNodes[2]).to.equal(firstBefore)
|
||||
})
|
||||
|
||||
it("retains subcomponent identity if child of keyed element", function () {
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
var root = mock.document.createElement("div")
|
||||
var list = [1, 2, 3]
|
||||
|
||||
var sub = pure(function () { return m("div") })
|
||||
|
||||
m.mount(root, pure(function () {
|
||||
return list.map(function (i) {
|
||||
return m("div", {key: i}, sub)
|
||||
})
|
||||
}))
|
||||
|
||||
var firstBefore = root.childNodes[0].childNodes[0]
|
||||
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
list.reverse()
|
||||
refresh(true)
|
||||
|
||||
expect(root.childNodes[2].childNodes[0]).to.equal(firstBefore)
|
||||
})
|
||||
|
||||
it("calls component onunload when removed from template", function () {
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
var root = mock.document.createElement("div")
|
||||
var list = [1, 2, 3]
|
||||
var spies = []
|
||||
|
||||
var sub = {
|
||||
controller: function (opts) {
|
||||
this.onunload = spies[opts.key] = sinon.spy()
|
||||
},
|
||||
view: function () {
|
||||
return m("div")
|
||||
}
|
||||
}
|
||||
|
||||
mount(root, pure(function () {
|
||||
return list.map(function (i) {
|
||||
return m.component(sub, {key: i})
|
||||
})
|
||||
}))
|
||||
|
||||
list = []
|
||||
refresh(true)
|
||||
|
||||
expect(spies[1]).to.have.been.called
|
||||
expect(spies[2]).to.have.been.called
|
||||
expect(spies[3]).to.have.been.called
|
||||
})
|
||||
|
||||
it("calls subcomponent onunload when removed from template", function () {
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
var root = mock.document.createElement("div")
|
||||
var list = [1, 2, 3]
|
||||
var spies1 = []
|
||||
var spies2 = []
|
||||
|
||||
var subsub = {
|
||||
controller: function (opts) {
|
||||
this.onunload = spies1[opts.key] = sinon.spy()
|
||||
},
|
||||
view: function () {
|
||||
return m("div")
|
||||
}
|
||||
}
|
||||
|
||||
var sub = {
|
||||
controller: function (opts) {
|
||||
this.onunload = spies2[opts.key] = sinon.spy()
|
||||
},
|
||||
view: function (ctrl, opts) {
|
||||
return m.component(subsub, {key: opts.key})
|
||||
}
|
||||
}
|
||||
|
||||
mount(root, pure(function () {
|
||||
return list.map(function (i) {
|
||||
return m.component(sub, {key: i})
|
||||
})
|
||||
}))
|
||||
|
||||
list = []
|
||||
refresh(true)
|
||||
|
||||
expect(spies1[1]).to.have.been.called
|
||||
expect(spies1[2]).to.have.been.called
|
||||
expect(spies1[3]).to.have.been.called
|
||||
|
||||
expect(spies2[1]).to.have.been.called
|
||||
expect(spies2[2]).to.have.been.called
|
||||
expect(spies2[3]).to.have.been.called
|
||||
})
|
||||
|
||||
it("doesn't redraw if m.render() is called by controller constructor", function () { // eslint-disable-line
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
var root = mock.document.createElement("div")
|
||||
var spy = sinon.stub().returns(m("div"))
|
||||
|
||||
var sub = {
|
||||
controller: function () {
|
||||
m.redraw()
|
||||
},
|
||||
view: spy
|
||||
}
|
||||
|
||||
mount(root, pure(function () { return sub }))
|
||||
|
||||
expect(spy).to.have.been.called
|
||||
})
|
||||
|
||||
it("doesn't redraw if m.render() is called by subcomponent controller constructor", function () { // eslint-disable-line
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
var root = mock.document.createElement("div")
|
||||
var spy = sinon.stub().returns(m("div"))
|
||||
|
||||
var subsub = {
|
||||
controller: function () {
|
||||
m.redraw()
|
||||
},
|
||||
view: spy
|
||||
}
|
||||
|
||||
var sub = pure(function () { return subsub })
|
||||
|
||||
mount(root, pure(function () { return sub }))
|
||||
|
||||
expect(spy).to.have.been.called
|
||||
})
|
||||
|
||||
it("renders nested components under keyed components", function () {
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
var root = mock.document.createElement("div")
|
||||
var spy = sinon.stub().returns(m(".reply"))
|
||||
|
||||
var Reply = pure(spy)
|
||||
|
||||
var CommentList = pure(function (ctrl, props) {
|
||||
return m(".list", props.list.map(function (i) {
|
||||
return m(".comment", [
|
||||
m.component(Reply, {key: i})
|
||||
])
|
||||
}))
|
||||
})
|
||||
|
||||
mount(root, pure(function () {
|
||||
return m(".outer", [
|
||||
m(".inner", m.component(CommentList, {list: [1, 2, 3]}))
|
||||
])
|
||||
}))
|
||||
|
||||
expect(spy).to.have.been.calledThrice
|
||||
})
|
||||
|
||||
it("calls unload when the component is replaced with another component", function () { // eslint-disable-line
|
||||
var root = mock.document.createElement("div")
|
||||
var spy = sinon.spy()
|
||||
|
||||
m.mount(root, {
|
||||
controller: function () {
|
||||
this.onunload = spy
|
||||
},
|
||||
view: function () {}
|
||||
})
|
||||
|
||||
m.mount(root, pure(function () {}))
|
||||
|
||||
expect(spy).to.have.been.called
|
||||
})
|
||||
|
||||
it("calls config with truthy init only once", function () {
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
var root = mock.document.createElement("div")
|
||||
var count = 0
|
||||
|
||||
mount(root, pure(function () {
|
||||
return m("div", {
|
||||
config: function (el, init) {
|
||||
if (init) count += 1
|
||||
}
|
||||
})
|
||||
}))
|
||||
|
||||
refresh()
|
||||
|
||||
expect(count).to.equal(1)
|
||||
})
|
||||
|
||||
it("doesn't recreate node that modifies DOM in config, but stays same between redraws", function () { // eslint-disable-line
|
||||
var root = mock.document.createElement("div")
|
||||
var child = mock.document.createElement("div")
|
||||
|
||||
var show = true
|
||||
|
||||
function test(el, init) {
|
||||
if (!init) {
|
||||
root.appendChild(child)
|
||||
}
|
||||
}
|
||||
|
||||
mount(root, pure(function () {
|
||||
return [
|
||||
m(".foo", {
|
||||
key: 1,
|
||||
config: test,
|
||||
onclick: function () { show = !show }
|
||||
}),
|
||||
show ? m(".bar", {key: 2}) : null
|
||||
]
|
||||
}))
|
||||
|
||||
show = false
|
||||
refresh()
|
||||
|
||||
show = true
|
||||
refresh()
|
||||
|
||||
expect(root.childNodes).to.have.length(3)
|
||||
})
|
||||
|
||||
it("correctly replaces nodes", function () {
|
||||
var root = mock.document.createElement("div")
|
||||
var show = true
|
||||
|
||||
var sub = pure(function () { return m("div", "component") })
|
||||
|
||||
mount(root, pure(function () {
|
||||
return show ? [
|
||||
m("h1", "1"),
|
||||
sub
|
||||
] : [
|
||||
m("h1", "2")
|
||||
]
|
||||
}))
|
||||
|
||||
show = false
|
||||
refresh()
|
||||
|
||||
show = true
|
||||
refresh()
|
||||
|
||||
expect(root.childNodes).to.have.length(2)
|
||||
})
|
||||
|
||||
// https://github.com/lhorie/mithril.js/issues/551
|
||||
it("only redraws a component when clicked", function () {
|
||||
var root = mock.document.createElement("div")
|
||||
var a = false
|
||||
var found = {}
|
||||
|
||||
var onunload = sinon.spy()
|
||||
var view = sinon.spy(function () {
|
||||
return m("div", {config: Comp.config}, [ // eslint-disable-line
|
||||
m("div", {
|
||||
onclick: function () {
|
||||
a = !a
|
||||
m.redraw(true)
|
||||
found = root.childNodes[0].childNodes[1]
|
||||
}
|
||||
}, "asd"),
|
||||
a ? m("#a", "aaa") : null,
|
||||
"test"
|
||||
])
|
||||
})
|
||||
|
||||
var Comp = {
|
||||
view: view,
|
||||
|
||||
config: function (el, init, ctx) {
|
||||
if (!init) ctx.onunload = onunload
|
||||
}
|
||||
}
|
||||
|
||||
m.mount(root, pure(function () { return Comp }))
|
||||
|
||||
var target = root.childNodes[0].childNodes[0]
|
||||
|
||||
target.onclick({currentTarget: target})
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
expect(onunload).to.not.be.called
|
||||
expect(found).to.have.property("id", "a")
|
||||
expect(view).to.have.been.calledThrice
|
||||
})
|
||||
|
||||
// https://github.com/lhorie/mithril.js/issues/551
|
||||
it("only redraws a component when clicked if the strategy is `none`", function () { // eslint-disable-line
|
||||
var root = mock.document.createElement("div")
|
||||
var a = false
|
||||
var found = {}
|
||||
|
||||
var onunload = sinon.spy()
|
||||
var view = sinon.spy(function () {
|
||||
return m("div", {config: Comp.config}, [ // eslint-disable-line
|
||||
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"
|
||||
])
|
||||
})
|
||||
|
||||
var Comp = {
|
||||
view: view,
|
||||
|
||||
config: function (el, init, ctx) {
|
||||
if (!init) ctx.onunload = onunload
|
||||
}
|
||||
}
|
||||
|
||||
m.mount(root, pure(function () { return Comp }))
|
||||
|
||||
var target = root.childNodes[0].childNodes[0]
|
||||
|
||||
target.onclick({currentTarget: target})
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
expect(onunload).to.not.be.called
|
||||
expect(found).to.have.property("id", "a")
|
||||
expect(view).to.have.been.calledTwice
|
||||
})
|
||||
|
||||
it("redraws when clicked and click handler forces redraw", function () {
|
||||
var root = mock.document.createElement("div")
|
||||
var view = sinon.stub().returns(m("div", {
|
||||
onclick: function () { m.redraw(true) }
|
||||
}))
|
||||
|
||||
m.mount(root, pure(view))
|
||||
|
||||
var target = root.childNodes[0]
|
||||
|
||||
target.onclick({currentTarget: target})
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
expect(view).to.be.calledThrice
|
||||
})
|
||||
|
||||
function resolveXhr() {
|
||||
mock.XMLHttpRequest.$instances.pop().$resolve().onreadystatechange()
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
}
|
||||
|
||||
it("doesn't redraw on a single synchronous request", function () {
|
||||
var root = mock.document.createElement("div")
|
||||
|
||||
var data
|
||||
var view = sinon.spy(function (ctrl) {
|
||||
data = ctrl.foo()
|
||||
return m("div")
|
||||
})
|
||||
|
||||
var Comp = {
|
||||
controller: function () {
|
||||
this.foo = m.request({method: "GET", url: "/foo"})
|
||||
},
|
||||
|
||||
view: view
|
||||
}
|
||||
|
||||
mount(root, pure(function () { return Comp }))
|
||||
|
||||
resolveXhr()
|
||||
|
||||
clear(root)
|
||||
|
||||
expect(view).to.be.calledOnce
|
||||
expect(data).to.have.property("url", "/foo")
|
||||
})
|
||||
|
||||
it("doesn't redraw on multiple synchronous requests", function () {
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
mock.location.search = "?"
|
||||
|
||||
var root = mock.document.createElement("div")
|
||||
var view1 = sinon.stub().returns(m("div"))
|
||||
var view2 = sinon.stub().returns(m("div"))
|
||||
|
||||
var Comp1 = {
|
||||
controller: function () {
|
||||
this.foo = m.request({method: "GET", url: "/foo"})
|
||||
},
|
||||
view: view1
|
||||
}
|
||||
|
||||
var Comp2 = {
|
||||
controller: function () {
|
||||
this.bar = m.request({method: "GET", url: "/bar"})
|
||||
},
|
||||
view: view2
|
||||
}
|
||||
|
||||
mount(root, pure(function () {
|
||||
return m("div", [
|
||||
Comp1,
|
||||
Comp2
|
||||
])
|
||||
}))
|
||||
|
||||
resolveXhr()
|
||||
resolveXhr()
|
||||
|
||||
clear(root)
|
||||
|
||||
expect(view1).to.be.calledOnce
|
||||
expect(view2).to.be.calledOnce
|
||||
})
|
||||
|
||||
it("instantiates different controllers for components without controller constructors", function () { // eslint-disable-line
|
||||
var root = mock.document.createElement("div")
|
||||
|
||||
var cond = true
|
||||
var controller1, controller2
|
||||
|
||||
var Comp1 = pure(function (ctrl) {
|
||||
controller1 = ctrl
|
||||
return m("div")
|
||||
})
|
||||
|
||||
var Comp2 = pure(function (ctrl) {
|
||||
controller2 = ctrl
|
||||
return m("div")
|
||||
})
|
||||
|
||||
mount(root, pure(function () { return cond ? Comp1 : Comp2 }))
|
||||
|
||||
cond = false
|
||||
refresh(true)
|
||||
|
||||
expect(controller1).to.not.equal(controller2)
|
||||
})
|
||||
|
||||
it("unloads removed components", function () {
|
||||
var root = mock.document.createElement("div")
|
||||
|
||||
var onunload = sinon.spy()
|
||||
var cond = true
|
||||
|
||||
var Comp1 = pure(function () {
|
||||
return m("div", {
|
||||
config: function (el, init, ctx) {
|
||||
ctx.onunload = onunload
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
var Comp2 = pure(function () { return m("div") })
|
||||
|
||||
mount(root, pure(function () { return cond ? Comp1 : Comp2 }))
|
||||
|
||||
cond = false
|
||||
refresh(true)
|
||||
|
||||
expect(onunload).to.be.called
|
||||
})
|
||||
|
||||
it("calls config with its second argument false first", function () {
|
||||
var root = mock.document.createElement("div")
|
||||
|
||||
var cond = true
|
||||
var config = sinon.spy()
|
||||
|
||||
var Comp1 = pure(function () { return m("div") })
|
||||
var Comp2 = pure(function () { return m("div", {config: config}) })
|
||||
|
||||
mount(root, pure(function () { return cond ? Comp1 : Comp2 }))
|
||||
|
||||
cond = false
|
||||
refresh(true)
|
||||
|
||||
expect(config.firstCall.args[1]).to.be.false
|
||||
})
|
||||
|
||||
it("refreshes the component when it's redrawn in a handler", function () {
|
||||
var root = mock.document.createElement("div")
|
||||
var sub = pure(function () { return m("#bar", "test") })
|
||||
var el
|
||||
|
||||
m.mount(root, pure(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(sub) : ""
|
||||
])
|
||||
}))
|
||||
|
||||
root.childNodes[0].childNodes[0].onclick({})
|
||||
|
||||
expect(el).to.have.property("id", "bar")
|
||||
})
|
||||
})
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
describe("m.prop()", function () {
|
||||
"use strict"
|
||||
|
||||
it("reads correct value", function () {
|
||||
var prop = m.prop("test")
|
||||
expect(prop()).to.equal("test")
|
||||
})
|
||||
|
||||
it("defaults to `undefined`", function () {
|
||||
var prop = m.prop()
|
||||
expect(prop()).to.be.undefined
|
||||
})
|
||||
|
||||
it("sets the correct value", function () {
|
||||
var prop = m.prop("test")
|
||||
prop("foo")
|
||||
expect(prop()).to.equal("foo")
|
||||
})
|
||||
|
||||
it("sets `null`", function () {
|
||||
var prop = m.prop(null)
|
||||
expect(prop()).to.be.null
|
||||
})
|
||||
|
||||
it("sets `undefined`", function () {
|
||||
var prop = m.prop(undefined)
|
||||
expect(prop()).to.be.undefined
|
||||
})
|
||||
|
||||
it("returns the new value when set", function () {
|
||||
var prop = m.prop()
|
||||
expect(prop("foo")).to.equal("foo")
|
||||
})
|
||||
|
||||
it("correctly stringifies to the correct value", function () {
|
||||
var prop = m.prop("test")
|
||||
expect(JSON.stringify(prop)).to.equal('"test"')
|
||||
})
|
||||
|
||||
it("correctly stringifies to the correct value as a child", function () {
|
||||
var obj = {prop: m.prop("test")}
|
||||
expect(JSON.stringify(obj)).to.equal('{"prop":"test"}')
|
||||
})
|
||||
|
||||
it("correctly wraps Mithril promises", function () {
|
||||
var defer = m.deferred()
|
||||
var prop = m.prop(defer.promise)
|
||||
defer.resolve("test")
|
||||
|
||||
expect(prop()).to.equal("test")
|
||||
})
|
||||
|
||||
it("returns a thenable when wrapping a Mithril promise", function () {
|
||||
var defer = m.deferred()
|
||||
|
||||
var prop = m.prop(defer.promise).then(function () {
|
||||
return "test2"
|
||||
})
|
||||
|
||||
defer.resolve("test")
|
||||
|
||||
expect(prop()).to.equal("test2")
|
||||
})
|
||||
})
|
||||
|
|
@ -1,220 +0,0 @@
|
|||
describe("m.redraw()", function () {
|
||||
"use strict"
|
||||
|
||||
beforeEach(function () {
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
})
|
||||
|
||||
it("exists", function () {
|
||||
expect(m.redraw).to.be.a("function")
|
||||
})
|
||||
|
||||
it("correctly renders a property if the controller value changes", function () { // eslint-disable-line
|
||||
var ctx
|
||||
var root = mock.document.createElement("div")
|
||||
|
||||
m.mount(root, {
|
||||
controller: function () { ctx = this }, // eslint-disable-line
|
||||
view: function (ctrl) { return ctrl.value }
|
||||
})
|
||||
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
var valueBefore = root.childNodes[0].nodeValue
|
||||
ctx.value = "foo"
|
||||
|
||||
m.redraw()
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
expect(valueBefore).to.equal("")
|
||||
expect(root.childNodes[0].nodeValue).to.equal("foo")
|
||||
})
|
||||
|
||||
it("runs unnecessary redraws asynchronously", function () {
|
||||
var root = mock.document.createElement("div")
|
||||
var view = sinon.spy()
|
||||
|
||||
m.mount(root, {
|
||||
controller: function () {},
|
||||
view: view
|
||||
})
|
||||
mock.requestAnimationFrame.$resolve() // teardown
|
||||
m.redraw()
|
||||
|
||||
// These should run asynchronously
|
||||
m.redraw()
|
||||
m.redraw()
|
||||
m.redraw()
|
||||
mock.requestAnimationFrame.$resolve() // teardown
|
||||
|
||||
expect(view).to.be.calledThrice
|
||||
})
|
||||
|
||||
it("runs unnecessary forced redraws asynchronously", function () {
|
||||
var root = mock.document.createElement("div")
|
||||
var view = sinon.spy()
|
||||
m.mount(root, {
|
||||
controller: function () {},
|
||||
view: view
|
||||
})
|
||||
mock.requestAnimationFrame.$resolve() // teardown
|
||||
m.redraw(true)
|
||||
|
||||
// These should run asynchronously
|
||||
m.redraw(true)
|
||||
m.redraw(true)
|
||||
m.redraw(true)
|
||||
mock.requestAnimationFrame.$resolve() // teardown
|
||||
|
||||
expect(view).to.have.callCount(5)
|
||||
})
|
||||
|
||||
context("m.redraw.strategy()", function () {
|
||||
// Use this instead of m.route() unless you have to call m.route and do
|
||||
// something else in the same frame.
|
||||
function route() {
|
||||
var res = m.route.apply(null, arguments)
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
return res
|
||||
}
|
||||
|
||||
// Little helper utility
|
||||
function noop() {}
|
||||
|
||||
// Use this if all you need to do is render a view (i.e. a pure
|
||||
// component).
|
||||
function pure(view) {
|
||||
return {
|
||||
controller: noop,
|
||||
view: view
|
||||
}
|
||||
}
|
||||
|
||||
// Use these instead of `it` and `xit` in this set of tests if you need
|
||||
// a root element.
|
||||
var dit = makeIt(it)
|
||||
|
||||
// Wraps the `it` function for dependency injection that doesn't require
|
||||
// `this`
|
||||
/* eslint-disable no-invalid-this */
|
||||
function makeIt(it) {
|
||||
return function (name, callback) {
|
||||
return it(name, function () {
|
||||
var args = [this.root]
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
args.push(arguments[i])
|
||||
}
|
||||
callback.apply(null, args)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
mock.location.search = "?"
|
||||
m.route.mode = "search"
|
||||
this.root = mock.document.createElement("div")
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
m.mount(this.root, null)
|
||||
})
|
||||
/* eslint-enable no-invalid-this */
|
||||
|
||||
it("exists", function () {
|
||||
expect(m.redraw.strategy).to.be.a("function")
|
||||
})
|
||||
|
||||
dit("works with \"all\"", function (root) {
|
||||
var strategy
|
||||
|
||||
route(root, "/foo1", {
|
||||
"/foo1": {
|
||||
controller: function () {
|
||||
strategy = m.redraw.strategy()
|
||||
m.redraw.strategy("none")
|
||||
},
|
||||
view: function () {
|
||||
return m("div")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
expect(strategy).to.equal("all")
|
||||
expect(root.childNodes).to.be.empty
|
||||
})
|
||||
|
||||
dit("works with \"redraw\"", function (root) {
|
||||
var count = 0
|
||||
var strategy
|
||||
function config(el, init) {
|
||||
if (!init) count++
|
||||
}
|
||||
|
||||
route(root, "/foo1", {
|
||||
"/foo1": pure(function () {
|
||||
return m("div", {config: config})
|
||||
}),
|
||||
"/bar1": {
|
||||
controller: function () {
|
||||
strategy = m.redraw.strategy()
|
||||
m.redraw.strategy("redraw")
|
||||
},
|
||||
view: function () {
|
||||
return m("div", {config: config})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
route("/bar1")
|
||||
|
||||
expect(strategy).to.equal("all")
|
||||
expect(count).to.equal(1)
|
||||
})
|
||||
|
||||
dit("works with \"diff\"", function (root) {
|
||||
var strategy
|
||||
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()
|
||||
|
||||
expect(strategy).to.equal("diff")
|
||||
expect(root.childNodes[0].childNodes[0].nodeValue).to.equal("1")
|
||||
})
|
||||
|
||||
dit("recreates the component when \"all\"", function (root) {
|
||||
var count = 0
|
||||
function config(el, init) {
|
||||
if (!init) count++
|
||||
}
|
||||
|
||||
m.route(root, "/foo1", {
|
||||
"/foo1": pure(function () {
|
||||
return m("div", {
|
||||
config: config,
|
||||
onclick: function () {
|
||||
m.redraw.strategy("all")
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
root.childNodes[0].onclick({})
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
expect(count).to.equal(2)
|
||||
})
|
||||
})
|
||||
})
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,344 +0,0 @@
|
|||
describe("m.request()", function () {
|
||||
"use strict"
|
||||
|
||||
// Much easier to read
|
||||
function resolve() {
|
||||
var xhr = mock.XMLHttpRequest.$instances.pop()
|
||||
xhr.$resolve.apply(xhr, arguments)
|
||||
xhr.onreadystatechange()
|
||||
return xhr
|
||||
}
|
||||
|
||||
// Common abstraction: request(opts, ...callbacks)
|
||||
function request(opts) {
|
||||
var ret = m.request(opts)
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
ret = ret.then(arguments[i])
|
||||
}
|
||||
resolve()
|
||||
return ret
|
||||
}
|
||||
|
||||
it("sets the correct properties on `GET`", function () {
|
||||
var prop = request({
|
||||
method: "GET",
|
||||
url: "test"
|
||||
})
|
||||
|
||||
expect(prop()).to.contain.keys({
|
||||
method: "GET",
|
||||
url: "test"
|
||||
})
|
||||
})
|
||||
|
||||
it("returns a Mithril promise (1)", function () {
|
||||
var prop = request(
|
||||
{method: "GET", url: "test"},
|
||||
function () { return "foo" })
|
||||
|
||||
expect(prop()).to.equal("foo")
|
||||
})
|
||||
|
||||
it("returns a Mithril promise (2)", function () {
|
||||
var prop = request({method: "GET", url: "test"})
|
||||
var result = prop()
|
||||
|
||||
expect(prop.then(function (value) { return value })()).to.equal(result)
|
||||
})
|
||||
|
||||
it("sets the correct properties on `POST`", function () {
|
||||
var prop = request({
|
||||
method: "POST",
|
||||
url: "http://domain.com:80",
|
||||
data: {}
|
||||
})
|
||||
|
||||
expect(prop()).to.contain.keys({
|
||||
method: "POST",
|
||||
url: "http://domain.com:80"
|
||||
})
|
||||
})
|
||||
|
||||
it("sets the correct arguments", function () {
|
||||
expect(request({
|
||||
method: "POST",
|
||||
url: "http://domain.com:80/:test1",
|
||||
data: {test1: "foo"}
|
||||
})().url).to.equal("http://domain.com:80/foo")
|
||||
})
|
||||
|
||||
it("propagates errors through the promise (1)", function () {
|
||||
var error = m.prop()
|
||||
|
||||
var prop = m.request({
|
||||
method: "GET",
|
||||
url: "test",
|
||||
deserialize: function () { throw new Error("error occurred") }
|
||||
}).then(null, error)
|
||||
resolve()
|
||||
|
||||
expect(prop().message).to.equal("error occurred")
|
||||
expect(error().message).to.equal("error occurred")
|
||||
})
|
||||
|
||||
it("propagates errors through the promise (2)", function () {
|
||||
var error = m.prop()
|
||||
|
||||
var prop = m.request({
|
||||
method: "GET",
|
||||
url: "test",
|
||||
deserialize: function () { throw new Error("error occurred") }
|
||||
}).catch(error)
|
||||
resolve()
|
||||
|
||||
expect(prop().message).to.equal("error occurred")
|
||||
expect(error().message).to.equal("error occurred")
|
||||
})
|
||||
|
||||
it("synchronously throws TypeErrors", function () {
|
||||
var error = m.prop()
|
||||
var exception
|
||||
var prop = m.request({
|
||||
method: "GET",
|
||||
url: "test",
|
||||
deserialize: function () { throw new TypeError("error occurred") }
|
||||
}).then(null, error)
|
||||
|
||||
try {
|
||||
resolve()
|
||||
} catch (e) {
|
||||
exception = e
|
||||
}
|
||||
|
||||
expect(prop()).to.not.exist
|
||||
expect(error()).to.not.exist
|
||||
expect(exception.message).to.equal("error occurred")
|
||||
})
|
||||
|
||||
it("sets correct Content-Type when given data", function () {
|
||||
var error = m.prop()
|
||||
|
||||
m.request({
|
||||
method: "POST",
|
||||
url: "test",
|
||||
data: {foo: 1}
|
||||
}).then(null, error)
|
||||
|
||||
var xhr = mock.XMLHttpRequest.$instances.pop()
|
||||
xhr.onreadystatechange()
|
||||
|
||||
expect(xhr.$headers).to.have.property(
|
||||
"Content-Type",
|
||||
"application/json; charset=utf-8")
|
||||
})
|
||||
|
||||
it("doesn't set Content-Type when it doesn't have data", function () {
|
||||
var error = m.prop()
|
||||
|
||||
m.request({
|
||||
method: "POST",
|
||||
url: "test"
|
||||
}).then(null, error)
|
||||
|
||||
var xhr = mock.XMLHttpRequest.$instances.pop()
|
||||
xhr.onreadystatechange()
|
||||
|
||||
expect(xhr.$headers).to.not.have.property("Content-Type")
|
||||
})
|
||||
|
||||
it("correctly sets initial value", function () {
|
||||
var prop = m.request({
|
||||
method: "POST",
|
||||
url: "test",
|
||||
initialValue: "foo"
|
||||
})
|
||||
|
||||
var initialValue = prop()
|
||||
resolve()
|
||||
|
||||
expect(initialValue).to.equal("foo")
|
||||
})
|
||||
|
||||
it("correctly propagates initial value when not completed", function () {
|
||||
var prop = m.request({
|
||||
method: "POST",
|
||||
url: "test",
|
||||
initialValue: "foo"
|
||||
}).then(function (value) { return value })
|
||||
|
||||
var initialValue = prop()
|
||||
resolve()
|
||||
|
||||
expect(initialValue).to.equal("foo")
|
||||
})
|
||||
|
||||
it("resolves `then` correctly with an initialValue", function () {
|
||||
var prop = m.request({
|
||||
method: "POST",
|
||||
url: "test",
|
||||
initialValue: "foo"
|
||||
}).then(function () { return "bar" })
|
||||
|
||||
resolve()
|
||||
expect(prop()).to.equal("bar")
|
||||
})
|
||||
|
||||
it("appends query strings to `url` from `data` for `GET`", function () {
|
||||
var prop = m.request({method: "GET", url: "/test", data: {foo: 1}})
|
||||
resolve()
|
||||
expect(prop().url).to.equal("/test?foo=1")
|
||||
})
|
||||
|
||||
it("doesn't append query strings to `url` from `data` for `POST`", function () { // eslint-disable-line
|
||||
var prop = m.request({method: "POST", url: "/test", data: {foo: 1}})
|
||||
resolve()
|
||||
expect(prop().url).to.equal("/test")
|
||||
})
|
||||
|
||||
it("appends children in query strings to `url` from `data` for `GET`", function () { // eslint-disable-line
|
||||
var prop = m.request({method: "GET", url: "test", data: {foo: [1, 2]}})
|
||||
resolve()
|
||||
expect(prop().url).to.equal("test?foo=1&foo=2")
|
||||
})
|
||||
|
||||
it("propagates initial value in call before request is completed", function () { // eslint-disable-line
|
||||
var value
|
||||
var prop1 = m.request({method: "GET", url: "test", initialValue: 123})
|
||||
expect(prop1()).to.equal(123)
|
||||
var prop2 = prop1.then(function () { return 1 })
|
||||
expect(prop2()).to.equal(123)
|
||||
var prop3 = prop1.then(function (v) { value = v })
|
||||
expect(prop3()).to.equal(123)
|
||||
resolve()
|
||||
|
||||
expect(value.method).to.equal("GET")
|
||||
expect(value.url).to.equal("test")
|
||||
})
|
||||
|
||||
context("over jsonp", function () {
|
||||
/* eslint-disable no-invalid-this */
|
||||
beforeEach(function () {
|
||||
var body = this.body = mock.document.createElement("body")
|
||||
mock.document.body = body
|
||||
mock.document.appendChild(body)
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
mock.document.removeChild(this.body)
|
||||
})
|
||||
/* eslint-enable no-invalid-this */
|
||||
|
||||
function request(data, callbackKey) {
|
||||
return m.request({
|
||||
url: "/test",
|
||||
dataType: "jsonp",
|
||||
data: data,
|
||||
callbackKey: callbackKey
|
||||
})
|
||||
}
|
||||
|
||||
function find(list, item, prop) {
|
||||
var res
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
var entry = list[i]
|
||||
if (prop != null) entry = entry[prop]
|
||||
if (entry.indexOf(item) >= 0) res = entry
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
function resolve(data) {
|
||||
var callback = find(Object.keys(mock), "mithril_callback")
|
||||
var url = find(mock.document.getElementsByTagName("script"),
|
||||
callback, "src")
|
||||
mock[callback](data)
|
||||
return url
|
||||
}
|
||||
|
||||
it("sets the `GET` url with the correct query parameters", function () {
|
||||
request({foo: "bar"})
|
||||
expect(resolve({foo: "bar"})).to.contain("foo=bar")
|
||||
})
|
||||
|
||||
it("correctly gets the value, without appending the script on the document", function () { // eslint-disable-line
|
||||
var data = m.prop()
|
||||
|
||||
request().then(data)
|
||||
|
||||
var url = resolve({foo: "bar"})
|
||||
|
||||
expect(url).to.contain("/test?callback=mithril_callback")
|
||||
expect(data()).to.eql({foo: "bar"})
|
||||
})
|
||||
|
||||
it("correctly gets the value with a custom `callbackKey`, without appending the script on the document", function () { // eslint-disable-line
|
||||
var data = m.prop()
|
||||
|
||||
request(null, "jsonpCallback").then(data)
|
||||
|
||||
var url = resolve({foo: "bar1"})
|
||||
|
||||
expect(url).to.contain("/test?jsonpCallback=mithril_callback")
|
||||
expect(data()).to.eql({foo: "bar1"})
|
||||
})
|
||||
|
||||
it("correctly gets the value on calling the function", function () {
|
||||
var req = request()
|
||||
resolve({foo: "bar1"})
|
||||
expect(req()).to.eql({foo: "bar1"})
|
||||
})
|
||||
})
|
||||
|
||||
it("ends the computation when a SyntaxError is thrown from `options.extract`", function () { // eslint-disable-line max-len
|
||||
var root = mock.document.createElement("div")
|
||||
var viewSpy = sinon.spy(function () { return m("div") })
|
||||
var resolved = sinon.spy()
|
||||
var rejected = sinon.spy()
|
||||
|
||||
m.mount(root, {
|
||||
controller: function () {
|
||||
m.request({
|
||||
url: "/test",
|
||||
extract: function () {
|
||||
throw new SyntaxError()
|
||||
}
|
||||
}).then(resolved, rejected)
|
||||
},
|
||||
|
||||
view: viewSpy
|
||||
})
|
||||
|
||||
// For good measure
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
|
||||
expect(function () {
|
||||
resolve()
|
||||
}).to.throw()
|
||||
|
||||
expect(resolved).to.not.have.been.called
|
||||
expect(rejected).to.not.have.been.called
|
||||
|
||||
// The controller should throw, but the view should still render.
|
||||
expect(viewSpy).to.have.been.called
|
||||
|
||||
// For good measure
|
||||
mock.requestAnimationFrame.$resolve()
|
||||
})
|
||||
|
||||
it("can use a config correctly", function () {
|
||||
var config = sinon.spy()
|
||||
var result = m.prop()
|
||||
var error = sinon.spy
|
||||
var opts = {
|
||||
method: "GET",
|
||||
url: "/test",
|
||||
config: config
|
||||
}
|
||||
m.request(opts).then(result, error)
|
||||
var xhr = resolve({foo: "bar"})
|
||||
|
||||
expect(config).to.be.calledWithExactly(xhr, opts)
|
||||
expect(result()).to.eql({foo: "bar"})
|
||||
expect(error).to.not.be.called
|
||||
})
|
||||
})
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
describe("m.route.buildQueryString()", function () {
|
||||
"use strict"
|
||||
|
||||
it("exists", function () {
|
||||
expect(m.route.buildQueryString).to.be.a("function")
|
||||
})
|
||||
|
||||
it("converts an empty object to an empty string", function () {
|
||||
expect(m.route.buildQueryString({})).to.equal("")
|
||||
})
|
||||
|
||||
it("converts an object into a correct query string", function () {
|
||||
expect(
|
||||
m.route.buildQueryString({
|
||||
foo: "bar",
|
||||
hello: ["world", "mars", "mars"],
|
||||
world: {
|
||||
test: 3
|
||||
},
|
||||
bam: "",
|
||||
yup: null,
|
||||
removed: undefined
|
||||
})
|
||||
).to.equal("foo=bar&hello=world&hello=mars&world%5Btest%5D=3&bam=&yup")
|
||||
})
|
||||
})
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,34 +0,0 @@
|
|||
describe("m.route.parseQueryString()", function () {
|
||||
"use strict"
|
||||
|
||||
it("exists", function () {
|
||||
expect(m.route.parseQueryString).to.be.a("function")
|
||||
})
|
||||
|
||||
it("parses an empty string as an empty object", function () {
|
||||
var args = m.route.parseQueryString("")
|
||||
expect(args).to.eql({})
|
||||
})
|
||||
|
||||
it("parses multiple parameters correctly", function () {
|
||||
var args = m.route.parseQueryString("foo=bar&hello=world&hello=mars" +
|
||||
"&bam=&yup")
|
||||
|
||||
expect(args).to.eql({
|
||||
foo: "bar",
|
||||
hello: ["world", "mars"],
|
||||
bam: "",
|
||||
yup: null
|
||||
})
|
||||
})
|
||||
|
||||
it("parses escapes correctly", function () {
|
||||
var args = m.route.parseQueryString("foo=bar&hello%5B%5D=world&" +
|
||||
"hello%5B%5D=mars&hello%5B%5D=pluto")
|
||||
|
||||
expect(args).to.eql({
|
||||
foo: "bar",
|
||||
"hello[]": ["world", "mars", "pluto"]
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
describe("m.startComputation(), m.endComputation()", function () {
|
||||
"use strict"
|
||||
|
||||
it("exists", function () {
|
||||
expect(m.startComputation).to.be.a("function")
|
||||
expect(m.endComputation).to.be.a("function")
|
||||
})
|
||||
|
||||
it("blocks automatic rendering", 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()
|
||||
expect(root.childNodes[0].nodeValue).to.equal("foo")
|
||||
})
|
||||
|
||||
// FIXME: this needs to be better tested
|
||||
})
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
describe("m.sync()", function () {
|
||||
"use strict"
|
||||
|
||||
it("exists", function () {
|
||||
expect(m.sync).to.be.a("function")
|
||||
})
|
||||
|
||||
it("joins multiple promises in order to an array", 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")
|
||||
|
||||
expect(value).to.eql(["test", "foo"])
|
||||
})
|
||||
|
||||
it("joins multiple promises out of order to an array", 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")
|
||||
|
||||
expect(value).to.eql(["test", "foo"])
|
||||
})
|
||||
|
||||
// FIXME: bad behavior?
|
||||
it("rejects to an array if one promise rejects", function () {
|
||||
var value
|
||||
var deferred = m.deferred()
|
||||
m.sync([deferred.promise]).catch(function (data) { value = data })
|
||||
deferred.reject("fail")
|
||||
expect(value).to.eql(["fail"])
|
||||
})
|
||||
|
||||
it("resolves immediately if given an empty array", function () {
|
||||
var value = 1
|
||||
m.sync([]).then(function () { value = 2 })
|
||||
expect(value).to.equal(2)
|
||||
})
|
||||
|
||||
it("resolves to an empty array if given an empty array", function () {
|
||||
var value
|
||||
m.sync([]).then(function (data) { value = data })
|
||||
expect(value).to.eql([])
|
||||
})
|
||||
})
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
describe("m.trust()", function () {
|
||||
"use strict"
|
||||
|
||||
it("exists", function () {
|
||||
expect(m.trust).to.be.a("function")
|
||||
})
|
||||
|
||||
it("returns an instance of String", function () {
|
||||
expect(m.trust("foo")).to.be.an.instanceof(String)
|
||||
})
|
||||
|
||||
it("does not modify the string", function () {
|
||||
expect(m.trust("foo").valueOf()).to.equal("foo")
|
||||
})
|
||||
|
||||
it("is not identical to the string", function () {
|
||||
expect(m.trust("foo")).to.not.equal("foo")
|
||||
})
|
||||
|
||||
// FIXME: implement document.createRange().createContextualFragment() in the
|
||||
// mock window for these tests
|
||||
dom(function () {
|
||||
it("isn't escaped in m.render()", function () {
|
||||
var root = document.createElement("div")
|
||||
m.render(root, m("div", "a", m.trust("&"), "b"))
|
||||
expect(root.childNodes[0].innerHTML).to.equal("a&b")
|
||||
})
|
||||
|
||||
it("works with mixed trusted content in div", function () {
|
||||
var root = document.createElement("div")
|
||||
m.render(root, [m.trust("<p>1</p><p>2</p>"), m("i", "foo")])
|
||||
expect(root.childNodes[2].tagName).to.equal("I")
|
||||
})
|
||||
|
||||
it("works with mixed trusted content in text nodes", function () {
|
||||
var root = document.createElement("div")
|
||||
m.render(root, [
|
||||
m.trust("<p>1</p>123<p>2</p>"),
|
||||
m("i", "foo")
|
||||
])
|
||||
expect(root.childNodes[3].tagName).to.equal("I")
|
||||
})
|
||||
|
||||
// TODO: m.trust's contents are having their tags stripped.
|
||||
xit("works with mixed trusted content in td", function () {
|
||||
var root = document.createElement("table")
|
||||
root.appendChild(root = document.createElement("tr"))
|
||||
|
||||
m.render(root, [
|
||||
m.trust("<td>1</td><td>2</td>"),
|
||||
m("td", "foo")
|
||||
])
|
||||
|
||||
expect(root.childNodes[2].tagName).to.equal("TD")
|
||||
})
|
||||
|
||||
it("works with trusted content in div", function () {
|
||||
var root = document.createElement("div")
|
||||
m.render(root, m("div", [
|
||||
m("p", "©"),
|
||||
m("p", m.trust("©")),
|
||||
m.trust("©")
|
||||
]))
|
||||
|
||||
expect(root.innerHTML)
|
||||
.to.equal("<div><p>&copy;</p><p>©</p>©</div>")
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
describe("m.withAttr()", function () {
|
||||
"use strict"
|
||||
|
||||
it("calls the handler with the right value/context without callbackThis", function () { // eslint-disable-line
|
||||
var spy = sinon.spy()
|
||||
var object = {}
|
||||
m.withAttr("test", spy).call(object, {currentTarget: {test: "foo"}})
|
||||
expect(spy).to.be.calledOn(object).and.calledWith("foo")
|
||||
})
|
||||
|
||||
it("calls the handler with the right value/context with callbackThis", function () { // eslint-disable-line
|
||||
var spy = sinon.spy()
|
||||
var object = {}
|
||||
m.withAttr("test", spy, object)({currentTarget: {test: "foo"}})
|
||||
expect(spy).to.be.calledOn(object).and.calledWith("foo")
|
||||
})
|
||||
})
|
||||
214
test/svg.html
214
test/svg.html
|
|
@ -1,214 +0,0 @@
|
|||
<!doctype html>
|
||||
<title>SVG test</title>
|
||||
<style>
|
||||
.path {
|
||||
stroke-dasharray: 1000;
|
||||
stroke-dashoffset: 1000;
|
||||
animation: dash 5s linear alternate infinite;
|
||||
-webkit-animation: dash 5s linear alternate infinite;
|
||||
}
|
||||
|
||||
@keyframes dash {
|
||||
from {
|
||||
stroke-dashoffset: 1000;
|
||||
}
|
||||
to {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
}
|
||||
@-webkit-keyframes dash {
|
||||
from {
|
||||
stroke-dashoffset: 1000;
|
||||
}
|
||||
to {
|
||||
stroke-dashoffset: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<p>
|
||||
This page is for testing SVG support in Mithril. This page should contain:
|
||||
</p>
|
||||
<ul>
|
||||
<li>an HTML link labeled "HTML link"</li>
|
||||
<li>an SVG link labeled "SVG link"</li>
|
||||
<li>a tilted blue square</li>
|
||||
<li>a cat picture</li>
|
||||
<li>an animated line drawing</li>
|
||||
<li>a clock with the current time</li>
|
||||
</ul>
|
||||
|
||||
<p>
|
||||
The links should open in a new tab. All items should display title tooltips
|
||||
when hovered over.
|
||||
</p>
|
||||
|
||||
<div id="test"></div>
|
||||
<script src="../mithril.js"></script>
|
||||
<script>
|
||||
m.render(document.getElementById("test"), [
|
||||
m("a[href='http://google.com'][target=_blank][title='HTML link']",
|
||||
"HTML link"),
|
||||
m("br"),
|
||||
m("svg[width=180][height=200]", [
|
||||
m("rect[title=Square]", {
|
||||
x: 50,
|
||||
y: 50,
|
||||
height: 100,
|
||||
width: 100,
|
||||
transform: "translate(30) rotate(45 50 50)",
|
||||
style: {stroke: "#000", fill: "#0086b2"}
|
||||
}),
|
||||
m("a[href='http://google.com'][title='SVG link'][target=_new]", {
|
||||
style: {textDecoration: "underline"}
|
||||
}, [
|
||||
m("text[x=0][y=20]", "SVG Link")
|
||||
])
|
||||
]),
|
||||
m("svg[height=201px][width=201px]", [
|
||||
m("image[href='http://placekitten.com/201/201']", {
|
||||
height: "200px",
|
||||
width: "200px",
|
||||
title: "Cat picture"
|
||||
})
|
||||
]),
|
||||
m("svg[title='Line drawings']", {
|
||||
"enable-background": "new 0 0 340 333",
|
||||
height: "333px",
|
||||
viewBox: "0 0 340 333",
|
||||
width: "340px",
|
||||
x: "0px",
|
||||
y: "0px"
|
||||
}, [
|
||||
m("path.path", {
|
||||
d: [
|
||||
"M 66.039,133.545",
|
||||
"c 0,0 -21 -57,18 -67",
|
||||
"s 49 -4,65,8",
|
||||
"s 30,41,53,27",
|
||||
"s 66,4,58,32",
|
||||
"s -5,44,18,57",
|
||||
"s 22,46,0,45",
|
||||
"s -54 -40 -68 -16",
|
||||
"s -40,88 -83,48",
|
||||
"s 11 -61 -11 -80",
|
||||
"s -79 -7 -70 -41",
|
||||
"C 46.039,146.545,53.039,128.545,66.039,133.545",
|
||||
"z",
|
||||
].join(" "),
|
||||
fill: "#FFFFFF",
|
||||
stroke: "#000000",
|
||||
"stroke-miterlimit": 10,
|
||||
"stroke-width": 4,
|
||||
}),
|
||||
]),
|
||||
m("svg[height=270px][width=270px][viewBox='0 0 270 270']", [
|
||||
m("g[transform='translate(150,150)'][title=Clock]", [
|
||||
m("g", [
|
||||
m("circle", {
|
||||
r: 108,
|
||||
fill: "none",
|
||||
"stroke-width": 4,
|
||||
stroke: "gray",
|
||||
}),
|
||||
m("circle", {
|
||||
r: 97,
|
||||
fill: "none",
|
||||
"stroke-width": 11,
|
||||
stroke: "black",
|
||||
"stroke-dasharray": "4,46.789082",
|
||||
transform: "rotate(-1.5)",
|
||||
}),
|
||||
m("circle", {
|
||||
r: 100,
|
||||
fill: "none",
|
||||
"stroke-width": 5,
|
||||
stroke: "black",
|
||||
"stroke-dasharray": "2,8.471976",
|
||||
transform: "rotate(-.873)",
|
||||
}),
|
||||
]),
|
||||
m("g[transform='rotate(180)']", [
|
||||
m("g#hour", [
|
||||
m("line", {
|
||||
"stroke-width": 5,
|
||||
y2: 75,
|
||||
"stroke-linecap": "round",
|
||||
stroke: "blue",
|
||||
opacity: 0.5,
|
||||
}),
|
||||
m("animateTransform[attributeName=transform]", {
|
||||
type: "rotate",
|
||||
repeatCount: "indefinite",
|
||||
dur: "12h",
|
||||
by: 360
|
||||
}),
|
||||
m("circle[r=7]"),
|
||||
]),
|
||||
m("g#minute", [
|
||||
m("line", {
|
||||
"stroke-width": 4,
|
||||
y2: 93,
|
||||
"stroke-linecap": "round",
|
||||
stroke: "green",
|
||||
opacity: 0.9
|
||||
}),
|
||||
m("animateTransform[attributeName=transform]", {
|
||||
type: "rotate",
|
||||
repeatCount: "indefinite",
|
||||
dur: "60min",
|
||||
by: 360,
|
||||
}),
|
||||
m("circle[r=6][fill=red]"),
|
||||
]),
|
||||
m("g#second", [
|
||||
m("line", {
|
||||
"stroke-width": 2,
|
||||
y1: -20,
|
||||
y2: 102,
|
||||
"stroke-linecap": "round",
|
||||
stroke: "red"
|
||||
}),
|
||||
m("animateTransform[attributeName=transform]", {
|
||||
type: "rotate",
|
||||
repeatCount: "indefinite",
|
||||
dur: "60s",
|
||||
by: 360
|
||||
}),
|
||||
m("circle[r=4][fill=blue]"),
|
||||
]),
|
||||
]),
|
||||
]),
|
||||
m("script", "(" + function () {
|
||||
"use strict"
|
||||
|
||||
function rotate(id, num) {
|
||||
document.getElementById(id)
|
||||
.setAttribute("transform", "rotate(" + num + ")")
|
||||
}
|
||||
|
||||
var date = new Date()
|
||||
var hours = date.getHours()
|
||||
if (hours > 12) hours -= 12
|
||||
var minutes = date.getMinutes()
|
||||
var seconds = date.getSeconds()
|
||||
rotate("hour", 30 * (hours + minutes / 60 + seconds / 3600))
|
||||
rotate("minute", 6 * (minutes + seconds / 60))
|
||||
rotate("second", 6 * seconds)
|
||||
}.toString() + ")()"),
|
||||
]),
|
||||
m("svg[height=200px][width=200px]", [
|
||||
m("foreignObject", {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: "100px",
|
||||
height: "100px",
|
||||
transform: "translate(0,0)",
|
||||
}, m("div", {xmlns: "http://www.w3.org/1999/xhtml"}, [
|
||||
m.trust("this is a piece of html rendered as " +
|
||||
"<a href=\"http://www.w3.org/TR/SVG11/extend.html\">" +
|
||||
"SVG foreignObject</a>")
|
||||
]))
|
||||
])
|
||||
])
|
||||
</script>
|
||||
Loading…
Add table
Add a link
Reference in a new issue