Как вводить зависимости в тесте жасмина для элемента angular
Вот тестовый файл spec:
describe('Test main controller', function(){
it('Should initialize value to Loading', function(){
$scope = {}
ctrl = new mainNavController($scope)
expect($scope.wksp_name).toBe('Loading')
})
})
Вот файл контроллера
function mainNavController($scope) {
$scope.wksp_name = 'Loading...'
$scope.$on('broadCastWkspNameEvent', function (e, args) {
$scope.wksp_name = args
})
}
mainNavController.$inject=['$scope']
Но мой тест не позволяет сказать Object #<Object> has no method '$on'
Я использую базовую настройку жасмина.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Jasmine Spec Runner</title>
<link rel="shortcut icon" type="image/png" href="testlib/jasmine-1.2.0/jasmine_favicon.png">
<link rel="stylesheet" type="text/css" href="testlib/jasmine-1.2.0/jasmine.css">
<script type="text/javascript" src="testlib/jasmine-1.2.0/jasmine.js"></script>
<script type="text/javascript" src="testlib/jasmine-1.2.0/jasmine-html.js"></script>
<!-- include source files here... -->
<script type="text/javascript" src="/static_files/js/test-specs/main-nav-spec.js"></script>
<!-- include spec files here... -->
<script type="text/javascript" src="/static_files/js/common/jquery/latest.js"></script>
<script type="text/javascript" src="/static_files/js/common/angular/angular-1.0.1.min.js"></script>
<script type="text/javascript" src="/static_files/js/common/angular/angular-resource-1.0.1.min.js"></script>
<script type="text/javascript" src="/static_files/js/section/main-nav-controller.js"></script>
<script type="text/javascript">
(function() {
var jasmineEnv = jasmine.getEnv();
jasmineEnv.updateInterval = 1000;
var htmlReporter = new jasmine.HtmlReporter();
jasmineEnv.addReporter(htmlReporter);
jasmineEnv.specFilter = function(spec) {
return htmlReporter.specFilter(spec);
};
var currentWindowOnload = window.onload;
window.onload = function() {
if (currentWindowOnload) {
currentWindowOnload();
}
execJasmine();
};
function execJasmine() {
jasmineEnv.execute();
}
})();
</script>
</head>
<body>
</body>
</html>
Что я делаю неправильно? Я не могу понять, как эта вещь должна работать:)
Ответы
Ответ 1
Основная проблема с вашим тестовым кодом заключается в том, что он пытается создать экземпляр контроллера "вручную" с использованием нового оператора. При этом у AngularJS нет возможности вводить зависимости. То, что вы должны делать, это разрешить зависания зависимостей AngularJS:
var $scope, ctrl;
//you need to inject dependencies first
beforeEach(inject(function($rootScope) {
$scope = $rootScope.$new();
}));
it('Should initialize value to Loading', inject(function($controller) {
ctrl = $controller('MainNavController', {
$scope: $scope
});
expect($scope.wksp_name).toBe('Loading...');
}));
Вот ссылка на полный jsFiddle: http://jsfiddle.net/pkozlowski_opensource/7a7KR/3/
В приведенном выше примере стоит отметить 2 вещи:
Как последнее замечание: я бы посоветовал контроллерам именования, начиная с буквы верхнего регистра - таким образом мы не будем путать их с именами переменных.
Ответ 2
Отличный ответ by @pkozlowski.opensource. Чтобы разработать немного больше... Иногда было бы также полезно утверждать, что $scope.$on
был действительно вызван вашим контроллером. В этом случае вы можете следить за $scope.$on
, как указано ниже:
beforeEach(inject(function($rootScope) {
$scope = $rootScope.$new();
spyOn($scope, '$on').andCallThrough();
}));
И тогда вы можете утверждать, что $on
был вызван с вашим именем события и некоторой функцией в качестве аргументов:
it('Should bind to "broadCastWkspNameEvent"', inject(function($controller) {
ctrl = $controller('MainNavController', {
$scope: $scope
});
expect($scope.$on).toHaveBeenCalledWith('broadCastWkspNameEvent', jasmine.any(Function));
}));
Ответ 3
Я согласен с ответом pkozowski, но для более прямого ответа на ваш вопрос вам нужно заглушить '$ on'
Ваш пример прошел бы, если бы ваша $scope выглядела так:
$scope = {
$on: function() {}
}