Cómo probar el objeto diferido hecho y fallado usando jasmine

Aquí está el código sobre la solicitud de envío javascript (1).
Aquí está la prueba para burlarse de la solicitud ajax usando jasmine (2).

Me gustaría burlarme del comportamiento del servidor. ¿Algunas ideas?
Vea el comentario en (1) y (2) para más detalles.

PD:
En realidad, en ambos casos, se llama al hecho y al objeto diferido fallido de fakeFunction.


(1)

submitForm: function () { // the server execute fail only if message.val() is empty // and I would like to mock this behaviour in (2) backendController.submitForm(message.val()).done(this.onSuccess).fail(this.onError); }, backendController.submitForm = function (message) { return $.ajax({ url: 'some url', type: 'POST', dataType: 'json', data: { message: message } }).done(function () { //some code; }); }; 

(2)

 describe('When Submit button handler fired', function () { var submitFormSpy, fakeFunction = function () { this.done = function () { return this; }; this.fail = function () { return this; }; return this; }; beforeEach(function () { submitFormSpy = spyOn(backendController, 'submitForm').andCallFake(fakeFunction); }); describe('if the message is empty', function () { beforeEach(function () { this.view.$el.find('#message').text(''); this.view.$el.find('form').submit(); }); it('backendController.submitForm and fail Deferred Object should be called', function () { expect(submitFormSpy).toHaveBeenCalled(); // how should I test that fail Deferred Object is called? }); }); describe('if the message is not empty', function () { beforeEach(function () { this.view.$el.find('#message').text('some text'); this.view.$el.find('form').submit(); }); it('backendController.submitForm should be called and the fail Deferred Object should be not called', function () { expect(submitFormSpy).toHaveBeenCalled(); // how should I test that fail Deferred Object is not called? }); }); }); 

En realidad nos encontramos con el mismo problema, tratando de probar los objetos diferidos que representan secuencias de comandos de plantillas AJAX para la plantilla sobre la marcha. Nuestra solución de prueba involucra el uso de la biblioteca Jasmine-Ajax junto con el propio Jasmine.

Así que probablemente será algo como esto:

 describe('When Submit button handler fired', function () { jasmine.Ajax.useMock(); describe('if the message is empty', function () { beforeEach(function() { spyOn(backendController, 'submitForm').andCallThrough(); // replace with wherever your callbacks are defined spyOn(this, 'onSuccess'); spyOn(this, 'onFailure'); this.view.$el.find('#message').text(''); this.view.$el.find('form').submit(); }); it('backendController.submitForm and fail Deferred Object should be called', function () { expect(backendController.submitForm).toHaveBeenCalledWith(''); mostRecentAjaxRequest().response({ status: 500, // or whatever response code you want responseText: '' }); expect( this.onSuccess ).not.toHaveBeenCalled(); expect( this.onFailure ).toHaveBeenCalled(); }); }); 

Otra cosa, si puede, intente dividir la funcionalidad para que no esté probando la ruta completa de callback de DOM a respuesta en una prueba. ¡Si eres lo suficientemente granular, puedes probar resoluciones diferidas asíncronas usando objetos diferidos dentro de tus pruebas!

La clave es usar objetos diferidos dentro de sus propias pruebas, de modo que el scope de la llamada expect aún se encuentre dentro de su bloque de función it .

 describe('loadTemplate', function() { it('passes back the response text', function() { jasmine.Ajax.mock(); loadTemplate('template-request').done(function(response) { expect(response).toBe('foobar'); }); mostRecentAjaxRequest().response({ status:200, responseText:'foobar' }); }); }); 

Aquí es cómo me las arreglé para hacerlo.

Esencialmente, el objeto $ .ajax devuelve un objeto diferido, por lo que puede espiar $ .ajax y devolver un diferido y luego activarlo manualmente para ejecutar el código .done () en su JavaScript

Código

 Index.prototype.sendPositions = function() { var me = this; $.ajax({ ... }).done(function(data, textStatus, jqXHR) { me.reload(); }).fail(function(jqXHR, textStatus, errorThrown) { console.log(errorThrown); }); }; 

Prueba

 it("should reload the page after a successful ajax call", function(){ var deferred = new jQuery.Deferred(); spyOn($, 'ajax').andReturn(deferred); spyOn(indexPage, 'reload'); indexPage.sendPositions(); deferred.resolve('test'); expect(indexPage.reload).toHaveBeenCalled(); }); 

Sería mucho más fácil de probar si tuviera una var con el objeto de promesa de solicitud ajax. En ese caso podrías hacer:

  it('should do an async thing', function() { var mutex = 1; var promF = jasmine.createSpy('prF'); runs( function() { var promise1 = $.ajax(); promise1.always(function(){ mutex--; }); promise1.fail(function(){ promF(); }); }); waitsFor(function(){ return !mutex; }, 'Fetch should end', 10000); runs( function() { expect(promF).toHaveBeenCalled(); }); }); 

Abajo publico un código no probado que podría ser adecuado para usted. Supongo que la llamada ajax se inicializa desde la clase .submit ()? Tal vez debería inicializar la solicitud ajax desde un bloque run () y no desde beforeEach (), pero debería probar cuál funciona.

 describe('When Submit button handler fired and city is defined', function () { var ajaxRequestSpy, failSpy, successSpy, alwaysSpy, mutex; beforeEach(function () { ajaxRequestSpy = spyOn(backendController, 'ajaxRequest').andCallThrough(); failSpy = spyOn(ajaxRequestSpy(), 'fail').andCallThrough() successSpy = spyOn(ajaxRequestSpy(), 'success').andCallThrough(); mutex = 1; // num of expected ajax queries alwaysSpy = spyOn(ajaxRequestSpy(), 'always').andCallFake(function() { mutex--; }); this.view = new MyView({ el: $('
' + '' + '' + '
') }); this.view.$el.find('form').submit(); }); it('backendController.ajaxRequest should be called', function () { runs( function() { // maybe init ajax here ? }); waitsFor( function() { return !mutex; }, 'ajax request should happen', 5000); runs( function() { expect(ajaxRequestSpy).toHaveBeenCalled(); // true expect(failSpy).toHaveBeenCalled(); // Error: Expected spy fail // to have been called. }); }); });

Pero, no estoy seguro de que la línea

 failSpy = spyOn(ajaxRequestSpy(), 'fail').andCallThrough(); 

hace lo que tu quieras ¿Es posible espiar a otro espía? Y si es así, ¿por qué llamas al espía? Tal vez deberias intentarlo

 failSpy = spyOn(ajaxRequestSpy, 'fail').andCallThrough();