I am trying to mock responses to API calls within Protractor tests. In different tests (and within tests), the application will POST to an API (always the same URL) with different data POSTed, and expecting different responses.
Specifically, it is a search engine, and I am sending different queries and expecting different results back. I have it working successfully like the code below, but it is getting unmanageable:
var httpBackendMock = function() {
angular.module('httpBackendMock', ['ngMockE2E'])
.run(function($httpBackend) {
$httpBackend.whenPOST('//search_endpoint').respond(function(method, url, query, headers) {
query = JSON.parse(query);
if (query.bla = 'foo') {
var results = {... lots of json ...};
} else if (query.bla = 'bar') {
var results = {... lots of json ...};
} else if (query.something.else != 'whatever') {
var results = {... lots of json ...};
... etc ...
} else {
var results = {... lots of json ...};
}
return [200, results];
});
$httpBackend.whenGET(/.*/).passThrough();
})
};
beforeEach(function(){
browser.addMockModule('httpBackendMock', httpBackendMock);
});
What I'd like to do is have each possible response in a separate mock, then remove the beforeEach
and add the mocks when needed, like so:
it('paginates', function(){
// mocking a search with 13 results, showing 10 results per page
browser.addMockModule('search_results', <some function>);
$('#searchbox').sendKeys('some keyword search');
$('#searchbutton').click();
expect($('#results li').count()).toEqual(10);
browser.clearMockModules();
browser.addMockModule('search_results_page2', <some other function>);
$('#next').click();
expect($('#results li').count()).toEqual(3)
});
There are two problems with this.
1) It doesn't work. After clearing and adding the second mock, getRegisteredMockModules()
shows only the second mock, however it seems like the first mock is still getting used, based on the expect
s and manual inspection when using browser.pause()
with ChromeDriver. It seems that you can't change the mocks without at least reloading the page.
2) Even if it did work, there is a huge amount of repeated code for each mock module, as it has to set up everything, including the passThrough()
.
What would be even better would be if I could pass my desired response into the mock I am adding, however I tried that and anything passed into my own function isn't available within the angular.module
scope. The only way I could think of to do that would be to create another angular module with a provider that had a single variable that would keep track of which response was desired, and inject that into the mocked module. I haven't tried that yet but it seems like an unnecessarily complex solution.