Angular тестирование модуля маршрутизатора ui (указывается в URL-адресах)
У меня возникла проблема с тестированием маршрутизатора в моем приложении, которое построено на маршрутизаторе Angular ui. То, что я хочу протестировать, - это то, будут ли изменения состояния соответствующим URL соответствующим образом (позже будут более сложные тесты, но это то, где я начинаю.)
Вот соответствующая часть моего кода приложения:
angular.module('scrapbooks')
.config( function($stateProvider){
$stateProvider.state('splash', {
url: "/splash/",
templateUrl: "/app/splash/splash.tpl.html",
controller: "SplashCtrl"
})
})
И тестовый код:
it("should change to the splash state", function(){
inject(function($state, $rootScope){
$rootScope.$apply(function(){
$state.go("splash");
});
expect($state.current.name).to.equal("splash");
})
})
Аналогичные вопросы о Stackoverflow (и официальном тестовом коде маршрутизатора) предполагают, что завершение вызова $state.go в $apply должно быть достаточно. Но я сделал это, и государство все еще не обновляется. $state.current.name остается пустым.
Ответы
Ответ 1
У этой проблемы также была проблема, и, наконец, выяснил, как это сделать.
Вот пример состояния:
angular.module('myApp', ['ui.router'])
.config(['$stateProvider', function($stateProvider) {
$stateProvider.state('myState', {
url: '/state/:id',
templateUrl: 'template.html',
controller: 'MyCtrl',
resolve: {
data: ['myService', function(service) {
return service.findAll();
}]
}
});
}]);
Ниже приведен список unit test, который будет проверять URL-адрес w/params и выполнять разрешения, которые вводят собственные зависимости:
describe('myApp/myState', function() {
var $rootScope, $state, $injector, myServiceMock, state = 'myState';
beforeEach(function() {
module('myApp', function($provide) {
$provide.value('myService', myServiceMock = {});
});
inject(function(_$rootScope_, _$state_, _$injector_, $templateCache) {
$rootScope = _$rootScope_;
$state = _$state_;
$injector = _$injector_;
// We need add the template entry into the templateCache if we ever
// specify a templateUrl
$templateCache.put('template.html', '');
})
});
it('should respond to URL', function() {
expect($state.href(state, { id: 1 })).toEqual('#/state/1');
});
it('should resolve data', function() {
myServiceMock.findAll = jasmine.createSpy('findAll').and.returnValue('findAll');
// earlier than jasmine 2.0, replace "and.returnValue" with "andReturn"
$state.go(state);
$rootScope.$digest();
expect($state.current.name).toBe(state);
// Call invoke to inject dependencies and run function
expect($injector.invoke($state.current.resolve.data)).toBe('findAll');
});
});
Ответ 2
Если вы хотите проверить только текущее состояние, проще использовать $state.transitionTo('splash')
it('should transition to splash', inject(function($state,$rootScope){
$state.transitionTo('splash');
$rootScope.$apply();
expect($state.current.name).toBe('splash');
}));
Ответ 3
Я понимаю, что это немного не по теме, но я пришел сюда из Google, ища простой способ проверить шаблон маршрута, контроллер и URL.
$state.get('stateName')
предоставит вам
{
url: '...',
templateUrl: '...',
controller: '...',
name: 'stateName',
resolve: {
foo: function () {}
}
}
в ваших тестах.
Итак, ваши тесты могут выглядеть примерно так:
var state;
beforeEach(inject(function ($state) {
state = $state.get('otherwise');
}));
it('matches a wild card', function () {
expect(state.url).toEqual('/path/to/page');
});
it('renders the 404 page', function () {
expect(state.templateUrl).toEqual('views/errors/404.html');
});
it('uses the right controller', function () {
expect(state.controller).toEqual(...);
});
it('resolves the right thing', function () {
expect(state.resolve.foo()).toEqual(...);
});
// etc
Ответ 4
При a state
, что без resolve
:
// TEST DESCRIPTION
describe('UI ROUTER', function () {
// TEST SPECIFICATION
it('should go to the state', function () {
module('app');
inject(function ($rootScope, $state, $templateCache) {
// When you transition to the state with $state, UI-ROUTER
// will look for the 'templateUrl' mentioned in the state's
// configuration, so supply those templateUrls with templateCache
$templateCache.put('app/templates/someTemplate.html');
// Now GO to the state.
$state.go('someState');
// Run a digest cycle to update the $state object
// you can also run it with $state.$digest();
$state.$apply();
// TEST EXPECTATION
expect($state.current.name)
.toBe('someState');
});
});
});
Примечание: -
Для вложенного состояния нам может потребоваться предоставить более одного шаблона. Напр. если у нас есть вложенное состояние core.public.home
и каждый state
, то есть core
, core.public
и core.public.home
имеет templateUrl
, нам нужно добавить $templateCache.put()
для каждого состояния templateUrl
: -
$templateCache.put('app/templates/template1.html');
$templateCache.put('app/templates/template2.html');
$templateCache.put('app/templates/template3.html');
Надеюсь, это поможет. Удачи.
Ответ 5
Вы можете использовать $state.$current.locals.globals
для доступа ко всем разрешенным значениям (см. фрагмент кода).
// Given
$httpBackend
.expectGET('/api/users/123')
.respond(200, { id: 1, email: '[email protected]');
// When
$state.go('users.show', { id: 123 });
$httpBackend.flush();
// Then
var user = $state.$current.locals.globals['user']
expact(user).to.have.property('id', 123);
expact(user).to.have.property('email', '[email protected]');
Ответ 6
Если вам не интересно что-либо в содержимом шаблона, вы можете просто высмеять $templateCache:
beforeEach(inject(function($templateCache) {
spyOn($templateCache,'get').and.returnValue('<div></div>');
}