2016-05-03 3 views
0

フィルタの変更に関する情報を格納するコードがあります。 ブラウザで$watch値を変更するたびにコールバックが発生します。 しかし、ジャスミン/カルマテストでそれを複製しようとすると、最初に変更した直後に起動します。コンソールで

コントローラ

var tableFilter = this 
    ; 

var init0 = true 
    ; 
$scope.$watch('tableFilter.config.period', function() { 
    console.log('watch'); 
    if (!init0) { 
    console.log('set dirty'); 
    tbFilterConfig.set('pristine', false); 
    tbFilterConfig.setDirty('period'); 
    } 
    init0 = false; 
}); 

テスト

describe('$scope $watch', function() { 
    it('should add period to dirty after second change', function() { 
    $scope.$apply(console.log(1), controller.config.period = 'test'); 
    expect(tbFilterConfigObj.get('dirty')).toEqual([]); 
    $scope.$apply(console.log(2), controller.config.period = 'test2'); 
    expect(tbFilterConfigObj.get('dirty')).toEqual([ 'period' ]); 
    }); 
}); 

出力:

LOG: 1 
LOG: 'watch' 
LOG: 2 
PhantomJS 1.9.8 (Windows 8 0.0.0) Controller: TableFilterCtrl $scope $watch should add period to dirty after second change FAILED 
Expected [ ] to equal [ 'period' ]. 
     at C:/Projects/trackback-network-insight-ui/test/spec/controllers/table_filter.js:74 

しかし、ブラウザで:

setTimeout(function () { 
    $scope.$apply(console.log(1), tableFilter.config.period = 'test'); 
    $scope.$apply(console.log(2), tableFilter.config.period = 'test2'); 
}, 1000); 

通知:

LOG: watch 
LOG: 1 
LOG: watch 
LOG: set dirty 
LOG: 2 
LOG: watch 
LOG: set dirty 

これは予想される動作です。

私のテストで何が間違っていますか?前もって感謝します!

EDIT

フルコントローラコード:

angular.module('insightApp') 
.controller('TableFilterCtrl', [ '$rootScope', 'tbConfig', '$scope', '$http', 'API_PATH', 'uiAlerts', 'tbFilterConfig', 
    function ($rootScope, tbConfig, $scope, $http, API_PATH, uiAlerts, tbFilterConfig) { 

    var tableFilter = this 
     , newData = {} 
     ; 

    /* EXTRACT INITIAL DATA OR LOAD DATA IF TYPE OF DATA IS STRING */ 
    /* FETCH !!SELECT!! DATA FROM API */ 
    function fetchData(url, name) { 
     return $http.post(API_PATH + url, tbFilterConfig.get()) 
     .success(function (data) { 
      newData[ name ] = data; 
     }) 
     .error(function (error) { 
      uiAlerts.set({ 
      error: 'Ooops! We were unable to get filter data.' 
      }); 
      console.error(error); 
     }); 
    } 

    tableFilter.filters = tbConfig.get('filters'); 
    tableFilter.reports = tbConfig.get('reports'); 
    tableFilter.config = tbFilterConfig.getRaw(); 

    /* RESET VALUES OF ALL DEPENDENT FILTERS */ 
    function resetDependent(name) { 
     var filters = tbConfig.get('filters') 
     ; 
     filters.forEach(function (filter) { 
     if (filter.dependencies && filter.dependencies.indexOf(name) > -1) { 
      if (tbFilterConfig.get(filter.key) !== filter.defaultVal) { 
      tbFilterConfig.set(filter.key, filter.defaultVal); 
      tbFilterConfig.setDirty(filter.key); 
      } 
     } 
     }); 
    } 

    /* GET INITIAL DATA FOR SELECT OPTIONS */ 
    tableFilter.getData = function (name, data, defaultVal) { 
     if (!(name in newData)) { 
     newData[ name ] = []; 
     if (typeof data === 'string') { 
      fetchData(data, name); 
     } else if (typeof data === 'object') { 
      newData[ name ] = data; 
     } else { 
      console.error('Unexpected data type:', typeof data, data); 
     } 
     if (!tbFilterConfig.get(name)) { 
      tbFilterConfig.set(name, defaultVal); 
     } 
     var init = true; 
     $scope.$watch('tableFilter.config.' + name, function() { 
      if (!init) { 
      resetDependent(name); 
      tbFilterConfig.set('pristine', false); 
      tbFilterConfig.setDirty(name); 
      } 
      init = false; 
     }); 
     } 
     return newData[ name ]; 
    }; 

    /* WATCH FIXED PROPERTIES: PERIOD, DATE_FROM, DATE_TO */ 
    var init0 = true 
     , init1 = true 
     , init2 = true 
     ; 

    $scope.$watch('tableFilter.config.period', function() { 
     if (!init0) { 
     tbFilterConfig.set('pristine', false); 
     tbFilterConfig.setDirty('period'); 
     } 
     init0 = false; 
    }); 

    /* WATCH FIXED PROPERTIES DATE_FORM */ 
    $scope.$watch('tableFilter.config.date_from', function() { 
     if (!init1) { 
     tbFilterConfig.set('pristine', false); 
     tbFilterConfig.setDirty('date_from'); 
     } 
     init1 = false; 
    }); 
    /* WATCH FIXED PROPERTIES DATE_TO */ 
    $scope.$watch('tableFilter.config.date_to', function() { 
     if (!init2) { 
     tbFilterConfig.set('pristine', false); 
     tbFilterConfig.setDirty('date_to'); 
     } 
     init2 = false; 
    }); 

    /* UPDATE FILTER DATA */ 
    tableFilter.updateSelectData = function (url, name, dependencies) { 
     if (typeof url === 'string') { 
     var touched = false; 
     /* CHECK IF DEPENDENCIES CHANGED */ 
     for (var i = 0; i < dependencies.length; i++) { 
      if (tableFilter.config.dirty.indexOf(dependencies[ i ]) > -1) { 
      touched = true; 
      break; 
      } 
     } 
     /* IF DEPENDENCIES CHANGED GET NEW DATA */ 
     if (touched) { 
      return fetchData(url, name); 
     } 
     } 
    }; 
    } ]); 

及び試験:

describe('Controller: TableFilterCtrl', function() { 

// load the controller's module 

beforeEach(function() { 
    module('insightApp'); 
}); 

var controller 
    , $scope 
    , alerts 
    , tbFilterConfigObj 
    ; 

// Initialize the controller and a mock scope 
beforeEach(inject(function ($controller, $rootScope, uiAlerts, tbFilterConfig) { 
    tbFilterConfigObj = tbFilterConfig; 
    $scope = $rootScope.$new(); 
    alerts = uiAlerts; 
    controller = $controller('TableFilterCtrl', { 
    $scope: $scope 
    }); 
    $scope.$apply(); 
})); 


describe('$scope $watch', function() { 
    it('should add period to dirty after second change', function() { 
    $scope.$apply(console.log(1), controller.config.period = 'test'); 
    expect(tbFilterConfigObj.get('dirty')).toEqual([]); 
    $scope.$apply(console.log(2), controller.config.period = 'test2'); 
    expect(tbFilterConfigObj.get('dirty')).toEqual([ 'period' ]); 
    }); 
}); 

})。

EDIT2

私は、コードの品質のために申し訳ないが、それはまだ生産ではありません。

+0

setTimeout(function(){expect(tbFilterConfigObj.get( 'dirty')))を使用して2番目のテストをラップする.toEqual(['period']); done();};テストでdoneパラメータを渡すことを忘れないでください。 – srinivasan

+0

@srinivasanどのように私の問題を解決すると思いますか? –

答えて

0

ブラウザでAngularJSを実行すると、digestサイクルが実行され、すべてのウォッチャとそのコールバックがトリガされます。これがAngularの仕事です。それは自動的に起こります。

このメカニズムは単体テストでは機能しません。テストを実行するときは、$applyまたは$digestを呼び出してダイジェストメカニズムを手動で起動する必要があります。

は(あなたのコンソールログにうまく表示されている)テスト仕様で何が起こるかを打破するのをしてみましょう:

  1. $scope.$apply(console.log(1), controller.config.period = 'test'); - >は、コンソールに1を書き込みます。 config.periodの値が変更されます。

  2. $scope.$apply(console.log(2), controller.config.period = 'test2'); - >が原因$applyに初めてためtableFilter.config.periodためウォッチャーコールバックをトリガーします。コンソールに2を書き込みます。 config.period.

ウォッチャーのコールバックがそれ以降2回発生することはありません。

解決策は簡単です:expectステートメントの前に$scope.$digest()(または$scope.$apply())に電話をかけてください。

+0

'$ scope。$ apply(...);'パラメータが評価された後にダイジェストをトリガしませんか?私はそれがそうだと思う。とにかく、 'beforeEach'に' $ apply'を追加しようとしましたが、変更するたびにそれを実行し、テストやコンソール出力の結果は変更していません。 –

+0

すべての 'expect'文の前に' $ scope。$ digest() 'を試すことができますか?それがうまくいかない場合は、コントローラ全体を投稿して、スペックコード – yarons

+0

を試してみてください。何か変更はありません。同じ方法で '$ apply'を介して' $ digest'を起動しています。質問の観点から何も変わらないので、変更を投稿することができます。 –

関連する問題