Mam problemy z testowaniem jednostkowym routera w mojej aplikacji, która jest zbudowana na routerze Angular ui. Chcę sprawdzić, czy przejścia stanów odpowiednio zmieniają adres URL (później będą bardziej skomplikowane testy, ale od tego zaczynam).
Oto odpowiednia część mojego kodu aplikacji:
angular.module('scrapbooks')
.config( function($stateProvider){
$stateProvider.state('splash', {
url: "/splash/",
templateUrl: "/app/splash/splash.tpl.html",
controller: "SplashCtrl"
})
})
A kod testowy:
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");
})
})
Podobne pytania dotyczące Stackoverflow (i oficjalnego kodu testowego routera interfejsu użytkownika) sugerują, że zawinięcie wywołania $ state.go w $ apply powinno wystarczyć. Ale zrobiłem to i stan nadal się nie aktualizuje. $ state.current.name pozostaje puste.
Odpowiedzi:
Miałem również ten problem i w końcu wymyśliłem, jak to zrobić.
Oto przykładowy stan:
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(); }] } }); }]);
Poniższy test jednostkowy obejmie testowanie adresu URL z parametrami i wykonywanie rozwiązań, które wstrzykują własne zależności:
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'); }); });
źródło
andReturn
mowa w powyższym komentarzu. Jednak moja $ state.current.name zwraca pusty ciąg. Czy ktoś wie, dlaczego?$state.current.name
- pusty ciąg.$q
. Wszystko musi wykorzystywać$q
obietnice,$rootScope.$digest()
aby spełnić wszystkie obietnice. Mój przypadek jest prawdopodobnie dość wyjątkowy, ale pomyślałem, że na wszelki wypadek podzielę się nim.Jeśli chcesz sprawdzić tylko nazwę bieżącego stanu, jest to łatwiejsze w użyciu
$state.transitionTo('splash')
it('should transition to splash', inject(function($state,$rootScope){ $state.transitionTo('splash'); $rootScope.$apply(); expect($state.current.name).toBe('splash'); }));
źródło
Zdaję sobie sprawę, że jest to nieco poza tematem, ale przyszedłem tutaj z Google, szukając prostego sposobu na przetestowanie szablonu trasy, kontrolera i adresu URL.
$state.get('stateName')
da tobie
{ url: '...', templateUrl: '...', controller: '...', name: 'stateName', resolve: { foo: function () {} } }
w twoich testach.
Więc twoje testy mogą wyglądać mniej więcej tak:
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
źródło
Do
state
tego bezresolve
:// 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'); }); }); });
UWAGA:-
W przypadku stanu zagnieżdżonego może być konieczne dostarczenie więcej niż jednego szablonu. Na przykład. jeśli mamy stan zagnieżdżony
core.public.home
i każdystate
, tjcore
,core.public
icore.public.home
matemplateUrl
określone, będziemy musieli dodać$templateCache.put()
do każdego państwatemplateUrl
klucza: -$templateCache.put('app/templates/template1.html'); $templateCache.put('app/templates/template2.html'); $templateCache.put('app/templates/template3.html');
Mam nadzieję że to pomoże. Powodzenia.
źródło
Możesz użyć,
$state.$current.locals.globals
aby uzyskać dostęp do wszystkich rozstrzygniętych wartości (zobacz fragment kodu).// 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]');
W ui-router 1.0.0 (obecnie beta) możesz spróbować wywołać
$resolve.resolve(state, locals).then((resolved) => {})
w specyfikacji. Na przykład https://github.com/lucassus/angular-webpack-seed/blob/9a5af271439fd447510c0e3e87332959cb0eda0f/src/app/contacts/one/one.state.spec.js#L29źródło
Jeśli nie interesuje Cię nic w treści szablonu, możesz po prostu mockować $ templateCache:
beforeEach(inject(function($templateCache) { spyOn($templateCache,'get').and.returnValue('<div></div>'); }
źródło