Javascript 使用Jasmine测试隔离作用域时出现意外变量类型

Javascript 使用Jasmine测试隔离作用域时出现意外变量类型,javascript,angularjs,jasmine,Javascript,Angularjs,Jasmine,我正在用隔离范围(angular)和Jasmine测试框架测试一个指令。一切正常,但有一个奇怪之处:如果我将$scope上的变量类型从string更改为number,Jasmine将继续将其视为字符串,即使指令代码本身正确地将其视为数字 我理解为什么这可能有直观的意义-parm最初是作为字符串插入的,可能Angular有一些机制来确保它保持为字符串。如果为真,我不知道它是如何在角度源中实现的,在哪里实现的(甚至不知道它是如何实现的) 总之:为什么Jasmine看到字符串而指令看到数字? 这是我的

我正在用隔离范围(angular)和Jasmine测试框架测试一个指令。一切正常,但有一个奇怪之处:如果我将$scope上的变量类型从string更改为number,Jasmine将继续将其视为字符串,即使指令代码本身正确地将其视为数字

我理解为什么这可能有直观的意义-parm最初是作为字符串插入的,可能Angular有一些机制来确保它保持为字符串。如果为真,我不知道它是如何在角度源中实现的,在哪里实现的(甚至不知道它是如何实现的)

总之:为什么Jasmine看到字符串而指令看到数字?

这是我的密码:

标记

<pane id={{myId}}></pane>
茉莉花规格

it("changes id from string to number", function () {

    var element,
        elementScope;

    $rootScope.myId = 1;

    element = $compile(html)($rootScope);

    $timeout(function () {
        businessTabScope = element.isolateScope();
        $rootScope.$digest();


        expect(elementScope.id).toBeDefined();

        //id is text '1' instead of number 1. Why?
        expect(elementScope.id).toEqual($rootScope.myId);
    }, 0, false);



   $timeout.flush();


});

问题

定义
@
绑定时,Angular将为该属性创建一个观察者,以便在该属性稍后更改时可以更新本地属性的值。您可以在第7676行()找到特定代码:

现在,让我们看看
$observe
上的内容(我的重点):

观察插值属性

观察者函数将在下一个$digest期间调用一次 以下是编译。然后,只要 插值会发生变化

因此,保证在编译指令后,即控制器和链接函数都执行后,只调用一次观察者。由于您正在为控制器函数中的
id
属性指定一个新值,它将被重写回其原始值-这是一个字符串,因为它是一个DOM属性

解决方案

考虑到您发布的代码,您似乎只关心
id
第一个值。要抓住它,您只需执行以下操作:

.directive('testPane', function () {
  return {
    ...
    scope: {},
    controller: function($scope, $attrs) {
      $scope.id = parseInt($attrs.id, '10');
    }
  };
});

如果需要,您可以继续使用
@
绑定,但请确保转换后的值存储在作用域的另一个属性中,这样它就不会被重写-无论是在编译指令之后还是以后。

这不是角度问题。当您从dom中读取数据时,它以字符串形式出现,而Angular不能假设类型为javascript是dinamic languageNot。我正在读取(隔离)范围上的属性。在指令中,类型是一个数字。这是茉莉花的一根线。两者都在看同一个对象范围。我不知道DOM是如何发挥作用的。也许在测试中检查值时,您的控制器代码(将数字解析为int)尚未执行?我想这就是为什么您在这里使用
$timeout
。。。您是否尝试添加日志语句以查看正在执行的代码?您是否尝试过增加超时值?顺便说一下,在测试指令时,我从未使用过
$timeout
。。。我只是在指令的父作用域上调用
$digest()
。存在$timeout是因为指令使用templateUrl。如果未添加,调用retreive isolateScope将失败b/c$http未及时解决。@Sunil我已验证控制器代码是否先执行。这可以通过引入仅在控制器中定义的另一个$scope变量来实现。Jasmine代码正确地读取了它。
case '@':
  attrs.$observe(attrName, function(value) {
    isolateBindingContext[scopeName] = value;
  });  
  ...
.directive('testPane', function () {
  return {
    ...
    scope: {},
    controller: function($scope, $attrs) {
      $scope.id = parseInt($attrs.id, '10');
    }
  };
});