rpd
Version:
RPD is a minimal framework for building Node-Based User Interfaces, powered by Reactive Programming
1,112 lines (803 loc) • 43.3 kB
JavaScript
describe('registration: renderer', function() {
describe('network (Rpd.renderNext)', function() {
afterEach(function() {
Rpd.stopRendering(); // TODO: test stopRendering itself
});
it('the inner function is called with target element', function() {
var fooTargetsSpy = jasmine.createSpy('foo-target');
Rpd.renderer('foo', function(patch) {
return fooTargetsSpy;
});
var target = { };
Rpd.renderNext('foo', target);
Rpd.addPatch();
expect(fooTargetsSpy).toHaveBeenCalledWith(target, undefined);
});
it('called once for every patch', function() {
var fooRendererSpy = jasmine.createSpy('foo-renderer');
Rpd.renderer('foo', fooRendererSpy);
Rpd.renderNext('foo', {});
var firstPatch = Rpd.addPatch();
var secondPatch = Rpd.addPatch();
expect(fooRendererSpy).toHaveBeenCalledTwice();
expect(fooRendererSpy).toHaveBeenCalledWith(firstPatch);
expect(fooRendererSpy).toHaveBeenCalledWith(secondPatch);
});
it('the inner function is called for every target element and passes configuration there', function() {
var fooTargetsSpy = jasmine.createSpy('foo-target');
Rpd.renderer('foo', function(patch) {
return fooTargetsSpy;
});
var targetOne = { };
var targetTwo = { };
var conf = { };
Rpd.renderNext('foo', [ targetOne, targetTwo ], conf);
Rpd.addPatch();
expect(fooTargetsSpy).toHaveBeenCalledWith(targetOne, conf);
expect(fooTargetsSpy).toHaveBeenCalledWith(targetTwo, conf);
});
it('the inner function is called for every renderer and target', function() {
var fooTargetsSpy = jasmine.createSpy('foo-target');
var barTargetsSpy = jasmine.createSpy('bar-target');
Rpd.renderer('foo', function(patch) { return fooTargetsSpy; });
Rpd.renderer('bar', function(patch) { return barTargetsSpy; });
var targetOne = { };
var targetTwo = { };
var conf = {};
Rpd.renderNext([ 'foo', 'bar' ], [ targetOne, targetTwo ], conf);
Rpd.addPatch();
expect(fooTargetsSpy).toHaveBeenCalled();
expect(barTargetsSpy).toHaveBeenCalledWith(targetOne, conf);
expect(barTargetsSpy).toHaveBeenCalledWith(targetTwo, conf);
});
it('outer function is called once for patch and inner is called once for target', function() {
var fooPatchRenderSpy = jasmine.createSpy('foo-patch');
var fooTargetRenderSpy = jasmine.createSpy('foo-target');
Rpd.renderer('foo', fooPatchRenderSpy.and.callFake(function(patch) { return fooTargetRenderSpy; }));
var targetOne = { };
var targetTwo = { };
Rpd.renderNext('foo', [ targetOne, targetTwo ]);
Rpd.addPatch();
Rpd.addPatch();
expect(fooPatchRenderSpy).toHaveBeenCalledTwice();
expect(fooTargetRenderSpy.calls.count()).toBe(4);
});
it('turning off is not required for two renderNext in sequence', function() {
var fooTargetsSpy = jasmine.createSpy('foo-target');
var barTargetsSpy = jasmine.createSpy('bar-target');
Rpd.renderer('foo', function(patch) { return fooTargetsSpy; });
Rpd.renderer('bar', function(patch) { return barTargetsSpy; });
var targetOne = { };
var targetTwo = { };
var conf = {};
Rpd.renderNext('foo', targetOne, conf);
Rpd.addPatch();
expect(fooTargetsSpy).toHaveBeenCalledOnce();
fooTargetsSpy.calls.reset();
Rpd.renderNext('bar', targetTwo, conf);
Rpd.addPatch();
expect(fooTargetsSpy).not.toHaveBeenCalled();
expect(barTargetsSpy).toHaveBeenCalledOnce();
});
it('passes the events to the handler object', function() {
var addNodeSpy = jasmine.createSpy('add-node');
var addInletSpy = jasmine.createSpy('add-inlet');
Rpd.renderer('foo', function(patch) {
return function(target, conf) {
return { 'patch/add-node': addNodeSpy,
'node/add-inlet': addInletSpy }
};
});
Rpd.renderNext('foo', {});
var patch = Rpd.addPatch();
var node = patch.addNode('spec/empty');
var inlet = node.addInlet('spec/any', 'foo');
expect(addNodeSpy).toHaveBeenCalledWith(jasmine.objectContaining({ node: node }));
expect(addInletSpy).toHaveBeenCalledWith(jasmine.objectContaining({ inlet: inlet }));
});
it('do not caches the events happened before setting up a renderer', function() {
var addNodeSpy = jasmine.createSpy('add-node'),
addInletSpy = jasmine.createSpy('add-inlet');
var patch = Rpd.addPatch();
var node = patch.addNode('spec/empty');
var inlet = node.addInlet('spec/any', 'foo');
Rpd.renderer('foo', function(patch) {
return function(target, conf) {
return { 'patch/add-node': addNodeSpy,
'node/add-inlet': addInletSpy }
};
});
Rpd.renderNext('foo', {});
expect(addNodeSpy).not.toHaveBeenCalled();
expect(addInletSpy).not.toHaveBeenCalled();
});
xit('if patch is closed, renderer gets no events, but they are pushed to it later', function() {
// see #322
var addNodeSpy = jasmine.createSpy('add-node'),
addInletSpy = jasmine.createSpy('add-inlet');
Rpd.renderer('foo', function(patch) {
return function(target, conf) {
return { 'patch/add-node': addNodeSpy,
'node/add-inlet': addInletSpy }
};
});
Rpd.renderNext('foo', {});
var patch = Rpd.addClosedPatch();
var node = patch.addNode('spec/empty');
var inlet = node.addInlet('spec/any', 'foo');
expect(addNodeSpy).not.toHaveBeenCalled();
expect(addInletSpy).not.toHaveBeenCalled();
patch.open();
expect(addNodeSpy).toHaveBeenCalled();
expect(addInletSpy).toHaveBeenCalled();
});
xit('renderer still gets no events while patch is closed second time, but receives them later', function() {
// see #322
});
xit('merges inlets and outlets updates happened while patch was closed', function() {
// see #322
});
describe('canvases and subpatches', function() {
function createRoot() {
return { canvases: [] };
}
function createCanvasMock(patch) {
return { patch: patch };
}
function createRendererMock() {
return function(patch) {
return function(root, conf) {
var conf = conf || {};
var canvasAttached = false;
var canvas = createCanvasMock(patch);
return {
'patch/open': function(update) {
if (canvasAttached) return;
if (conf.closeParent && update.parent) update.parent.close();
root.canvases.push(canvas);
canvasAttached = true;
},
'patch/close': function(update) {
if (!canvasAttached) return;
var position = root.canvases.indexOf(canvas/*patchToCanvas[patch.id]*/);
root.canvases.splice(position, 1);
canvasAttached = false;
}
}
}
}
};
var rendererMock;
beforeEach(function() {
rendererMock = createRendererMock();
});
describe('single root', function() {
it('initially adds all the canvases to this root', function() {
var root = createRoot();
Rpd.renderer('mock', rendererMock);
Rpd.renderNext('mock', root);
expect(root.canvases.length).toBe(0);
var firstPatch = Rpd.addPatch('first');
expect(root.canvases.length).toBe(1);
expect(root.canvases[0]).toEqual(jasmine.objectContaining({
patch: firstPatch
}));
var secondPatch = Rpd.addPatch('second');
expect(root.canvases.length).toBe(2);
expect(root.canvases[1]).toEqual(jasmine.objectContaining({
patch: secondPatch
}));
});
it('when patch was added as closed, do not appends its canvas to the root', function() {
var root = createRoot();
Rpd.renderer('mock', rendererMock);
Rpd.renderNext('mock', root);
var firstPatch = Rpd.addClosedPatch('first');
expect(root.canvases.length).toBe(0);
var secondPatch = Rpd.addPatch('second');
expect(root.canvases.length).toBe(1);
expect(root.canvases[0]).toEqual(jasmine.objectContaining({
patch: secondPatch
}));
});
it('when patch was added as closed (with `patch.close` method), do not appends its canvas to the root', function() {
var root = createRoot();
Rpd.renderer('mock', rendererMock);
Rpd.renderNext('mock', root);
var firstPatch = Rpd.addPatch('first').close();
expect(root.canvases.length).toBe(0);
var secondPatch = Rpd.addPatch('second');
expect(root.canvases.length).toBe(1);
expect(root.canvases[0]).toEqual(jasmine.objectContaining({
patch: secondPatch
}));
});
it('when patch was closed later, also removes its canvas from the root', function() {
var root = createRoot();
Rpd.renderer('mock', rendererMock);
Rpd.renderNext('mock', root);
expect(root.canvases.length).toBe(0);
var firstPatch = Rpd.addPatch('first');
expect(root.canvases.length).toBe(1);
firstPatch.addNode('spec/empty', 'Foo');
firstPatch.close();
expect(root.canvases.length).toBe(0);
var secondPatch = Rpd.addPatch('second');
expect(root.canvases.length).toBe(1);
expect(root.canvases[0]).toEqual(jasmine.objectContaining({
patch: secondPatch
}));
secondPatch.close();
expect(root.canvases.length).toBe(0);
});
it('opening and closing properly works in sequences', function() {
var root = createRoot();
Rpd.renderer('mock', rendererMock);
Rpd.renderNext('mock', root);
var firstPatch = Rpd.addPatch('first');
expect(root.canvases.length).toBe(1);
var secondPatch = Rpd.addClosedPatch('second');
expect(root.canvases.length).toBe(1);
expect(root.canvases[0]).toEqual(jasmine.objectContaining({
patch: firstPatch
}));
var thirdPatch = Rpd.addClosedPatch('third');
expect(root.canvases.length).toBe(1);
expect(root.canvases[0]).toEqual(jasmine.objectContaining({
patch: firstPatch
}));
secondPatch.open();
expect(root.canvases.length).toBe(2);
expect(root.canvases[1]).toEqual(jasmine.objectContaining({
patch: secondPatch
}));
firstPatch.close();
thirdPatch.open();
expect(root.canvases.length).toBe(2);
expect(root.canvases[0]).toEqual(jasmine.objectContaining({
patch: secondPatch
}));
expect(root.canvases[1]).toEqual(jasmine.objectContaining({
patch: thirdPatch
}));
});
it('always closes parent patch with `conf.closeParent` option', function() {
var root = createRoot();
Rpd.renderer('mock', rendererMock);
Rpd.renderNext('mock', root, { closeParent: true });
var firstPatch = Rpd.addPatch('first');
expect(root.canvases.length).toBe(1);
expect(root.canvases[0]).toEqual(jasmine.objectContaining({
patch: firstPatch
}));
var secondPatch = Rpd.addPatch('second', null, firstPatch); // set firstPatch as a parent
expect(root.canvases.length).toBe(1);
expect(root.canvases[0]).toEqual(jasmine.objectContaining({
patch: secondPatch
}));
});
});
describe('several roots', function() {
it('properly adds patches to a separate roots', function() {
var firstRoot = createRoot(),
secondRoot = createRoot(),
thirdRoot = createRoot();
Rpd.renderer('mock', rendererMock);
Rpd.renderNext('mock', firstRoot);
expect(firstRoot.canvases.length).toBe(0);
Rpd.addPatch('root-1-patch-1');
expect(firstRoot.canvases.length).toBe(1);
Rpd.addPatch('root-1-patch-2');
expect(firstRoot.canvases.length).toBe(2);
Rpd.addPatch('root-1-patch-3');
expect(firstRoot.canvases.length).toBe(3);
Rpd.renderNext('mock', secondRoot);
Rpd.addPatch('root-2-patch-1');
expect(secondRoot.canvases.length).toBe(1);
Rpd.addPatch('root-2-patch-2');
expect(secondRoot.canvases.length).toBe(2);
Rpd.addPatch('root-2-patch-3');
expect(secondRoot.canvases.length).toBe(3);
expect(firstRoot.canvases.length).toBe(3);
Rpd.renderer('mock-2', createRendererMock());
Rpd.renderNext('mock-2', thirdRoot);
Rpd.addPatch('root-3-patch-1');
expect(thirdRoot.canvases.length).toBe(1);
expect(secondRoot.canvases.length).toBe(3);
});
it('properly opens and closes patches', function() {
var firstRoot = createRoot(),
secondRoot = createRoot();
Rpd.renderer('mock', rendererMock);
Rpd.renderNext('mock', firstRoot);
expect(firstRoot.canvases.length).toBe(0);
Rpd.addPatch('root-1-patch-1');
var rootOnePatchTwo = Rpd.addPatch('root-1-patch-2');
var rootOnePatchThree = Rpd.addClosedPatch('root-1-patch-3');
// root-1-patch-1 [o]
// root-1-patch-2 [o]
// root-1-patch-3 [x]
expect(firstRoot.canvases.length).toBe(2);
Rpd.renderNext('mock', secondRoot);
Rpd.addPatch('root-2-patch-1');
expect(secondRoot.canvases.length).toBe(1);
var rootTwoPatchTwo = Rpd.addPatch('root-2-patch-2');
expect(secondRoot.canvases.length).toBe(2);
var rootTwoPatchThree = Rpd.addPatch('root-2-patch-3');
// root-2-patch-1 [o]
// root-2-patch-2 [o]
// root-2-patch-3 [o]
expect(secondRoot.canvases.length).toBe(3);
expect(secondRoot.canvases[1]).toEqual(jasmine.objectContaining({
patch: rootTwoPatchTwo
}));
rootOnePatchTwo.close();
// root-1-patch-1 [o]
// root-1-patch-2 [x]
// root-1-patch-3 [x]
expect(firstRoot.canvases.length).toBe(1);
expect(secondRoot.canvases.length).toBe(3);
rootTwoPatchTwo.close();
// root-2-patch-1 [o]
// root-2-patch-2 [x]
// root-2-patch-3 [o]
expect(firstRoot.canvases.length).toBe(1);
expect(secondRoot.canvases.length).toBe(2);
expect(secondRoot.canvases[1]).toEqual(jasmine.objectContaining({
patch: rootTwoPatchThree
}));
rootOnePatchThree.open();
// root-1-patch-1 [o]
// root-1-patch-2 [x]
// root-1-patch-3 [o]
expect(firstRoot.canvases.length).toBe(2);
expect(secondRoot.canvases.length).toBe(2);
expect(firstRoot.canvases[1]).toEqual(jasmine.objectContaining({
patch: rootOnePatchThree
}));
});
it('always closes parent patch with `conf.closeParent` option', function() {
var firstRoot = createRoot(),
secondRoot = createRoot();
Rpd.renderer('mock', rendererMock);
Rpd.renderNext('mock', firstRoot, { closeParent: true });
var rootOnePatchOne = Rpd.addPatch('root-1-patch-1');
expect(firstRoot.canvases.length).toBe(1);
expect(firstRoot.canvases[0]).toEqual(jasmine.objectContaining({
patch: rootOnePatchOne
}));
var rootOnePatchTwo = Rpd.addPatch('root-1-patch-2', null, rootOnePatchOne); // set rootOnePatchOne as a parent
expect(firstRoot.canvases.length).toBe(1);
expect(firstRoot.canvases[0]).toEqual(jasmine.objectContaining({
patch: rootOnePatchTwo
}));
Rpd.renderNext('mock', secondRoot, { closeParent: true });
var rootTwoPatchOne = Rpd.addPatch('root-2-patch-1');
expect(secondRoot.canvases.length).toBe(1);
expect(secondRoot.canvases[0]).toEqual(jasmine.objectContaining({
patch: rootTwoPatchOne
}));
var rootTwoPatchTwo = Rpd.addClosedPatch('root-2-patch-2').open(rootTwoPatchOne); // set rootTwoPatchOne as a parent
expect(secondRoot.canvases.length).toBe(1);
expect(secondRoot.canvases[0]).toEqual(jasmine.objectContaining({
patch: rootTwoPatchTwo
}));
});
});
});
});
describe('patch (path.render)', function() {
it('called once for every patch', function() {
var fooRendererSpy = jasmine.createSpy('foo-renderer');
Rpd.renderer('foo', fooRendererSpy);
var firstPatch = Rpd.addPatch().render('foo', {});
var secondPatch = Rpd.addPatch().render('foo', {});
expect(fooRendererSpy).toHaveBeenCalledTwice();
expect(fooRendererSpy).toHaveBeenCalledWith(firstPatch);
expect(fooRendererSpy).toHaveBeenCalledWith(secondPatch);
Rpd.stopRendering();
});
it('the inner function is called with target element', function() {
var fooTargetsSpy = jasmine.createSpy('foo-target');
Rpd.renderer('foo', function(patch) {
return fooTargetsSpy;
});
var target = { };
Rpd.addPatch().render('foo', target);
expect(fooTargetsSpy).toHaveBeenCalledWith(target, undefined);
});
it('the inner function is called for every target element and passes configuration there', function() {
var fooTargetsSpy = jasmine.createSpy('foo-target');
Rpd.renderer('foo', function(patch) {
return fooTargetsSpy;
});
var targetOne = { };
var targetTwo = { };
var conf = { };
Rpd.addPatch().render('foo', [ targetOne, targetTwo ], conf);
expect(fooTargetsSpy).toHaveBeenCalledWith(targetOne, conf);
expect(fooTargetsSpy).toHaveBeenCalledWith(targetTwo, conf);
});
it('the inner function is called for every renderer and target', function() {
var fooTargetsSpy = jasmine.createSpy('foo-target');
var barTargetsSpy = jasmine.createSpy('bar-target');
Rpd.renderer('foo', function(patch) { return fooTargetsSpy; });
Rpd.renderer('bar', function(patch) { return barTargetsSpy; });
var targetOne = { };
var targetTwo = { };
var conf = {};
Rpd.addPatch().render([ 'foo', 'bar' ], [ targetOne, targetTwo ], conf);
expect(fooTargetsSpy).toHaveBeenCalled();
expect(barTargetsSpy).toHaveBeenCalledWith(targetOne, conf);
expect(barTargetsSpy).toHaveBeenCalledWith(targetTwo, conf);
});
it('outer function is called once for patch and inner is called once for target', function() {
var fooPatchRenderSpy = jasmine.createSpy('foo-patch');
var fooTargetRenderSpy = jasmine.createSpy('foo-target');
Rpd.renderer('foo', fooPatchRenderSpy.and.callFake(function(patch) { return fooTargetRenderSpy; }));
var targetOne = { };
var targetTwo = { };
Rpd.addPatch().render('foo', [ targetOne, targetTwo ]);
Rpd.addPatch().render('foo', [ targetOne, targetTwo ]);
expect(fooPatchRenderSpy).toHaveBeenCalledTwice();
expect(fooTargetRenderSpy.calls.count()).toBe(4);
});
it('passes the events to the handler object', function() {
var addNodeSpy = jasmine.createSpy('add-node');
var addInletSpy = jasmine.createSpy('add-inlet');
Rpd.renderer('foo', function(patch) {
return function(target, conf) {
return { 'patch/add-node': addNodeSpy,
'node/add-inlet': addInletSpy }
};
});
var patch = Rpd.addPatch().render('foo', {});
var node = patch.addNode('spec/empty');
var inlet = node.addInlet('spec/any', 'foo');
expect(addNodeSpy).toHaveBeenCalledWith(jasmine.objectContaining({ node: node }));
expect(addInletSpy).toHaveBeenCalledWith(jasmine.objectContaining({ inlet: inlet }));
});
it('provides events for all subscribed patches', function() {
var addNodeSpy = jasmine.createSpy('add-node');
var addInletSpy = jasmine.createSpy('add-inlet');
Rpd.renderer('foo', function(patch) {
return function(target, conf) {
return { 'patch/add-node': addNodeSpy }
};
});
Rpd.renderer('bar', function(patch) {
return function(target, conf) {
return { 'node/add-inlet': addInletSpy }
};
});
var patchOne = Rpd.addPatch().render(['foo', 'bar'], {});
var nodeOne = patchOne.addNode('spec/empty');
var inletOne = nodeOne.addInlet('spec/any', 'foo');
var patchTwo = Rpd.addPatch().render('bar', {});
var nodeTwo = patchTwo.addNode('spec/empty');
var inletTwo = nodeTwo.addInlet('spec/any', 'foo');
expect(addNodeSpy).toHaveBeenCalledWith(jasmine.objectContaining({ node: nodeOne }));
expect(addInletSpy).toHaveBeenCalledWith(jasmine.objectContaining({ inlet: inletOne }));
expect(addInletSpy).toHaveBeenCalledWith(jasmine.objectContaining({ inlet: inletTwo }));
});
it('renderer could also return a function handling any event', function() {
var fooEventSpy = jasmine.createSpy('foo-events');
var barEventSpy = jasmine.createSpy('bar-events');
Rpd.renderer('foo', function(patch) {
return function(target, conf) {
return fooEventSpy;
};
});
Rpd.renderer('bar', function(patch) {
return function(target, conf) {
return barEventSpy;
};
});
var patchOne = Rpd.addPatch().render(['foo', 'bar'], {});
var nodeOne = patchOne.addNode('spec/empty');
var patchTwo = Rpd.addPatch().render('bar', {});
var nodeTwo = patchTwo.addNode('spec/empty');
var inletTwo = nodeTwo.addInlet('spec/any', 'foo');
expect(fooEventSpy).toHaveBeenCalledWith(jasmine.objectContaining({ type: 'patch/add-node', node: nodeOne }));
expect(barEventSpy).toHaveBeenCalledWith(jasmine.objectContaining({ type: 'patch/add-node', node: nodeTwo }));
expect(barEventSpy).toHaveBeenCalledWith(jasmine.objectContaining({ type: 'node/add-inlet', inlet: inletTwo }));
expect(fooEventSpy).not.toHaveBeenCalledWith(jasmine.objectContaining({ type: 'patch/add-inlet', inlet: inletTwo }));
});
it('continues rendering patches with assigned configurations', function() {
var fooAddNodeSpy = jasmine.createSpy('foo-add-node');
var fooAddInletSpy = jasmine.createSpy('foo-add-inlet');
var barAddNodeSpy = jasmine.createSpy('bar-add-node');
var barAddInletSpy = jasmine.createSpy('bar-add-inlet');
Rpd.renderer('foo', function(patch) {
return function(target, conf) {
return { 'patch/add-node': fooAddNodeSpy,
'node/add-inlet': fooAddInletSpy }
};
});
Rpd.renderer('bar', function(patch) {
return function(target, conf) {
return { 'patch/add-node': barAddNodeSpy,
'node/add-inlet': barAddInletSpy }
};
});
var patchOne = Rpd.addPatch().render('foo', {});
var nodeOne = patchOne.addNode('spec/empty');
expect(fooAddNodeSpy).toHaveBeenCalledWith(jasmine.objectContaining({ node: nodeOne, patch: patchOne }));
expect(barAddNodeSpy).not.toHaveBeenCalled();
fooAddNodeSpy.calls.reset();
var patchTwo = Rpd.addPatch().render('bar', {});
var nodeTwo = patchTwo.addNode('spec/empty');
expect(fooAddNodeSpy).not.toHaveBeenCalled();
expect(barAddNodeSpy).toHaveBeenCalledWith(jasmine.objectContaining({ node: nodeTwo, patch: patchTwo }));
var inletOne = nodeOne.addInlet('spec/any', 'foo');
expect(fooAddInletSpy).toHaveBeenCalledWith(jasmine.objectContaining({ inlet: inletOne, node: nodeOne }));
expect(barAddInletSpy).not.toHaveBeenCalled();
fooAddInletSpy.calls.reset();
var inletTwo = nodeTwo.addInlet('spec/any', 'bar');
expect(fooAddInletSpy).not.toHaveBeenCalled();
expect(barAddInletSpy).toHaveBeenCalledWith(jasmine.objectContaining({ inlet: inletTwo, node: nodeTwo }));
});
it('caches the events happened before setting up a renderer and passses them later', function() {
var addNodeSpy = jasmine.createSpy('add-node'),
addInletSpy = jasmine.createSpy('add-inlet');
var patch = Rpd.addPatch();
var node = patch.addNode('spec/empty');
var inlet = node.addInlet('spec/any', 'foo');
Rpd.renderer('foo', function(patch) {
return function(target, conf) {
return { 'patch/add-node': addNodeSpy,
'node/add-inlet': addInletSpy }
};
});
expect(addNodeSpy).not.toHaveBeenCalled();
expect(addInletSpy).not.toHaveBeenCalled();
patch.render('foo', {});
expect(addNodeSpy).toHaveBeenCalledWith(jasmine.objectContaining({ patch: patch, node: node }));
expect(addInletSpy).toHaveBeenCalledWith(jasmine.objectContaining({ node: node, inlet: inlet }));
});
xit('if patch is closed, renderer gets no events, but they are pushed to it later', function() {
// see #322
var addNodeSpy = jasmine.createSpy('add-node'),
addInletSpy = jasmine.createSpy('add-inlet');
Rpd.renderer('foo', function(patch) {
return function(target, conf) {
return { 'patch/add-node': addNodeSpy,
'node/add-inlet': addInletSpy }
};
});
var patch = Rpd.addClosedPatch().render('foo', {});
var node = patch.addNode('spec/empty');
var inlet = node.addInlet('spec/any', 'foo');
expect(addNodeSpy).not.toHaveBeenCalled();
expect(addInletSpy).not.toHaveBeenCalled();
patch.open();
expect(addNodeSpy).toHaveBeenCalled();
expect(addInletSpy).toHaveBeenCalled();
});
xit('renderer still gets no events while patch is closed second time, but receives them later', function() {
// see #322
});
xit('merges inlets and outlets updates happened while patch was closed', function() {
// see #322
});
describe('canvases and subpatches', function() {
function createRoot() {
return { canvases: [] };
}
function createCanvasMock(patch) {
return { patch: patch };
}
function createRendererMock() {
return function(patch) {
return function(root, conf) {
var conf = conf || {};
var canvasAttached = false;
var canvas = createCanvasMock(patch);
return {
'patch/open': function(update) {
if (canvasAttached) return;
if (conf.closeParent && update.parent) update.parent.close();
root.canvases.push(canvas);
canvasAttached = true;
},
'patch/close': function(update) {
if (!canvasAttached) return;
var position = root.canvases.indexOf(canvas/*patchToCanvas[patch.id]*/);
root.canvases.splice(position, 1);
canvasAttached = false;
}
}
}
}
};
var rendererMock;
beforeEach(function() {
rendererMock = createRendererMock();
});
describe('single root', function() {
it('properly adds all the canvases to the given root', function() {
var root = createRoot();
Rpd.renderer('mock', rendererMock);
expect(root.canvases.length).toBe(0);
var firstPatch = Rpd.addPatch('first').render('mock', root);
expect(root.canvases.length).toBe(1);
expect(root.canvases[0]).toEqual(jasmine.objectContaining({
patch: firstPatch
}));
var secondPatch = Rpd.addPatch('second').render('mock', root);
expect(root.canvases.length).toBe(2);
expect(root.canvases[1]).toEqual(jasmine.objectContaining({
patch: secondPatch
}));
});
it('when patch was added as closed, do not appends its canvas to the root', function() {
var root = createRoot();
Rpd.renderer('mock', rendererMock);
var firstPatch = Rpd.addClosedPatch('first').render('mock', root);
expect(root.canvases.length).toBe(0);
var secondPatch = Rpd.addPatch('second').render('mock', root);
expect(root.canvases.length).toBe(1);
expect(root.canvases[0]).toEqual(jasmine.objectContaining({
patch: secondPatch
}));
});
it('when patch was added as closed (with `patch.close` method), do not appends its canvas to the root', function() {
var root = createRoot();
Rpd.renderer('mock', rendererMock);
var firstPatch = Rpd.addPatch('first').render('mock', root).close();
expect(root.canvases.length).toBe(0);
var secondPatch = Rpd.addPatch('second').render('mock', root);
expect(root.canvases.length).toBe(1);
expect(root.canvases[0]).toEqual(jasmine.objectContaining({
patch: secondPatch
}));
});
it('when patch was closed later, also removes its canvas from the root', function() {
var root = createRoot();
Rpd.renderer('mock', rendererMock);
expect(root.canvases.length).toBe(0);
var firstPatch = Rpd.addPatch('first').render('mock', root);
expect(root.canvases.length).toBe(1);
firstPatch.addNode('spec/empty', 'Foo');
firstPatch.close();
expect(root.canvases.length).toBe(0);
var secondPatch = Rpd.addPatch('second').render('mock', root);
expect(root.canvases.length).toBe(1);
expect(root.canvases[0]).toEqual(jasmine.objectContaining({
patch: secondPatch
}));
secondPatch.close();
expect(root.canvases.length).toBe(0);
});
it('opening and closing properly works in sequences', function() {
var root = createRoot();
Rpd.renderer('mock', rendererMock);
var firstPatch = Rpd.addPatch('first').render('mock', root);
expect(root.canvases.length).toBe(1);
var secondPatch = Rpd.addClosedPatch('second').render('mock', root);
expect(root.canvases.length).toBe(1);
expect(root.canvases[0]).toEqual(jasmine.objectContaining({
patch: firstPatch
}));
var thirdPatch = Rpd.addClosedPatch('third').render('mock', root);
expect(root.canvases.length).toBe(1);
expect(root.canvases[0]).toEqual(jasmine.objectContaining({
patch: firstPatch
}));
secondPatch.open();
expect(root.canvases.length).toBe(2);
expect(root.canvases[1]).toEqual(jasmine.objectContaining({
patch: secondPatch
}));
firstPatch.close();
thirdPatch.open();
expect(root.canvases.length).toBe(2);
expect(root.canvases[0]).toEqual(jasmine.objectContaining({
patch: secondPatch
}));
expect(root.canvases[1]).toEqual(jasmine.objectContaining({
patch: thirdPatch
}));
});
it('always closes previous patch with `conf.closeParent` option', function() {
var root = createRoot();
Rpd.renderer('mock', rendererMock);
var firstPatch = Rpd.addPatch('first').render('mock', root);
expect(root.canvases.length).toBe(1);
expect(root.canvases[0]).toEqual(jasmine.objectContaining({
patch: firstPatch
}));
var secondPatch = Rpd.addPatch('second', null, firstPatch) // set firstPatch as a parent
.render('mock', root, { closeParent: true });
expect(root.canvases.length).toBe(1);
expect(root.canvases[0]).toEqual(jasmine.objectContaining({
patch: secondPatch
}));
});
});
describe('several roots', function() {
it('properly adds patches to a separate roots', function() {
var firstRoot = createRoot(),
secondRoot = createRoot(),
thirdRoot = createRoot();
Rpd.renderer('mock', rendererMock);
expect(firstRoot.canvases.length).toBe(0);
Rpd.addPatch('root-1-patch-1').render('mock', firstRoot);
expect(firstRoot.canvases.length).toBe(1);
Rpd.addPatch('root-1-patch-2').render('mock', firstRoot);
expect(firstRoot.canvases.length).toBe(2);
Rpd.addPatch('root-1-patch-3').render('mock', firstRoot);
expect(firstRoot.canvases.length).toBe(3);
Rpd.addPatch('root-2-patch-1').render('mock', secondRoot);
expect(secondRoot.canvases.length).toBe(1);
Rpd.addPatch('root-2-patch-2').render('mock', secondRoot);
expect(secondRoot.canvases.length).toBe(2);
Rpd.addPatch('root-2-patch-3').render('mock', secondRoot);
expect(secondRoot.canvases.length).toBe(3);
expect(firstRoot.canvases.length).toBe(3);
Rpd.renderer('mock-2', createRendererMock());
Rpd.addPatch('root-3-patch-1').render('mock-2', thirdRoot);
expect(thirdRoot.canvases.length).toBe(1);
expect(secondRoot.canvases.length).toBe(3);
});
it('properly opens and closes patches', function() {
var firstRoot = createRoot(),
secondRoot = createRoot();
Rpd.renderer('mock', rendererMock);
expect(firstRoot.canvases.length).toBe(0);
var rootOnePatchOne = Rpd.addPatch('root-1-patch-1').render('mock', firstRoot);
var rootOnePatchTwo = Rpd.addPatch('root-1-patch-2').render('mock', firstRoot);
// root-1-patch-1 [o]
// root-1-patch-2 [o]
expect(firstRoot.canvases.length).toBe(2);
Rpd.addPatch('root-2-patch-1').render('mock', secondRoot);
expect(secondRoot.canvases.length).toBe(1);
var rootTwoPatchTwo = Rpd.addPatch('root-2-patch-2').render('mock', secondRoot);;
expect(secondRoot.canvases.length).toBe(2);
var rootTwoPatchThree = Rpd.addPatch('root-2-patch-3').render('mock', secondRoot);;
expect(secondRoot.canvases.length).toBe(3);
// root-2-patch-1 [o]
// root-2-patch-2 [o]
// root-2-patch-3 [o]
expect(secondRoot.canvases[1]).toEqual(jasmine.objectContaining({
patch: rootTwoPatchTwo
}));
rootOnePatchTwo.close();
// root-1-patch-1 [o]
// root-1-patch-2 [x]
expect(firstRoot.canvases.length).toBe(1);
expect(secondRoot.canvases.length).toBe(3);
var rootOnePatchThree = Rpd.addClosedPatch('root-1-patch-3').render('mock', firstRoot);
// root-1-patch-1 [o]
// root-1-patch-2 [x]
// root-1-patch-3 [x]
rootTwoPatchTwo.close();
// root-2-patch-1 [o]
// root-2-patch-2 [x]
// root-2-patch-3 [o]
expect(firstRoot.canvases.length).toBe(1);
expect(secondRoot.canvases.length).toBe(2);
expect(secondRoot.canvases[1]).toEqual(jasmine.objectContaining({
patch: rootTwoPatchThree
}));
rootOnePatchOne.close();
rootOnePatchThree.open();
// root-1-patch-1 [x]
// root-1-patch-2 [x]
// root-1-patch-3 [o]
expect(firstRoot.canvases.length).toBe(1);
expect(secondRoot.canvases.length).toBe(2);
expect(firstRoot.canvases[0]).toEqual(jasmine.objectContaining({
patch: rootOnePatchThree
}));
});
});
});
});
xit('moving canvas', function() {
// see #320
});
xit('resizing canvas', function() {
// see #320
});
});