javascript - 使用 Jasmine 测试隔离范围时出现意外的变量类型

标签 javascript angularjs jasmine

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

我理解为什么这可能具有直观意义 - parm 最初作为字符串进行插值,也许 Angular 有某种机制来确保它保持字符串状态。如果属实,我不知道它在 Angular 源代码中的实现方式和位置(甚至不知道它可能是如何实现的)。

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

这是我的代码:

标记

<pane id={{myId}}></pane>

指令

.directive('testPane', function () {

    function thisController($scope) {

       //$scope.id is string '1'
       $scope.id = parseInt($scope.id);

       //now it is number 1 (as expected)
       console.log($scope.id);


    };


    return {
        restrict: 'E',
        transclude: true,
        scope: { id: '@'},
        controller: thisController,
        link: function (scope, element, attrs, tabsController) {


        },
        templateUrl: 'test/test.html',
        replace: true
    };
})

Jasmine 规范

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


});

最佳答案

问题

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

case '@':
  attrs.$observe(attrName, function(value) {
    isolateBindingContext[scopeName] = value;
  });  
  ...

现在让我们看看 the docs $observe 上对此进行了说明(强调我的):

Observes an interpolated attribute.

The observer function will be invoked once during the next $digest following compilation. The observer is then invoked whenever the interpolated value changes.

因此,在编译指令后,即在执行 Controller 和链接函数之后,保证观察者被调用一次。由于您在 Controller 函数中为 id 属性分配了一个新值,因此它会被覆盖回其原始值 - 这是一个字符串,因为它是一个 DOM 属性。

解决方案

鉴于您发布的代码,您似乎只关心 id 第一个值。要获取它,您只需执行以下操作:

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

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

关于javascript - 使用 Jasmine 测试隔离范围时出现意外的变量类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30464764/

相关文章:

javascript - 将 angular js 服务/工厂注入(inject) Jasmine

javascript - Angular 单元测试http请求问题

javascript - AngularJS 将过滤后的值传递给范围值

javascript - 如何在angularjs中只获取选中的复选框?

javascript - 如何修复 javascript 没有分配正确的值?

javascript - 我的标签不算数

angularjs - 使用 $httpBackend 单元测试 AngularJS 给出 "Error: Unexpected Request"

angular - 如何以 HTMLInputElement 作为参数对 Angular 方法进行单元测试?

javascript - 如何更改 localStorage 项目中的单个值?

javascript - 扩展框 - 整理