Cargando un archivo JSON simulado dentro de la prueba Karma + AngularJS


Tengo una aplicación AngularJS configurada con pruebas usando Karma+Jasmine. Tengo una función que quiero probar que toma un objeto JSON grande, lo convierte a un formato que es más consumible por el resto de la aplicación, y devuelve ese objeto convertido. Eso es.

Para mis pruebas, me gustaría tener archivos JSON separados (*.json) con contenido JSON simulado solamente no sin script. Para la prueba, me gustaría poder cargar el archivo JSON y bombear el objeto en la función que estoy probando.

Lo sé Puedo incrustar el JSON dentro de una fábrica simulada como se describe aquí: http://dailyjs.com/2013/05/16/angularjs-5 / pero realmente quiero que el JSON no esté contenido dentro del script just solo archivos JSON rectos.

He intentado algunas cosas, pero soy bastante novato en esta área. Primero, configuré mi Karma para incluir mi archivo JSON solo para ver lo que haría:

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

Esto resultó en:

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

Entonces lo cambié para servir los archivos y no" incluirlos":

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

Ahora que solo se sirven, pensé en intentar cargar el archivo usando http http desde dentro de mi especificación:

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

Cuando corrí la especificación recibí:

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

Lo que a mi entender significa que espera una respuesta burlada de $httpBackend. So...at en este punto no sabía cómo cargar el archivo usando Angular utilities, así que pensé en probar jQuery para ver si al menos podía hacer que funcionara:

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

Esto resulta en:

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

Inspecciono esto solicitud en Charles y está haciendo una solicitud a

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

Mientras que el resto de los archivos que he configurado para ser "incluidos" por Karma están siendo solicitados en, por ejemplo:

/base/src/app.js

Aparentemente Karma está configurando algún tipo de directorio base desde el que servir los archivos. Así que para patadas cambié mi solicitud de datos de jquery a

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

Y funciona! Pero ahora me siento sucio y necesito ducharme. Ayúdame a sentirme limpio otra vez.

Author: Aaronius, 2013-06-28

8 answers

Estoy usando una configuración angular con angular seed. Terminé resolviendo esto con straight .json fixture files and jasmine-jquery.js. Otros habían aludido a esta respuesta, pero me tomó un tiempo poner todas las piezas en el lugar correcto. Espero que esto ayude a alguien más.

Tengo mis archivos json en una carpeta /test/mock y mi aplicación web está en /app.

Mi karma.conf.js tiene estas entradas (entre otras):

basePath: '../',

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

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

Entonces mi archivo de prueba tiene:

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

});

El verdadero truco fue El jasmine.getJSONFixtures().fixturesPath='base/test/mock'; Yo tenía originalmente se estableció en solo test/mock pero necesitaba el base allí. Sin la base, tengo errores como este:

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
Author: Cameron,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-30 01:44:39

Servir JSON a través del fixture es lo más fácil, pero debido a nuestra configuración no pudimos hacerlo fácilmente, así que escribí una función auxiliar alternativa:

Repositorio

Instalar

$ bower install karma-read-json --save

  OR

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

  OR

$ yarn add karma-read-json --dev

Uso

  1. Pon karma-read-json.js en tus archivos de Karma. Ejemplo:

    files = [
      ...
      'bower_components/karma-read-json/karma-read-json.js',
      ...
    ]
    
  2. Asegúrese de que su JSON esté siendo servido por Karma. Ejemplo:

    files = [
      ...
      {pattern: 'json/**/*.json', included: false},
      ...
    ]
    
  3. Utilice la función readJSON en sus pruebas. Ejemplo:

    var valid_respond = readJSON('json/foobar.json');
    $httpBackend.whenGET(/.*/).respond(valid_respond);
    
 40
Author: PizzaPanther,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-15 23:29:25

He estado luchando para encontrar una solución a la carga de datos externos en mis casos de prueba. El enlace anterior: http://dailyjs.com/2013/05/16/angularjs-5 / Funcionó para mí.

Algunas notas:

"defaultJSON" debe usarse como clave en su archivo de datos simulado, esto está bien, ya que solo puede referirse a defaultJSON.

MockedDashboardJSON.js:

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

Luego en su archivo de prueba:

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
Author: TOBlender,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-16 15:34:24

Parece que su solución es la correcta, pero hay 2 cosas que no me gustan de ella:

  • utiliza jazmín
  • requiere una nueva curva de aprendizaje

Me encontré con este problema y tuve que resolverlo rápidamente ya que no me quedaba tiempo para la fecha límite, e hice lo siguiente

Mi recurso json era enorme, y no podía copiarlo y pegarlo en la prueba, así que tuve que mantenerlo en un archivo separado, pero decidí mantenerlo como javascript en lugar de json, y luego simplemente lo hizo:

var someUniqueName = ... the json ...

E incluí esto en karma conf incluye..

Todavía puedo simular una respuesta http de backend si es necesario con ella.

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

También podría escribir un nuevo módulo angular para ser incluido aquí y luego cambiar el recurso json para que sea algo como

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

Y luego simplemente inyecte SomeUniqueName en la prueba, que se ve más limpia.

Tal vez incluso envolverlo en un servicio

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

Esta solución fue más rápida para mí, igual de limpio, y no requiere ninguna nueva curva de aprendizaje. así que prefiero esta.

 6
Author: guy mograbi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-02 21:39:09

Yo estaba buscando lo mismo. Voy a probar este enfoque. Utiliza los archivos de configuración para incluir los archivos de datos simulados, pero los archivos son un poco más que json, porque el json necesita ser pasado a angular.módulo('MockDataModule').value y luego sus pruebas unitarias también pueden cargar varios módulos y luego el conjunto de valores está disponible para inyectarse en la llamada beforeEach inject.

También se encontró otro enfoque que parece prometedor para las solicitudes xhr que no son costosos, es un gran post que describe las pruebas de midway, que si entiendo bien permite que su controlador/servicio realmente recupere datos como en una prueba e2e, pero su prueba de midway tiene acceso real al alcance del controlador (e2e no creo).

 4
Author: user1683523,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-11 19:56:16

Hay preprocesadores Karma que también funcionan con archivos JSON. Hay uno aquí:

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

Y shameless plug, este es uno que desarrollé que tiene soporte RequireJS

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

 2
Author: sma,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-06-04 12:49:44

Puede usar el karma-html2js-preprocessor para obtener los archivos json agregados al global __html__.

Vea esta respuesta para más detalles: https://stackoverflow.com/a/22103160/439021

 1
Author: kenglxn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:46:55

Aquí hay una alternativa a La respuesta de Cameron , sin la necesidad de jasmine-jquery ni ninguna configuración adicional de Karma, para probar, por ejemplo, un servicio Angular usando $resource:

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

Y la prueba unitaria correspondiente:

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
Author: Lucas Cimon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:34