如何使用$ setViewValue()在ng-repeat中测试动态命名的输入

时间:2013-11-25 15:25:02

标签: angularjs angularjs-directive jasmine angularjs-ng-repeat karma-runner

我正在尝试测试一个使用ng-repeat动态地将表单输入添加到页面的指令。代码在浏览器中运行良好,但尝试用Jasmine测试它我发现(对我来说)是一个bug或至少在Angular中的奇怪行为。

我希望能够使用

在输入上设置视图值
form.questions.answer1.$setViewValue();

但在我的测试中,当我控制台记录form.questions对象时,我得到了这个:

form.questions.answer{{ question.questionId }} 

即。尚未解析对象的索引(尽管正确输出了html)。

是否还有其他触发ng-change事件的方法?我已经尝试使用jQuery(在我的测试中)设置输入的值,但是虽然它成功地更改了值,但它不会触发ng-change事件。

plunker (检查控制台的内容,看看我的意思。)。

我的代码:

<!-- language: lang-js -->
app.directive('repeatedInputs', function(){
  var template ='<div  ng-form name="questions">'+
  '<div ng-repeat="(key, question) in questions" >' +                                                   
    '<span id="question{{ question.questionId }}">{{ question.questionText }}</span>'+
    '<span><input type="text" name="answer{{ question.questionId }}"' +
     ' id="answer{{question.questionId}}"' +                                                                  
    '  ng-model="question.answer" ng-change="change()"/></span>' +
  '</div>' +
  '</div>';

  return {                                                                                                                             
      template: template,
      scope: {
        answers: '=',
        singleAnswer: '='
      },

      /**                                                                                                                                
       * Links the directive to the view.                                                                                                
       *                                                                                                                                 
       * @param {object} scope                                                                                                           
       * Reference to the directive scope.                                                                                               
       *                                                                                                                                 
       * @param {object} elm                                                                                                             
       * Reference to the directive element.                                                                                             
       */                                                                                                                                
      link: function (scope, element) {                                                                                                  

        scope.questions = [
          {
            questionId: '1',
            questionText: 'What is your name?',
            answer: null
          },
          { 
            questionId: '2',
            questionText: 'What is your quest?',
            answer: null
          },
          { 
            questionId: '3',
            questionText: 'What is your favourite colour?',
            answer: null
          }
        ];

        scope.change = function () {
          for (var i in scope.questions) {
            scope.answers[i] = scope.questions[i].answer;
          }
        };
      }
   };
});

这是我的spec文件:

<!-- language: lang-js -->
describe('repeating inputs directive', function () {                           

  var element, scope, $compile;                                                                     

  beforeEach(function(){
    module('plunker');
    inject(function ($rootScope, _$compile_) {                   

      scope = $rootScope.$new();                                                  
      scope.theAnswers = [];
      scope.singleAnswer = null;

      element = angular.element(                                                  
        '<form name="form">'
        +'<div repeated-inputs answers="theAnswers" single-answer="singleAnswer">'
        +'</div></form>'                 
      );                                                                          
      $compile = _$compile_;
      $compile(element)(scope);
      scope.$apply();
    })
  });

  it('should store the input from the answers in the parent scope',             
      function () {                                                             

    // I want to do this
    //scope.form.questions.answer1.$setViewValue('Ben');

    // but inside the object, the answers name field is not being parsed
    // I am expecting the path to the answer to look like this:
    // scope.form.questions.answer1
    // instead it looks like this:
    // scope.form.questions.answer{{ question.questionId }}
    console.log(scope.form.questions);

    expect(scope.theAnswers[0]).toEqual('Ben');

  }); 
});  

2 个答案:

答案 0 :(得分:0)

所以我发现在Angular中我目前无法做到的事情。测试这个的唯一方法是使用网络浏览器 - 我现在有一个量角器测试这个功能。

目前不支持插值名称(对于ngModel)。

答案 1 :(得分:0)

你必须这样做:

elementScope = $compile(element)(scope).isolateScope();
...
expect(elementScope.theAnswers[0]).toEqual('Ben');

由于以下原因将为指令创建隔离范围:

 scope: {
        answers: '=',
        singleAnswer: '='
      }