2016-10-05 103 views
0

我的单元测试保持与以下错误消息失败的对象:未定义不是(评估“value.phrase.replace”)

LOG: 'f40e0e47-6457-463b-a5f9-9dc97bd2d0ce' 
LOG: [Object{phrase_id: 'f40e0e47-6457-463b-a5f9-9dc97bd2d0ce', phrase: 'Training {{group}} to develop their {{attribute}} by ensuring they are comfortable with {{factor}}'}] 
PhantomJS 2.1.1 (Windows 8 0.0.0) PhraseDetailCtrl #initialisation should initialise the controller's scope with details on a single phrase FAILED 
     TypeError: undefined is not an object (evaluating 'value.phrase.replace') in D:/myapp-mobile/www/js/myapp.controllers.js (line 87) 
     D:/myapp-mobile/www/js/myapp.controllers.js:87:34 
     [email protected][native code] 
     D:/myapp-mobile/www/js/myapp.controllers.js:85:35 
     [email protected]/phrase-detail.controller.tests.js:32:26 
     [email protected]:/myapp-mobile/www/js/myapp.controllers.js:78:55 
     [email protected][native code] 
     [email protected]:/myapp-mobile/www/lib/ionic/js/ionic.bundle.js:18010:61 
     [email protected]:/myapp-mobile/www/lib/ionic/js/ionic.bundle.js:23412:39 
     D:/myapp-mobile/www/lib/angular-mocks/angular-mocks.js:2221:21 
     unit-tests/phrase-detail.controller.tests.js:44:31 
     [email protected]://localhost:9876/context.js:151:17 
PhantomJS 2.1.1 (Windows 8 0.0.0): Executed 3 of 3 (1 FAILED) (0.01 secs/0.084 secs) 

这是我试图测试控制器:

function PhraseDetailCtrl($scope, $stateParams, PhraseService, CompetencyService, PopupService, ModalService, FilterService, $ionicLoading, $ionicActionSheet, $timeout) { 

    // $ionicLoading.show({ 
    // content: 'Loading', 
    // animation: 'fade-in', 
    // showBackdrop: true, 
    // maxWidth: 200, 
    // showDelay: 0 
    // }); 


    // $timeout(function() { 

     // $ionicLoading.hide(); 
     $scope.dataLoaded = true; 
     $scope.phraseId = $stateParams.phraseId; 

     console.log($scope.phraseId); 

     PhraseService.getPhraseDetail($scope.phraseId).then(function(dataResponse) { 
      $scope.phraseDetail = dataResponse.data; 

      console.log($scope.phraseDetail); 

      var replacers = FilterService.getItemFilter(); 

      Object.keys(replacers).forEach(function(key){ 
       var value = $scope.phraseDetail; 
       value.phrase = value.phrase.replace(new RegExp(key, 'g'), replacers[key]); 
      }) 
     }) 


     PhraseService.getPhraseCompetency($scope.phraseId).then(function(dataResponse) { 
      $scope.phraseCompetencyList = dataResponse.data; 
     }) 


     PhraseService.getPhraseExample($scope.phraseId).then(function(dataResponse) { 

      var data = dataResponse.data; 

     var phrase = data[0].phrase; 
     // console.log("phrase: " + phrase); 

     var tokens = data.map(function(tmp) { 
      return tmp.example; 
     }); 
     // console.log("tokens: " + tokens); 

     var re = /{{[^}]*}}/gi; 
     var placeholders = phrase.match(re); 
     // console.log("placeholders: " + placeholders); 

      if (tokens.length != placeholders.length) { 
       throw new Error("Mismatch number of tokens and placeholders"); 
      } 

      for (var i = 0; i < tokens.length; ++i) { 
       var token = tokens[i]; 
       var placeholder = placeholders[i]; 
       phrase = phrase.replace(placeholder, "<button class=\"button button-small button-outline button-dark button-side-padding\">" + token + "</button>"); 
      } 
     // console.log(phrase); 

     $scope.phraseExample = phrase; 

     }) 


     CompetencyService.getCompetencyList().then(function(dataResponse) { 
      $scope.competencyList = dataResponse.data; 
     }) 


    // }, 1000); 


    // Action sheet 

    $scope.showOptions = function() { 

     $ionicActionSheet.show({ 
      titleText: 'Options', 
      buttons: [ 
       { text: '<i class="icon ion-heart"></i>Add to Favourites' }, 
       { text: '<i class="icon ion-chatbubble"></i> Suggest Improvement' } 
      ], 
      cancelText: 'Cancel', 
      buttonClicked: function(index) { 
       if(index === 0) { 
        $scope.addtoFavouritesPopup(); 
       } else if(index === 1) { 
        $scope.suggestimprovementModal(); 
       } 
       //console.log('BUTTON CLICKED', index); 
       return true; 
      }, 
      cancel: function() { 
       //console.log('CANCELLED'); 
      }, 
     }); 

    }; 


    // Popups 

    $scope.phraseExamplePopup = function() { 
     var myPopup = PopupService.phraseExamplePopup($scope); 
    }; 

    $scope.addtoFavouritesPopup = function() { 
     var myPopup = PopupService.addtoFavouritesPopup($scope); 
    }; 


    // Modals 

    $scope.phraseCompetencyModal = function() { 
     var vm = $scope; 
     ModalService.show('templates/modals/phrase-competency-modal.html', 'PhraseDetailCtrl as vm'); 
    } 

    $scope.suggestimprovementModal = function() { 
     var vm = $scope; 
     ModalService.show('templates/modals/suggest-improvement-modal.html', 'PhraseDetailCtrl as vm'); 
    } 

} 

我认为错误消息在这一点上发生的事情,但我不知道如何在我的单元测试嘲笑它:

Object.keys(replacers).forEach(function(key){ 
       var value = $scope.phraseDetail; 
       value.phrase = value.phrase.replace(new RegExp(key, 'g'), replacers[key]); 
      }) 

这是我的单元测试:

describe('PhraseDetailCtrl', function() { 

    var $controller, $stateParams, $ionicModal, $ionicPopup, $PhraseService, $CompetencyService, $PopupService, $ModalService, $FilterService 

    $stateParams = { 
    phraseId: "f40e0e47-6457-463b-a5f9-9dc97bd2d0ce" 
    }; 

    var response = { 
    status: 200, 
    data: [{ 
     "phrase_id": "f40e0e47-6457-463b-a5f9-9dc97bd2d0ce", 
     "phrase": "Training {{group}} to develop their {{attribute}} by ensuring they are comfortable with {{factor}}" 
    }] 
    }; 

    beforeEach(module('ionic')); 
    beforeEach(module('dingocv.services')); 
    beforeEach(module('dingocv.controllers')); 

    beforeEach(inject(function (_$controller_, _PhraseService_, _CompetencyService_, _ModalService_, _PopupService_, _FilterService_) { 
    $controller = _$controller_; 
    $PhraseService = _PhraseService_; 
    $CompetencyService = _CompetencyService_; 
    $ModalService = _ModalService_; 
    $PopupService = _PopupService_; 
    $FilterService = _FilterService_; 

    spyOn(_PhraseService_, 'getPhraseDetail').and.callFake(function(){ 
     return{ 
     then: function(successCallback){ 
      successCallback(response); 
     } 
     } 
    }); 
    })); 

    describe('#initialisation', function() { 

    var $scope, controller; 

    beforeEach(function() { 
     $scope = {}; 
     controller = $controller('PhraseDetailCtrl', { 
     $scope: $scope, 
     $stateParams: $stateParams, 
     $ionicModal: $ionicModal, 
     $ionicPopup: $ionicPopup, 
     PhraseService: $PhraseService, 
     CompetencyService: $CompetencyService, 
     PopupService: $PopupService, 
     ModalService: $ModalService, 
     FilterService: $FilterService 
     }); 
    }); 

    it('should initialise the controller\'s scope with details on a single phrase', function(){ 
     expect($PhraseService.getPhraseDetail).toHaveBeenCalled(); 
     expect($scope.phraseDetail).toBeDefined(); 
    }); 

    }); 

}); 

回答

1

在尝试使用对象之前,您应该检查null/undefined。

if(replacers!=undefined){ 
 
    Object.keys(replacers).forEach(function(key){ 
 
       var value = $scope.phraseDetail; 
 
       if(value !=undefined && value.phrase !=undefined){ 
 
       value.phrase = value.phrase.replace(new RegExp(key, 'g'), replacers[key]); 
 
       } 
 
      }) 
 
}

+0

感谢您的回复。然而,我仍然得到相同的错误信息:'不能读取属性'取代'未定义,它指向这一行:'value.phrase = value.phrase.replace(new RegExp(key,'g'), ' – methuselah

+0

我已经更新了答案,以检查值为null的值以及它的属性'phrase'。我相信它现在应该可以工作。 – Owuor

0

在测试你有data属性作为array of objects响应对象。

为了访问phrase你必须这样做response.data[0].phrase。您在此处访问data属性的第0个object

var response = { 
    status: 200, 
    data: [{ 
     "phrase_id": "f40e0e47-6457-463b-a5f9-9dc97bd2d0ce", 
     "phrase": "Training {{group}} to develop their {{attribute}} by ensuring they are comfortable with {{factor}}" 
    }] 
    }; 

controller代码你有这样的

PhraseService.getPhraseDetail($scope.phraseId).then(function(dataResponse) { 
      // here "dataResponse.data" is returning an array 
      $scope.phraseDetail = dataResponse.data; 

      console.log($scope.phraseDetail); 

      var replacers = FilterService.getItemFilter(); 
      var i = 0; 
      Object.keys(replacers).forEach(function(key){ 
       // Since $scope.phraseDetail is an array of objects, you have to select particular object in the array. 
       var value = $scope.phraseDetail[i]; 
       value.phrase = value.phrase.replace(new RegExp(key, 'g'), replacers[key]); 
       i++; 
      }) 
     }) 

希望这有助于。

相关问题