rpd
Version:
RPD is a minimal framework for building Node-Based User Interfaces, powered by Reactive Programming
522 lines (360 loc) • 17.9 kB
JavaScript
describe('building: inlet', function() {
it('informs it has been added to a node', function() {
withNewPatch(function(patch, updateSpy) {
var node = patch.addNode('spec/empty');
var inlet = node.addInlet('spec/any', 'foo');
expect(updateSpy).toHaveBeenCalledWith(
jasmine.objectContaining({ type: 'node/add-inlet',
inlet: inlet }));
});
});
it('informs it has been removed from a node with an event', function() {
withNewPatch(function(patch, updateSpy) {
var node = patch.addNode('spec/empty');
var inlet = node.addInlet('spec/any', 'foo');
node.removeInlet(inlet);
expect(updateSpy).toHaveBeenCalledWith(
jasmine.objectContaining({ type: 'node/remove-inlet',
inlet: inlet }));
});
});
it('receives no updates on creation', function() {
withNewPatch(function(patch, updateSpy) {
var node = patch.addNode('spec/empty');
var inlet = node.addInlet('spec/any', 'foo');
expect(updateSpy).not.toHaveBeenCalledWith(
jasmine.objectContaining({ type: 'inlet/update' }));
});
});
it('receives default value on creation, if it was specified', function() {
withNewPatch(function(patch, updateSpy) {
var node = patch.addNode('spec/empty');
var defaultValue = { 'foo': 'bar' };
var inlet = node.addInlet('spec/any', 'foo', {
'default': defaultValue
});
expect(updateSpy).toHaveBeenCalledWith(
jasmine.objectContaining({ type: 'inlet/update',
inlet: inlet,
value: defaultValue }));
});
});
it('receives single value given explicitly by user', function() {
withNewPatch(function(patch, updateSpy) {
var node = patch.addNode('spec/empty');
var userValue = { 'foo': 'bar' };
var inlet = node.addInlet('spec/any', 'foo');
inlet.receive(userValue);
expect(updateSpy).toHaveBeenCalledWith(
jasmine.objectContaining({ type: 'inlet/update',
inlet: inlet,
value: userValue }));
});
});
it('receives values when follows a stream provided by user', function() {
withNewPatch(function(patch, updateSpy) {
var node = patch.addNode('spec/empty');
var userValue = { 'foo': 'bar' };
var inlet = node.addInlet('spec/any', 'foo');
inlet.stream(Kefir.constant(userValue));
expect(updateSpy).toHaveBeenCalledWith(
jasmine.objectContaining({ type: 'inlet/update',
inlet: inlet,
value: userValue }));
});
});
it('may receive sequences of values from a stream', function() {
jasmine.clock().install();
withNewPatch(function(patch, updateSpy) {
var node = patch.addNode('spec/empty');
var userSequence = [ 2, 'foo', { 'foo': 'bar' } ];
var period = 30;
var inlet = node.addInlet('spec/any', 'foo');
inlet.stream(Kefir.sequentially(period, userSequence));
jasmine.clock().tick(period * (userSequence.length + 1));
for (var i = 0; i < userSequence.length; i++) {
expect(updateSpy).toHaveBeenCalledWith(
jasmine.objectContaining({ type: 'inlet/update',
inlet: inlet,
value: userSequence[i] }));
}
});
jasmine.clock().uninstall();
});
it('stops receiving values when it was removed from a node', function() {
withNewPatch(function(patch, updateSpy) {
var node = patch.addNode('spec/empty');
var inlet = node.addInlet('spec/any', 'foo');
node.removeInlet(inlet);
inlet.receive(10);
expect(updateSpy).not.toHaveBeenCalledWith(
jasmine.objectContaining({ type: 'inlet/update' }));
});
});
it('stops receiving streamed values when it was removed from a node', function() {
jasmine.clock().install();
withNewPatch(function(patch, updateSpy) {
var node = patch.addNode('spec/empty');
var sequence = [ 1, 2, 3 ];
var period = 30;
var inlet = node.addInlet('spec/any', 'foo');
node.removeInlet(inlet);
inlet.stream(Kefir.sequentially(period, sequence));
jasmine.clock().tick(period * (sequence.length + 1));
expect(updateSpy).not.toHaveBeenCalledWith(
jasmine.objectContaining({ type: 'inlet/update' }));
});
jasmine.clock().uninstall();
});
it('adds new stream to a previous one when new stream sent to it', function() {
withNewPatch(function(patch, updateSpy) {
var node = patch.addNode('spec/empty');
var firstStream = Kefir.emitter();
var secondStream = Kefir.emitter();
var inlet = node.addInlet('spec/any', 'foo');
inlet.stream(firstStream.map(function() { return 1; }));
firstStream.emit({});
expect(updateSpy).toHaveBeenCalledWith(
jasmine.objectContaining({ type: 'inlet/update', value: 1 }));
updateSpy.calls.reset();
inlet.stream(secondStream.map(function() { return 2; }));
secondStream.emit({});
firstStream.emit({});
expect(updateSpy).toHaveBeenCalledWith(
jasmine.objectContaining({ type: 'inlet/update', value: 2 }));
expect(updateSpy).toHaveBeenCalledWith(
jasmine.objectContaining({ type: 'inlet/update', value: 1 }));
});
});
it('requires alias to be specified', function() {
withNewPatch(function(patch, updateSpy) {
var node = patch.addNode('spec/empty');
expect(function() {
node.addInlet('spec/any');
}).toReportError('inlet/error');
});
});
it('sets the label, if it was specified (in contrast to alias)', function() {
withNewPatch(function(patch, updateSpy) {
var node = patch.addNode('spec/empty');
function inletWithLabel(value) {
return inletWithDefinition({ label: value });
}
node.addInlet('spec/any', 'foo', 'Foo');
expect(updateSpy).toHaveBeenCalledWith(
jasmine.objectContaining({ type: 'node/add-inlet',
inlet: inletWithLabel('Foo') }));
updateSpy.calls.reset();
node.addInlet('spec/any', 'foo', { label: 'Foo' });
expect(updateSpy).toHaveBeenCalledWith(
jasmine.objectContaining({ type: 'node/add-inlet',
inlet: inletWithLabel('Foo') }));
updateSpy.calls.reset();
node.addInlet('spec/any', 'foo', 'Foo', { label: 'Bar' });
expect(updateSpy).toHaveBeenCalledWith(
jasmine.objectContaining({ type: 'node/add-inlet',
inlet: inletWithLabel('Foo') }));
updateSpy.calls.reset();
node.addInlet('spec/any', 'foo', null, { label: 'Bar' });
expect(updateSpy).toHaveBeenCalledWith(
jasmine.objectContaining({ type: 'node/add-inlet',
inlet: inletWithLabel('Bar') }));
});
});
it('sets the hidden and readonly flags, if they were specified', function() { // should also be checked for
withNewPatch(function(patch, updateSpy) {
var node = patch.addNode('spec/empty');
node.addInlet('spec/any', 'foo');
expect(updateSpy).not.toHaveBeenCalledWith(
jasmine.objectContaining({ type: 'node/add-inlet',
inlet: inletWithDefinition(
jasmine.objectContaining({ hidden: true })
) }));
expect(updateSpy).not.toHaveBeenCalledWith(
jasmine.objectContaining({ type: 'node/add-inlet',
inlet: inletWithDefinition(
jasmine.objectContaining({ readonly: true })
) }));
updateSpy.calls.reset();
node.addInlet('spec/any', 'foo', {
readonly: true,
hidden: true
});
expect(updateSpy).toHaveBeenCalledWith(
jasmine.objectContaining({ type: 'node/add-inlet',
inlet: inletWithDefinition(
jasmine.objectContaining({ hidden: true, readonly: true })
) }));
});
});
it('makes it hot by default and it could separately be set to be cold', function() {
withNewPatch(function(patch, updateSpy) {
var processSpy = jasmine.createSpy('process');
var node = patch.addNode('spec/empty', { process: processSpy });
var hotInlet = node.addInlet('spec/any', 'hot');
hotInlet.receive(2);
expect(processSpy).toHaveBeenCalledWith(
jasmine.objectContaining({ hot: 2 }), jasmine.any(Object));
var coldInlet = node.addInlet('spec/any', 'cold', {
cold: true
});
processSpy.calls.reset();
coldInlet.receive(4);
expect(processSpy).not.toHaveBeenCalledWith(jasmine.objectContaining({ cold: 4 }), jasmine.any(Object));
expect(processSpy).not.toHaveBeenCalled();
processSpy.calls.reset();
hotInlet.receive(8);
expect(processSpy).toHaveBeenCalledWith(
jasmine.objectContaining({ hot: 8, cold: 4 }), jasmine.any(Object));
});
});
describe('overriding channel type definition', function() {
it('overriding inlet allow function', function() {
withNewPatch(function(patch, updateSpy) {
var node = patch.addNode('spec/empty');
var inlet = node.addInlet('spec/any', {
allow: function(value) {
return value == 'foo';
}
});
inlet.receive('bar');
expect(updateSpy).not.toHaveBeenCalledWith({
type: 'inlet/update', inlet: inlet
});
inlet.receive('foo');
expect(updateSpy).toHaveBeenCalledWith({
type: 'inlet/update', inlet: inlet, value: 'foo'
});
});
});
it('allows to set/override default value for an instance', function() {
Rpd.channeltype('spec/foo', { default: 42 });
Rpd.channeltype('spec/bar', {});
withNewPatch(function(patch, updateSpy) {
var node = patch.addNode('spec/empty');
var inletAny = node.addInlet('spec/any', 'a', { default: 12 });
expect(updateSpy).toHaveBeenCalledWith(
jasmine.objectContaining({ type: 'inlet/update',
inlet: inletAny,
value: 12 }));
updateSpy.calls.reset();
var inletFoo = node.addInlet('spec/foo', 'b', { default: 12 });
expect(updateSpy).toHaveBeenCalledWith(
jasmine.objectContaining({ type: 'inlet/update',
inlet: inletFoo,
value: 12 }));
expect(updateSpy).not.toHaveBeenCalledWith(
jasmine.objectContaining({ type: 'inlet/update',
outlet: inletFoo,
value: 42 }));
updateSpy.calls.reset();
var inletBar = node.addInlet('spec/bar', 'c', { default: 12 });
expect(updateSpy).toHaveBeenCalledWith(
jasmine.objectContaining({ type: 'inlet/update',
inlet: inletBar,
value: 12 }));
});
});
xit('overriding inlet accept function', function() {});
xit('overriding inlet adapt function', function() {});
xit('overriding inlet show function', function() {});
xit('overriding inlet tune function', function() {});
xit('subscribing to inlet events', function() {
withNewPatch(function(patch, updateSpy) {
var node = patch.addNode('spec/empty');
});
});
});
it('core/any inlet type exists', function() {
withNewPatch(function(patch, updateSpy) {
expect(function() {
patch.addNode('core/basic').addInlet('core/any', 'foo');
}).not.toReportAnyError();
});
});
describe('allowing connections', function() {
it('inlets do not accept connection from other types of outlets by default', function() {
Rpd.channeltype('docs/foo', {});
Rpd.channeltype('docs/bar', {});
withNewPatch(function(patch, updateSpy) {
expect(function() {
var node = patch.addNode('core/basic')
fooOutlet = node.addOutlet('docs/foo', 'foo');
var node = patch.addNode('core/basic')
barInlet = node.addInlet('core/bar', 'bar');
fooOutlet.connect(barInlet);
}).toReportError('outlet/error');
});
withNewPatch(function(patch, updateSpy) {
expect(function() {
var node = patch.addNode('core/basic')
barOutlet = node.addOutlet('docs/bar', 'bar');
var node = patch.addNode('core/basic')
fooInlet = node.addInlet('docs/foo', 'foo');
barOutlet.connect(fooInlet);
}).toReportError('outlet/error');
});
});
it('it is allowed to connect inlet and outlet of core/any types', function() {
withNewPatch(function(patch, updateSpy) {
expect(function() {
var node = patch.addNode('core/basic')
anyOutlet = node.addOutlet('core/any', 'any');
var node = patch.addNode('core/basic')
anyInlet = node.addInlet('core/any', 'any');
anyOutlet.connect(anyInlet);
}).not.toReportAnyError();
});
});
it('it is allowed to connect inlet and outlet of same types', function() {
Rpd.channeltype('docs/foo', {});
Rpd.channeltype('docs/bar', {});
withNewPatch(function(patch, updateSpy) {
expect(function() {
var node = patch.addNode('core/basic')
fooOutlet = node.addOutlet('docs/foo', 'foo');
var node = patch.addNode('core/basic')
fooInlet = node.addInlet('docs/foo', 'foo');
fooOutlet.connect(fooInlet);
}).not.toReportAnyError();
});
withNewPatch(function(patch, updateSpy) {
expect(function() {
var node = patch.addNode('core/basic')
barOutlet = node.addOutlet('docs/bar', 'bar');
var node = patch.addNode('core/basic')
barInlet = node.addInlet('docs/bar', 'bar');
barOutlet.connect(barInlet);
}).not.toReportAnyError();
});
});
it('any inlet type allows connections from core/any type of outlet', function() {
Rpd.channeltype('docs/foo', {});
Rpd.channeltype('docs/bar', {});
withNewPatch(function(patch, updateSpy) {
expect(function() {
var node = patch.addNode('core/basic')
fooOutlet = node.addOutlet('docs/foo', 'foo');
var node = patch.addNode('core/basic')
anyInlet = node.addInlet('core/any', 'any');
fooOutlet.connect(anyInlet);
}).not.toReportAnyError();
});
withNewPatch(function(patch, updateSpy) {
expect(function() {
var node = patch.addNode('core/basic')
barOutlet = node.addOutlet('docs/foo', 'foo');
var node = patch.addNode('core/basic')
anyInlet = node.addInlet('core/any', 'foo');
barOutlet.connect(anyInlet);
}).not.toReportAnyError();
});
});
});
xit('allows to substitute/extend renderer', function() {
// i#311
});
function inletWithDefinition(defSample) {
return jasmine.objectContaining({ def: defSample });
}
});