2016-05-03 8 views
0

Ich habe Code, der Informationen über Filteränderungen speichern sollte. Im Browser $watch wird der Rückruf jedes Mal ausgelöst, wenn ich den Wert ändere. Wenn ich jedoch versuche, das im Jasmin/Karma-Test zu replizieren, wird es gleich nach der ersten Änderung ausgelöst.

-Controller

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

-Test

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' ]); 
    }); 
}); 

Ausgabe in der Konsole:

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 

Aber in Browser:

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

Gibt mir:

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

Das Verhalten erwartet wird.

Was ist dann falsch an meinem Test? Danke im Voraus!

EDIT

Voll Controller-Code:

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); 
     } 
     } 
    }; 
    } ]); 

und Test:

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

Ich bin für die Code-Qualität leid, aber es ist noch nicht die Produktion.

+0

den zweiten Test mit setTimeout (function() {{expect (tbFilterConfigObj.get ('dirty')) .toEqual (['period']); done();}, 500); und vergessen Sie nicht, die Parameter im Test zu übergeben. – srinivasan

+0

@srinivasan wie es mein Problem lösen soll? –

Antwort

0

Wenn AngularJS in Ihrem Browser ausgeführt wird, werden digest Zyklen ausgeführt, um alle Beobachter und ihre Rückrufe auszulösen. Dies macht Angular arbeiten, und es geschieht automatisch.

Dieser Mechanismus funktioniert nicht bei Komponententests. Wenn Sie Tests ausführen, müssen Sie den Digest-Mechanismus manuell auslösen, indem Sie $apply oder $digest aufrufen.

Lasst uns brechen, was in Ihrem Test spec passiert (was gut in der Konsolenprotokolle angezeigt):

  1. $scope.$apply(console.log(1), controller.config.period = 'test'); -> schreibt 1 zu trösten; Ändert den Wert config.period.

  2. $scope.$apply(console.log(2), controller.config.period = 'test2'); -> löst den Beobachter Rückruf für tableFilter.config.periodzum ersten Mal aufgrund der $apply; schreibt 2 zur Konsole; ändert sich der Wert von config.period.

Nichts ist Beobachter Rückruf zum zweiten Mal nach der Auslösung.

Die Lösung ist einfach: Fügen Sie vor jeder Ihrer expect Anweisungen einen Anruf zu $scope.$digest() (oder $scope.$apply()) hinzu.

+0

Führt '$ scope. $ Apply (...);' den Digest nach dem, was in Parametern ist, aus? Ich denke, das tut es. Jedenfalls habe ich versucht, '$ apply' an' beforeEach' anzuhängen sowie nach jeder Änderung auszuführen und die Ergebnisse der Test- oder Konsolenausgabe nicht zu verändern. –

+0

können Sie '$ scope. $ Digest()' vor jeder 'expect' Anweisung versuchen? Wenn das nicht funktioniert, bitte posten Sie Ihren gesamten Controller und Testspezifikationscode – yarons

+0

Ich habe versucht und es ändert nichts, weil es bereits "$ Digest" über "$ apply" auf genau die gleiche Weise auslöst, will ich nicht um das zu posten, ändert es nichts an der Frageperspektive. –

Verwandte Themen