Подтвердить что ты не робот

Как написать unit test с Jest для кода с Promise

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

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;
},
4b9b3361

Ответ 1

Это расстроило меня сегодня большую часть дня. Вот что я закончил (тестируя мой ActionCreator (Flux), который использует API, который возвращает promises и отправляет материал на основе обещания). В основном я изворачиваю метод API, который возвращает обещание и сразу его устраняет. Вы могли бы подумать, что этого было бы достаточно, чтобы получить методы .then(...) для запуска, но код ямы должен был, чтобы мой 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 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;