describe('instance api',function(){ "use strict"; var oboeBus, oboeInstance; beforeEach(function(){ oboeBus = spiedPubSub(); oboeInstance = instanceApi(oboeBus); }); function anAscent(){ return list(namedNode(ROOT_PATH, {}) ); } describe('header method', function(){ it('returns undefined if not available', function() { expect( oboeInstance.header() ).toBeUndefined(); }); it('can provide object once available', function() { var headers = {"x-remainingRequests": 100}; oboeBus(HTTP_START).emit( 200, headers ); expect( oboeInstance.header() ).toEqual(headers); }); it('can provide single header once available', function() { var headers = {"x-remainingRequests": 100}; oboeBus(HTTP_START).emit( 200, headers ); expect( oboeInstance.header('x-remainingRequests') ).toEqual(100); }); it('gives undefined for non-existent single header', function() { var headers = {"x-remainingRequests": 100}; oboeBus(HTTP_START).emit( 200, headers ); expect( oboeInstance.header('x-remainingBathtubs') ).toBeUndefined(); }); }); describe('root method', function(){ it('returns undefined if not available', function() { expect( oboeInstance.root() ).toBeUndefined(); }); it('can provide object once available', function() { var root = {I:'am', the:'root'}; oboeBus(ROOT_FOUND).emit( root); expect( oboeInstance.root() ).toEqual(root); }); }); describe('node and path callbacks', function(){ it('calls node callback when notified of matching node', function() { var callback = jasmine.createSpy('node callback'), node = {}, path = [], ancestors = []; oboeInstance.on('node', 'a_pattern', callback); expect(callback).not.toHaveBeenCalled() oboeBus('node:a_pattern').emit( node, path, ancestors ); expect(callback).toHaveBeenCalledWith( node, path, ancestors ); }); it('calls path callback when notified of matching path', function() { var callback = jasmine.createSpy('path callback'), node = {}, path = [], ancestors = []; oboeInstance.on('path', 'a_pattern', callback); expect(callback).not.toHaveBeenCalled() oboeBus('path:a_pattern').emit( node, path, ancestors ); expect(callback).toHaveBeenCalledWith( node, path, ancestors ); }); it('allows short-cut node matching', function() { var callback1 = jasmine.createSpy(), callback2 = jasmine.createSpy(); oboeInstance.on('node', { pattern1: callback1, pattern2: callback2 }); expect(callback1).not.toHaveBeenCalled() expect(callback2).not.toHaveBeenCalled() oboeBus('node:pattern1').emit( {}, anAscent()) expect(callback1).toHaveBeenCalled() expect(callback2).not.toHaveBeenCalled() oboeBus('node:pattern2').emit( {}, anAscent()) expect(callback2).toHaveBeenCalled() }); it('calls node callback added using 2-arg mode when notified of match to pattern', function() { var callback = jasmine.createSpy('node callback'), node = {}, path = [], ancestors = []; oboeInstance.on('node:a_pattern', callback) expect(callback).not.toHaveBeenCalled() oboeBus('node:a_pattern').emit( node, path, ancestors ); expect(callback).toHaveBeenCalledWith( node, path, ancestors ); }); it('allows adding using addListener method', function() { var callback = jasmine.createSpy('node callback'), node = {}, path = [], ancestors = []; oboeInstance.addListener('node:a_pattern', callback) expect(callback).not.toHaveBeenCalled() oboeBus('node:a_pattern').emit( node, path, ancestors ); expect(callback).toHaveBeenCalledWith( node, path, ancestors ); }); it('calls path callback added using 2-arg mode when notified of match to pattern', function() { var callback = jasmine.createSpy('path callback'), node = {}, path = [], ancestors = []; oboeInstance.on('path:a_pattern', callback); expect(callback).not.toHaveBeenCalled() oboeBus('path:a_pattern').emit( node, path, ancestors ); expect(callback).toHaveBeenCalledWith( node, path, ancestors ); }); it('doesn\'t call node callback on path found', function() { var callback = jasmine.createSpy('node callback'); oboeInstance.on('node', 'a_pattern', callback); expect(callback).not.toHaveBeenCalled() oboeBus('path:a_pattern').emit( {}, list(namedNode(ROOT_PATH, {}) ) ); expect(callback).not.toHaveBeenCalled(); }); it('doesn\'t call again after forget called from inside callback', function() { var callback = jasmine.createSpy().andCallFake(function(){ this.forget(); }), ascent = list(namedNode('node', {})); oboeInstance.on('node', 'a_pattern', callback); oboeBus('node:a_pattern').emit( {}, ascent); expect(callback.call.length).toBe(1) oboeBus('node:a_pattern').emit( {}, ascent); expect(callback.calls.length).toBe(1) }); it('doesn\'t call node callback after callback is removed', function() { var callback = jasmine.createSpy(), ascent = list(namedNode('node', {})); oboeInstance.on('node', 'a_pattern', callback); oboeInstance.removeListener('node', 'a_pattern', callback); oboeBus('node:a_pattern').emit( {}, ascent); expect(callback).not.toHaveBeenCalled() }); it('doesn\'t call node callback after callback is removed using 2-arg form', function() { var callback = jasmine.createSpy(), ascent = list(namedNode('node', {})); oboeInstance.on('node', 'a_pattern', callback); oboeInstance.removeListener('node:a_pattern', callback); oboeBus('node:a_pattern').emit( {}, ascent); expect(callback).not.toHaveBeenCalled() }); it('doesn\'t call path callback after callback is removed', function() { var callback = jasmine.createSpy(), ascent = list(namedNode('path', {})); oboeInstance.on('path', 'a_pattern', callback); oboeInstance.removeListener('path', 'a_pattern', callback); oboeBus('path:a_pattern').emit( {}, ascent); expect(callback).not.toHaveBeenCalled() }); it('doesn\'t remove callback if wrong pattern is removed', function() { var callback = jasmine.createSpy(), ascent = list(namedNode('node', {})); oboeInstance.on('node', 'a_pattern', callback); oboeInstance.removeListener('node', 'wrong_pattern', callback); oboeBus('node:a_pattern').emit( {}, ascent); expect(callback).toHaveBeenCalled() }); it('doesn\'t remove callback if wrong callback is removed', function() { var callback = jasmine.createSpy(), wrongCallback = jasmine.createSpy(), ascent = list(namedNode('node', {})); oboeInstance.on('node', 'a_pattern', callback); oboeInstance.removeListener('node', 'a_pattern', wrongCallback); oboeBus('node:a_pattern').emit( {}, ascent); expect(callback).toHaveBeenCalled() }); it('allows nodes node to be removed in a different ' + 'style than they were added', function() { var callback1 = jasmine.createSpy(), callback2 = jasmine.createSpy(), callback3 = jasmine.createSpy(), ascent = list(namedNode('node', {})); oboeInstance.node('pattern1', callback1); oboeInstance.on('node', 'pattern2', callback2); oboeInstance.on('node', {pattern3: callback3}); oboeInstance.removeListener('node:pattern1', callback1); oboeInstance.removeListener('node:pattern2', callback2); oboeInstance.removeListener('node:pattern3', callback3); oboeBus('node:pattern1').emit( {}, ascent); oboeBus('node:pattern2').emit( {}, ascent); oboeBus('node:pattern3').emit( {}, ascent); expect(callback1).not.toHaveBeenCalled() expect(callback2).not.toHaveBeenCalled() expect(callback3).not.toHaveBeenCalled() }); }); describe('start event', function() { it('notifies .on(start) listener when http response starts', function(){ var callback = jasmine.createSpy(); oboeInstance.on('start', callback); expect(callback).not.toHaveBeenCalled() oboeBus(HTTP_START).emit( 200, {a_header:'foo'} ) expect(callback).toHaveBeenCalledWith( 200, {a_header:'foo'} ) }); it('notifies .start listener when http response starts', function(){ var callback = jasmine.createSpy(); oboeInstance.start(callback); expect(callback).not.toHaveBeenCalled() oboeBus(HTTP_START).emit( 200, {a_header:'foo'} ) expect(callback).toHaveBeenCalledWith( 200, {a_header:'foo'} ) }); it('can be de-registered', function() { var callback = jasmine.createSpy(); oboeInstance.on('start', callback); oboeInstance.removeListener('start', callback); oboeBus(HTTP_START).emit( 200, {a_header:'foo'} ) expect(callback).not.toHaveBeenCalled() }); }); describe('done event', function(){ it('calls listener on end of JSON when added using .on(done)', function() { var callback = jasmine.createSpy(); oboeInstance.on('done', callback); expect(callback).not.toHaveBeenCalled() oboeBus('node:!').emit( {}, anAscent()) expect(callback).toHaveBeenCalled() }); it('calls listener on end of JSON when added using .done', function() { var callback = jasmine.createSpy(); oboeInstance.done(callback); expect(callback).not.toHaveBeenCalled() oboeBus('node:!').emit( {}, anAscent()) expect(callback).toHaveBeenCalled() }); it('can be de-registered', function() { var callback = jasmine.createSpy(); oboeInstance.on('done', callback); oboeInstance.removeListener('done', callback); oboeBus('node:!').emit( {}, anAscent()) expect(callback).not.toHaveBeenCalled() }); }); it('emits ABORTING when .abort() is called', function() { oboeInstance.abort(); expect(oboeBus(ABORTING).emit).toHaveBeenCalled() }); describe('errors cases', function(){ describe('calling fail listener', function() { it('notifies .on(fail) listener when something fails', function(){ var callback = jasmine.createSpy(); oboeInstance.on('fail', callback); expect(callback).not.toHaveBeenCalled() oboeBus(FAIL_EVENT).emit( 'something went wrong' ) expect(callback).toHaveBeenCalledWith( 'something went wrong' ) }); it('notifies .fail listener when something fails', function(){ var callback = jasmine.createSpy(); oboeInstance.fail(callback); expect(callback).not.toHaveBeenCalled() oboeBus(FAIL_EVENT).emit( 'something went wrong' ) expect(callback).toHaveBeenCalledWith( 'something went wrong' ) }); it('can be de-registered', function() { var callback = jasmine.createSpy(); oboeInstance.on('fail', callback); oboeInstance.removeListener('fail', callback); oboeBus(FAIL_EVENT).emit( 'something went wrong' ) expect(callback).not.toHaveBeenCalled() }); }); it('is protected from error in node callback', function() { var e = "an error"; var callback = jasmine.createSpy().andThrow(e); expect(function(){ oboeInstance.on('node', 'a_pattern', callback); }).not.toThrow(); oboeBus('node:a_pattern').emit( {}, anAscent()) expect(callback).toHaveBeenCalled() expect(oboeBus(FAIL_EVENT).emit) .toHaveBeenCalledWith(errorReport(undefined, undefined, e)) }); it('is protected from error in node callback added via shortcut', function() { var e = "an error"; var callback = jasmine.createSpy().andThrow(e); expect(function(){ oboeInstance.on('node', {'a_pattern': callback}); }).not.toThrow(); oboeBus('node:a_pattern').emit( {}, anAscent()) expect(callback).toHaveBeenCalled() expect(oboeBus(FAIL_EVENT).emit) .toHaveBeenCalledWith(errorReport(undefined, undefined, e)) }); it('is protected from error in path callback', function() { var e = "an error"; var callback = jasmine.createSpy().andThrow(e); expect(function(){ oboeInstance.on('path', 'a_pattern', callback); }).not.toThrow(); oboeBus('path:a_pattern').emit( {}, anAscent()) expect(callback).toHaveBeenCalled() expect(oboeBus(FAIL_EVENT).emit) .toHaveBeenCalledWith(errorReport(undefined, undefined, e)) }); it('is protected from error in start callback', function() { var e = "an error"; var callback = jasmine.createSpy().andThrow(e); expect(function(){ oboeInstance.on('start', callback); }).not.toThrow(); oboeBus(HTTP_START).emit() expect(callback).toHaveBeenCalled() expect(oboeBus(FAIL_EVENT).emit) .toHaveBeenCalledWith(errorReport(undefined, undefined, e)) }); it('is protected from error in done callback', function() { var e = "an error"; var callback = jasmine.createSpy().andThrow(e); expect(function(){ oboeInstance.done( callback); }).not.toThrow(); oboeBus( 'node:!').emit( {}, anAscent()) expect(callback).toHaveBeenCalled() expect(oboeBus(FAIL_EVENT).emit) .toHaveBeenCalledWith(errorReport(undefined, undefined, e)) }); }); describe('unknown event types', function() { it('can be added and fired', function() { var spy1 = jasmine.createSpy(); var spy2 = jasmine.createSpy(); expect(function(){ oboeInstance .on('xyzzy', spy1) .on('end_of_universe', spy2); }).not.toThrow(); oboeInstance.emit('xyzzy', 'hello'); oboeInstance.emit('end_of_universe', 'oh no!'); expect( spy1 ).toHaveBeenCalledWith('hello'); expect( spy2 ).toHaveBeenCalledWith('oh no!'); }); it('is allows removal', function() { var spy1 = jasmine.createSpy(); var spy2 = jasmine.createSpy(); oboeInstance .on('xyzzy', spy1) .on('end_of_universe', spy2); oboeInstance.removeListener('xyzzy', spy1); oboeInstance.removeListener('end_of_universe', spy2); oboeInstance.emit('xyzzy', 'hello'); oboeInstance.emit('end_of_universe', 'oh no!'); expect( spy1 ).not.toHaveBeenCalled() expect( spy2 ).not.toHaveBeenCalled() }); }); });