From cdabc4d85f00f2744d0edeb2a64d80b2fb2e0aa7 Mon Sep 17 00:00:00 2001 From: Ben Drucker Date: Thu, 30 Jun 2016 16:42:29 -0700 Subject: [PATCH 01/19] Return outerHTML from toString if available, fall back to toString() --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 872e066..0aa1283 100644 --- a/index.js +++ b/index.js @@ -40,7 +40,7 @@ function choo (opts) { const state = _store.state({ state: serverState }) const router = createRouter(_defaultRoute, _routes, createSend) const tree = router(route, state) - return tree.toString() + return tree.outerHTML || tree.toString() function createSend () { return function send () { From 0a191566d67c5a176623a2432020eeb3e16edc7e Mon Sep 17 00:00:00 2001 From: Ben Drucker Date: Sat, 2 Jul 2016 12:29:22 -0700 Subject: [PATCH 02/19] Fix effect test: barracks requires a callback --- tests/browser/basic.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/browser/basic.js b/tests/browser/basic.js index f5397fb..444c282 100644 --- a/tests/browser/basic.js +++ b/tests/browser/basic.js @@ -25,8 +25,8 @@ tape('should render on the client', function (t) { } }, effects: { - 'triggers-reducers': (action, state, send) => { - send('test:mutate-on-return', {beep: 'barp'}) + 'triggers-reducers': (action, state, send, done) => { + send('test:mutate-on-return', {beep: 'barp'}, done) } } }) From 6f97b1c468e85939d30fb25a3408886f3211beb8 Mon Sep 17 00:00:00 2001 From: Ben Drucker Date: Sat, 2 Jul 2016 12:58:46 -0700 Subject: [PATCH 03/19] Add test:electron script for all tests --- package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/package.json b/package.json index d91c355..957832c 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "main": "index.js", "scripts": { "deps": "dependency-check . && dependency-check . --extra --no-dev -i xhr", + "test:electron": "browserify tests/**/*.js -t es2020 | tape-run", "test:server": "standard && npm run deps && NODE_ENV=test node tests/server/*", "test:server:cov": "standard && npm run deps && NODE_ENV=test istanbul cover tests/server/*", "test:browser": "standard && npm run deps && NODE_ENV=test zuul tests/browser/*", @@ -47,6 +48,7 @@ "standard": "^7.1.0", "tachyons": "^4.0.0-beta.19", "tape": "^4.5.1", + "tape-run": "~2.1.4", "yo-yoify": "^3.1.0", "zuul": "toddself/zuul" } From 5f4fda6646b9aeaacb39da99dd7e3a40808882f8 Mon Sep 17 00:00:00 2001 From: Ben Drucker Date: Sun, 3 Jul 2016 13:23:16 -0700 Subject: [PATCH 04/19] Generate test coverage via electron with tape-istanbul --- .gitignore | 1 + package.json | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 823b3d1..7582006 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ node_modules/ coverage/ +coverage.json tmp/ npm-debug.log* .DS_Store diff --git a/package.json b/package.json index 957832c..4a90e6c 100644 --- a/package.json +++ b/package.json @@ -6,11 +6,10 @@ "scripts": { "deps": "dependency-check . && dependency-check . --extra --no-dev -i xhr", "test:electron": "browserify tests/**/*.js -t es2020 | tape-run", + "test:cov": "browserify tests/**/*.js -t es2020 -p tape-istanbul/plugin | tape-run | tape-istanbul && istanbul report", "test:server": "standard && npm run deps && NODE_ENV=test node tests/server/*", - "test:server:cov": "standard && npm run deps && NODE_ENV=test istanbul cover tests/server/*", "test:browser": "standard && npm run deps && NODE_ENV=test zuul tests/browser/*", "test:browser:local": "standard && npm run deps && NODE_ENV=test zuul --local 8080 -- tests/browser/*", - "test:cov": "npm run test:server:cov", "preversion": "if [ ! -z $SKIP_TEST ]; then npm run test:browser; fi", "test": "npm run test:server" }, @@ -48,6 +47,7 @@ "standard": "^7.1.0", "tachyons": "^4.0.0-beta.19", "tape": "^4.5.1", + "tape-istanbul": "~1.0.2", "tape-run": "~2.1.4", "yo-yoify": "^3.1.0", "zuul": "toddself/zuul" From 3fc66acdc3d493568be229f0c1c2d18aebc6a4f4 Mon Sep 17 00:00:00 2001 From: Ben Drucker Date: Sun, 3 Jul 2016 13:34:44 -0700 Subject: [PATCH 05/19] Add test confirming `toString()` works with min-document elements --- package.json | 1 + tests/server/index.js | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/package.json b/package.json index 4a90e6c..b342259 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "insert-css": "^0.2.0", "istanbul": "^0.4.4", "karma-sauce-launcher": "^1.0.0", + "min-document": "~2.18.0", "server-router": "^2.1.0", "sheetify": "^5.0.0", "standard": "^7.1.0", diff --git a/tests/server/index.js b/tests/server/index.js index c4e4a67..7d5a440 100644 --- a/tests/server/index.js +++ b/tests/server/index.js @@ -1,4 +1,5 @@ const tape = require('tape') +const minDocument = require('min-document') const choo = require('../../') const view = require('../../html') @@ -16,6 +17,19 @@ tape('should render on the server', function (t) { t.equal(html, expected, 'strings are equal') }) + t.test('can render without a real DOM', function (t) { + t.plan(1) + + const app = choo() + app.router((route) => [ + route('/', () => minDocument.createElement('div')) + ]) + + const html = app.toString('/') + const expected = '
' + t.equal(html, expected, 'strings are equal') + }) + t.test('should accept a state object', function (t) { t.plan(1) From 57030b4e0e205c7ea9766acfd8c129c4d1d86f9f Mon Sep 17 00:00:00 2001 From: Ben Drucker Date: Sun, 3 Jul 2016 13:41:35 -0700 Subject: [PATCH 06/19] Update browser tests for new router fn arguments See 6407188ee9a3297cb25d998a5b3d6adc2f1e9cba --- tests/browser/basic.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/browser/basic.js b/tests/browser/basic.js index 444c282..e9a7fba 100644 --- a/tests/browser/basic.js +++ b/tests/browser/basic.js @@ -47,7 +47,7 @@ tape('should render on the client', function (t) { ] app.router((route) => [ - route('/', function (params, state, send) { + route('/', function (state, prev, send) { ++loop asserts[loop] && asserts[loop](state.test) setTimeout(() => triggers[loop] && triggers[loop](send), 5) From 180ea8ae103a9e346efdc17f7f6eb429f8a3925a Mon Sep 17 00:00:00 2001 From: Ben Drucker Date: Sun, 3 Jul 2016 13:44:41 -0700 Subject: [PATCH 07/19] Remove all the "should" grammar from tests --- tests/browser/basic.js | 102 ++++++++++++++++++++--------------------- tests/server/index.js | 18 ++++---- 2 files changed, 59 insertions(+), 61 deletions(-) diff --git a/tests/browser/basic.js b/tests/browser/basic.js index e9a7fba..46745f6 100644 --- a/tests/browser/basic.js +++ b/tests/browser/basic.js @@ -1,61 +1,59 @@ -const tape = require('tape') +const test = require('tape') const choo = require('../../') const view = require('../../html') -tape('should render on the client', function (t) { - t.test('state should not be mutable', function (t) { - t.plan(4) +test('state is immutable', function (t) { + t.plan(4) - const app = choo() - const state = { - foo: 'baz', - beep: 'boop' - } + const app = choo() + const state = { + foo: 'baz', + beep: 'boop' + } - app.model({ - state: state, - namespace: 'test', - reducers: { - 'no-reducer-mutate': (action, state) => { - return {} - }, - 'mutate-on-return': (action, state) => { - delete action.type - return action - } + app.model({ + state: state, + namespace: 'test', + reducers: { + 'no-reducer-mutate': (action, state) => { + return {} }, - effects: { - 'triggers-reducers': (action, state, send, done) => { - send('test:mutate-on-return', {beep: 'barp'}, done) - } + 'mutate-on-return': (action, state) => { + delete action.type + return action } - }) - - let loop = -1 - - const asserts = [ - (state) => t.deepEqual(state, {foo: 'baz', beep: 'boop'}, 'intial state'), - (state) => t.deepEqual(state, {foo: 'baz', beep: 'boop'}, 'no change in state'), - (state) => t.deepEqual(state, {foo: 'oof', beep: 'boop'}, 'change in state from reducer'), - (state) => t.deepEqual(state, {foo: 'oof', beep: 'barp'}, 'change in state from effect') - ] - - const triggers = [ - (send) => send('test:no-reducer-mutate'), - (send) => send('test:mutate-on-return', {foo: 'oof'}), - (send) => send('test:triggers-reducers') - ] - - app.router((route) => [ - route('/', function (state, prev, send) { - ++loop - asserts[loop] && asserts[loop](state.test) - setTimeout(() => triggers[loop] && triggers[loop](send), 5) - return view`
${state.foo}:${state.beep}
` - }) - ]) - - const tree = app.start() - document.body.appendChild(tree) + }, + effects: { + 'triggers-reducers': (action, state, send, done) => { + send('test:mutate-on-return', {beep: 'barp'}, done) + } + } }) + + let loop = -1 + + const asserts = [ + (state) => t.deepEqual(state, {foo: 'baz', beep: 'boop'}, 'intial state'), + (state) => t.deepEqual(state, {foo: 'baz', beep: 'boop'}, 'no change in state'), + (state) => t.deepEqual(state, {foo: 'oof', beep: 'boop'}, 'change in state from reducer'), + (state) => t.deepEqual(state, {foo: 'oof', beep: 'barp'}, 'change in state from effect') + ] + + const triggers = [ + (send) => send('test:no-reducer-mutate'), + (send) => send('test:mutate-on-return', {foo: 'oof'}), + (send) => send('test:triggers-reducers') + ] + + app.router((route) => [ + route('/', function (state, prev, send) { + ++loop + asserts[loop] && asserts[loop](state.test) + setTimeout(() => triggers[loop] && triggers[loop](send), 5) + return view`
${state.foo}:${state.beep}
` + }) + ]) + + const tree = app.start() + document.body.appendChild(tree) }) diff --git a/tests/server/index.js b/tests/server/index.js index 7d5a440..871b035 100644 --- a/tests/server/index.js +++ b/tests/server/index.js @@ -1,10 +1,10 @@ -const tape = require('tape') +const test = require('tape') const minDocument = require('min-document') const choo = require('../../') const view = require('../../html') -tape('should render on the server', function (t) { - t.test('should render a static response', function (t) { +test('server', function (t) { + t.test('renders a static html response', function (t) { t.plan(1) const app = choo() @@ -17,7 +17,7 @@ tape('should render on the server', function (t) { t.equal(html, expected, 'strings are equal') }) - t.test('can render without a real DOM', function (t) { + t.test('renders without a real DOM', function (t) { t.plan(1) const app = choo() @@ -30,7 +30,7 @@ tape('should render on the server', function (t) { t.equal(html, expected, 'strings are equal') }) - t.test('should accept a state object', function (t) { + t.test('receives a state object', function (t) { t.plan(1) const app = choo() @@ -45,7 +45,7 @@ tape('should render on the server', function (t) { t.equal(html, expected, 'strings are equal') }) - t.test('should extend flat existing models', function (t) { + t.test('extends flat existing models', function (t) { t.plan(1) const app = choo() @@ -62,7 +62,7 @@ tape('should render on the server', function (t) { t.equal(html, expected, 'strings are equal') }) - t.test('should extend namespaced existing models', function (t) { + t.test('extends namespaced existing models', function (t) { t.plan(1) const app = choo() @@ -89,7 +89,7 @@ tape('should render on the server', function (t) { t.equal(html, expected, 'strings are equal') }) - t.test('should throw if called without route', function (t) { + t.test('throws if called without route', function (t) { t.plan(1) const app = choo() @@ -102,7 +102,7 @@ tape('should render on the server', function (t) { t.throws(app.toString.bind(null), /route must be a string/) }) - t.test('should throw if calling send()', function (t) { + t.test('throws when calling send()', function (t) { t.plan(1) const app = choo() From e2f0c5429cf532e0caaeaa3ddf76feebc954c2bc Mon Sep 17 00:00:00 2001 From: Ben Drucker Date: Sun, 3 Jul 2016 14:19:30 -0700 Subject: [PATCH 08/19] Add tests for onError, onAction, and onState hooks from barracks --- tests/browser/hooks.js | 57 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 tests/browser/hooks.js diff --git a/tests/browser/hooks.js b/tests/browser/hooks.js new file mode 100644 index 0000000..a72638f --- /dev/null +++ b/tests/browser/hooks.js @@ -0,0 +1,57 @@ +const test = require('tape') +const choo = require('../../') +const view = require('../../html') + +test('hooks', function (t) { + t.plan(11) + + const app = choo({ + onError: function (err, state, createSend) { + t.equal(err.message, 'effect error', 'receives err') + t.equal(state.clicks, 1, 'current state: 1 clicks') + t.equal(typeof createSend, 'function', 'createSend fn') + }, + onAction: function (action, state, name, caller, createSend) { + if (name === 'explodes') return + t.deepEqual(action, {foo: 'bar'}, 'action data') + t.equal(state.clicks, 0, 'current state: 0 clicks') + t.equal(name, 'click', 'action name') + t.equal(caller, '/', 'caller name') + t.equal(typeof createSend, 'function', 'createSend fn') + }, + onState: function (action, state, prev, createSend) { + t.deepEqual(action, {foo: 'bar'}, 'action data') + t.deepEqual(state.clicks, 1, 'new state: 1 clicks') + t.deepEqual(prev.clicks, 0, 'prev state: 0 clicks') + } + }) + + app.model({ + state: { + clicks: 0 + }, + reducers: { + click: (action, state) => ({clicks: state.clicks + 1}) + }, + effects: { + explodes: (action, state, send, done) => { + setTimeout(() => done(new Error('effect error')), 5) + } + } + }) + + var sent = false + app.router((route) => [ + route('/', function (state, prev, send) { + if (!sent) { + send('click', {foo: 'bar'}) + send('explodes') + } + sent = true + return view`` + }) + ]) + + const tree = app.start() + document.body.appendChild(tree) +}) From e0783320f7f5d986a7f354054471003f22186a5d Mon Sep 17 00:00:00 2001 From: Ben Drucker Date: Sun, 3 Jul 2016 15:08:48 -0700 Subject: [PATCH 09/19] Add tests and fixes for rehydration * Barracks must get an initial state or state.location is undefined * Replaces document.addEventListener w/ pkg handling existing ready doc --- index.js | 5 +++-- package.json | 1 + tests/browser/rehydration.js | 28 ++++++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 tests/browser/rehydration.js diff --git a/index.js b/index.js index 0aa1283..d005b55 100644 --- a/index.js +++ b/index.js @@ -1,6 +1,7 @@ const history = require('sheet-router/history') const sheetRouter = require('sheet-router') const document = require('global/document') +const onReady = require('document-ready') const href = require('sheet-router/href') const hash = require('sheet-router/hash') const hashMatch = require('hash-match') @@ -61,14 +62,14 @@ function choo (opts) { _store.model(appInit(startOpts)) const createSend = _store.start(startOpts) _router = start._router = createRouter(_defaultRoute, _routes, createSend) - const state = _store.state() + const state = _store.state({state: {}}) if (!selector) { const tree = _router(state.location.pathname, state) _rootNode = tree return tree } else { - document.addEventListener('DOMContentLoaded', function (event) { + onReady(function onReady () { const oldTree = document.querySelector(selector) assert.ok(oldTree, 'could not query selector: ' + selector) const newTree = _router(state.location.pathname, state) diff --git a/package.json b/package.json index b342259..f43fce5 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "license": "MIT", "dependencies": { "barracks": "^7.0.3", + "document-ready": "~1.0.1", "global": "^4.3.0", "hash-match": "^1.0.2", "sheet-router": "^3.1.0", diff --git a/tests/browser/rehydration.js b/tests/browser/rehydration.js new file mode 100644 index 0000000..1d75e48 --- /dev/null +++ b/tests/browser/rehydration.js @@ -0,0 +1,28 @@ +const test = require('tape') +const onReady = require('document-ready') +const choo = require('../../') +const view = require('../../html') + +test('rehydration', function (t) { + t.plan(2) + + const app = choo() + + app.router((route) => [ + route('/', function (state, prev, send) { + return view`
send('test')}>Hello world!` + }) + ]) + + var node = document.createElement('div') + node.innerHTML = app.toString('/') + node = node.childNodes[0] + document.body.appendChild(node) + + app.start('#app-root') + + onReady(function () { + t.equal(node.innerHTML, 'Hello world!', 'same content') + t.equal(typeof node.onclick, 'function', 'attaches dom listeners') + }) +}) From 30a228b3e06c8a6eeffbca86c0e76d1462a5393e Mon Sep 17 00:00:00 2001 From: Ben Drucker Date: Sun, 3 Jul 2016 15:13:59 -0700 Subject: [PATCH 10/19] Update onError hook test to only expect err argument --- tests/browser/hooks.js | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/tests/browser/hooks.js b/tests/browser/hooks.js index a72638f..bbcc73b 100644 --- a/tests/browser/hooks.js +++ b/tests/browser/hooks.js @@ -3,26 +3,24 @@ const choo = require('../../') const view = require('../../html') test('hooks', function (t) { - t.plan(11) + t.plan(9) const app = choo({ - onError: function (err, state, createSend) { - t.equal(err.message, 'effect error', 'receives err') - t.equal(state.clicks, 1, 'current state: 1 clicks') - t.equal(typeof createSend, 'function', 'createSend fn') + onError: function (err) { + t.equal(err.message, 'effect error', 'onError: receives err') }, onAction: function (action, state, name, caller, createSend) { if (name === 'explodes') return - t.deepEqual(action, {foo: 'bar'}, 'action data') - t.equal(state.clicks, 0, 'current state: 0 clicks') - t.equal(name, 'click', 'action name') - t.equal(caller, '/', 'caller name') - t.equal(typeof createSend, 'function', 'createSend fn') + t.deepEqual(action, {foo: 'bar'}, 'onAction: action data') + t.equal(state.clicks, 0, 'onAction: current state: 0 clicks') + t.equal(name, 'click', 'onAction: action name') + t.equal(caller, '/', 'onAction: caller name') + t.equal(typeof createSend, 'function', 'onAction: createSend fn') }, onState: function (action, state, prev, createSend) { - t.deepEqual(action, {foo: 'bar'}, 'action data') - t.deepEqual(state.clicks, 1, 'new state: 1 clicks') - t.deepEqual(prev.clicks, 0, 'prev state: 0 clicks') + t.deepEqual(action, {foo: 'bar'}, 'onState: action data') + t.deepEqual(state.clicks, 1, 'onState: new state: 1 clicks') + t.deepEqual(prev.clicks, 0, 'onState: prev state: 0 clicks') } }) From c3293b59535f606e428c7c1d9b306a578829d571 Mon Sep 17 00:00:00 2001 From: Ben Drucker Date: Sun, 3 Jul 2016 15:24:31 -0700 Subject: [PATCH 11/19] Remove dead check for strict prev/current state equality * Barracks will always return a new object https://github.com/yoshuawuyts/barracks/blob/11d3c6d1822beadce0251279f9bc8370c569ea5e/index.js#L144 --- index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/index.js b/index.js index d005b55..f739f04 100644 --- a/index.js +++ b/index.js @@ -82,7 +82,6 @@ function choo (opts) { // (obj, obj, obj, str, fn) -> null function render (data, state, prev, name, createSend) { if (opts.onState) opts.onState(data, state, prev, name, createSend) - if (state === prev) return const newTree = _router(state.location.pathname, state, prev) _rootNode = yo.update(_rootNode, newTree) From fb38d151c6f447aa3eb616afe2acb9ad7ea56c03 Mon Sep 17 00:00:00 2001 From: Ben Drucker Date: Sun, 3 Jul 2016 16:35:58 -0700 Subject: [PATCH 12/19] Add test for default freezing + noFreeze option --- tests/browser/freeze.js | 46 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tests/browser/freeze.js diff --git a/tests/browser/freeze.js b/tests/browser/freeze.js new file mode 100644 index 0000000..a073bf8 --- /dev/null +++ b/tests/browser/freeze.js @@ -0,0 +1,46 @@ +const test = require('tape') +const choo = require('../../') + +test('freeze (default)', function (t) { + t.plan(2) + const app = choo() + + app.model({ + state: { + foo: 'bar' + } + }) + + app.router((route) => [ + route('/', function (state, prev, send) { + state.foo = '' + t.equal(state.foo, 'bar', 'cannot modify property') + state.bar = 'baz' + t.equal(state.bar, undefined, 'cannot add property') + }) + ]) + + app.start() +}) + +test('noFreeze', function (t) { + t.plan(2) + const app = choo({noFreeze: true}) + + app.model({ + state: { + foo: 'bar' + } + }) + + app.router((route) => [ + route('/', function (state, prev, send) { + state.foo = '' + t.equal(state.foo, '', 'can modify property') + state.bar = 'baz' + t.equal(state.bar, 'baz', 'can add property') + }) + ]) + + app.start() +}) From 37976c86f5c693f46e013289c8faebe5c36b4813 Mon Sep 17 00:00:00 2001 From: Ben Drucker Date: Sun, 3 Jul 2016 17:05:03 -0700 Subject: [PATCH 13/19] Add a routing test using proxyquire to short-circuit history handlers * proxyquire (pq) replaces choo's sheet-router/history with a mock * pq-universal replaces pq w/ pqify in the browser * magic! --- package.json | 8 ++++-- tests/browser/routing.js | 60 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 tests/browser/routing.js diff --git a/package.json b/package.json index f43fce5..e8b46b3 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,8 @@ "main": "index.js", "scripts": { "deps": "dependency-check . && dependency-check . --extra --no-dev -i xhr", - "test:electron": "browserify tests/**/*.js -t es2020 | tape-run", - "test:cov": "browserify tests/**/*.js -t es2020 -p tape-istanbul/plugin | tape-run | tape-istanbul && istanbul report", + "test:electron": "browserify tests/**/*.js -t es2020 -p proxyquire-universal | tape-run", + "test:cov": "browserify tests/**/*.js -t es2020 -p proxyquire-universal -p tape-istanbul/plugin | tape-run | tape-istanbul && istanbul report", "test:server": "standard && npm run deps && NODE_ENV=test node tests/server/*", "test:browser": "standard && npm run deps && NODE_ENV=test zuul tests/browser/*", "test:browser:local": "standard && npm run deps && NODE_ENV=test zuul --local 8080 -- tests/browser/*", @@ -40,10 +40,14 @@ "bundle-collapser": "^1.2.1", "dependency-check": "^2.5.1", "es2020": "^1.0.1", + "geval": "~2.1.1", "insert-css": "^0.2.0", "istanbul": "^0.4.4", "karma-sauce-launcher": "^1.0.0", "min-document": "~2.18.0", + "proxyquire": "~1.7.10", + "proxyquire-universal": "~1.0.8", + "proxyquireify": "~3.2.0", "server-router": "^2.1.0", "sheetify": "^5.0.0", "standard": "^7.1.0", diff --git a/tests/browser/routing.js b/tests/browser/routing.js new file mode 100644 index 0000000..168fcdf --- /dev/null +++ b/tests/browser/routing.js @@ -0,0 +1,60 @@ +const test = require('tape') +const Event = require('geval/event') +const proxyquire = require('proxyquire') +const view = require('../../html') + +test('routing', function (t) { + t.test('history', function (t) { + t.plan(3) + + const history = Event() + const choo = proxyquire('../..', { + 'sheet-router/history': history.listen + }) + + const app = choo() + + app.model({ + state: { + user: null + }, + reducers: { + set: (action, state) => ({user: action.id}) + }, + effects: { + open: function (action, state, send, done) { + t.deepEqual(action, {id: 1}) + send('set', {id: 1}, function (err) { + if (err) return done(err) + history.broadcast('https://foo.com/users/1') + }) + } + } + }) + + app.router('/users', (route) => [ + route('/users', parentView, [ + route('/:user', childView) + ]) + ]) + + const tree = app.start() + document.body.appendChild(tree) + + t.equal(tree.innerHTML.trim(), 'Open') + tree.onclick() + + function parentView (state, prev, send) { + return view` + + ` + } + + function childView (state, prev, send) { + t.equal(state.user, 1) + return view`
${state.user}
` + } + }) +}) From e6a2a8c01dd86a30a97b34f72b0635d85ba4a22f Mon Sep 17 00:00:00 2001 From: Ben Drucker Date: Sun, 3 Jul 2016 17:13:42 -0700 Subject: [PATCH 14/19] Add test for hash based routing --- tests/browser/routing.js | 52 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/tests/browser/routing.js b/tests/browser/routing.js index 168fcdf..23b5806 100644 --- a/tests/browser/routing.js +++ b/tests/browser/routing.js @@ -57,4 +57,56 @@ test('routing', function (t) { return view`
${state.user}
` } }) + + t.test('hash', function (t) { + t.plan(1) + + const hash = Event() + const choo = proxyquire('../..', { + 'sheet-router/hash': hash.listen + }) + + const app = choo() + + app.model({ + state: { + user: null + }, + reducers: { + set: (action, state) => ({user: action.id}) + }, + effects: { + open: function (action, state, send, done) { + send('set', {id: 1}, function (err) { + if (err) return done(err) + hash.broadcast('#users/1') + }) + } + } + }) + + app.router('/users', (route) => [ + route('/users', parentView, [ + route('/:user', childView) + ]) + ]) + + const tree = app.start({hash: true}) + document.body.appendChild(tree) + + tree.onclick() + + function parentView (state, prev, send) { + return view` + + ` + } + + function childView (state, prev, send) { + t.equal(state.user, 1) + return view`
${state.user}
` + } + }) }) From 04b9e0efd2fed267fd7a9f0f4d06437f818cb069 Mon Sep 17 00:00:00 2001 From: Ben Drucker Date: Sun, 3 Jul 2016 17:18:30 -0700 Subject: [PATCH 15/19] Add test coverage for disabling sheet-router history/href listeners --- tests/browser/routing.js | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/browser/routing.js b/tests/browser/routing.js index 23b5806..53daee6 100644 --- a/tests/browser/routing.js +++ b/tests/browser/routing.js @@ -109,4 +109,40 @@ test('routing', function (t) { return view`
${state.user}
` } }) + + t.test('disabling history', function (t) { + t.plan(1) + + const choo = proxyquire('../..', { + 'sheet-router/history': () => t.fail('history listener attached') + }) + + const app = choo() + + app.router('/', (route) => [ + route('/', function () { + t.pass('rendered') + }) + ]) + + app.start({history: false}) + }) + + t.test('disabling href', function (t) { + t.plan(1) + + const choo = proxyquire('../..', { + 'sheet-router/href': () => t.fail('href listener attached') + }) + + const app = choo() + + app.router('/', (route) => [ + route('/', function () { + t.pass('rendered') + }) + ]) + + app.start({href: false}) + }) }) From 57ec042e1a67c4ba93ca33df61377ec740ec44a7 Mon Sep 17 00:00:00 2001 From: Ben Drucker Date: Sun, 3 Jul 2016 17:23:11 -0700 Subject: [PATCH 16/19] Add test nesting using sheet router (cov 100!) --- tests/browser/routing.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/browser/routing.js b/tests/browser/routing.js index 53daee6..aa08c84 100644 --- a/tests/browser/routing.js +++ b/tests/browser/routing.js @@ -145,4 +145,21 @@ test('routing', function (t) { app.start({href: false}) }) + + t.test('viewless nesting', function (t) { + t.plan(1) + + const choo = require('../..') + const app = choo() + + app.router('/users/123', (route) => [ + route('/users', [ + route('/:user', function (state) { + t.deepEqual(state.params, {user: '123'}) + }) + ]) + ]) + + app.start() + }) }) From 6d0070e62fea8bf9644144bd3e6afa5bb8d84ccb Mon Sep 17 00:00:00 2001 From: Ben Drucker Date: Sun, 3 Jul 2016 17:26:17 -0700 Subject: [PATCH 17/19] Update `npm test` command to use electron --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e8b46b3..c53e9ec 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "test:browser": "standard && npm run deps && NODE_ENV=test zuul tests/browser/*", "test:browser:local": "standard && npm run deps && NODE_ENV=test zuul --local 8080 -- tests/browser/*", "preversion": "if [ ! -z $SKIP_TEST ]; then npm run test:browser; fi", - "test": "npm run test:server" + "test": "npm run test:electron" }, "repository": "yoshuawuyts/choo", "keywords": [ From 1e006f3716c05e0ec266cdd0dcd7c91f5e52ca29 Mon Sep 17 00:00:00 2001 From: Ben Drucker Date: Mon, 4 Jul 2016 08:12:59 -0700 Subject: [PATCH 18/19] Enable xvfb on travis to run electron --- .travis.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.travis.yml b/.travis.yml index c1e0e35..99ea9e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,13 @@ node_js: - '6' sudo: false language: node_js +addons: + apt: + packages: + - xvfb +before_install: + - export DISPLAY=':99.0' + - Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & script: npm run test:cov after_script: npm i -g codecov.io && cat ./coverage/lcov.info | codecov env: From e3f715f71b3d3d41a21bc5ae552e0aadb482fc64 Mon Sep 17 00:00:00 2001 From: Ben Drucker Date: Mon, 4 Jul 2016 09:09:43 -0700 Subject: [PATCH 19/19] Clean up all DOM nodes when tests end As the test suite grows it's bad for debugging to leak tons of elements onto document.body. In order to concisely append/remove on the tests' "end" event, we need to make sure the root tagName doesn't change. If it does, the `tree` returned from `app.start` will no longer be the root node and the removal fn will throw. --- package.json | 1 + tests/browser/basic.js | 3 ++- tests/browser/hooks.js | 3 ++- tests/browser/rehydration.js | 3 ++- tests/browser/routing.js | 9 +++++---- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index c53e9ec..453e9d5 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "yo-yo": "^1.2.2" }, "devDependencies": { + "append-child": "~1.0.0", "bankai": "^2.0.2", "browserify": "^13.0.1", "browserify-istanbul": "^2.0.0", diff --git a/tests/browser/basic.js b/tests/browser/basic.js index 46745f6..368ca46 100644 --- a/tests/browser/basic.js +++ b/tests/browser/basic.js @@ -1,4 +1,5 @@ const test = require('tape') +const append = require('append-child') const choo = require('../../') const view = require('../../html') @@ -55,5 +56,5 @@ test('state is immutable', function (t) { ]) const tree = app.start() - document.body.appendChild(tree) + t.on('end', append(tree)) }) diff --git a/tests/browser/hooks.js b/tests/browser/hooks.js index bbcc73b..278ce01 100644 --- a/tests/browser/hooks.js +++ b/tests/browser/hooks.js @@ -1,4 +1,5 @@ const test = require('tape') +const append = require('append-child') const choo = require('../../') const view = require('../../html') @@ -51,5 +52,5 @@ test('hooks', function (t) { ]) const tree = app.start() - document.body.appendChild(tree) + t.on('end', append(tree)) }) diff --git a/tests/browser/rehydration.js b/tests/browser/rehydration.js index 1d75e48..1b91995 100644 --- a/tests/browser/rehydration.js +++ b/tests/browser/rehydration.js @@ -1,5 +1,6 @@ const test = require('tape') const onReady = require('document-ready') +const append = require('append-child') const choo = require('../../') const view = require('../../html') @@ -17,7 +18,7 @@ test('rehydration', function (t) { var node = document.createElement('div') node.innerHTML = app.toString('/') node = node.childNodes[0] - document.body.appendChild(node) + t.on('end', append(node)) app.start('#app-root') diff --git a/tests/browser/routing.js b/tests/browser/routing.js index aa08c84..6bf0f36 100644 --- a/tests/browser/routing.js +++ b/tests/browser/routing.js @@ -1,6 +1,7 @@ const test = require('tape') const Event = require('geval/event') const proxyquire = require('proxyquire') +const append = require('append-child') const view = require('../../html') test('routing', function (t) { @@ -39,7 +40,7 @@ test('routing', function (t) { ]) const tree = app.start() - document.body.appendChild(tree) + t.on('end', append(tree)) t.equal(tree.innerHTML.trim(), 'Open') tree.onclick() @@ -54,7 +55,7 @@ test('routing', function (t) { function childView (state, prev, send) { t.equal(state.user, 1) - return view`
${state.user}
` + return view`` } }) @@ -92,7 +93,7 @@ test('routing', function (t) { ]) const tree = app.start({hash: true}) - document.body.appendChild(tree) + t.on('end', append(tree)) tree.onclick() @@ -106,7 +107,7 @@ test('routing', function (t) { function childView (state, prev, send) { t.equal(state.user, 1) - return view`
${state.user}
` + return view`` } })