How to verify $httpBackend mock expectations in a Protractor test?

三世轮回 提交于 2019-12-21 13:57:09

问题


I'm developing a frontend for a REST API. I'm using Protractor for end-to-end tests with the API mocked out because I want to be able to test the frontend in isolation.

Here's a simple test I got:

describe('partner', function () {
    it('should list partners', function () {
        var page = new PartnerListPage();
        var httpBackendMock = function () {
            angular.module('httpBackendMock', ['ngMockE2E'])
                .run(function ($httpBackend) {
                    $httpBackend.whenGET('/api/partners').respond(200, {
                        _embedded: {
                            partners: [
                                {
                                    firstName: 'Elnur',
                                    lastName: 'Abdurrakhimov'
                                }
                            ]
                        }
                    });
                    $httpBackend.whenGET(/.*/).passThrough();
                });
        };
        browser.addMockModule('httpBackendMock', httpBackendMock);

        page.open();
        expect(page.isOpen()).toBeTruthy();
        expect(page.getPartner(0).firstName).toBe('Elnur');
        expect(page.getPartner(0).lastName).toBe('Abdurrakhimov');
    });
});

What it does is basically create a mock of the backend so that it returns something I want it to.

It's all fine and dandy except for one thing. I want to be able to call the following methods at the end of the test:

$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();

The reason I want to do that is to verify that the mock is getting the expected requests. It doesn't make much sense for the test I've provided, but let's say I want to verify that when I submit some form, a particular POST request with particular data is being executed. I want to do the verification on the backend mock itself so that my test is isolated from outputting the result of the response of that POST request because that will be tested in another test.

How do I get access to the same $httpBackend instance that's being used in the httpBackendMock I've added to browser?

As far as I understand, Protractor and the app itself run in separate processes. Therefore I can't get access to $httpBackend directly the same way I can in a unit test.


回答1:


Your application is execute in the browser and protractor in a separate process. So you are right you can't access directly the browser context.

Fortunately, protractor provide a mechanism to execute javascript in the browser. I guess you could use this mechanism to access the $httpBackendMock.

browser.executeAsyncScript(function() {
  var $httpBackend = angular.injector(['httpBackendMock']).get('$httpBackend');
  $httpBackend.verifyNoOutstandingExpectation();
  $httpBackend.verifyNoOutstandingRequest();
});

NB: Code adapted from this answer.


Another option could be to expose a "check URL"

$httpBackend.whenGET('/api/check').respond(function() {
    $httpBackend.verifyNoOutstandingExpectation();
    $httpBackend.verifyNoOutstandingRequest();
    return [200];
});

and use it in your test:

browser.get('/api/check');



回答2:


You should try to avoid httpBackend stubs in your protractor tests. It can make changing your test data at a later date a lot more complicated then it needs to be. Protractor has a nice alternative to the mockHttp and that is Protractor#addMockModule. You can use this to mock out an individual module to have it return the desired result. You need to add this code before you call Protractor#get(). It will load after your application services overriding if it has the same name as an existing service.

You can use it as follows :

var dataUtilMockModule = function () {
     // Create a new module which depends on your data creation utilities
    var utilModule = angular.module('dataUtil', ['platform']);
    // Create a new service in the module that creates a new entity
    utilModule.service('EntityCreation', ['EntityDataService', '$q', function (EntityDataService, $q) {

        /**
         * Returns a promise which is resolved/rejected according to entity creation success
         * @returns {*}
         */
        this.createEntity = function (details,type) {
            // This is your business logic for creating entities
            var entity = EntityDataService.Entity(details).ofType(type);
            var promise = entity.save();
            return promise;
        };
    }]);
};

browser.addMockModule('dataUtil', dataUtilMockModule);

You can have this run as part of the before setup of you test and then return to the default in the after section by calling Protractor#clearMockModules() to clear the list of mock modules, ready for the next setup.




回答3:


I've found a much better solution than using the $httpBackend way.

Since you run Protractor tests on Node.js, it makes more sense to just use some Node.js package to mock the backend instead of this ugly and hacky solution I proposed in the question.

Hock worked great for me and hence I recommend using it or something similar.



来源:https://stackoverflow.com/questions/24419310/how-to-verify-httpbackend-mock-expectations-in-a-protractor-test

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!