2

Warnung, dies ist für ein Arbeitsprojekt und als solches sind die Informationen begrenzt. Wenn mehr Informationen notwendig sind, fragen Sie, und wenn ich finde, dass es angemessen ist hinzuzufügen, werde ich es tun.Verwenden von Jasmine/Karma zum Komponententest Ein Service wird keine Kopie des Service injizieren

Ich habe etwa anderthalb Tage mit einem Problem verbracht, bei dem mein Komponententest keine Kopie des Dienstes lädt, den ich versuche zu testen. Die app.js (die die wichtigsten app „CC“ beherbergt hat den entsprechenden Bereich:

angular 
    .module("CC", [ 
    "ui.router", 
    "angularMoment", 
    "focus-if", 
    "ngCapsLock", 
    "CC.AuthInterceptor", 
    "CC.Filters", 
    "CC.Body", 
    "CC.Login", 
    "CC.Courtyard", 
    "CC.SocketService", 
    "CC.HeaderNavbar", 
    "CC.footerBar", 
    "CC.AcademicHall", 
    "CC.ResourceCenter", 
    "CC.UserSettings", 
    "CC.imageOnLoad", 
    "CC.recommendedResources", 
    "CC.Constants" 
    ]) 
    .config(ConfigureCookies) 
    .config(ConfigureResources) 
    .config(ConfigureInterceptors) 
    .config(ConfigureDefaultPage) 
    .config(ConfigureHTML5Mode) 
    .config(ConfigureRouter) 
    .run(AuthRedirect); 

Die entsprechenden Module (wie ich es sehe und dies könnte mein Problem sein) sind CC.Constants (ein Modul von Grunt geschrieben . enthalten Konstanten enthält relevante URLs) und CC.SocketService (der eigentliche Dienst getestet wird)

CC.Constants wie folgt aussieht:

(function() { 
    "use strict"; 
    angular.module('CC.Constants', []) 
     .constant('apiUrl', "<URL1>") 
     .constant('socialUrl', "<URL2>"); 
}()); 

Dies ist, was ich Ihnen von SocketService zeigen kann, fühle ich, dass es alles Relevante, wenn man bedenkt, dass ich an dieser Stelle nicht explizit versuche Testen Sie es, lassen Sie sich testen.

(function() { 
    "use strict"; 
    function SocketService($rootScope, $cookies, $log, $state, jwtHelper, moment, socialUrl) { 
    var socket = {}; 
    socket.socket = {}; //This holds the socket connection after a specific function is run 
    socket.data = {}; 
    socket.data.sortedMessages = []; 
    socket.data.userChannels = []; 
    socket.supportFunctions = {}; 
    socket.supportFunctions.sortPost = function(post) { 
     for (var x = socket.data.userChannels.length - 1; x >= 0; x--) { 
     if (post.courtyard_post_to === socket.data.userChannels[x].pk) { 
      socket.data.userChannels[x].post_to_channel.push(post); 
      return; 
     } 
     } 
    }; 
    /* A bunch of other functions live here all under the socket object in one way or another */ 
    return socket; 
    } 
    SocketService.$inject = ["$rootScope", "$cookies", "$log", "$state", "jwtHelper", "moment", "socialUrl"]; 
    angular 
    .module("CC.SocketService", [ 
     "ngCookies", 
     "ui.router", 
     "angularMoment", 
     "angular-jwt" 
    ]) 
    .factory("SocketService", SocketService); 
})(); 

Unten ist der Test wie es jetzt ist.

(function() { 
    "use strict"; 

    describe("ConnectedCampus.SocketService", function() { 
     var $cookies, 
      $state, 
      Socket; 
     var channel1 = {an imitation channel goes here}; 
     var channel2 = {an imitation channel goes here}; 
     var channel3 = {an imitation channel goes here}; 
     var postToChannel1 = {an imitation post goes here}; 

     beforeEach(function(){ 
      $cookies = jasmine.createSpyObj("$cookies", ["get", "put"]); 
      $cookies.get.and.returnValue("<valid Login Token Goes Here>"); 
      $state = jasmine.createSpyObj("$state", ["go"]); 
      module("CC"); 
      module("CC.SocketService"); 
      module(function ($provide) { 
       $provide.value("$cookies", $cookies); 
       $provide.value("$state", $state); 
       $provide.constant("socialUrl", "fakeAddress"); 
      }); 
      inject(function (SocketService) { 
       Socket = SocketService; 
      }) 
     }); 
     describe("Support Functions", function() { 
      it("socket.supportFunctions.sortPost should push a new post into the channel's posts array.", function (done) { 
       console.log("Socket"); 
       console.log(Socket);//this logs "undefined" 
       Socket.data.userChannels = [channel1, channel2, channel3]; 
       Socket.supportFunctions.sortPost(postToChannel1); 
       expect(Socket.data.userChannels[0].post_to_channel).toContain(postToChannel1); 
       done(); 
      }) 
     }); 
    }); 
}()); 

Hier ist der Stacktrace:

[email protected]<path to app>/app/socket/socket.js:320:25 //the file is only 208 lines long 
[email protected]<path to app>/app/libs/angular/angular.js:4535:22 
[email protected]<path to app>/app/libs/angular/angular.js:4387:43 
[email protected]<path to app>/app/libs/angular/angular.js:4535:22 
<path to app>/app/libs/angular/angular.js:4352:43 
[email protected]<path to app>/app/libs/angular/angular.js:4494:46 
[email protected]<path to app>/app/libs/angular/angular.js:4526:23 
[email protected]<path to app>/app/libs/angular-mocks/angular-mocks.js:2517:26 
[email protected]<path to app>/app/libs/angular-mocks/angular-mocks.js:2489:41 
<path to app>/app/socket/socket_test.js:321:19 
<path to app>/app/login/login_test.js:49:17 //I don't know why these are here, login tests are passing 
<path to app>/app/login/login_test.js:43:17 //I don't know why these are here, login tests are passing 
<path to app>/app/courtyard/courtyard_test.js:474:21 
TypeError: undefined is not an object (evaluating 'Socket.data') in <path to app>/app/socket/socket_test.js (line 337) //Line 337 is the line 'Socket.data.userChannels = [channel1, channel2, channel3];' 
/home/anton/git/connected_campus-ng/app/socket/socket_test.js:337:23 
<path to app>/app/login/login_test.js:49:17 //I don't know why these are here, login tests are passing 
<path to app>/app/login/login_test.js:43:17 //I don't know why these are here, login tests are passing 
<path to app>/app/courtyard/courtyard_test.js:474:21 //I don't know why these are here, courtyard tests are passing 

Und hier ist meine Dateien von Karma über Grunzen gesehen:

files: [ 
    "app/libs/angular/angular.js", 
    "app/libs/moment/moment.min.js", 
    "app/libs/**/*.js", 
    "app/app.js", 
    "app/constants.js", 
    "app/**/*.js"//SocketService lives in 'app/socket/socket.js' 
], 

Ein paar Dinge, die ich versucht habe:

  1. I habe die Unterstrichnotation
  2. versucht
  3. I haben die before innerhalb der inneren versucht sein beschreiben
  4. I haben versucht, die before in mehrere before Einrichtungen in der (angenommenen) korrekten Reihenfolge Trennen
  5. I inline Einspritzung für die einzelnen Test versucht haben
  6. habe ich versucht mit $ injector.get() und dann jede Anforderung
  7. Injektion I $ injector.get versucht haben ("SocketService")

Hier meine Versionsnummern für Abhängigkeiten sind (von bower und Paket gezogen).

BOWER:

"angular": "1.4.9", 
"angular-cookies": "1.4.9", 
"angular-resource": "1.4.9", 
"angular-animate": "1.4.9", 
"angular-ui-router": "0.2.18", 
"ng-file-upload-shim": "12.0.1", 
"ng-file-upload": "12.0.1", 
"bootstrap":"3.3.6", 
"angular-loader": "1.4.9", 
"angular-mocks": "1.4.9", 
"angular-bootstrap": "1.1.2", 
"fontawesome": "4.5.0", 
"moment": "2.12.0", 
"angular-moment": "1.0.0-beta.5", 
"socket.io-client": "1.4.6", 
"angular-jwt": "0.0.9", 
"ng-focus-if": "1.0.5", 
"ng-caps-lock": "1.0.2", 
"animate.css": "3.5.1", 
"angular-media-queries": "0.5.1" 

PAKET:

"bower": "1.7.9", 
"bower-installer": "1.2.0", 
"grunt": "1.0.1", 
"grunt-contrib-concat": "1.0.1", 
"grunt-contrib-cssmin": "1.0.1", 
"grunt-contrib-htmlmin": "1.4.0", 
"grunt-contrib-jshint": "1.0.0", 
"grunt-contrib-sass": "1.0.0", 
"grunt-contrib-watch": "1.0.0", 
"grunt-githooks": "0.6.0", 
"grunt-karma": "1.0.0", 
"grunt-ng-annotate": "2.0.2", 
"grunt-ng-constant": "2.0.1", 
"http-server": "0.9.0", 
"jasmine-core": "2.4.1", 
"jshint-stylish": "2.2.0", 
"karma": "0.13.22", 
"karma-coverage": "1.0.0", 
"karma-ie-launcher": "1.0.0", 
"karma-jasmine": "1.0.2", 
"karma-junit-reporter": "1.0.0", 
"karma-phantomjs-launcher": "1.0.0", 
"karma-safari-launcher": "1.0.0", 
"phantomjs-prebuilt": "2.1.7", 
"protractor": "3.3.0", 
"shelljs": "0.7.0" 

Absolut jede Hilfe sehr geschätzt würde. Ich verstehe das nicht, ich habe die Dienste vorher getestet, und der eigentliche Socket-Code funktioniert. Nochmals, wenn Sie mehr Informationen benötigen, zögern Sie nicht zu fragen, aber ich kann es Ihnen vielleicht nicht geben.

+0

sollte der Socket-Service js gehören vor app.js oder etwas im Karma conf? Wenn nichts anderes, muss es vor dem Test js kommen, oder? Ohne Dateinamen, die Pfade haben, ist es schwer zu sagen, ob das Karma-Conf die Dinge in der richtigen Reihenfolge enthält - aber ich weiß, dass ich ähnliche Probleme mit fehlenden Services hatte und dass es darauf hinausläuft. –

+0

Es funktioniert für alle meine anderen Tests, es gibt ungefähr 30 andere Tests für andere Controller und Dienste. Es soll angular (vor beliebigen Winkelmodulen), Moment (also lädt es vor dem angularMoment-Modul), dann alle externen Module, dann das Apps-Hauptmodul, dann Konstanten, schließlich alle anderen Anwendungsmodule laden. Tests befinden sich in dem Ordner mit dem Element, das sie testen, und werden mit "_test.js" angehängt. So leben socket.js und socket_test.js im Ordner Socket in der Ordner-App. Ich werde versuchen, es zu wechseln, um zu sehen, ob das einen Unterschied macht, und ich werde zu dir zurückkommen. – AntonMiles

+0

Wenn ich es umschalte, so ist die Ladeanweisung 'Dateien: [ " app/libs/eckig/angular.js ", " app/libs/moment/moment.min.js ", " app/libs /**/*.js“, "app/constants.js", "app/**/*. js", "app/app.js" ]' Es funktioniert immer noch nicht . Aber nichts Neues bricht ab. EDIT: Ich habe auch versucht, die Datei socket.js explizit hinzufügen, immer noch den gleichen Fehler. – AntonMiles

Antwort

1

Ich fand das Problem, und es liegt außerhalb dessen, was ich aufgedeckt habe.Ich bin mir nicht sicher, warum meine Änderungen funktionierte, aber in meinem Fall tat es, und falls jemand das gleiche Problem hat, möchte ich meinen Fix da draußen setzen.

Der SocketService ist ein Dienst, der einen Socket.IO-Socket in eine persönliche Logik umschließt und die javascript globale io.connect() - und andere io/socket-Funktionalität in das eckige Ökosystem einbringt. Ich hatte es so, dass die tatsächliche Verbindung beim Aufruf eines Ereignisses socket.createConnection() erstellt wurde, das im eigentlichen Code funktionierte, aber aus irgendeinem Grund nicht im Test funktioniert. Ich habe die Verbindung zu einem Ereignis gemacht, das jedes Mal ausgelöst wird, wenn Sie den Dienst aka socket.socket = io.connect(socialUrl) nahe dem Anfang der Datei initialisieren und dies schien es zu beheben. So, jetzt der Anfang der Datei wie folgt aussieht:

function SocketService($rootScope, $cookies, $log, $state, jwtHelper, moment, socialUrl) { 
    /* The object to be returned by the service, includes: 
    * .data(actual data), 
    * .supportFunctions(functions to sort and place data), 
    * .callbackFunctions(callbacks to call on 'on' events 
    * .socket which contains the actual socket connection */ 
    var socket = {}; 
    /* Object to hold socket connection */ 
    socket.socket = io.connect(socialUrl); //This is the important change 
    /* Holds all the data gathered so far by the socket */ 
    socket.data = {}; 
    /* Holds all the sorted messages */ 
    socket.data.sortedMessages = []; 
    /* Holds all the channels the user is a member of */ 
    socket.data.userChannels = []; 
    /* Object holding all the support functions necessary for the data to be manipulated as expected */ 
    socket.supportFunctions = {}; 

Dies ist nun mit dem äußeren Arbeits einem Unterstrich notiert-Meldung enthält. Wie unten zu sehen ist, geht dieser Test nun die Änderung bedeutet gearbeitet:

(function() { 
    "use strict"; 

    describe("ConnectedCampus.SocketService", function() { 
     /* jshint unused: false */ 
     var $rootScope, 
      $cookies, 
      $log, 
      $state, 
      jwtHelper, 
      moment, 
      SocketService; 
     var channel1 = <imitation channel object>; 
     var channel2 = <imitation channel object>; 
     var channel3 = <imitation channel object>; 
     var postToChannel1 = <imitation post to 1st channel>; 

     beforeEach(function(){ 
      $cookies = jasmine.createSpyObj("$cookies", ["get", "put"]); 
      $cookies.get.and.returnValue("<valid auth token>"); 
      $state = jasmine.createSpyObj("$state", ["go"]); 
      module("angularMoment"); 
      module("angular-jwt"); 
      module("ConnectedCampus.Constants"); 
      module("ConnectedCampus.SocketService"); 
      module(function ($provide) { 
       $provide.value("$cookies", $cookies); 
       $provide.value("$state", $state); 
       $provide.constant("socialUrl", "Yellow"); 
      }); 
      inject(function (_$rootScope_, _$log_, _jwtHelper_, _moment_, _SocketService_) { 
       $rootScope = _$rootScope_.$new(); 
       $log = _$log_; 
       jwtHelper = _jwtHelper_; 
       moment = _moment_; 
       SocketService = _SocketService_; 
      }) 
     }); 

     describe("Support Functions", function() { 


      it("socket.supportFunctions.sortPost should push a new post into the channel's posts array.", function (done) { 
       SocketService.data.userChannels = [channel1, channel2, channel3]; 
       SocketService.supportFunctions.sortPost(postToChannel1); 
       expect(SocketService.data.userChannels[0].post_to_channel).toContain(postToChannel1); 
       done(); 
      }) 
     }); 
    }); 
}()); 

Noch einmal, ich bin nicht sicher, warum dies funktioniert, und ich will nicht, Meinungen werfen um, aber wenn Sie jemals ein ähnliches haben Ausgabe, diese könnte die Lösung sein.

Verwandte Themen