atlas-relax
Version:
A minimal, powerful declarative VDOM and reactive programming framework.
1,083 lines (1,078 loc) • 181 kB
JavaScript
const { describe, it } = require("mocha")
const { expect } = require("chai")
const { LCRSRenderer, Tracker } = require("./effects");
const { diff, Frame } = require("../");
const { StemCell } = require("./cases/Frames");
const DeferredTests = require("./DeferredTests")
const { has, copy, inject } = require("./util")
const addHooks = ["willAdd", "didAdd"];
const updateHooks = ["willUpdate", "didUpdate"];
const allHooks = [...addHooks, ...updateHooks];
const p = StemCell.h
const h = (id, hooks, next) => p(id, {hooks}, next);
const hooks = (hook, job) => ({[hook]: function(){job(this)}})
const m = id => ({name:"div", data:{id}});
const k = (id, hooks, next) => { // keyed
const node = p(id, {hooks}, next);
node.key = id;
return node;
}
/* merging consecutive synchronous diffs is done by "rebasing" the current path onto the latter diff.
_----_----_
| | | | venn diagram of derived affected regions for first diff (A)
| A | | B | and the second diff (B). fill(O1) = A, fill(O2) = B where
-____-____- O1 is the originator set for A as O2 is for B.
O1 and O2 may be disjoint and |path| = |A U B|. */
// performing an outer-diff during mutation events is strictly not supported.
// XXX this code is dripping wet, need to wring it out so it becomes DRY
// e.g. 'should not X during Y' tests can be abstracted out into a factory or fn
// pretty easy refactor opportunity here, this file should be 100s of lines, not 1000s
describe("rebasing (merging a new diff into current diff)", function(){
describe("mounting", function(){
describe("virtual (managed) nodes", function(){
it("should not mount nodes during a constructor", function(){
let called = 0;
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const temp = h(0, hooks("ctor", f => {
const res = diff(m(1), null, f);
expect(res).to.be.false;
called++
}))
diff(temp, null, [renderer, tracker]);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(copy(temp)));
expect(events).to.eql([{wA: 0}, {mWA: 0}])
})
it("should not mount nodes during cleanup", function(){
let called = 0;
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const temp = h(0, hooks("cleanup", f => {
const res = diff(m(1), null, f);
expect(res).to.be.false;
called++
}))
const f = diff(temp, null, [renderer, tracker]);
diff(null, f);
expect(called).to.equal(1);
expect(renderer.tree).to.be.null;
expect(events).to.eql([{wA: 0}, {mWA: 0}, {mWP: 0}])
})
it("should not mount nodes during add mutation event", function(){
let called = 0;
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
diff(h(0), null, [renderer, tracker, {add: f => {
const res = diff(h(1), null, f);
expect(res).to.be.false;
called++
}}])
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0)));
expect(events).to.eql([{wA: 0}, {mWA: 0}])
})
it("should not mount nodes during remove mutation event", function(){
let called = 0;
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const f = diff(h(0, null, h(1)), null, [renderer, tracker, {remove: (f, p, s, t) => {
if (t.data.id === 1){
const res = diff(h(2), null, f);
expect(res).to.be.false;
called++
}
}}])
diff(h(0), f);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0)));
expect(events).to.eql([
{wA: 0}, {wA: 1}, {mWA: 0}, {mWA: 1}, {wU: 0}, {mWP: 1}, {mWR: 0}
])
})
it("should not mount nodes during temp mutation event", function(){
let called = 0;
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const f = diff(h(0), null, [renderer, tracker, {temp: f => {
const res = diff(h(1), null, f);
expect(res).to.be.false;
called++
}}])
diff(h(0), f);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0)));
expect(events).to.eql([
{wA: 0}, {mWA: 0}, {wU: 0}, {mWR: 0},
])
})
it("should not mount nodes during move mutation event", function(){
let called = 0;
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const f = diff(h(0, null, [k(1), k(2)]), null, [renderer, tracker, {move: f => {
if (f.temp.data.id === 2){
const res = diff(h(3), null, f);
expect(res).to.be.false;
called++
}
}}])
diff(h(0, null, [k(2), k(1)]), f);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, [k(2), k(1)])));
expect(events).to.eql([
{wA: 0}, {wA: 1}, {wA: 2}, {mWA: 0}, {mWA: 1}, {mWA: 2},
{wU: 0}, {wU: 1}, {wU: 2}, {mWR: 0}, {mWR: 2}, {mWM: 2}, {mWR: 1}
])
})
allHooks.forEach(hook => {
it(`should immediately return the root's ref during ${hook}`, function(){
const managedTemp = m(1)
let called = 0;
const temp = h(0, hooks(hook, f => {
const managedNode = diff(managedTemp, null, f);
expect(managedNode).to.be.an.instanceOf(Frame);
expect(managedNode.temp).to.equal(managedTemp);
called++;
}))
const f = diff(temp);
if (has(updateHooks, hook)) diff(copy(temp), f);
expect(called).to.equal(1);
})
it(`should properly mount the node during ${hook}`, function(){
const managedTemp = m(1)
const renderer = new LCRSRenderer
const temp = h(0, hooks(hook, f => {
diff(managedTemp, null, f)
}));
const f = diff(temp, null, renderer);
if (has(updateHooks, hook)) diff(copy(temp), f);
expect(renderer.tree).to.eql(renderer.renderStatic(inject(copy(temp), managedTemp)));
})
it(`should mount multiple sibling nodes in reverse call order by default during ${hook}`, function(){
const managedChildren = [m(1), m(2), m(3)], reverse = [...managedChildren].reverse();
const renderer = new LCRSRenderer
const temp = h(0, hooks(hook, f => {
for (let m of managedChildren) diff(m, null, f);
}));
const f = diff(temp, null, renderer);
if (has(updateHooks, hook)) diff(copy(temp), f);
expect(renderer.tree).to.eql(renderer.renderStatic(inject(copy(temp), reverse)));
})
it(`should otherwise mount multiple sibling nodes in a specified order during ${hook}`, function(){
const managedChildren = [m(1), m(2), m(3)];
const renderer = new LCRSRenderer
const temp = h(0, hooks(hook, f => {
const first = diff(managedChildren[0], null, f); // first is first child
const second = diff(managedChildren[1], null, f, first); // second after first
diff(managedChildren[2], null, f, second); // third after second
}));
const f = diff(temp, null, renderer);
if (has(updateHooks, hook)) diff(copy(temp), f);
expect(renderer.tree).to.eql(renderer.renderStatic(inject(copy(temp), managedChildren)));
})
})
const mount = f => {
diff(h(3, hooks("willAdd", f => {})), null, f);
diff(h(4, hooks("willAdd", f => {})), null, f);
}
it("should defer rendering new nodes in reverse order until all updates have run during willUpdate", function(){
const events = [], tracker = new Tracker(events);
const temp = h(0, null, [
h(1),
h(2, hooks("willUpdate", f => mount(f)))
])
const f = diff(temp, null, tracker);
events.length = 0; // we don't care about initial mount
diff(copy(temp), f);
expect(events).to.eql([
{wU: 0}, {wU: 1}, {wU: 2}, {wA: 4}, {wA: 3},
{mWR: 0}, {mWR: 1}, {mWR: 2}, {mWA: 4}, {mWA: 3}
])
})
it("should defer rendering new nodes in reverse order until after flush during didUpdate", function(){
const events = [], tracker = new Tracker(events);
const temp = h(0, null, [
h(1),
h(2, hooks("didUpdate", f => mount(f)))
])
const f = diff(temp, null, tracker);
events.length = 0; // we don't care about initial mount
diff(copy(temp), f);
expect(events).to.eql([
{wU: 0}, {wU: 1}, {wU: 2}, {mWR: 0}, {mWR: 1}, {mWR: 2}, {dU: 2},
{wA: 4}, {wA: 3}, {mWA: 4}, {mWA: 3}
])
})
it("should immediately add new nodes in reverse order during willAdd", function(){
const events = [], tracker = new Tracker(events);
const temp = h(0, null, [
h(1, hooks("willAdd", f => mount(f))),
h(2)
])
const f = diff(temp, null, tracker);
expect(events).to.eql([
{wA: 0}, {wA: 1}, {wA: 4}, {wA: 3}, {wA: 2},
{mWA: 0}, {mWA: 1}, {mWA: 4}, {mWA: 3}, {mWA: 2}
])
})
it("should defer adding new nodes in reverse order after flush during didAdd", function(){
const events = [], tracker = new Tracker(events);
const temp = h(0, null, [
h(1, hooks("didAdd", f => mount(f))),
h(2)
])
const f = diff(temp, null, tracker);
expect(events).to.eql([
{wA: 0}, {wA: 1}, {wA: 2}, {mWA: 0}, {mWA: 1}, {mWA: 2}, {dA: 1},
{wA: 4}, {wA: 3}, {mWA: 4}, {mWA: 3},
])
})
})
describe("free (unmanaged) nodes", function(){
it("should not mount nodes during a constructor", function(){
let called = 0;
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const temp = h(0, hooks("ctor", f => {
const res = diff(m(1), null, [renderer, tracker]);
expect(res).to.be.false;
called++
}))
diff(temp);
expect(called).to.equal(1);
expect(renderer.tree).to.be.null;
expect(events).to.be.empty
})
it("should not mount nodes during cleanup", function(){
let called = 0;
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const temp = h(0, hooks("cleanup", f => {
const res = diff(m(1), null, [renderer, tracker]);
expect(res).to.be.false;
called++
}))
const f = diff(temp);
diff(null, f);
expect(called).to.equal(1);
expect(renderer.tree).to.be.null;
expect(events).to.be.empty
})
it("should not mount nodes during add mutation event", function(){
let called = 0;
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
diff(h(0), null, {add: f => {
const res = diff(h(1), null, [renderer, tracker]);
expect(res).to.be.false;
called++
}})
expect(called).to.equal(1);
expect(renderer.tree).to.be.null
expect(events).to.be.empty;
})
it("should not mount nodes during remove mutation event", function(){
let called = 0;
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const f = diff(h(0, null, h(1)), null, {remove: (f, p, s, t) => {
if (t.data.id === 1){
const res = diff(h(2), null, [renderer, tracker]);
expect(res).to.be.false;
called++
}
}})
diff(h(0), f);
expect(called).to.equal(1);
expect(renderer.tree).to.be.null
expect(events).to.be.empty
})
it("should not mount nodes during temp mutation event", function(){
let called = 0;
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const f = diff(h(0), null, {temp: f => {
const res = diff(h(1), null, [renderer, tracker]);
expect(res).to.be.false;
called++
}})
diff(h(0), f);
expect(called).to.equal(1);
expect(renderer.tree).to.be.null
expect(events).to.be.empty;
})
it("should not mount nodes during move mutation event", function(){
let called = 0;
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const f = diff(h(0, null, [k(1), k(2)]), null, {move: f => {
if (f.temp.data.id === 2){
const res = diff(h(3), null, [renderer, tracker]);
expect(res).to.be.false;
called++
}
}})
diff(h(0, null, [k(2), k(1)]), f);
expect(called).to.equal(1);
expect(renderer.tree).to.be.null;
expect(events).to.be.empty;
})
allHooks.forEach(hook => {
it(`should immediately return the root's ref during ${hook}`, function(){
const managedTemp = m(1)
let called = 0;
const temp = h(0, hooks(hook, f => {
const managedNode = diff(managedTemp);
expect(managedNode).to.be.an.instanceOf(Frame);
expect(managedNode.temp).to.equal(managedTemp);
called++;
}))
const f = diff(temp);
if (has(updateHooks, hook)) diff(copy(temp), f);
expect(called).to.equal(1);
})
it(`should properly mount the node during ${hook}`, function(){
const managedTemp = m(1)
const renderer = new LCRSRenderer
const temp = h(0, hooks(hook, f => {
diff(managedTemp)
}));
const f = diff(temp, null, renderer);
if (has(updateHooks, hook)) diff(copy(temp), f);
expect(renderer.tree).to.eql(renderer.renderStatic(temp));
})
it(`should mount multiple nodes in reverse call order during ${hook}`, function(){
const managedIds = [1, 2, 3];
let order = [];
const temp = h(0, hooks(hook, f => {
for (let id of managedIds) diff(h(id, hooks("willAdd", f => {
order.push(id);
})));
}));
const f = diff(temp);
if (has(updateHooks, hook)) diff(copy(temp), f);
expect(order).to.eql([3,2,1])
})
})
const mount = tracker => {
diff(h(3, hooks("willAdd", f => {})), null, tracker);
diff(h(4, hooks("willAdd", f => {})), null, tracker);
}
it("should defer rendering new nodes in reverse order until all updates have run during willUpdate", function(){
const events = [], tracker = new Tracker(events);
const temp = h(0, null, [
h(1),
h(2, hooks("willUpdate", f => mount(tracker)))
])
const f = diff(temp, null, tracker);
events.length = 0; // we don't care about initial mount
diff(copy(temp), f);
expect(events).to.eql([
{wU: 0}, {wU: 1}, {wU: 2}, {wA: 4}, {wA: 3},
{mWR: 0}, {mWR: 1}, {mWR: 2}, {mWA: 3}, {mWA: 4}
])
})
it("should defer rendering new nodes in reverse order until after flush during didUpdate", function(){
const events = [], tracker = new Tracker(events);
const temp = h(0, null, [
h(1),
h(2, hooks("didUpdate", f => mount(tracker)))
])
const f = diff(temp, null, tracker);
events.length = 0; // we don't care about initial mount
diff(copy(temp), f);
expect(events).to.eql([
{wU: 0}, {wU: 1}, {wU: 2}, {mWR: 0}, {mWR: 1}, {mWR: 2}, {dU: 2},
{wA: 4}, {wA: 3}, {mWA: 3}, {mWA: 4}
])
})
it("should immediately render new nodes in reverse order during willAdd", function(){
const events = [], tracker = new Tracker(events);
const temp = h(0, null, [
h(1, hooks("willAdd", f => mount(tracker))),
h(2)
])
const f = diff(temp, null, tracker);
expect(events).to.eql([
{wA: 0}, {wA: 1}, {wA: 4}, {wA: 3}, {wA: 2},
{mWA: 0}, {mWA: 1}, {mWA: 2}, {mWA: 3}, {mWA: 4}
])
})
it("should defer adding new nodes in reverse order after flush during didAdd", function(){
const events = [], tracker = new Tracker(events);
const temp = h(0, null, [
h(1, hooks("didAdd", f => mount(tracker))),
h(2)
])
const f = diff(temp, null, tracker);
expect(events).to.eql([
{wA: 0}, {wA: 1}, {wA: 2}, {mWA: 0}, {mWA: 1}, {mWA: 2}, {dA: 1},
{wA: 4}, {wA: 3}, {mWA: 3}, {mWA: 4},
])
})
})
})
describe("unmounting", function(){
describe("virtual (managed) nodes", function(){
it("should not unmount nodes during a constructor", function(){
let called = 0;
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const r = diff(h(0, null), null, [renderer, tracker]);
const managedR = diff(h(1), null, r);
diff(h(2, hooks("ctor", f => {
const res = diff(null, managedR);
expect(res).to.be.false;
called++
})))
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, h(1))));
expect(events).to.eql([{wA: 0}, {mWA: 0}, {wA: 1}, {mWA: 1}])
})
it("should not unmount nodes during cleanup", function(){
let called = 0;
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const r = diff(h(0, null), null, [renderer, tracker]);
const managedR = diff(h(1), null, r);
const f = diff(h(2, hooks("cleanup", f => {
const res = diff(null, managedR);
expect(res).to.be.false;
called++
})))
diff(null, f);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, h(1))));
expect(events).to.eql([{wA: 0}, {mWA: 0}, {wA: 1}, {mWA: 1}])
})
it("should not unmount nodes during add mutation event", function(){
let called = 0;
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const r = diff(h(0, null), null, [renderer, tracker]);
const m = diff(h(1), null, r);
diff(h(2), null, {add: f => {
const res = diff(null, m);
expect(res).to.be.false;
called++
}})
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, h(1))));
expect(events).to.eql([{wA: 0}, {mWA: 0}, {wA: 1}, {mWA: 1}])
})
it("should not unmount nodes during remove mutation event", function(){
let called = 0;
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const r = diff(h(0, null), null, [renderer, tracker]);
const m = diff(h(1), null, r);
const f = diff(h(2), null, {remove: f => {
const res = diff(null, m);
expect(res).to.be.false;
called++
}})
diff(null, f);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, h(1))));
expect(events).to.eql([{wA: 0}, {mWA: 0}, {wA: 1}, {mWA: 1}])
})
it("should not unmount nodes during temp mutation event", function(){
let called = 0;
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const r = diff(h(0, null), null, [renderer, tracker]);
const m = diff(h(1), null, r);
const f = diff(h(2), null, {temp: f => {
const res = diff(null, m);
expect(res).to.be.false;
called++
}})
diff(h(2), f)
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, h(1))));
expect(events).to.eql([{wA: 0}, {mWA: 0}, {wA: 1}, {mWA: 1}])
})
it("should not unmount nodes during move mutation event", function(){
let called = 0;
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const r = diff(h(0, null), null, [renderer, tracker]);
const m = diff(h(1), null, r);
const f = diff(h(2, null, [k(3), k(4)]), null, {move: f => {
if (f.temp.data.id === 4){
const res = diff(null, m);
expect(res).to.be.false;
called++
}
}})
diff(h(2, null, [k(4), k(3)]), f);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, h(1))));
expect(events).to.eql([{wA: 0}, {mWA: 0}, {wA: 1}, {mWA: 1}])
})
it("should unmount nodes created during willAdd in the next cycle", function(){
const managedTemp = h(1);
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
let called = 0;
const hooks = {
willAdd: f => {f.managed = diff(managedTemp, null, f)},
willUpdate: f => {
expect(f.managed).to.be.an.instanceOf(Frame);
expect(f.managed.temp).to.equal(managedTemp);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, hooks, h(1))))
const res = diff(null, f.managed)
expect(res).to.be.true;
called++;
}
}
const r = diff(h(0, hooks), null, [renderer, tracker]);
diff(h(0, hooks), r);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, hooks)))
expect(events).to.eql([
{ wA: 0 }, { wA: 1 }, { mWA: 0 }, { mWA: 1 }, { wU: 0 }, { mWP: 1 }, { mWR: 0 }
])
})
it("should unmount nodes created during willAdd in didAdd", function(){
const managedTemp = h(1);
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
let called = 0;
const hooks = {
willAdd: f => {f.managed = diff(managedTemp, null, f)},
didAdd: f => {
expect(f.managed).to.be.an.instanceOf(Frame);
expect(f.managed.temp).to.equal(managedTemp);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, hooks, h(1))))
const res = diff(null, f.managed)
expect(res).to.be.true;
called++;
}
}
diff(h(0, hooks), null, [renderer, tracker]);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, hooks)))
expect(events).to.eql([
{ wA: 0 }, { wA: 1 }, { mWA: 0 }, { mWA: 1 }, {dA: 0}, { mWP: 1 }
])
})
it("should unmount an external node during willAdd", function(){
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const r1 = diff(h(0, null), null, [renderer, tracker]);
const managedRoot = diff(h(1), null, r1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, h(1))))
let called = 0;
const temp = h(2, hooks("willAdd", f => {
const res = diff(null, managedRoot);
expect(res).to.be.true;
called++;
}));
diff(temp, null, tracker);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null)))
expect(events).to.eql([
{ wA: 0 }, { mWA: 0 }, {wA: 1}, { mWA: 1 }, {wA: 2}, { mWP: 1 }, {mWA: 2}
])
})
it("should unmount an external node during didAdd", function(){
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const r1 = diff(h(0, null), null, [renderer, tracker]);
const managedRoot = diff(h(1), null, r1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, h(1))))
let called = 0;
const temp = h(2, hooks("didAdd", f => {
const res = diff(null, managedRoot);
expect(res).to.be.true;
called++;
}));
diff(temp, null, tracker);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null)))
expect(events).to.eql([
{ wA: 0 }, { mWA: 0 }, {wA: 1}, { mWA: 1 }, {wA: 2}, {mWA: 2}, {dA: 2}, { mWP: 1 }
])
})
it("should unmount an external node during willUpdate", function(){
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const r1 = diff(h(0, null), null, [renderer, tracker]);
const managedRoot = diff(h(1), null, r1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, h(1))))
let called = 0;
const temp = h(2, hooks("willUpdate", f => {
const res = diff(null, managedRoot);
expect(res).to.be.true;
called++;
}));
const r2 = diff(temp, null, tracker);
events.length = 0;
diff(copy(temp), r2);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null)))
expect(events).to.eql([
{wU: 2}, { mWP: 1 }, {mWR: 2}
])
})
it("should unmount an external node during didUpdate", function(){
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const r1 = diff(h(0, null), null, [renderer, tracker]);
const managedRoot = diff(h(1), null, r1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, h(1))))
let called = 0;
const temp = h(2, hooks("didUpdate", f => {
const res = diff(null, managedRoot);
expect(res).to.be.true;
called++;
}));
const r2 = diff(temp, null, tracker);
events.length = 0;
diff(copy(temp), r2);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null)))
expect(events).to.eql([
{wU: 2}, {mWR: 2}, {dU: 2}, {mWP: 1}
])
})
it("should unmount a node that has not yet been rendered during willAdd", function(){
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const t = h(0, hooks("willAdd", f => {
const r = diff(m(1), null, f);
diff(null, r);
}))
diff(t, null, [renderer, tracker]);
expect(renderer.tree).to.eql(renderer.renderStatic(copy(t)));
expect(events).to.eql([{ wA: 0 }, { mWA: 0 }])
})
it("should unmount a node that has not yet been rendered during didAdd", function(){
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const t = h(0, hooks("didAdd", f => {
const r = diff(m(1), null, f);
diff(null, r);
}))
diff(t, null, [renderer, tracker]);
expect(renderer.tree).to.eql(renderer.renderStatic(copy(t)));
expect(events).to.eql([{ wA: 0 }, { mWA: 0 }, {dA: 0}])
})
it("should unmount a node that has not yet been rendered during willUpdate", function(){
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const t = h(0, hooks("willUpdate", f => {
const r = diff(m(1), null, f);
diff(null, r);
}))
const r = diff(t, null, [renderer, tracker]);
events.length = 0;
diff(copy(t), r);
expect(renderer.tree).to.eql(renderer.renderStatic(copy(t)));
expect(events).to.eql([{ wU: 0 }, { mWR: 0 }])
})
it("should unmount a node that has not yet been rendered during didUpdate", function(){
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const t = h(0, hooks("didUpdate", f => {
const r = diff(m(1), null, f);
diff(null, r);
}))
const r = diff(t, null, [renderer, tracker]);
events.length = 0;
diff(copy(t), r);
expect(renderer.tree).to.eql(renderer.renderStatic(copy(t)));
expect(events).to.eql([{ wU: 0 }, { mWR: 0 }, {dU: 0}])
})
it("should properly unmount itself during willAdd", function(){
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const r = diff(h(0), null, [renderer, tracker]);
const temp = h(1, hooks("willAdd", f => diff(null, f)));
diff(temp, null, r);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0)));
expect(events).to.eql([ { wA: 0 }, { mWA: 0 }, { wA: 1 }])
})
it("should properly unmount itself during didAdd", function(){
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const r = diff(h(0), null, [renderer, tracker]);
const temp = h(1, hooks("didAdd", f => diff(null, f)));
diff(temp, null, r);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0)));
expect(events).to.eql([ { wA: 0 }, { mWA: 0 }, { wA: 1 }, {mWA: 1}, {dA: 1}, {mWP: 1}])
})
it("should properly unmount itself during willUpdate", function(){
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const r = diff(h(0), null, [renderer, tracker]);
const temp = h(1, hooks("willUpdate", f => diff(null, f)));
const r2 = diff(temp, null, r);
events.length = 0;
diff(copy(temp), r2)
expect(renderer.tree).to.eql(renderer.renderStatic(h(0)));
expect(events).to.eql([ { wU: 1 }, { mWP: 1 }])
})
it("should properly unmount itself during didUpdate", function(){
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const r = diff(h(0), null, [renderer, tracker]);
const temp = h(1, hooks("didUpdate", f => diff(null, f)));
const r2 = diff(temp, null, r);
events.length = 0;
diff(copy(temp), r2)
expect(renderer.tree).to.eql(renderer.renderStatic(h(0)));
expect(events).to.eql([ { wU: 1 }, {mWR: 1}, {dU: 1}, { mWP: 1 }])
})
it("should unmount multiple nodes in default order during willAdd", function(){
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const r1 = diff(h(0, null), null, [renderer, tracker]);
const managedRoot1 = diff(h(1), null, r1);
const managedRoot2 = diff(h(2), null, r1, managedRoot1);
const managedRoot3 = diff(h(3), null, r1, managedRoot2);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, [h(1), h(2), h(3)])))
let called = 0;
const temp = h(4, hooks("willAdd", f => {
expect(diff(null, managedRoot1)).to.be.true;
expect(diff(null, managedRoot2)).to.be.true;
expect(diff(null, managedRoot3)).to.be.true;
called++;
}));
diff(temp, null, tracker);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null)))
expect(events).to.eql([
{ wA: 0 }, { mWA: 0 },
{wA: 1}, { mWA: 1 }, {wA: 2}, {mWA: 2}, {wA: 3}, { mWA: 3},
{ wA: 4}, {mWP: 1}, {mWP: 2}, {mWP: 3}, {mWA: 4}
])
})
it("should unmount multiple nodes in default order during didAdd", function(){
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const r1 = diff(h(0, null), null, [renderer, tracker]);
const managedRoot1 = diff(h(1), null, r1);
const managedRoot2 = diff(h(2), null, r1, managedRoot1);
const managedRoot3 = diff(h(3), null, r1, managedRoot2);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, [h(1), h(2), h(3)])))
let called = 0;
const temp = h(4, hooks("didAdd", f => {
expect(diff(null, managedRoot1)).to.be.true;
expect(diff(null, managedRoot2)).to.be.true;
expect(diff(null, managedRoot3)).to.be.true;
called++;
}));
diff(temp, null, tracker);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null)))
expect(events).to.eql([
{ wA: 0 }, { mWA: 0 },
{wA: 1}, { mWA: 1 }, {wA: 2}, {mWA: 2}, {wA: 3}, { mWA: 3},
{ wA: 4}, {mWA: 4}, {dA: 4}, {mWP: 1}, {mWP: 2}, {mWP: 3}
])
})
it("should unmount multiple nodes in default order during willUpdate", function(){
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const r1 = diff(h(0, null), null, [renderer, tracker]);
const managedRoot1 = diff(h(1), null, r1);
const managedRoot2 = diff(h(2), null, r1, managedRoot1);
const managedRoot3 = diff(h(3), null, r1, managedRoot2);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, [h(1), h(2), h(3)])))
let called = 0;
const temp = h(4, hooks("willUpdate", f => {
expect(diff(null, managedRoot1)).to.be.true;
expect(diff(null, managedRoot2)).to.be.true;
expect(diff(null, managedRoot3)).to.be.true;
called++;
}));
const r2 = diff(temp, null, tracker);
events.length = 0;
diff(copy(temp), r2);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null)))
expect(events).to.eql([
{wU: 4}, { mWP: 1 }, { mWP: 2 }, { mWP: 3 }, {mWR: 4}
])
})
it("should unmount multiple nodes in default order during didUpdate", function(){
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const r1 = diff(h(0, null), null, [renderer, tracker]);
const managedRoot1 = diff(h(1), null, r1);
const managedRoot2 = diff(h(2), null, r1, managedRoot1);
const managedRoot3 = diff(h(3), null, r1, managedRoot2);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, [h(1), h(2), h(3)])))
let called = 0;
const temp = h(4, hooks("didUpdate", f => {
expect(diff(null, managedRoot1)).to.be.true;
expect(diff(null, managedRoot2)).to.be.true;
expect(diff(null, managedRoot3)).to.be.true;
called++;
}));
const r2 = diff(temp, null, tracker);
events.length = 0;
diff(copy(temp), r2);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null)))
expect(events).to.eql([
{wU: 4}, {mWR: 4}, {dU: 4}, { mWP: 1 }, { mWP: 2 }, { mWP: 3 }
])
})
it("should unmount multiple nodes in a specified order during willAdd", function(){
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const r1 = diff(h(0, null), null, [renderer, tracker]);
const managedRoot1 = diff(h(1), null, r1);
const managedRoot2 = diff(h(2), null, r1, managedRoot1);
const managedRoot3 = diff(h(3), null, r1, managedRoot2);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, [h(1), h(2), h(3)])))
let called = 0;
const temp = h(4, hooks("willAdd", f => {
expect(diff(null, managedRoot3)).to.be.true;
expect(diff(null, managedRoot2)).to.be.true;
expect(diff(null, managedRoot1)).to.be.true;
called++;
}));
diff(temp, null, tracker);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null)))
expect(events).to.eql([
{ wA: 0 }, { mWA: 0 },
{wA: 1}, { mWA: 1 }, {wA: 2}, {mWA: 2}, {wA: 3}, { mWA: 3},
{ wA: 4}, {mWP: 3}, {mWP: 2}, {mWP: 1}, {mWA: 4}
])
})
it("should unmount multiple nodes in a specified order during didAdd", function(){
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const r1 = diff(h(0, null), null, [renderer, tracker]);
const managedRoot1 = diff(h(1), null, r1);
const managedRoot2 = diff(h(2), null, r1, managedRoot1);
const managedRoot3 = diff(h(3), null, r1, managedRoot2);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, [h(1), h(2), h(3)])))
let called = 0;
const temp = h(4, hooks("didAdd", f => {
expect(diff(null, managedRoot3)).to.be.true;
expect(diff(null, managedRoot2)).to.be.true;
expect(diff(null, managedRoot1)).to.be.true;
called++;
}));
diff(temp, null, tracker);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null)))
expect(events).to.eql([
{ wA: 0 }, { mWA: 0 },
{wA: 1}, { mWA: 1 }, {wA: 2}, {mWA: 2}, {wA: 3}, { mWA: 3},
{ wA: 4}, {mWA: 4}, {dA: 4}, {mWP: 3}, {mWP: 2}, {mWP: 1}
])
})
it("should unmount multiple nodes in a specified order during willUpdate", function(){
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const r1 = diff(h(0, null), null, [renderer, tracker]);
const managedRoot1 = diff(h(1), null, r1);
const managedRoot2 = diff(h(2), null, r1, managedRoot1);
const managedRoot3 = diff(h(3), null, r1, managedRoot2);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, [h(1), h(2), h(3)])))
let called = 0;
const temp = h(4, hooks("willUpdate", f => {
expect(diff(null, managedRoot3)).to.be.true;
expect(diff(null, managedRoot2)).to.be.true;
expect(diff(null, managedRoot1)).to.be.true;
called++;
}));
const r2 = diff(temp, null, tracker);
events.length = 0;
diff(copy(temp), r2);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null)))
expect(events).to.eql([
{wU: 4}, { mWP: 3 }, { mWP: 2 }, { mWP: 1 }, {mWR: 4}
])
})
it("should unmount multiple nodes in a specified order during didUpdate", function(){
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const r1 = diff(h(0, null), null, [renderer, tracker]);
const managedRoot1 = diff(h(1), null, r1);
const managedRoot2 = diff(h(2), null, r1, managedRoot1);
const managedRoot3 = diff(h(3), null, r1, managedRoot2);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, [h(1), h(2), h(3)])))
let called = 0;
const temp = h(4, hooks("didUpdate", f => {
expect(diff(null, managedRoot3)).to.be.true;
expect(diff(null, managedRoot2)).to.be.true;
expect(diff(null, managedRoot1)).to.be.true;
called++;
}));
const r2 = diff(temp, null, tracker);
events.length = 0;
diff(copy(temp), r2);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null)))
expect(events).to.eql([
{wU: 4}, {mWR: 4}, {dU: 4}, { mWP: 3 }, { mWP: 2 }, { mWP: 1 }
])
})
it("should rebase all entangled affects during willAdd", function(){
const events = [], tracker = new Tracker(events);
const renderer = new LCRSRenderer, renderer2 = new LCRSRenderer, renderer3 = new LCRSRenderer;
const r1 = diff(h(0, null), null, [renderer, tracker]);
const managedRoot = diff(h(1, null, h(2)), null, r1);
const affectedRoot1 = diff(h(3, null, h(4)), null, [renderer2, tracker]);
const affectedRoot2 = diff(h(5, null, [h(6), h(7)]), null, [renderer3, tracker]);
affectedRoot1.sub(managedRoot), affectedRoot2.sub(managedRoot.next);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, h(1, null, h(2)))))
let called = 0;
const temp = h(8, hooks("willAdd", f => {
const res = diff(null, managedRoot);
expect(res).to.be.true;
called++;
}));
diff(temp, null, tracker);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null)))
expect(renderer2.tree).to.eql(renderer2.renderStatic(h(3, null, h(4))))
expect(renderer3.tree).to.eql(renderer3.renderStatic(h(5, null, [h(6), h(7)])))
expect(events).to.eql([
{ wA: 0 }, { mWA: 0 },
{wA: 1}, {wA: 2}, {mWA: 1}, { mWA: 2 },
{wA: 3}, {wA: 4}, {mWA: 3}, {mWA: 4},
{wA: 5}, {wA: 6}, {wA: 7}, {mWA: 5}, {mWA:6}, {mWA: 7},
{wA: 8}, {wU: 3}, {wU: 4}, {wU: 5}, {wU: 6}, {wU: 7},
{mWP: 1}, {mWP: 2}, {mWA: 8}, {mWR: 4}, {mWR: 6}, {mWR: 7}
])
})
it("should not rebase laggard entangled affects during willAdd", function(){
const events = [], tracker = new Tracker(events);
const renderer = new LCRSRenderer, renderer2 = new LCRSRenderer, renderer3 = new LCRSRenderer;
const r1 = diff(h(0, null), null, [renderer, tracker]);
const managedRoot = diff(h(1, null, h(2)), null, r1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, h(1, null, h(2)))))
let called = 0;
const temp = h(8, hooks("willAdd", f => {
const affectedRoot1 = diff(h(3, null, h(4)), null, [renderer2, tracker]);
const affectedRoot2 = diff(h(5, null, [h(6), h(7)]), null, [renderer3, tracker]);
affectedRoot1.sub(managedRoot), affectedRoot2.sub(managedRoot.next);
const res = diff(null, managedRoot);
expect(res).to.be.true;
called++;
}));
diff(temp, null, tracker);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null)))
expect(renderer2.tree).to.eql(renderer2.renderStatic(h(3, null, h(4))))
expect(renderer3.tree).to.eql(renderer3.renderStatic(h(5, null, [h(6), h(7)])))
expect(events).to.eql([
{ wA: 0 }, { mWA: 0 },
{wA: 1}, {wA: 2}, {mWA: 1}, { mWA: 2 },
{wA: 8}, {wA: 5}, {wA: 6}, {wA: 7}, {wA: 3}, {wA: 4},
{mWP: 1}, {mWP: 2}, {mWA: 8}, {mWA: 3}, {mWA: 4}, {mWA: 5}, {mWA:6}, {mWA: 7}
])
})
it("should rebase all entangled affects during didAdd", function(){
const events = [], tracker = new Tracker(events);
const renderer = new LCRSRenderer, renderer2 = new LCRSRenderer, renderer3 = new LCRSRenderer;
const r1 = diff(h(0, null), null, [renderer, tracker]);
const managedRoot = diff(h(1, null, h(2)), null, r1);
const affectedRoot1 = diff(h(3, null, h(4)), null, [renderer2, tracker]);
const affectedRoot2 = diff(h(5, null, [h(6), h(7)]), null, [renderer3, tracker]);
affectedRoot1.sub(managedRoot), affectedRoot2.sub(managedRoot.next);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, h(1, null, h(2)))))
let called = 0;
const temp = h(8, hooks("didAdd", f => {
const res = diff(null, managedRoot);
expect(res).to.be.true;
called++;
}));
diff(temp, null, tracker);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null)))
expect(renderer2.tree).to.eql(renderer2.renderStatic(h(3, null, h(4))))
expect(renderer3.tree).to.eql(renderer3.renderStatic(h(5, null, [h(6), h(7)])))
expect(events).to.eql([
{ wA: 0 }, { mWA: 0 },
{wA: 1}, {wA: 2}, {mWA: 1}, { mWA: 2 },
{wA: 3}, {wA: 4}, {mWA: 3}, {mWA: 4},
{wA: 5}, {wA: 6}, {wA: 7}, {mWA: 5}, {mWA:6}, {mWA: 7},
{wA: 8}, {mWA: 8}, {dA: 8}, {wU: 3}, {wU: 4}, {wU: 5}, {wU: 6}, {wU: 7},
{mWP: 1}, {mWP: 2}, {mWR: 4}, {mWR: 6}, {mWR: 7}
])
})
it("should rebase all entangled affects during willUpdate", function(){
const events = [], tracker = new Tracker(events);
const renderer = new LCRSRenderer, renderer2 = new LCRSRenderer, renderer3 = new LCRSRenderer;
const r1 = diff(h(0, null), null, [renderer, tracker]);
const managedRoot = diff(h(1, null, h(2)), null, r1);
const affectedRoot1 = diff(h(3, null, h(4)), null, [renderer2, tracker]);
const affectedRoot2 = diff(h(5, null, [h(6), h(7)]), null, [renderer3, tracker]);
affectedRoot1.sub(managedRoot), affectedRoot2.sub(managedRoot.next);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, h(1, null, h(2)))))
let called = 0;
const temp = h(8, hooks("willUpdate", f => {
const res = diff(null, managedRoot);
expect(res).to.be.true;
called++;
}));
const r2 = diff(temp, null, tracker);
events.length = 0;
diff(copy(temp), r2);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null)))
expect(renderer2.tree).to.eql(renderer2.renderStatic(h(3, null, h(4))))
expect(renderer3.tree).to.eql(renderer3.renderStatic(h(5, null, [h(6), h(7)])))
expect(events).to.eql([
{wU: 8}, {wU: 3}, {wU: 4}, {wU: 5}, {wU: 6}, {wU: 7},
{mWP: 1}, {mWP: 2}, {mWR: 8}, {mWR: 4}, {mWR: 6}, {mWR: 7}
])
})
it("should not rebase laggard entangled affects during willUpdate", function(){
const events = [], tracker = new Tracker(events);
const renderer = new LCRSRenderer, renderer2 = new LCRSRenderer, renderer3 = new LCRSRenderer;
const r1 = diff(h(0, null), null, [renderer, tracker]);
const managedRoot = diff(h(1, null, h(2)), null, r1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, h(1, null, h(2)))))
let called = 0;
const temp = h(8, hooks("willUpdate", f => {
const affectedRoot1 = diff(h(3, null, h(4)), null, [renderer2, tracker]);
const affectedRoot2 = diff(h(5, null, [h(6), h(7)]), null, [renderer3, tracker]);
affectedRoot1.sub(managedRoot), affectedRoot2.sub(managedRoot.next);
const res = diff(null, managedRoot);
expect(res).to.be.true;
called++;
}));
const r2 = diff(temp, null, tracker);
events.length = 0;
diff(copy(temp), r2);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null)))
expect(renderer2.tree).to.eql(renderer2.renderStatic(h(3, null, h(4))))
expect(renderer3.tree).to.eql(renderer3.renderStatic(h(5, null, [h(6), h(7)])))
expect(events).to.eql([
{wU: 8}, {wA: 5}, {wA: 6}, {wA: 7}, {wA: 3}, {wA: 4},
{mWP: 1}, {mWP: 2}, {mWR: 8}, {mWA: 3}, {mWA: 4}, {mWA: 5}, {mWA: 6}, {mWA: 7}
])
})
it("should rebase all entangled affects during didUpdate", function(){
const events = [], tracker = new Tracker(events);
const renderer = new LCRSRenderer, renderer2 = new LCRSRenderer, renderer3 = new LCRSRenderer;
const r1 = diff(h(0, null), null, [renderer, tracker]);
const managedRoot = diff(h(1, null, h(2)), null, r1);
const affectedRoot1 = diff(h(3, null, h(4)), null, [renderer2, tracker]);
const affectedRoot2 = diff(h(5, null, [h(6), h(7)]), null, [renderer3, tracker]);
affectedRoot1.sub(managedRoot), affectedRoot2.sub(managedRoot.next);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null, h(1, null, h(2)))))
let called = 0;
const temp = h(8, hooks("didUpdate", f => {
const res = diff(null, managedRoot);
expect(res).to.be.true;
called++;
}));
const r2 = diff(temp, null, tracker);
events.length = 0;
diff(copy(temp), r2);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0, null)))
expect(renderer2.tree).to.eql(renderer2.renderStatic(h(3, null, h(4))))
expect(renderer3.tree).to.eql(renderer3.renderStatic(h(5, null, [h(6), h(7)])))
expect(events).to.eql([
{wU: 8}, {mWR: 8}, {dU: 8}, {wU: 3}, {wU: 4}, {wU: 5}, {wU: 6}, {wU: 7},
{mWP: 1}, {mWP: 2}, {mWR: 4}, {mWR: 6}, {mWR: 7}
])
})
})
describe("free (unmanaged) nodes", function(){
it("should not unmount nodes during a constructor", function(){
let called = 0;
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const r = diff(h(0), null, [renderer, tracker]);
diff(h(1, hooks("ctor", f => {
const res = diff(null, r);
expect(res).to.be.false;
called++
})))
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0)));
expect(events).to.eql([{wA: 0}, {mWA: 0}])
})
it("should not unmount nodes during cleanup", function(){
let called = 0;
const events = [], renderer = new LCRSRenderer, tracker = new Tracker(events);
const r = diff(h(0), null, [renderer, tracker]);
const f = diff(h(1, hooks("cleanup", f => {
const res = diff(null, r);
expect(res).to.be.false;
called++
})))
diff(null, f);
expect(called).to.equal(1);
expect(renderer.tree).to.eql(renderer.renderStatic(h(0)));
expect(events).to.eql([{wA: 0}, {mWA: 0}])
})
it("should not unmount nodes during add mutation event", function(){
let called = 0;
const events = [], rend