web-dev-qa-db-fra.com

Chargement d'un fichier JSON simulé dans le test Karma + AngularJS

J'ai une application AngularJS configurée avec des tests utilisant Karma + Jasmine. Je souhaite tester une fonction qui prend un objet JSON volumineux, le convertit en un format plus compatible avec le reste de l'application et renvoie cet objet converti. C'est ça.

Pour mes tests, j'aimerais que vous ayez des fichiers JSON séparés (* .json) avec un contenu simulé JSON uniquement - pas de script. Pour le test, j'aimerais pouvoir charger le fichier JSON et pomper l'objet dans la fonction que je teste.

Je sais que je peux intégrer le JSON dans une maquette d'usine comme décrit ici: http://dailyjs.com/2013/05/16/angularjs-5/ mais je veux vraiment que le JSON ne soit pas contenu dans le script - juste des fichiers JSON droits.

J'ai essayé quelques choses mais je suis assez noob dans ce domaine. D'abord, j'ai configuré mon Karma pour inclure mon fichier JSON juste pour voir ce qu'il ferait:

files = [
    ...
    'mock-data/**/*.json'
    ...
]

Cela a abouti à:

Chrome 27.0 (Mac) ERROR
Uncaught SyntaxError: Unexpected token :
at /Users/aaron/p4workspace4/depot/sitecatalyst/branches/anomaly_detection/client/anomaly-detection/mock-data/two-metrics-with-anomalies.json:2

Alors je l'ai changé pour simplement servir les fichiers et non les "inclure":

files = [
    ...
    { pattern: 'mock-data/**/*.json', included: false }
    ...
]

Maintenant qu'ils ne font que servir, j'ai décidé d'essayer de charger le fichier avec $ http à partir de mes spécifications:

$http('mock-data/two-metrics-with-anomalies.json')

Lorsque j'ai exécuté les spécifications que j'ai reçues:

Error: Unexpected request: GET mock-data/two-metrics-with-anomalies.json

Ce qui, à mon avis, signifie qu'il attend une réponse simulée de $ httpBackend. Donc ... à ce stade, je ne savais pas comment charger le fichier à l'aide des utilitaires Angular), alors j'ai décidé d'essayer jQuery pour voir si je pouvais au moins le faire fonctionner:

$.getJSON('mock-data/two-metrics-with-anomalies.json').done(function(data) {
    console.log(data);
}).fail(function(response) {
    console.log(response);
});

Cela se traduit par:

Chrome 27.0 (Mac) LOG: { readyState: 4,
responseText: 'NOT FOUND',
status: 404,
statusText: 'Not Found' }

J'inspecte cette demande chez Charles et il fait une demande pour

/mock-data/two-metrics-with-anomalies.json

Considérant que le reste des fichiers que j'ai configurés pour être "inclus" par Karma sont demandés à, par exemple:

/base/src/app.js

Apparemment, Karma est en train de mettre en place une sorte de répertoire de base pour servir les fichiers. Donc, pour les coups de pied, j’ai modifié ma demande de données JQuery en

$.getJSON('base/mock-data/two-metrics-with-anomalies.json')...

Et il fonctionne! Mais maintenant je me sens sale et j'ai besoin de prendre une douche. Aide-moi à me sentir propre à nouveau.

83
Aaronius

J'utilise une configuration angular avec angular graine. J'ai fini par résoudre ce problème avec des fichiers de montage droits .json et jasmine-jquery.js. D'autres avaient déjà fait allusion. à cette réponse, mais il m'a fallu un certain temps pour mettre toutes les pièces au bon endroit, j'espère que cela aidera quelqu'un d'autre.

J'ai mes fichiers JSON dans un dossier /test/mock Et mon application Web est dans /app.

mon karma.conf.js a ces entrées (entre autres):

basePath: '../',

files: [
      ... 
      'test/vendor/jasmine-jquery.js',
      'test/unit/**/*.js',

      // fixtures
      {pattern: 'test/mock/*.json', watched: true, served: true, included: false}
    ],

alors mon fichier de test a:

describe('JobsCtrl', function(){
var $httpBackend, createController, scope;

beforeEach(inject(function ($injector, $rootScope, $controller) {

    $httpBackend = $injector.get('$httpBackend');
    jasmine.getJSONFixtures().fixturesPath='base/test/mock';

    $httpBackend.whenGET('http://blahblahurl/resultset/').respond(
        getJSONFixture('test_resultset_list.json')
    );

    scope = $rootScope.$new();
    $controller('JobsCtrl', {'$scope': scope});

}));


it('should have some resultsets', function() {
    $httpBackend.flush();
    expect(scope.result_sets.length).toBe(59);
});

});

Le vrai truc était la jasmine.getJSONFixtures().fixturesPath='base/test/mock'; que j'avais initialement réglée sur test/mock, Mais il avait besoin du base. Sans la base, j'ai des erreurs comme celle-ci:

Error: JSONFixture could not be loaded: /test/mock/test_resultset_list.json (status: error, message: undefined)
at /Users/camd/gitspace/treeherder-ui/webapp/test/vendor/jasmine-jquery.js:295
80
Cameron

Servir JSON via le support est le plus simple, mais en raison de notre configuration, nous ne pouvions pas le faire facilement. J'ai donc écrit une fonction d'assistance alternative:

référentiel

Installer

$ bower install karma-read-json --save

  OR

$ npm install karma-read-json --save-dev

  OR

$ yarn add karma-read-json --dev

Usage

  1. Mettez karma-read-json.js dans vos fichiers Karma. Exemple:

    files = [
      ...
      'bower_components/karma-read-json/karma-read-json.js',
      ...
    ]
    
  2. Assurez-vous que votre JSON est servi par Karma. Exemple:

    files = [
      ...
      {pattern: 'json/**/*.json', included: false},
      ...
    ]
    
  3. Utilisez la fonction readJSON dans vos tests. Exemple:

    var valid_respond = readJSON('json/foobar.json');
    $httpBackend.whenGET(/.*/).respond(valid_respond);
    
42
PizzaPanther

J'ai eu du mal à trouver une solution pour charger des données externes dans mes cas de test. Le lien ci-dessus: http://dailyjs.com/2013/05/16/angularjs-5/ a fonctionné pour moi.

Quelques notes:

"defaultJSON" doit être utilisé comme clé dans votre fichier de données fictif. Très bien, vous pouvez simplement vous référer à defaultJSON.

mockedDashboardJSON.js:

'use strict'
angular.module('mockedDashboardJSON',[])
.value('defaultJSON',{
    fakeData1:{'really':'fake2'},
    fakeData2:{'history':'faked'}
});

Puis dans votre fichier de test:

beforeEach(module('yourApp','mockedDashboardJSON'));
var YourControlNameCtrl, scope, $httpBackend, mockedDashboardJSON;
beforeEach(function(_$httpBackend_,defaultJSON){
    $httpBackend.when('GET','yourAPI/call/here').respond(defaultJSON.fakeData1);
    //Your controller setup 
    ....
});

it('should test my fake stuff',function(){
    $httpBackend.flush();
    //your test expectation stuff here
    ....
}
10
TOBlender

on dirait que votre solution est la bonne, mais il y a 2 choses que je n'aime pas à ce sujet:

  • il utilise du jasmin
  • il faut une nouvelle courbe d'apprentissage

je viens de rencontrer ce problème et je devais le résoudre rapidement car je n'avais plus de temps pour la date limite, et j'ai fait ce qui suit

ma ressource json était énorme, et je ne pouvais pas la coller dans le test, je devais donc la conserver dans un fichier séparé - mais j’ai décidé de la conserver au format javascript plutôt que json.

var someUniqueName = ... the json ...

et j'ai inclus cela dans le karma conf comprend ..

je peux toujours me moquer d'une réponse http backend si nécessaire avec elle.

$httpBackend.whenGET('/some/path').respond(someUniqueName);

je pourrais aussi écrire un nouveau module angular à inclure ici, puis changer la ressource json pour qu'elle ressemble à quelque chose comme

angular.module('hugeJsonResource', []).constant('SomeUniqueName', ... the json ... );

et ensuite simplement injecter SomeUniqueName dans le test, qui a l’air plus propre.

peut-être même l'envelopper dans un service

angular.module('allTestResources',[]).service('AllTestResources', function AllTestResources( SomeUniqueName , SomeOtherUniqueName, ... ){
   this.resource1 = SomeUniqueName;
   this.resource2 = SomeOtherUniqueName; 
})

cette solution était plus rapide pour moi, tout aussi propre et ne nécessitait aucune nouvelle courbe d'apprentissage. donc je préfère celui-ci.

6
guy mograbi

Je cherchais la même chose. Je vais essayer cette approche . Il utilise les fichiers de configuration pour inclure les fichiers de données fictifs, mais les fichiers sont un peu plus que json, car le json doit être passé à angular.module ('MockDataModule'). Value et vos tests unitaires peuvent également charger plusieurs modules. La valeur définie est ensuite disponible pour être injectée dans l'appel beforeEach inject.

Également trouvé ne autre approche qui semble prometteur pour les requêtes xhr qui ne coûtent pas cher, c’est un excellent article qui décrit les tests à mi-parcours, qui, si je comprends bien, permet à votre contrôleur/service de récupérer les données comme dans un test e2e , mais votre test à mi-parcours a un accès réel à la portée du contrôleur (e2e ne me semble pas).

4
user1683523

Certains préprocesseurs Karma fonctionnent également avec les fichiers JSON. Il y en a un ici:

https://www.npmjs.org/package/karma-ng-json2js-preprocessor

Et fiche éhontée, c’est celle que j’ai développée et qui prend en charge RequireJS

https://www.npmjs.org/package/karma-ng-json2js-preprocessor-requirejs

2
sma

Voici une alternative à la réponse de Cameron , sans la nécessité de jasmine-jquery ni aucune configuration Karma supplémentaire, pour tester par exemple un service Angular utilisant $resource:

angular.module('myApp').factory('MyService', function ($resource) {
    var Service = $resource('/:user/resultset');
    return {
        getResultSet: function (user) {
            return Service.get({user: user}).$promise;
        }
    };
});

Et le test unitaire correspondant:

describe('MyServiceTest', function(){
    var $httpBackend, MyService, testResultSet, otherTestData ;

    beforeEach(function (done) {
        module('myApp');
        inject(function ($injector) {
            $httpBackend = $injector.get('$httpBackend');
            MyService = $injector.get('MyService');
        });
        // Loading fixtures
        $.when(
            $.getJSON('base/test/mock/test_resultset.json', function (data) { testResultSet = data; }),
            $.getJSON('base/test/mock/test_other_data.json', function (data) { otherTestData = data; })
        ).then(done);
    });

    it('should have some resultset', function() {
        $httpBackend.expectGET('/blahblahurl/resultset').respond(testResultSet);
        MyService.getResultSet('blahblahurl').then(function (resultSet) {
            expect(resultSet.length).toBe(59);
        });
        $httpBackend.flush();
    });
});
1
Lucas Cimon

Vous pouvez utiliser le karma-html2js-preprocessor pour obtenir les fichiers JSON ajoutés au fichier __html__ global.

voir cette réponse pour plus de détails: https://stackoverflow.com/a/22103160/439021

1
kenglxn