我正在测试一个指令。该指令监视范围变量,但从不调用手表。将$watch
调用直接放在单元测试中。为什么指令中的$watch
没有被调用?
谢谢!
这是我原来的测试。该指令有一个手表,看着'reEvalCreateDate'
。它永远不会被调用,日期字符串总是空的。
it('should inject a date string', function()
{
scope.reEvalCreateDate = reEvalCreateDateAsNumber;
expect(elm.text()).toBe('');
scope.$digest();
expect(elm.text()).toBe(new Date(reEvalCreateDateAsNumber).toUTCString());
});
作为测试,我将手表放在单元测试中。它被正确调用并且测试通过。
it('should inject a date string', function()
{
scope.$watch('reEvalCreateDate', function(newValue, oldValue)
{
var date = new Date(newValue);
scope.dateString = date.toUTCString();
dump(scope.dateString)
});
scope.reEvalCreateDate = reEvalCreateDateAsNumber;
expect(elm.text()).toBe('');
scope.$digest();
expect(elm.text()).toBe(new Date(reEvalCreateDateAsNumber).toUTCString()); //This passes!
});
这是带有watch语句的指令代码。
link: function(scope, element, attrs)
{
scope.$watch('show',function(shouldShow){
console.log('should show reeval timer? ' + shouldShow);
if(shouldShow) {
$(element).fadeIn('slow');
}
else if(shouldShow === false){
$(element).fadeOut('slow');
}
});
//this statement's never called when testing!!
scope.$watch('reEvalCreateDate', function(newValue, oldValue)
{
var date = new Date(newValue);
scope.dateString = date.toUTCString();
});
}
这是测试的所有初始化代码。
var elm, scope;
var reEvalCreateDateAsNumber = 1359487598000;
beforeEach(inject(function($rootScope, $compile)
{
// we might move this tpl into an html file as well...
elm = angular.element(
'<reeval-timer show="showTimePopup" re-eval-create-date="reEvalCreateDate" class="re-eval-timer" ng-cloak >' +
'{{dateString}}' +
'</reeval-timer>');
scope = $rootScope.$new();
$compile(elm)(scope);
scope.$digest();
}));
根据评论,我认为我没有在指令上设定范围;我没有在API上看到任何允许我这样做的东西。我尝试了$compile
调用的几种排列,试图在其上设置范围:
从html创建一个元素,将其传递给compile。没有运气。
elm = angular.element(
'<div>' +
'<tabs>' +
'<pane title="First Tab">' +
'first content is {{first}}' +
'</pane>' +
'<pane title="Second Tab">' +
'second content is {{second}}' +
'</pane>' +
'</tabs>' +
'</div>');
scope = $rootScope;
$compile(elm)(scope);
并首先创建一个元素
var element = $compile('<p>{{total}}</p>')(scope);
如果问题是我只是没有在指令上设置范围,我认为错误可能在我的beforeEach
中。这是:
describe('Reeval Timer', function()
{
var elm, scope,element;
var reEvalCreateDateAsNumber = 1359487598000;
beforeEach(inject(function($rootScope, $compile)
{
// we might move this tpl into an html file as well...
elm = angular.element(
'<reeval-timer show="showTimePopup" re-eval-create-date="reEvalCreateDate" class="re-eval-timer" ng-cloak >' +
'</reeval-timer>');
scope = $rootScope.$new();
element = $compile(elm.contents())(scope);
scope.$digest();
}));
....
答案 0 :(得分:3)
我在测试带有隔离范围的指令时遇到了类似的问题。
没有被调用的原因是$digest
&#34;处理当前范围内的所有观察者及其子女&#34; (http://docs.angularjs.org/api/ng。$ rootScope.Scope)。现在,您会认为指令的双向绑定变量(用&#34; =&#34;定义)会观察测试的范围,但我发现我的{{1}没有被人召唤。这是角度的错误吗?
我的解决方案是将$watch
之后的所有测试代码包装到scope.$digest()
中,例如:
$timeout
修改:另请参阅Unit testing an AngularJS directive that watches an an attribute with isolate scope
答案 1 :(得分:1)
我遇到了同样的问题。在我的情况下,我的指令设置了templateUrl
而不是硬编码template
,因此在我的单元测试中,我还必须通过调用来设置模拟的http请求:
$httpBackend.expectGET('/template.html').respond('<div></div>');
其他一切看起来与你的例子相同,我的手表没有被召唤。
然后我记得在使用$httpBackend
模拟请求时,你必须像这样调用$httpBackend.flush()
:
$compile(elem)(scope);
$httpBackend.flush();
一旦冲洗电话响起,我的手表就会被召唤。
希望这会有所帮助......
杰森