UI-маршрутизатор взаимодействует с $httpbackend unit test, angular js
Это контроллер с функцией отправки:
$scope.submit = function(){
$http.post('/api/project', $scope.project)
.success(function(data, status){
$modalInstance.dismiss(true);
})
.error(function(data){
console.log(data);
})
}
}
Это мой тест
it('should make a post to /api/project on submit and close the modal on success', function() {
scope.submit();
$httpBackend.expectPOST('/api/project').respond(200, 'test');
$httpBackend.flush();
expect(modalInstance.dismiss).toHaveBeenCalledWith(true);
});
Ошибка, которую я получаю:
Error: Unexpected request: GET views/appBar.html
views/appBar.html - это мой шаблон url:
.state('project', {
url: '/',
templateUrl:'views/appBar.html',
controller: 'ProjectsCtrl'
})
Итак, как-то ui-router делает мой пункт $httpBackend для этого вместо моей функции отправки. У меня такая же проблема во всех моих тестах, используя $httpBackend.
Есть ли какое-либо решение для этого?
Ответы
Ответ 1
Возьмите этот смысл
https://gist.github.com/wilsonwc/8358542
angular.module('stateMock',[]);
angular.module('stateMock').service("$state", function($q){
this.expectedTransitions = [];
this.transitionTo = function(stateName){
if(this.expectedTransitions.length > 0){
var expectedState = this.expectedTransitions.shift();
if(expectedState !== stateName){
throw Error("Expected transition to state: " + expectedState + " but transitioned to " + stateName );
}
}else{
throw Error("No more transitions were expected! Tried to transition to "+ stateName );
}
console.log("Mock transition to: " + stateName);
var deferred = $q.defer();
var promise = deferred.promise;
deferred.resolve();
return promise;
}
this.go = this.transitionTo;
this.expectTransitionTo = function(stateName){
this.expectedTransitions.push(stateName);
}
this.ensureAllTransitionsHappened = function(){
if(this.expectedTransitions.length > 0){
throw Error("Not all transitions happened!");
}
}
});
Добавьте его в файл с именем stateMock в папке test/mock, включите этот файл в конфигурацию вашей кармы, если он еще не был выбран.
Настройка перед вашим тестом должна выглядеть примерно так:
beforeEach(module('stateMock'));
// Initialize the controller and a mock scope
beforeEach(inject(function ($state //other vars as needed) {
state = $state;
//initialize other stuff
}
Затем в вашем тесте вы должны добавить
state.expectTransitionTo('project');
Ответ 2
Этот вопрос Github о Unit Testing UI Router более подробно объясняет, что происходит.
Проблема заключается в том, что $httpBackend.flush()
запускает широковещательную передачу, которая затем запускает в противном случае случай stateProvider
.
Простым решением может быть следующая настройка, о которой упоминается в статье @darinclark в упомянутой выше статье Github. Это действительно, если вам не нужно проверять состояние переходов. В противном случае посмотрите @rosswil answer, который вдохновлен @Ответ Vratislav на Github.
beforeEach(module(function ($urlRouterProvider) {
$urlRouterProvider.otherwise(function(){return false;});
}));
EDITED
Спасибо Крису Т сообщить об этом в комментариях, кажется, после v0.2.14? лучший способ сделать это - использовать
beforeEach(module(function($urlRouterProvider) {
$urlRouterProvider.deferIntercept();
}));
Ответ 3
Если вы не хотите добавлять gist файлы, как указано в правильном решении, вы можете добавить условие "когда" к вашему $httpBackend, чтобы игнорировать петиции GET видов вроде этого:
$httpBackend.when("GET", function (url) {
// This condition works for my needs, but maybe you need to improve it
return url.indexOf(".tpl.html") !== -1;
}).passThrough();
Ответ 4
У меня такая же ошибка, о которой вы прокомментировали, после службы вызова они спрашивают меня о URL-адресе другого маршрута ui.
Чтобы решить проблему вызова, иначе ui-route при тестировании не введет $state в beforeach. В моем тестировании $state не имеет смысла использовать его.
Ответ 5
Переместите свои службы в собственный модуль, не зависящий от ui.router. ваше основное приложение зависит от этого модуля. Когда вы тестируете не тестируете основное приложение, проверьте модуль, в котором есть ваши службы. Stateprovider не будет пытаться изменить состояние/маршрут, потому что этот модуль ничего не знает о ui.router. Это сработало для меня.