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


85

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 que tuviera archivos JSON separados (* .json) con contenido JSON simulado únicamente, sin script. Para la prueba, me gustaría poder cargar el archivo JSON y bombear el objeto a la función que estoy probando.

Sé que 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 en el script, solo JSON directo archivos.

He intentado algunas cosas, pero soy bastante novato en esta área. Primero, configuré mi Karma para incluir mi archivo JSON solo para ver qué 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 desde mi especificación:

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

Cuando ejecuté la especificación recibí:

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

Lo que, según tengo entendido, significa que espera una respuesta simulada de $ httpBackend. Entonces ... en este punto no sabía cómo cargar el archivo usando las utilidades de Angular, así que pensé en probar jQuery para ver si al menos podía hacer que eso 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 esta 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 se solicitan en, por ejemplo:

/base/src/app.js

Aparentemente, Karma está configurando una especie de directorio base desde el que servir los archivos. Así que, por diversión, cambié mi solicitud de datos jquery a

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

¡Y funciona! Pero ahora me siento sucia y necesito darme una ducha. Ayúdame a sentirme limpio de nuevo.

Respuestas:


82

Estoy usando una configuración angular con semilla angular. Terminé resolviendo esto con archivos de accesorios .json y 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/mocky mi aplicación web está en /app.

my karma.conf.jstiene 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'; que originalmente lo había configurado, test/mockpero necesitaba el baseallí. 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

1
Hola Cameron, recibo un error: TypeError: Object # <Object> no tiene método 'getJSONFixtures' ... ¿se ha realizado un cambio en jazmín o algo así?
Melbourne2991

7
no me di cuenta de que necesitaba jasmine-jquery ... lo instalé y el error ha desaparecido
Melbourne2991

Este enfoque suena bastante detallado y complicado ... No sé si estos "accesorios" brindan beneficios adicionales, pero el siguiente enfoque gana si todo lo que desea es leer un archivo JSON de vez en cuando.
Septagrama

43

Servir JSON a través del dispositivo 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 en pc

$ bower install karma-read-json --save

  OR

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

  OR

$ yarn add karma-read-json --dev

Uso

  1. Coloque karma-read-json.js en sus 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 readJSONfunción en sus pruebas. Ejemplo:

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

1
karma-read-json es una excelente opción si no puede usar o instalar bower, que jasmine-jquery requiere. (Política de grandes corporaciones, en mi caso). Acabo de instalar a través de npm ( npmjs.com/package/karma-read-json ) y funcionó muy bien.
Melissa Avery-Weir

2
Creo que este es el mejor enfoque, ya que no requiere una dependencia de bower ... solo karma / jasmine y karma-read-json. Incluso pude hacer esto corriendo en npm install karma-read-jsonlugar debower install karma-read-json
Eric Fuller

Gran respuesta para el enfoque del karma, ¡gracias por la descripción clara!
nomadoj

A) algo nuevo en esta plataforma, B) no usar jquery tratando de construir un módulo angular. Esto funcionó bien para mí. mi configuración se ahogó en karma.config.json -> archivos [] .. No agregué nada en karma.config.json .. También: "const valid_respond = readJSON ('../ assets / Organizations.json'); "donde activos es la ubicación estándar de los activos.
2019

10

He estado luchando por encontrar una solución para cargar 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 la clave en su archivo de datos simulado, esto está bien, ya que 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
    ....
}

Tengo una duda ... ¿Habrá un módulo por archivo json? porque intenté agregar más de un valor en valores únicos, obtengo un error de proveedor desconocido para el segundo json
Pawan

6

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

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

Acabo de encontrarme 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 pude 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 hice:

var someUniqueName = ... the json ...

e incluí esto en karma conf incluye ...

Todavía puedo burlarme de una respuesta http backend si es necesario.

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

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

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

y luego simplemente inyecte SomeUniqueNameen 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 limpia y no requirió ninguna nueva curva de aprendizaje. así que prefiero este.


4

Yo buscaba 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 debe pasarse al valor angular.module ('MockDataModule'). 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 de inyección beforeEach.

También encontré otro enfoque que parece prometedor para las solicitudes xhr que no son costosas, es una excelente publicación que describe las pruebas intermedias, que si entiendo bien, permite que su controlador / servicio recupere datos como en una prueba e2e, pero su prueba intermedia tiene datos reales acceso al alcance del controlador (e2e no creo).




1

Aquí hay una alternativa a la respuesta de Cameron , sin la necesidad de jasmine-jqueryninguna 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();
    });
});

¿Qué es $ as en $ .when y $ .getJSON?
Matt

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.