2015-01-30 1 views
12

Я пытаюсь написать единичный тест с Jest и Jasmine-pit для приведенного ниже кода, и я полностью в тупике с ним. Код - это вызов ajax, который извлекает некоторые данные из ресурса и сохраняет его в переменной.Как написать единичный тест с Jest для кода с Promise

init = function() { 
    var deferred = Q.defer(); 
    $.ajax({ 
     type: 'GET', 
     datatype: 'json', 
     url: window.location.origin + name, 
     success: function (data) { 
      userId = data.userId; 
      apiKey = data.apiKey; 
      deferred.resolve(); 
     } 
    }); 
    return deferred.promise; 
}, 
+0

Unrelated комментарий (у вас уже есть свой ответ): [отложила является антипаттерн] (https://github.com/petkaantonov/bluebird/wiki/Promise-anti-patterns), не используй их :). –

ответ

9

Это разочаровывало меня сегодня. Вот что я закончил (тестируя мой ActionCreator (Flux), который использует API, который возвращает обещания и отправляет материал на основе обещания). В основном я изворачиваю метод API, который возвращает обещание и сразу его устраняет. Вы могли бы подумать, что этого было бы достаточно, чтобы получить способы ... (...) для стрельбы, но код ямы должен был, чтобы мой ActionCreator действительно работал на основе разрешенных обещаний.

jest.dontMock('../LoginActionCreators.js'); 
jest.dontMock('rsvp'); //has to be above the require statement 

var RSVP = require('rsvp'); //could be other promise library 

describe('LoginActionCreator', function() { 
    pit('login: should call the login API', function() { 
    var loginActionCreator = require('../LoginActionCreators'); 
    var Dispatcher = require('../../dispatcher/Dispatcher'); 
    var userAPI = require('../../api/User'); 
    var Constants = require('../../constants/Constants'); 

    //my api method needs to return this 
    var successResponse = { body: {"auth_token":"Ve25Mk3JzZwep6AF7EBw=="} }; 

    //mock out the API method and resolve the promise right away 
    var apiMock = jest.genMockFunction().mockImplementation(function() { 
     var promise = new RSVP.Promise(function(resolve, reject) { 
     resolve(successResponse); 
     }); 

     return promise; 
    }); 
    //my action creator will dispatch stuff based on the promise resolution, so let's mock that out too 
    var dispatcherMock = jest.genMockFunction(); 

    userAPI.login = apiMock; 
    Dispatcher.dispatch = dispatcherMock; 

    var creds = { 
     username: 'username', 
     password: 'password' 
    }; 

    //call the ActionCreator 
    loginActionCreator.login(creds.username, creds.password); 

    //the pit code seems to manage promises at a slightly higher level than I could get to on my 
    // own, the whole pit() and the below return statement seem like they shouldnt be necessary 
    // since the promise is already resolved in the mock when it is returned, but 
    // I could not get this to work without pit. 
    return (new RSVP.Promise(function(resolve) { resolve(); })).then(function() { 
     expect(apiMock).toBeCalledWith(creds); 
     expect(dispatcherMock.mock.calls.length).toBe(2); 
     expect(dispatcherMock.mock.calls[0][0]).toEqual({ actionType: Constants.api.user.LOGIN, queryParams: creds, response: Constants.request.PENDING}); 
     expect(dispatcherMock.mock.calls[1][0]).toEqual({ actionType: Constants.api.user.LOGIN, queryParams: creds, response: successResponse}); 
    }); 
    }); 
}); 

Вот ActionCreator, которая связывает API диспетчеру:

'use strict'; 

var Dispatcher = require('../dispatcher/Dispatcher'); 
var Constants = require('../constants/Constants'); 
var UserAPI = require('../api/User'); 


function dispatch(key, response, params) { 
    var payload = {actionType: key, response: response}; 
    if (params) { 
    payload.queryParams = params; 
    } 
    Dispatcher.dispatch(payload); 
} 

var LoginActionCreators = { 

    login: function(username, password) { 
    var params = { 
     username: username, 
     password: password 
    }; 

    dispatch(Constants.api.user.LOGIN, Constants.request.PENDING, params); 

    var promise = UserAPI.login(params); 

    promise.then(function(res) { 
     dispatch(Constants.api.user.LOGIN, res, params); 
    }, function(err) { 
     dispatch(Constants.api.user.LOGIN, Constants.request.ERROR, params); 
    }); 
    } 
}; 

module.exports = LoginActionCreators;