diff --git a/package.json b/package.json index a5e28c3..0dd1aac 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "npm-run-all": "^1.6.0", "object-assign": "^4.1.0", "own-enumerable-keys": "^1.0.0", + "pull-defer": "^0.2.2", "pull-delay": "^1.0.1", "sheet-router": "^3.0.1", "standard": "^7.0.1", diff --git a/test/zalgo.js b/test/zalgo.js new file mode 100644 index 0000000..21a4e8d --- /dev/null +++ b/test/zalgo.js @@ -0,0 +1,91 @@ +const test = require('tape') +const defer = require('pull-defer') +const extend = require('extend') +const inu = require('../') +const pull = inu.pull + +test('infinite loop if sync dispatch, model always new, and effect needs to run async', function (t) { + var i = 0 + var ended = false + const app = { + init: function () { + return { model: {}, effect: 'INIT' } + }, + update: function (model, action) { + switch (action) { + case 'TICK': + return { model: {}, effect: 'NEXT' } + case 'DONE': + return { model: false } + } + return { model: model } + }, + view: function (model, dispatch) { + if (ended) return + if (i++ > 1000) { + ended = true + t.ok(true) + return t.end() + } + if (model) return dispatch('TICK') + t.ok(false) + }, + run: function (effect) { + switch (effect) { + case 'NEXT': + const deferred = defer.source() + process.nextTick(function () { + deferred.resolve(pull.values(['DONE'])) + }) + return deferred + } + } + } + const sources = inu.start(app) +}) + +test('no infinite loop if async dispatch, model always new, and effect needs to run async', function (t) { + var i = 0 + var ended = false + const app = { + init: function () { + return { model: {}, effect: 'INIT' } + }, + update: function (model, action) { + switch (action) { + case 'TICK': + return { model: {}, effect: 'NEXT' } + case 'DONE': + return { model: false } + } + return { model: model } + }, + view: function (model, dispatch) { + if (ended) return + if (i++ > 1000) { + ended = true + t.ok(false) + return t.end() + } + if (model) { + process.nextTick(() => { + return dispatch('TICK') + }) + return + } + t.ok(true) + t.end() + }, + run: function (effect) { + switch (effect) { + case 'NEXT': + const deferred = defer.source() + process.nextTick(function () { + deferred.resolve(pull.values(['DONE'])) + }) + return deferred + } + } + } + const sources = inu.start(app) +})