rpd
Version:
RPD is a minimal framework for building Node-Based User Interfaces, powered by Reactive Programming
490 lines (371 loc) • 17.8 kB
JavaScript
describe('navigation', function() {
var networkUpdatesSpy;
var networkErrorSpy;
var changePathSpy;
var SEPARATOR = '+';
beforeEach(function() {
networkUpdatesSpy = jasmine.createSpy('network-updates');
Rpd.events.onValue(networkUpdatesSpy);
//changePathSpy = jasmine.createSpy('change-path', Rpd.navigation.changePath).and.callThrough();
changePathSpy = spyOn(Rpd.navigation, 'changePath').and.callThrough();
networkErrorSpy = jasmine.createSpy('network-errors');
Rpd.events.onError(networkErrorSpy);
Rpd.navigation.enable();
});
afterEach(function() {
Rpd.navigation.disable();
Rpd.events.offValue(networkUpdatesSpy);
});
describe('handling empty path', function() {
it('leaves first added patch opened and updates path with it', function() {
var firstPatch = Rpd.addPatch('first');
var secondPatch = Rpd.addPatch('second');
changePathSpy.calls.reset();
Rpd.navigation.handlePath('');
expect(networkUpdatesSpy).not.toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/close',
patch: firstPatch
}));
expect(changePathSpy).toHaveBeenCalledWith(firstPatch.id);
expect(changePathSpy).toHaveBeenCalledOnce();
});
it('opens first added patch if it was closed before', function() {
var firstPatch = Rpd.addPatch('first');
firstPatch.close();
var secondPatch = Rpd.addPatch('second');
networkUpdatesSpy.calls.reset();
changePathSpy.calls.reset();
Rpd.navigation.handlePath('');
expect(networkUpdatesSpy).toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/open',
patch: firstPatch
}));
expect(changePathSpy).toHaveBeenCalledWith(firstPatch.id);
});
it('closes other patches except the first one', function() {
var firstPatch = Rpd.addPatch('first');
var secondPatch = Rpd.addPatch('second');
changePathSpy.calls.reset();
Rpd.navigation.handlePath('');
expect(networkUpdatesSpy).toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/close',
patch: secondPatch
}));
});
it('closes all other patches', function() {
var firstPatch = Rpd.addPatch('first');
var secondPatch = Rpd.addPatch('second');
var thirdPatch = Rpd.addClosedPatch('third');
thirdPatch.open();
networkUpdatesSpy.calls.reset();
changePathSpy.calls.reset();
Rpd.navigation.handlePath('');
expect(networkUpdatesSpy).toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/close',
patch: secondPatch
}));
expect(networkUpdatesSpy).toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/close',
patch: thirdPatch
}));
expect(changePathSpy).toHaveBeenCalledWith(firstPatch.id);
});
});
describe('when path contains wrong ID or gibberish', function() {
var GIBBER = 'gibber';
it('fires an error, but opens first added patch', function() {
var firstPatch = Rpd.addPatch('first');
var secondPatch = Rpd.addPatch('second');
networkUpdatesSpy.calls.reset();
changePathSpy.calls.reset();
Rpd.navigation.handlePath(GIBBER);
expect(networkErrorSpy).toHaveBeenCalled();
expect(networkUpdatesSpy).toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/close',
patch: secondPatch
}));
expect(networkUpdatesSpy).not.toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/close',
patch: firstPatch
}));
expect(changePathSpy).toHaveBeenCalledWith(firstPatch.id);
});
it('fires an error, opens first added patch even if it was closed before', function() {
var firstPatch = Rpd.addPatch('first');
firstPatch.close();
var secondPatch = Rpd.addPatch('second');
networkUpdatesSpy.calls.reset();
changePathSpy.calls.reset();
Rpd.navigation.handlePath(GIBBER);
expect(networkErrorSpy).toHaveBeenCalled();
expect(networkUpdatesSpy).toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/open',
patch: firstPatch
}));
expect(changePathSpy).toHaveBeenCalledWith(firstPatch.id);
});
it('fires an error, but yet closes all other patches', function() {
var firstPatch = Rpd.addPatch('first');
var secondPatch = Rpd.addPatch('second');
var thirdPatch = Rpd.addClosedPatch('third');
thirdPatch.open();
networkUpdatesSpy.calls.reset();
changePathSpy.calls.reset();
Rpd.navigation.handlePath(GIBBER);
expect(networkErrorSpy).toHaveBeenCalled();
expect(networkUpdatesSpy).toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/close',
patch: secondPatch
}));
expect(networkUpdatesSpy).toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/close',
patch: thirdPatch
}));
expect(changePathSpy).toHaveBeenCalledWith(firstPatch.id);
});
it('fires an error when no patches were opened', function() {
Rpd.navigation.handlePath(SEPARATOR + SEPARATOR);
expect(networkErrorSpy).toHaveBeenCalled();
expect(changePathSpy).toHaveBeenCalledWith('');
});
});
describe('when path contains single patch ID', function() {
it('leaves specified patch opened', function() {
var firstPatch = Rpd.addPatch('first');
var secondPatch = Rpd.addPatch('second');
changePathSpy.calls.reset();
Rpd.navigation.handlePath(secondPatch.id);
expect(networkUpdatesSpy).not.toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/close',
patch: secondPatch
}));
expect(changePathSpy).not.toHaveBeenCalled();
});
it('opens specified patch if it was closed before', function() {
var firstPatch = Rpd.addPatch('first');
var secondPatch = Rpd.addClosedPatch('second');
networkUpdatesSpy.calls.reset();
changePathSpy.calls.reset();
Rpd.navigation.handlePath(secondPatch.id);
expect(networkUpdatesSpy).toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/open',
patch: secondPatch
}));
expect(changePathSpy).not.toHaveBeenCalled();
});
it('closes other patches except the specified one', function() {
var firstPatch = Rpd.addPatch('first');
var secondPatch = Rpd.addPatch('second');
changePathSpy.calls.reset();
Rpd.navigation.handlePath(secondPatch.id);
expect(networkUpdatesSpy).toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/close',
patch: firstPatch
}));
expect(changePathSpy).not.toHaveBeenCalled();
});
it('closes all other patches', function() {
var firstPatch = Rpd.addPatch('first');
var secondPatch = Rpd.addPatch('second');
var thirdPatch = Rpd.addClosedPatch('third');
thirdPatch.open();
networkUpdatesSpy.calls.reset();
changePathSpy.calls.reset();
Rpd.navigation.handlePath(secondPatch.id);
expect(networkUpdatesSpy).toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/close',
patch: firstPatch
}));
expect(networkUpdatesSpy).toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/close',
patch: thirdPatch
}));
expect(changePathSpy).not.toHaveBeenCalled();
});
it('handling same path is not causing changePath to be called next time', function() {
var firstPatch = Rpd.addPatch('first');
//Rpd.navigation.handlePath(firstPatch.id);
changePathSpy.calls.reset();
Rpd.navigation.handlePath(firstPatch.id);
Rpd.navigation.handlePath(firstPatch.id);
expect(changePathSpy).not.toHaveBeenCalled();
});
});
describe('when path contains several patch IDs', function() {
it('opens all patches specified in the list while they exist', function() {
var firstPatch = Rpd.addClosedPatch('first');
var secondPatch = Rpd.addPatch('second');
var thirdPatch = Rpd.addClosedPatch('third');
networkUpdatesSpy.calls.reset();
changePathSpy.calls.reset();
Rpd.navigation.handlePath(thirdPatch.id + SEPARATOR + firstPatch.id + SEPARATOR + secondPatch.id);
expect(networkUpdatesSpy).toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/open',
patch: firstPatch
}));
expect(networkUpdatesSpy).toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/open',
patch: thirdPatch
}));
expect(networkUpdatesSpy).not.toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/close',
patch: secondPatch
}));
expect(changePathSpy).not.toHaveBeenCalled();
});
it('opens all patches specified in the list while they exist, even if there\'s a separator in the end', function() {
var firstPatch = Rpd.addClosedPatch('first');
var secondPatch = Rpd.addPatch('second');
var thirdPatch = Rpd.addClosedPatch('third');
networkUpdatesSpy.calls.reset();
changePathSpy.calls.reset();
Rpd.navigation.handlePath(thirdPatch.id + SEPARATOR + firstPatch.id + SEPARATOR + secondPatch.id + SEPARATOR);
expect(networkUpdatesSpy).toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/open',
patch: firstPatch
}));
expect(networkUpdatesSpy).toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/open',
patch: thirdPatch
}));
expect(networkUpdatesSpy).not.toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/close',
patch: secondPatch
}));
expect(changePathSpy).toHaveBeenCalledWith(thirdPatch.id + SEPARATOR + firstPatch.id + SEPARATOR + secondPatch.id);
});
it('closed patches stay closed if they were not specified in the list', function() {
var firstPatch = Rpd.addClosedPatch('first');
var secondPatch = Rpd.addPatch('second');
var thirdPatch = Rpd.addClosedPatch('third');
networkUpdatesSpy.calls.reset();
changePathSpy.calls.reset();
Rpd.navigation.handlePath(thirdPatch.id + SEPARATOR + secondPatch.id);
expect(networkUpdatesSpy).not.toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/open',
patch: firstPatch
}));
expect(networkUpdatesSpy).toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/open',
patch: thirdPatch
}));
expect(changePathSpy).not.toHaveBeenCalled();
})
it('do not opens patches which don\'t exist, fires an error for them, but fixes path', function() {
var firstPatch = Rpd.addClosedPatch('first');
var secondPatch = Rpd.addClosedPatch('second');
var thirdPatch = Rpd.addClosedPatch('third');
expect(changePathSpy).not.toHaveBeenCalled();
networkUpdatesSpy.calls.reset();
var GIBBER = 'gibber';
Rpd.navigation.handlePath(thirdPatch.id + SEPARATOR + firstPatch.id + SEPARATOR + /*!*/GIBBER/*!*/ + SEPARATOR);
expect(networkErrorSpy).toHaveBeenCalled();
expect(networkUpdatesSpy).toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/open',
patch: firstPatch
}));
expect(networkUpdatesSpy).toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/open',
patch: thirdPatch
}));
expect(networkUpdatesSpy).not.toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/open',
patch: secondPatch
}));
expect(changePathSpy).toHaveBeenCalledWith(thirdPatch.id + SEPARATOR + firstPatch.id);
});
xit('when parent patch was closed, also closes the child patch', function() {
var firstPatch = Rpd.addClosedPatch('first');
var secondPatch = Rpd.addPatch('second');
var thirdPatch = Rpd.addPatch('third');
secondPatch.open(thirdPatch);
networkUpdatesSpy.calls.reset();
thirdPatch.close();
expect(networkUpdatesSpy).toHaveBeenCalledWith(
jasmine.objectContaining({
type: 'patch/close',
patch: secondPatch
}));
});
it('handling same path is not causing changePath to be called next time', function() {
var firstPatch = Rpd.addPatch('first');
var secondPatch = Rpd.addPatch('second');
var bothPatchesPath = firstPatch.id + SEPARATOR + secondPatch.id;
//Rpd.navigation.handlePath(bothPatchesPath);
changePathSpy.calls.reset();
Rpd.navigation.handlePath(bothPatchesPath);
Rpd.navigation.handlePath(bothPatchesPath);
expect(changePathSpy).not.toHaveBeenCalled();
});
});
describe('reaction on patches opened by user', function() {
it('writes every opened patch to a path', function() {
var firstPatch = Rpd.addPatch('first');
expect(changePathSpy).toHaveBeenCalledWith(firstPatch.id);
var secondPatch = Rpd.addPatch('second');
expect(changePathSpy).toHaveBeenCalledWith(firstPatch.id + SEPARATOR + secondPatch.id);
var thirdPatch = Rpd.addPatch('third');
expect(changePathSpy).toHaveBeenCalledWith(firstPatch.id + SEPARATOR + secondPatch.id + SEPARATOR + thirdPatch.id);
});
it('if one of the patches is closed, do not writes it to the path', function() {
var firstPatch = Rpd.addPatch('first');
changePathSpy.calls.reset();
var secondPatch = Rpd.addClosedPatch('second');
expect(changePathSpy).not.toHaveBeenCalled();
var thirdPatch = Rpd.addPatch('third');
expect(changePathSpy).toHaveBeenCalledWith(firstPatch.id + SEPARATOR + thirdPatch.id);
});
it('leaves single opened patch in a path and do not updates it if no patches were opened later', function() {
var firstPatch = Rpd.addClosedPatch('first');
var secondPatch = Rpd.addPatch('second');
expect(changePathSpy).toHaveBeenCalledWith(secondPatch.id);
changePathSpy.calls.reset();
var thirdPatch = Rpd.addClosedPatch('third');
expect(changePathSpy).not.toHaveBeenCalled();
});
it('follows opening and closing patches', function() {
var firstPatch = Rpd.addPatch('first');
var secondPatch = Rpd.addClosedPatch('second');
var thirdPatch = Rpd.addPatch('third');
changePathSpy.calls.reset();
secondPatch.open();
expect(changePathSpy).toHaveBeenCalledWith(firstPatch.id + SEPARATOR + thirdPatch.id + SEPARATOR + secondPatch.id);
thirdPatch.close();
expect(changePathSpy).toHaveBeenCalledWith(firstPatch.id + SEPARATOR + secondPatch.id);
});
xit('when parent patch was passed to open method, stores it in the path in first position', function() {
var firstPatch = Rpd.addClosedPatch('first');
var secondPatch = Rpd.addPatch('second');
var thirdPatch = Rpd.addPatch('third');
changePathSpy.calls.reset();
secondPatch.open(thirdPatch);
expect(changePathSpy).toHaveBeenCalledWith(thirdPatch.id + SEPARATOR + secondPatch.id);
});
});
});