У меня возникли проблемы с модульным тестированием маршрутизатора в моем приложении, которое построено на маршрутизаторе 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 (и официальном тестовом коде ui router) предполагают, что обернуть вызов $ state.go в $ apply должно быть достаточно. Но я сделал это, и состояние все еще не обновляется. $ state.current.name остается пустым.
Ответы:
У меня тоже была эта проблема, и я, наконец, понял, как это сделать.
Вот примерное состояние:
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(); }] } }); }]);
Приведенный ниже модульный тест будет охватывать тестирование URL с параметрами и выполнение разрешений, которые вводят свои собственные зависимости:
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'); }); });
источник
andReturn
подобными упомянутым в комментарии выше. Однако мой $ state.current.name возвращает пустую строку. Кто-нибудь знает почему?$state.current.name
- пустая строка.$q
. Все должно использовать$q
обещания, чтобы$rootScope.$digest()
выполнить все обещания. Мой случай, наверное, довольно уникален, но думал, что поделюсь на всякий случай.Если вы хотите проверить только имя текущего состояния, проще использовать
$state.transitionTo('splash')
it('should transition to splash', inject(function($state,$rootScope){ $state.transitionTo('splash'); $rootScope.$apply(); expect($state.current.name).toBe('splash'); }));
источник
Я понимаю, что это немного не по теме, но я пришел сюда из 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
источник
Для того,
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');
Надеюсь это поможет. Удачи.
источник
Вы можете использовать
$state.$current.locals.globals
для доступа ко всем разрешенным значениям (см. Фрагмент кода).// Given $httpBackend .expectGET('/api/users/123') .respond(200, { id: 1, email: 'test@email.com'); // 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', 'test@email.com');
В ui-router 1.0.0 (в настоящее время бета) вы можете попробовать вызвать
$resolve.resolve(state, locals).then((resolved) => {})
в спецификациях. Например, https://github.com/lucassus/angular-webpack-seed/blob/9a5af271439fd447510c0e3e87332959cb0eda0f/src/app/contacts/one/one.state.spec.js#L29источник
Если вас ничего не интересует в содержимом шаблона, вы можете просто имитировать $ templateCache:
beforeEach(inject(function($templateCache) { spyOn($templateCache,'get').and.returnValue('<div></div>'); }
источник