9

问题

我正在测试一个指令。该指令在范围变量上有一个监视,但从不调用监视。将$watch调用直接放在单元测试中是可行的。为什么$watch不调用指令中的?

谢谢!

细节

这是我的原始测试。该指令中有一个手表,看着'reEvalCreateDate'. 它从未被调用,并且日期字符串始终为空。

测试中没有 watch 语句

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 创建一个元素,将其传递给编译。没运气。

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);

如果问题是我只是没有在指令上设置范围,那么我认为错误可能在 mybeforeEach中。这里是:

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();
    }));

....
4

2 回答 2

3

我在测试具有隔离范围的指令时遇到了类似的问题。

没有调用它的原因是$digest“处理当前范围及其子范围的所有观察者”(http://docs.angularjs.org/api/ng .$rootScope.Scope)。现在,您会认为指令的双向绑定变量(用“=”定义)会监视测试的范围,但我发现 my$watch没有被调用。这是角度的错误吗?

我的解决方案是将所有测试代码包装scope.$digest()到 a$timeout中,例如:

inject(function($timeout) {
  // change test scope variable
  scope.$digest();
  $timeout(function() {
    // assertions
    expect(...)
  }, 0);
}

编辑:另请参阅单元测试 AngularJS 指令,该指令监视具有隔离范围的属性

于 2013-08-29T17:07:02.840 回答
1

我遇到了同样的问题。就我而言,我的指令有一个templateUrlset 而不是硬编码template,所以在我的单元测试中,我还必须通过调用来设置一个模拟的 http 请求:

$httpBackend.expectGET('/template.html').respond('<div></div>');

其他一切看起来都和你的例子一样,我的手表没有被调用。

然后我记得在使用$httpBackend模拟请求时,你必须这样调用$httpBackend.flush()

$compile(elem)(scope);
$httpBackend.flush();

一旦同花跟注被击中,我的手表就被叫了。

希望这可以帮助....

杰森

于 2013-02-13T17:43:27.213 回答