Javascript 角度ui路由器单元测试(状态到URL)
在我的应用程序中对路由器进行单元测试时遇到了一些问题,该应用程序构建在Angular ui路由器上。我想测试的是状态转换是否会适当地更改URL(稍后会有更复杂的测试,但这就是我要开始的地方。) 以下是我的申请代码的相关部分:Javascript 角度ui路由器单元测试(状态到URL),javascript,unit-testing,angularjs,angular-ui-router,Javascript,Unit Testing,Angularjs,Angular Ui Router,在我的应用程序中对路由器进行单元测试时遇到了一些问题,该应用程序构建在Angular ui路由器上。我想测试的是状态转换是否会适当地更改URL(稍后会有更复杂的测试,但这就是我要开始的地方。) 以下是我的申请代码的相关部分: angular.module('scrapbooks') .config( function($stateProvider){ $stateProvider.state('splash', { url: "/splash/", temp
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路由器测试代码)的类似问题建议将$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');
});
});
如果只想检查当前状态的名称,则更容易使用
$state.transitiono('splash')
我意识到这有点离题,但我从谷歌来到这里,寻找一种简单的方法来测试路由的模板、控制器和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
对于未经
解决的状态
:
// 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
,我们必须为每个状态的templateUrl
键添加$templateCache.put()
:-
$templateCache.put('app/templates/template1.html');
$templateCache.put('app/templates/template2.html');
$templateCache.put('app/templates/template3.html');
希望这有帮助。祝您好运。您可以使用$state.$current.locals.globals
访问所有解析的值(请参阅代码片段)
//给定
$httpBackend
.expectGET('/api/users/123'))
.回复(200,{id:1,电子邮件:'test@email.com');
//什么时候
$state.go('users.show',{id:123});
$httpBackend.flush();
//然后
var user=$state.$current.locals.globals['user']
expact(user).to.have.property('id',123);
expact(user).to.have.property('email','test@email.com“);
如果您对模板内容中的任何内容都不感兴趣,可以模拟$templateCache:
beforeEach(inject(function($templateCache) {
spyOn($templateCache,'get').and.returnValue('<div></div>');
}
beforeach(注入(函数($templateCache){
spyOn($templateCache,'get')。和.returnValue(“”);
}
好的,算出来了(有点)如果我定义一个模拟路由器,使用内联模板而不是模板URL,转换就会成功。你能发布你的工作代码作为答案吗?我差不多一年前就提出了这个问题。我现在的观点是,解决这个问题的最佳方法是使用in-Karma。更具体地说,问题是如果模板下载在测试中失败(即,由于没有服务器),状态更改将失败。但是,除非您正在监视$stateChangeError事件,否则不会看到错误。然而,由于状态更改失败,将不会更新$state.current.name。非常好的帖子,节省时间如果您使用字符串定义服务,请使用get而不是invoke.expect($injector.get($state.current.resolve.data)).toBe('findAll');我按照上面的代码调整了andReturn
,就像上面的评论中提到的那样。但是,我的$state.current.name返回一个空字符串。有人知道为什么吗?@Philip我面临着同样的问题$state.current.name
是空字符串。@Joy@VLeong我遇到了同样的问题,然后意识到这是由于ui路由器ut造成的我正在写的是使用ES6承诺,而不是$q
。为了$rootScope.$digest()
来解决所有的承诺。我的案例可能非常独特,但我想我会分享以防万一。@Joy$state.current.name返回空字符串时遇到了同样的问题。我不得不将$rootScope.$digest()替换为$httpBackend.flush().在这一变化之后,我得到了我所期望的。为了保持简单,我发现这个答案是最可以接受的。有测试是很好的,但必须编写一个比我的整个ui路由定义更长的测试,只是为了测试一个端点,这是效率低下的方式。无论如何,我投票支持这一点
beforeEach(inject(function($templateCache) {
spyOn($templateCache,'get').and.returnValue('<div></div>');
}