Как издеваться над jQuery с помощью Jasmine

Что я хочу сделать: мы пишем несколько тестов для существующей базы кода Javascript, в которой интенсивно используется jQuery. Для тестов нам не нужны настоящие HTML-элементы (HTML-фикстуры). Мы бы предпочли, чтобы у нас был фиктивный объект jQuery, который не делает ничего, связанного с HTML.

Моя отправная точка: наиболее многообещающий подход, который я нашел здесь:

http://eclipsesource.com/blogs/2014/03/27/mocks-in-jasmine-tests/

Это создает вспомогательный метод, который создает макет, просматривая функции объекта и создавая шпион для каждой функции:

window.mock = function (constr, name) {
  var keys = [];
  for (var key in constr.prototype)
    keys.push( key );
  return keys.length > 0 ? jasmine.createSpyObj( name || "mock", keys ) : {};
};

Затем, если я правильно его понял, он использует это так (адаптированный пример из его сообщения в блоге):

var el = mock($);
el('.some-not-existing-class').css('background', 'red');
expect(el.css).toHaveBeenCalledWith('background', 'red');

Однако это не работает, так как el является object, а не function.

Мой подход к решению этой проблемы: я реорганизовал его функцию mock, чтобы учесть случай, когда constr является function:

mock (constr, name) {
  var keys = [];
  for (var key in constr.prototype)
    keys.push(key);
  var result = keys.length > 0 ? jasmine.createSpyObj(name || "mock", keys) : {};

  // make sure that if constr is a function (like in the case of jQuery), the mock is too
  if (typeof constr === 'function') {
    var result2 = result;
    result = jasmine.createSpy(name || 'mock-fn');
    for (var key in result2)
      result[key] = result2[key];
  }
  return result;
}

Однако вторая строка в тесте выдает ошибку Cannot read property css of undefined:

var el = mock($);
el('.some-not-existing-class').css('background', 'red');
expect(el.css).toHaveBeenCalledWith('background', 'red');

Другие идеи: я также пытался объединить шпионский объект с jQuery, но это тоже не помогло.

Любые идеи? Надеюсь, мы не единственные, кто делает это без HTML-фикстур.


person cheesus    schedule 21.06.2015    source источник


Ответы (2)


Нашел. Когда моя версия функции mock настроена на возврат объекта jQuery при вызове функции jQuery, тест работает:

mock (constr, name) {
  var keys = [];
  for (var key in constr.prototype)
    keys.push(key);
  var result = keys.length > 0 ? jasmine.createSpyObj(name || "mock", keys) : {};

  // make sure that if constr is a function (like in the case of jQuery), the mock is too
  if (typeof constr === 'function') {
    var result2 = result;
    result = jasmine.createSpy(name || 'mock-fn');
    result.and.returnValue(result);
    for (var key in result2)
      result[key] = result2[key];
  }
  return result;
}
person cheesus    schedule 21.06.2015

Вы можете использовать заглушки sinon.js вместо создания собственных вспомогательных методов.

stub = sinon.stub(jQuery.fn, 'css');

// invoke code which calls the stubbed function

expect(stub.calledWith({ 'background': 'red' })).toBe(true);
stub.restore();
person Dimitris Zorbas    schedule 21.06.2015
comment
Пробовал это со строкой $('abc').css('background', 'red'); в качестве тестового кода. Однако утверждение не выполняется, sub.calledWith возвращает false. - person cheesus; 21.06.2015