Подтвердить что ты не робот

Используйте $httpBackend, чтобы издеваться над $http-вызовами, чтобы изменить ожидаемый URL Angular

Я пытаюсь проверить службу, которая использует $http

 var APIClient = function($http) {
     this.send = function(data) {
         $http({
             method: data.method,
             url: data.url,
             headers: data.headers,
             data: data.data
         }).success(function(response, status) {
             data.success(response, status);
         }).error(function(response, status) {
             data.error(response, status);
         });
     }
 }

 angular.module('api.client', []).factory('APIClient', ['$http'
     function($http) {
         var client = new APIClient($http);

         return {
             send: function(data) {
                 return client.send(data);
             },
         }

     }
 ]);

И тест

  describe('send', function() {

      var apiClient, $httpBackend;

      beforeEach(module('compare'));

      beforeEach(inject(function($injector) {
          $httpBackend = $injector.get('$httpBackend');
          apiClient = $injector.get('APIClient');
      }));

      it('Should check if send() exists', function() {
          expect(apiClient.send).toBeDefined();
      });

      it('Should send GET request', function(done) {
          var url = '/';

          $httpBackend.expect('GET', url).respond({});

          apiClient.send({
              url: url,
              success: function(data, status) {
                  console.log(status);
                  done();
              },
              error: function(data, status) {
                  console.log(status);
                  done();
              }
          });

          $httpBackend.flush();
      });
  });

Но у меня всегда есть эта ошибка

PhantomJS 1.9.8 (Mac OS X) send Should send GET request FAILED
        Error: Unexpected request: GET templates/test.html
        Expected GET /

Ожидаемый URL всегда является последним состоянием моего app.js В этом случае

// Ionic Starter App

// angular.module is a global place for creating, registering and retrieving Angular modules
// 'starter' is the name of this angular module example (also set in a <body> attribute in index.html)
// the 2nd parameter is an array of 'requires'
// 'starter.services' is found in services.js
// 'starter.controllers' is found in controllers.js

angular.module('compare',
    [
        'ionic',
        'manager.user',
        'api.client',
        'api.user',
        'api.compare',
        'user.controllers',
        'test.controllers'
    ]
)

    .run(function ($ionicPlatform) {
        $ionicPlatform.ready(function () {
            // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
            // for form inputs)
            if (window.cordova && window.cordova.plugins && window.cordova.plugins.Keyboard) {
                cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
            }
            if (window.StatusBar) {
                // org.apache.cordova.statusbar required
                StatusBar.styleLightContent();
            }
        });
    })

    .config(function ($stateProvider, $urlRouterProvider) {

        // Ionic uses AngularUI Router which uses the concept of states
        // Learn more here: https://github.com/angular-ui/ui-router
        // Set up the various states which the app can be in.
        // Each state controller can be found in controllers.js
        $stateProvider

            // setup an abstract state for the tabs directive
            .state('tab', {
                url: "/tab",
                abstract: true,
                templateUrl: "templates/tabs.html"
            })

            // Each tab has its own nav history stack:

            .state('tab.dash', {
                url: '/dash',
                views: {
                    'tab-dash': {
                        templateUrl: 'templates/tab-dash.html',
                        controller: 'DashCtrl'
                    }
                }
            })

            .state('subscription', {
                url: '/subscription',
                templateUrl: 'templates/subscription.html',
                controller: 'SubscriptionCtrl'
            })

            .state('login', {
                url: '/login',
                templateUrl: 'templates/login.html',
                controller: 'LoginCtrl'
            })

            .state('test-compare', {
                url: '/test/compare',
                templateUrl: 'templates/test.html',
                controller: 'TestCompareCtrl'
            })

        // if none of the above states are matched, use this as the fallback
        $urlRouterProvider.otherwise('/login');

    });

Я не понимаю, почему меняется URL-адрес. Я даю /, и он тестирует templates/test.html, который всегда является последним шаблоном состояния

4b9b3361

Ответ 1

Ваша основная проблема здесь в этой строке:

beforeEach(module('compare'));

Здесь вы загружаете все приложение, а не только apiClient. По сути, вы выполняете полный интеграционный тест вместо unit test.

Вы должны загружать только api.client.

beforeEach(module('api.client'));

Что-то полезное для заметки, вы также можете сделать что-то вроде:

$httpBackend.whenGET(/templates\/(.*)/).respond('');, который в основном игнорирует все шаблоны, которые загружаются маршрутизаторами, контроллерами или директивами. Если вы это сделаете, это все равно не будет считаться unit test, потому что вы не строго проверяете только свой APIClient.

Еще одно полезное замечание:

Все, что вы выполняете внутри .run или .config, не должно быть анонимной функцией, таким образом вы могли бы издеваться над этим.

Пример этого:

.config(CompareStateLoader);

CompareStateLoader.$inject = [
    '$stateProvider', 
    '$urlRouterProvider'
];

function CompareStateLoader(
    $stateProvider, 
    $urlRouterProvider
){
    //configure states here 
}

Выполнение этого позволит вам высмеять CompareStateLoader и загрузить его в тестовый бегун.

Подробнее об этом см. в разделе "Руководство по стилю" .

.

Ответ 2

Я бы предложил скомпилировать все ваши шаблоны в JS файл (например, с помощью grunt " html2js" или препроцессором кармы " ng-html2js" ) и не иметь головная боль с шаблонами GETing.

Или вы также можете использовать passThrough

$httpBackend.when('GET', /\.html$/).passThrough()

Пример - http://plnkr.co/edit/pbjcDl?p=preview

Но я бы предложил использовать первый вариант.

Ответ 3

var apiClient, $httpBackend, $loc;

    beforeEach(module('compare'));

    beforeEach(inject(function($injector, $location) {
        $httpBackend = $injector.get('$httpBackend');
        apiClient = $injector.get('APIClient');
        $loc = $location;
    }));


it ('Should send GET request', function(done) {
        expect($loc.path()).toEqual('');
        var url = '/';

        $httpBackend.expect('GET', $loc.path('/')).respond({});

        apiClient.send({
            url: url,
            success: function(data, status) {
                console.log(status);
                done();
            },
            error: function(data, status) {
                console.log(status);
                done();
            }
        });

        $httpBackend.flush();
    });

Edit Вы должны использовать angular -mock для использования $location

beforeEach(inject(function(_$httpBackend_, APIClient) {
        $httpBackend = _$httpBackend_;
        apiClient = APIClient;
    }));

Ответ 4

Добавьте эту строку в свой блок перед каждым блоком - $httpBackend.expect('GET', "templates/test.html" ). answer (200);