范围。$ watch在单元测试时未在指令中调用

时间:2013-01-30 20:47:06

标签: unit-testing angularjs angularjs-directive

问题

我正在测试一个指令。该指令监视范围变量,但从不调用手表。将$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();
    }));

....

2 个答案:

答案 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();

一旦冲洗电话响起,我的手表就会被召唤。

希望这会有所帮助......

杰森