Skip to content

Commit

Permalink
Merge pull request #497 from jamestalmage/test-coverage
Browse files Browse the repository at this point in the history
Add test coverage.
  • Loading branch information
Jacob Wenger committed Jan 15, 2015
2 parents a8c1585 + cc149b9 commit 1197e1b
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 17 deletions.
20 changes: 11 additions & 9 deletions src/firebase.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,14 +212,6 @@
}
}

function assertArray(arr) {
if( !angular.isArray(arr) ) {
var type = Object.prototype.toString.call(arr);
throw new Error('arrayFactory must return a valid array that passes ' +
'angular.isArray and Array.isArray, but received "' + type + '"');
}
}

var def = $firebaseUtils.defer();
var array = new ArrayFactory($inst, destroy, def.promise);
var batch = $firebaseUtils.batch();
Expand Down Expand Up @@ -256,17 +248,27 @@
}
}
});

assertArray(array);

var error = batch(array.$$error, array);
var resolve = batch(_resolveFn);

var self = this;
self.isDestroyed = false;
self.getArray = function() { return array; };

assertArray(array);
init();
}

function assertArray(arr) {
if( !angular.isArray(arr) ) {
var type = Object.prototype.toString.call(arr);
throw new Error('arrayFactory must return a valid array that passes ' +
'angular.isArray and Array.isArray, but received "' + type + '"');
}
}

function SyncObject($inst, ObjectFactory) {
function destroy(err) {
self.isDestroyed = true;
Expand Down
3 changes: 2 additions & 1 deletion tests/automatic_karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ module.exports = function(config) {
coverageReporter: {
reporters: [
{
type: "lcovonly",
// Nice HTML reports on developer machines, but not on Travis
type: process.env.TRAVIS ? "lcovonly" : "lcov",
dir: "coverage",
subdir: "."
},
Expand Down
54 changes: 54 additions & 0 deletions tests/unit/FirebaseArray.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,15 @@ describe('$FirebaseArray', function () {
arr.$$notify('child_removed', 'removedkey123', 'prevkey456');
expect(spy).not.toHaveBeenCalled();
});

it('calling the deregistration function twice should be silently ignored', function(){
var spy = jasmine.createSpy('$watch');
var off = arr.$watch(spy);
off();
off();
arr.$$notify('child_removed', 'removedkey123', 'prevkey456');
expect(spy).not.toHaveBeenCalled();
});
});

describe('$destroy', function() {
Expand All @@ -398,6 +407,14 @@ describe('$FirebaseArray', function () {
expect(arr.$$$destroyFn).toHaveBeenCalled();
});

it('should only call destroyFn the first time it is called', function() {
arr.$destroy();
expect(arr.$$$destroyFn).toHaveBeenCalled();
arr.$$$destroyFn.calls.reset();
arr.$destroy();
expect(arr.$$$destroyFn).not.toHaveBeenCalled();
});

it('should empty the array', function() {
expect(arr.length).toBeGreaterThan(0);
arr.$destroy();
Expand Down Expand Up @@ -601,6 +618,16 @@ describe('$FirebaseArray', function () {
expect(spy).toHaveBeenCalled();
});

it('"child_added" should not invoke $$notify if it already exists after prevChild', function() {
var spy = jasmine.createSpy('$$notify');
var arr = stubArray(STUB_DATA, $FirebaseArray.$extendFactory({ $$notify: spy }));
var index = arr.$indexFor('e');
var prevChild = arr.$$getKey(arr[index -1]);
spy.calls.reset();
arr.$$process('child_added', arr.$getRecord('e'), prevChild);
expect(spy).not.toHaveBeenCalled();
});

///////////////// UPDATE

it('should invoke $$notify with "child_changed" event', function() {
Expand Down Expand Up @@ -647,6 +674,16 @@ describe('$FirebaseArray', function () {
expect(spy).toHaveBeenCalled();
});

it('"child_moved" should not trigger $$notify if prevChild is already the previous element' , function() {
var spy = jasmine.createSpy('$$notify');
var arr = stubArray(STUB_DATA, $FirebaseArray.$extendFactory({ $$notify: spy }));
var index = arr.$indexFor('e');
var prevChild = arr.$$getKey(arr[index - 1]);
spy.calls.reset();
arr.$$process('child_moved', arr.$getRecord('e'), prevChild);
expect(spy).not.toHaveBeenCalled();
});

///////////////// REMOVE
it('should remove from local array', function() {
var len = arr.length;
Expand All @@ -665,6 +702,23 @@ describe('$FirebaseArray', function () {
arr.$$process('child_removed', arr.$getRecord('e'));
expect(spy).toHaveBeenCalled();
});

it('"child_removed" should not trigger $$notify if the record is not in the array' , function() {
var spy = jasmine.createSpy('$$notify');
var arr = stubArray(STUB_DATA, $FirebaseArray.$extendFactory({ $$notify: spy }));
spy.calls.reset();
arr.$$process('child_removed', {$id:'f'});
expect(spy).not.toHaveBeenCalled();
});

//////////////// OTHER
it('should throw an error for an unknown event type',function(){
var arr = stubArray(STUB_DATA);
expect(function(){
arr.$$process('unknown_event', arr.$getRecord('e'));
}).toThrow();
});

});

describe('$extendFactory', function() {
Expand Down
90 changes: 87 additions & 3 deletions tests/unit/FirebaseObject.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
describe('$FirebaseObject', function() {
'use strict';
var $firebase, $FirebaseObject, $utils, $rootScope, $timeout, obj, $fb, testutils, $interval;
var $firebase, $FirebaseObject, $utils, $rootScope, $timeout, obj, $fb, testutils, $interval, log;

var DEFAULT_ID = 'recc';
var FIXTURE_DATA = {
Expand All @@ -11,8 +11,18 @@ describe('$FirebaseObject', function() {
};

beforeEach(function () {
log = {
error:[]
};

module('firebase');
module('testutils');
module('testutils',function($provide){
$provide.value('$log',{
error:function(){
log.error.push(Array.prototype.slice.call(arguments));
}
})
});
inject(function (_$firebase_, _$interval_, _$FirebaseObject_, _$timeout_, $firebaseUtils, _$rootScope_, _testutils_) {
$firebase = _$firebase_;
$FirebaseObject = _$FirebaseObject_;
Expand Down Expand Up @@ -252,6 +262,34 @@ describe('$FirebaseObject', function() {
expect($scope.test).toEqual({foo: 'bar', $id: obj.$id, $priority: obj.$priority});
});

it('will replace the object on scope if new server value is not deeply equal', function () {
var $scope = $rootScope.$new();
obj.$bindTo($scope, 'test');
$timeout.flush();
$fb.$set.calls.reset();
obj.$$updated(fakeSnap({foo: 'bar'}));
obj.$$notify();
flushAll();
var oldTest = $scope.test;
obj.$$updated(fakeSnap({foo: 'baz'}));
obj.$$notify();
expect($scope.test === oldTest).toBe(false);
});

it('will leave the scope value alone if new server value is deeply equal', function () {
var $scope = $rootScope.$new();
obj.$bindTo($scope, 'test');
$timeout.flush();
$fb.$set.calls.reset();
obj.$$updated(fakeSnap({foo: 'bar'}));
obj.$$notify();
flushAll();
var oldTest = $scope.test;
obj.$$updated(fakeSnap({foo: 'bar'}));
obj.$$notify();
expect($scope.test === oldTest).toBe(true);
});

it('should stop binding when off function is called', function () {
var origData = $utils.scopeData(obj);
var $scope = $rootScope.$new();
Expand Down Expand Up @@ -346,6 +384,31 @@ describe('$FirebaseObject', function() {
});
});

describe('$watch', function(){
it('should return a deregistration function',function(){
var spy = jasmine.createSpy('$watch');
var off = obj.$watch(spy);
obj.foo = 'watchtest';
obj.$save();
flushAll();
expect(spy).toHaveBeenCalled();
spy.calls.reset();
off();
expect(spy).not.toHaveBeenCalled();
});

it('additional calls to the deregistration function should be silently ignored',function(){
var spy = jasmine.createSpy('$watch');
var off = obj.$watch(spy);
off();
off();
obj.foo = 'watchtest';
obj.$save();
flushAll();
expect(spy).not.toHaveBeenCalled();
});
});

describe('$remove', function() {
it('should return a promise', function() {
expect(obj.$remove()).toBeAPromise();
Expand Down Expand Up @@ -390,6 +453,13 @@ describe('$FirebaseObject', function() {
expect(obj.$$$destroyFn).toHaveBeenCalled();
});

it('should NOT invoke destroyFn if it is invoked a second time', function () {
obj.$destroy();
obj.$$$destroyFn.calls.reset();
obj.$destroy();
expect(obj.$$$destroyFn).not.toHaveBeenCalled();
});

it('should dispose of any bound instance', function () {
var $scope = $rootScope.$new();
spyOnWatch($scope);
Expand Down Expand Up @@ -507,6 +577,20 @@ describe('$FirebaseObject', function() {
});
});

describe('$$error',function(){
it('will log an error',function(){
obj.$$error(new Error());
expect(log.error).toHaveLength(1);
});

it('will call $destroy',function(){
obj.$destroy = jasmine.createSpy('$destroy');
var error = new Error();
obj.$$error(error);
expect(obj.$destroy).toHaveBeenCalledWith(error);
});
});

function flushAll() {
Array.prototype.slice.call(arguments, 0).forEach(function (o) {
angular.isFunction(o.resolve) ? o.resolve() : o.flush();
Expand Down Expand Up @@ -614,4 +698,4 @@ describe('$FirebaseObject', function() {
return offSpy;
});
}
});
});
23 changes: 19 additions & 4 deletions tests/unit/firebase.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('$firebase', function () {
$get: function() {
return function() {};
}
});
}).value('NonFunctionFactory','NonFunctionValue');
inject(function (_$firebase_, _$timeout_, _$rootScope_, $firebaseUtils) {
$firebase = _$firebase_;
$timeout = _$timeout_;
Expand Down Expand Up @@ -69,14 +69,28 @@ describe('$firebase', function () {
it('should throw an error if factory name for arrayFactory does not exist', function() {
var ref = new Firebase('Mock://');
expect(function() {
$firebase(ref, {arrayFactory: 'notarealarrayfactorymethod'})
$firebase(ref, {arrayFactory: 'notarealarrayfactorymethod'}); //injectable by that name doesn't exist.
}).toThrowError();
});

it('should throw an error if factory name for arrayFactory exists, but is not a function', function() {
var ref = new Firebase('Mock://');
expect(function() {
$firebase(ref, {arrayFactory: 'NonFunctionFactory'}); //injectable exists, but is not a function.
}).toThrowError();
});

it('should throw an error if factory name for objectFactory does not exist', function() {
var ref = new Firebase('Mock://');
expect(function() {
$firebase(ref, {objectFactory: 'notarealobjectfactorymethod'})
$firebase(ref, {objectFactory: 'notarealobjectfactorymethod'}); //injectable by that name doesn't exist.
}).toThrowError();
});

it('should throw an error if factory name for objectFactory exists, but is not a function', function() {
var ref = new Firebase('Mock://');
expect(function() {
$firebase(ref, {objectFactory: 'NonFunctionFactory'}); //injectable exists, but is not a function.
}).toThrowError();
});
});
Expand Down Expand Up @@ -477,7 +491,8 @@ describe('$firebase', function () {
expect(function() {
function fn() { return {}; }
$firebase(new Firebase('Mock://').child('data'), {arrayFactory: fn}).$asArray();
}).toThrowError(Error);
}).toThrow(new Error('arrayFactory must return a valid array that passes ' +
'angular.isArray and Array.isArray, but received "[object Object]"'));
});

it('should contain data in ref() after load', function() {
Expand Down

0 comments on commit 1197e1b

Please sign in to comment.