2

I am trying to write a unit test for a AngularJS service with Karma and Jasmine using the PhantomJS browser. The service that I want to test uses nested promises (for reading a IndexedDB database, getting responses from the server and writing the response back to the database).

The same has to be done when writing to the database (write local db, post/put to server, update local db with server id). The tests I am writing all work except for the tests for handling a loss of connection to the server.

When that happens the sync() method sets the online status to false and creates a $timeout that repeatedly checks for a connection by doing a recursive call. If the connection is up again, all unsynced data will be synced (and the promises of the corresponding sync() calls will be resolved).

describe('Harmonized', function() {
var ... // setting all 'global' variables

[...] 

beforeEach(function(){
  // Address that the service sends a ping to check if online again
  pingGet = backend.when('GET', 'http://localhost:2403');
  pingGet.respond(0);

  testTablePut121 = backend.when('PUT', 'http://localhost:2403/test_table/121');
  testTablePut121.respond(function(method, url, data, headers) { ... } // returns 200

  [...]
}

[...]

it('should try to sync a SAVED element but should fail because of missing server connectivity', function() {
  var list;
  var timeoutCounter = 0;
  _checkOnline = harmonized._checkOnline; // harmonized is the service that has to be testet
  harmonized._checkOnline = function () {
    // only call the original function two times
    if (timeoutCounter++ < 2) {
      _checkOnline();
      // flush the $timeout and the $httpBackend
      timeout.flush(2000);
      backend.flush(1);
      // this also gives me an error because of the $digest already in progress
      console.log('after tick');
    }
  };


  all.getList().then(function(entries) {
    list = entries;

    testTablePut121.respond(0);
    pingGet = backend.expect('GET', 'http://localhost:2403');
    pingGet.respond(0);

    spyOn(list[0], 'sync').and.callThrough();
    list[0].save().then(
    // resolve is called when the server call was successfull
    function() {
      expect(list[0]._synchronized).toBeTruthy();
      expect(list[0].sync.calls.count()).toBe(2);
      console.log('done');
    }, 
    // reject is called when the server response an error other than 0 (which is not the case in this test spec)
    null, 
    // notify is called when the local db save is made
    function(){
      expect(list[0].sync.calls.count()).toBe(1);
      expect(list[0]._synchronized).toBeFalsy();
    });
    backend.flush(1);
  });
  backend.flush(1);
});

When the backend.flush() function is called a second time (to flush the http request made in the save() function, I get an error telling me that the $digest is already in progress. Omitting the line, doesn't flush the request (and a also get an error because of that).

Is there a way to flush everything at the right time without getting the $digest error?

Simon Jentsch
  • 707
  • 5
  • 10
  • I think I asked the same thing and got an answer. http://stackoverflow.com/questions/25210951/how-to-change-httpbackend-whenmethod-statements-between-requests-in-unit-test – FlavorScape Apr 09 '15 at 00:00

0 Answers0