Multiple sequential httpBackend requests cause unexpected request
Asked Answered
C

2

6

I'm testing a sequence that polls a resource until a condition is met.

Book = $resource("/books/:id", {id: "@id"});

function poll(success) {
  Book.get({id:1}, function() {
    if (canStop) {
       success();
    } else {
       $timeout(poll, 1000);
    }

  });
};

The test below fails with Error: Unsatisfied requests: GET /user_workshops/1

describe('poll', function() {
  beforeEach(function() {
    $httpBackend.expectGET('/books/1').respond(200,{id:1});
    $httpBackend.expectGET('/books/1').respond(200,{id:1, newVal:1});

    poll(function() {
       successCalled = true;
    });

    $httpBackend.flush();
    $timeout.flush();

    canStop=true;

    $httpBackend.flush();
  });

  it('should call success when canStop is true', function() {
     expect(successCalled).toBe(true);
  });
});

I've tried rearranging test order to put the second expectGET just before the second httpBackend.flush() but then I get:

Error: Unexpected request: POST /books/1
No more request expected
Carping answered 28/7, 2015 at 6:16 Comment(0)
C
11

After an hour of hair pulling I realised that the httpBackend is very specific about the order that tests a called in - the expectation must be set not just before you call flush, but before the resource request is made, and when you call flush you must have made exactly and only the requests expected.

This means if you want to flush between sequential requests, the order of requests and expectations must be exactly:

$httpBackend.expectGET('...')
resource.get();
$httpBackend.flush()
$httpBackend.expectGET('...')
resource.get();
$httpBackend.flush()
...
etc

So in the case of the code above, it works if I change the ordering to:

describe('poll', function() {
  beforeEach(function() {
    $httpBackend.expectGET('/books/1').respond(200,{id:1});

    poll(function() {
       successCalled = true;
    });

    $httpBackend.flush();

    $httpBackend.expectGET('/books/1').respond(200,{id:1, newVal:1});

    $timeout.flush();
    canStop=true;

    $httpBackend.flush();
  });

  it('should call success when canStop is true', function() {
     expect(successCalled).toBe(true);
  });
});
Carping answered 28/7, 2015 at 6:16 Comment(1)
If you have a directive within a directive in which both have a templateUrl, this also appliesSamul
E
0

You can also rearm $httpBackend method on each call. Some kind like:

var deleteMethod = function () {
    $httpBackend.when('DELETE', /.*/gi).respond(function(method, url, data) {
        deleteMethod(); // <--- See here method is rearmed
        return [200, 'OK', {}];
    });
}
deleteMethod();
Enforcement answered 6/2, 2017 at 22:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.