Move public APIs into their own folder

And start writing actual tests for them
This commit is contained in:
Pat Cavit 2016-05-18 17:18:52 -07:00
parent 724361af6a
commit 960812308c
9 changed files with 192 additions and 6 deletions

35
api/limiter.js Normal file
View file

@ -0,0 +1,35 @@
var FRAME_BUDGET = 16 // 60 frames per second = 1 call per 16 ms
module.exports = function($window, render) {
var rAF = $window.requestAnimationFrame || $window.setTimeout
var cAF = $window.cancelAnimationFrame || $window.clearTimeout
var last = 0
var pending
return function() {
var now = new Date()
// First render, OR if the time since the last render is greater
// than the frame budget
// just immediately render
if(!last || now - last > FRAME_BUDGET) {
last = now;
return render()
}
// Redraw already pending, abort
if(pending) {
return
}
// Schedule a redraw for the next tick
pending = rAF(function() {
render()
last = new Date()
pending = null
}, FRAME_BUDGET - (now - last))
}
}

16
api/mount.js Normal file
View file

@ -0,0 +1,16 @@
var createRenderer = require("../render/render")
var limiter = require("./limiter");
module.exports = function($window, redraw) {
return function(root, component) {
var renderer = createRenderer($window)
var draw = limiter($window, function draw() {
renderer.render(root, {tag: component})
})
renderer.setEventCallback(draw)
redraw.run = draw
draw()
}
}

22
api/router.js Normal file
View file

@ -0,0 +1,22 @@
var createRenderer = require("../render/render")
var createRouter = require("../router/router")
var limiter = require("./limiter")
module.exports = function($window, redraw) {
var renderer = createRenderer($window)
var router = createRouter($window)
var route = function(root, defaultRoute, routes) {
var replay = limiter($window, router.defineRoutes(routes, function(component, args) {
renderer.render(root, {tag: component, attrs: args})
}, function() {
router.setPath(defaultRoute)
}))
renderer.setEventCallback(replay)
redraw.run = replay
}
route.link = router.link
route.prefix = router.setPrefix
return route
}

12
api/tests/async.js Normal file
View file

@ -0,0 +1,12 @@
module.exports = {
setTimeout : function($window) {
$window.setTimeout = window.setTimeout;
$window.clearTimeout = window.clearTimeout;
},
requestAnimationFrame : function($window) {
$window.requestAnimationFrame = window.requestAnimationFrame;
$window.cancelAnimationFrame = window.cancelAnimationFrame;
}
}

31
api/tests/index.html Normal file
View file

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script src="../../module/module.js"></script>
<script src="../../ospec/ospec.js"></script>
<script src="../../test-utils/callAsync.js"></script>
<script src="../../test-utils/domMock.js"></script>
<script src="../../render/node.js"></script>
<script src="../../render/trust.js"></script>
<script src="../../render/hyperscript.js"></script>
<script src="../../render/render.js"></script>
<script src="../../querystring/build.js"></script>
<script src="../../querystring/parse.js"></script>
<script src="../../request/request.js"></script>
<script src="../../router/router.js"></script>
<script src="../limiter.js"></script>
<script src="../mount.js"></script>
<script src="../router.js"></script>
<script src="./async.js"></script>
<script src="./test-limiter.js"></script>
<script src="./test-mount.js"></script>
<script>require("../../ospec/ospec").run()</script>
</body>
</html>

29
api/tests/test-limiter.js Normal file
View file

@ -0,0 +1,29 @@
"use strict"
var o = require("../../ospec/ospec")
var domMock = require("../../test-utils/domMock")
var async = require("./async")
var limiter = require("../limiter")
o.spec("fps limiter", function() {
var $window, root
[ "setTimeout", "requestAnimationFrame" ].forEach(function(type) {
o.spec(type, function() {
o.beforeEach(function() {
$window = domMock()
async[type]($window)
})
o("is a function", function() {
o(typeof limiter).equals("function")
})
o("it returns a function", function() {
o(typeof limiter(false)).equals("function")
})
})
})
})

114
api/tests/test-mount.js Normal file
View file

@ -0,0 +1,114 @@
"use strict"
var o = require("../../ospec/ospec")
var domMock = require("../../test-utils/domMock")
var async = require("./async")
var m = require("../../render/hyperscript")
var createMounter = require("../mount")
o.spec("m.mount", function() {
var $window, root
o.beforeEach(function() {
$window = domMock()
async.setTimeout($window)
root = $window.document.body
})
o("is a function", function() {
o(typeof createMounter).equals("function")
})
o("returns a function after invocation", function() {
o(typeof createMounter()).equals("function")
})
o("updates passed in redraw object", function() {
var redraw = {}
var mount = createMounter($window, redraw)
mount(root, {
view : function() {
return m("div")
}
})
o(typeof redraw.run).equals("function")
})
o("renders into `root`", function() {
var mount = createMounter($window, {})
mount(root, {
view : function() {
return m("div")
}
})
o(root.firstChild.nodeName).equals("DIV")
})
o("redraws on redraw.run()", function(done) {
var onupdate = o.spy()
var oninit = o.spy()
var redraw = {}
var mount = createMounter($window, redraw)
mount(root, {
view : function() {
return m("div", {
oninit : oninit,
onupdate : onupdate
})
}
})
o(oninit.callCount).equals(1)
redraw.run()
// Wrapped to give time for the rate-limited redraw to fire
setTimeout(function() {
o(onupdate.callCount).equals(1)
done()
}, 20)
})
o("redraws on events", function(done, timeout) {
var onupdate = o.spy()
var oninit = o.spy()
var onclick = o.spy()
var mount = createMounter($window, {})
var e = $window.document.createEvent("MouseEvents")
e.initEvent("click", true, true)
mount(root, {
view : function() {
return m("div", {
oninit : oninit,
onupdate : onupdate,
onclick : onclick,
})
}
})
root.firstChild.dispatchEvent(e)
o(oninit.callCount).equals(1)
o(onclick.callCount).equals(1)
o(onclick.this).equals(root.firstChild)
o(onclick.args[0].type).equals("click")
o(onclick.args[0].target).equals(root.firstChild)
// Wrapped to give time for the rate-limited redraw to fire
setTimeout(function() {
o(onupdate.callCount).equals(1)
done()
}, 20)
})
})