Угловое тестирование с использованием passThrough в модульном тестировании

Я пытаюсь протестировать директиву в Angular, но не могу заставить работать соответствующий шаблон.

Директива перечисляет templateUrl так

templateUrl: 'directives/listview/view.html'

Теперь, когда я пишу любой модульный тест, я получаю

Error: Unexpected request: GET directives/listview/view.html

Поэтому я должен использовать $httpBackend и ответить чем-то разумным, например

httpBackend.whenGET('directives/listview/view.html').respond("<div>som</div>");

Но на самом деле я хочу просто вернуть фактический файл, а также сделать это синхронно, чтобы не было проблем с ожиданием, отложенными объектами и т. д. Как это сделать?


person Willem Mulder    schedule 11.10.2013    source источник


Ответы (2)


Теперь я использую https://github.com/karma-runner/karma-ng-html2js-preprocessor. Что он делает, так это считывает все шаблоны, которые вы используете, конвертирует их в шаблоны Angular и устанавливает их в $templateCache, поэтому, когда они нужны вашему приложению, оно будет извлекать их из кеша, а не запрашивать их с сервера.

В моем файле конфигурации кармы

files: [
    // templates
    '../**/*.html'
],

preprocessors : {
  // generate js files from html templates
  '../**/*.html': 'ng-html2js'
},

ngHtml2JsPreprocessor: {
    // setting this option will create only a single module that contains templates
    // from all the files, so you can load them all with module('templates')
    moduleName: 'templates'
},

А потом в тесте сделай лайк

// Load templates
angular.mock.module('templates');

И это работает!

person Willem Mulder    schedule 12.10.2013
comment
Всем привет. У меня проблемы с загрузкой шаблонов. Я следовал инструкциям, которые довольно ясны, но тест все еще пытается загрузить шаблон. Вот код, если у вас есть время проверить gist.github.com/andreareginato/7168181. - person Andrea Reginato; 26.10.2013
comment
Вероятно, вам нужно установить что-то вроде cacheIdFromPath : function(filepath) { return filepath.substr(filepath.indexOf(appname)+8); } в части ngHtml2JsPreprocessor. Потому что пути, по которым он кэширует шаблоны, по умолчанию относятся к диску, а мы хотим, чтобы они относились к корню нашего приложения. Также см. willemmulder.tumblr.com/post/ 63827986070/ для более подробной инструкции - person Willem Mulder; 28.10.2013
comment
Ваше предложение было правильным. Это была проблема пути. Я решил это таким образом github.com/angular/angular.js/ вопросы/2512#issuecomment-27146056 - person Andrea Reginato; 28.10.2013
comment
Это тоже работает, да! Здорово, что вы заставили его работать :-) Любой ответ на ответ также приветствуется. - person Willem Mulder; 28.10.2013
comment
@WillemMulder, хотя этот ответ может сработать для вашего сценария, имхо, лучший ответ - это тот, который правильно отвечает на вопрос, как он был сформулирован - именно для этого люди приходят к этому вопросу. - person cyberwombat; 03.11.2013
comment
Мне нужно было добавить stripPrefix: 'app/' в конфиг кармы ngHtml2JsPreprocessor. - person Leopd; 13.02.2014
comment
Я запускаю свои модульные тесты в Jasmine test runner. Я полагал, что может быть то же самое, но скоро он не сможет работать без бегуна кармы. И почему? Потому что хочу passThrough только для e2e-тестов... Извините, но директива с ее шаблоном является единым программным блоком и я хочу его протестировать. - person Plap; 24.06.2014

Обязательно включите модуль ngMockE2E в свой файл beforeEach.

Если вы этого не сделаете, макет службы $browser не будет создан при вызове whenGET, а возвращаемое значение не будет устанавливать функцию passThrough

beforeEach(function() {
   module('yourModule');
   module('ngMockE2E'); //<-- IMPORTANT!

   inject(function(_$httpBackend_) {
    $httpBackend = _$httpBackend_;
    $httpBackend.whenGET('somefile.html').passThrough();
   });
});

Место в angular-mocks.js, где это настроено:

Рассматриваемый исходный код находится в функции when $httpBackend mock:

function (method, url, data, headers) {
  var definition = new MockHttpExpectation(method, url, data, headers),
      chain = {
        respond: function(status, data, headers) {
          definition.response = createResponse(status, data, headers);
        }
      };

  if ($browser) {
    chain.passThrough = function() {
      definition.passThrough = true;
    };
  }
  definitions.push(definition);
  return chain;
} 
person Ben Lesh    schedule 11.10.2013
comment
К сожалению, это работает только с e2e-тестированием, а не с модульным тестированием. - person Willem Mulder; 11.10.2013
comment
Если это не работает в ваших модульных тестах, возможно, ваши модульные тесты настроены странно. Я использую это все время в своих модульных тестах. Во всяком случае, для тестирования e2e я даже не использую angular-mocks, я использую для этого транспортир. - person Ben Lesh; 11.10.2013
comment
В конфиг кармы я включаю angular, angular-mock и файлы моего проекта. Затем в тесте я могу использовать $httpBackend, но когда я пытаюсь использовать .passThrough(), я получаю TypeError: 'undefined' не является функцией, оценивающей 'httpBackend.whenGET(/.*/).passThrough()'). Включаете ли вы специальные зависимости, чтобы заставить его работать? - person Willem Mulder; 11.10.2013
comment
Обновлено это с более полным ответом. - person Ben Lesh; 11.10.2013
comment
Спасибо. Я пробовал это, но запросы, похоже, не обслуживаются. Я получаю сообщение об ошибке: Неожиданный запрос: GET directives/listview/view.html. Больше никаких запросов не ожидается, хотя я установил правило httpBackend.whenGET(directives/listview/view.html).passThrough(); что должно работать, верно? - person Willem Mulder; 12.10.2013