Как я могу заглянуть на свойство геттера с помощью жасмина?
Как я могу отслеживать свойство геттера с помощью жасмина?
var o = { get foo() {}, };
spyOn(o, 'foo').and.returnValue('bar'); // Doesn't work.
Это также не работает AFAICT:
spyOn(Object.getOwnPropertyDescriptor(o, 'foo'), 'get').and.returnValue('bar');
Ответы
Ответ 1
Эта функция, похоже, не реализована, но нет причин, почему этого не может быть. (Я открыл запрос и он выполнил в запрос на перенос как spyOnProperty
, но не сливается с мастером.)
Жасмин spyOn
работает, переписывая метод объекта с помощью новой функции, которая вызывает старую функцию. spyOn(obj, prop)
делает что-то вроде этого:
var oldFunc = obj[prop];
obj[prop] = function() {
doSpyStuff();
return oldFunc.apply(this, arguments);
}
Этот подход не работает для геттеров и сеттеров, так как нотация в виде скобок будет запускать setter/getter, но он не получит к ней доступа. Ваша попытка использовать getOwnPropertyDescriptor
находится на правильном пути, но getOwnPropertyDescriptor
просто возвращает новый объект, который описывает свойство getters/seters. Изменение свойства на возвращаемом объекте описания с obj[prop] = function() { ... }
не вызывает изменения самого свойства.
Вместо этого вам придется придерживаться принципиально иного подхода к перезаписи функции. Вместо того, чтобы переписывать свойство с помощью функции, вам нужно переопределить свойство, чтобы использовать новый getter:
var oldDescriptor = Object.getOwnPropertyDescriptor(o, 'foo');
// test if this is an accessor property
if(oldDescriptor.get) {
Object.defineProperty(o, 'foo', {
set: oldDescriptor.set,
get: function() {
doSpyStuff();
return oldDescriptor.get.apply(this);
}
});
}
Код Жасмин для spyOn
находится в /src/core/SpyRegistry.js
, и, в частности, код, который заменяет метод функцией spy, в настоящее время:
var spy = j$.createSpy(methodName, obj[methodName]);
currentSpies().push({
spy: spy,
baseObj: obj,
methodName: methodName,
originalValue: obj[methodName]
});
obj[methodName] = spy;
Как описано выше, это полностью переписывает свойства со шпионскими функциями; в настоящее время он не поддерживает переписывание только set
или get
свойства accessor с помощью definePrpoerty
.
Ответ 2
В феврале 2017 года они объединили PR, добавив эту функцию, и выпустили ее в апреле 2017 года.
чтобы шпионить за геттерами/сеттерами, которые вы используете:
const spy = spyOnProperty(myObj, 'myGetterName', 'get');
где myObj - ваш экземпляр, "myGetterName" - это имя того, которое определено в вашем классе как get myGetterName() {}
, а третий параметр - это тип get
или set
.
Вы можете использовать те же утверждения, которые вы уже используете со шпионами, созданными с помощью spyOn
.
Итак, вы можете, например:
const spy = spyOnProperty(myObj, 'myGetterName', 'get'); // to stub and return nothing. Just spy and stub.
const spy = spyOnProperty(myObj, 'myGetterName', 'get').and.returnValue(1); // to stub and return 1 or any value as needed.
const spy = spyOnProperty(myObj, 'myGetterName', 'get').and.callThrough(); // Call the real thing.
Здесь строка в исходном коде github, где этот метод доступен, если вы заинтересованы.
https://github.com/jasmine/jasmine/blob/7f8f2b5e7a7af70d7f6b629331eb6fe0a7cb9279/src/core/requireInterface.js#L199
Отвечая на исходный вопрос, с жасмином 2.6.1, вы должны:
var o = { get foo() {} };
spyOnProperty(o, 'foo', 'get').and.returnValue('bar');
Ответ 3
Я принял вдохновение от ответа @apsillers и написал следующий помощник (требуется, чтобы prop настраивался, как указано выше)
let activeSpies = [];
let handlerInstalled = false;
function afterHandler() {
activeSpies.forEach(({ obj, prop, descriptor }) => Object.defineProperty(obj, prop, descriptor));
activeSpies = [];
}
export function spyOnGetter(obj, prop) {
const env = jasmine.getEnv();
const descriptor = Object.getOwnPropertyDescriptor(obj, prop);
const spy = jasmine.createSpy(`${prop} spy`);
const copy = Object.assign({}, descriptor, { get: spy });
Object.defineProperty(obj, prop, copy);
activeSpies.push({
obj,
prop,
descriptor,
});
if (!handlerInstalled) {
handlerInstalled = true;
env.afterEach(() => afterHandler());
}
return spy;
}
И его можно использовать так:
import { spyOnGetter } from spyExtra;
it('tests the thing', () => {
spyOnGetter(myObj, 'myProp').and.returnValue(42);
expect(myObj.myProp).toBe(42);
});
Надеюсь, это полезно!
Ответ 4
Я думаю, что лучший способ - использовать spyOnProperty
. Он ожидает 3 свойства, и вам необходимо передать get
или set
в качестве третьего свойства.
spyOnProperty(o, 'foo', 'get').and.returnValue('bar');
Ответ 5
Я не верю, что ты можешь шпионить за геттерами. Точка геттера заключается в том, что он действует точно так же, как свойство, поэтому как жасмин сможет шпионить за ним, когда он никогда не вызывается как функция, а скорее доступен как свойство.
В качестве обходного пути вы можете заставить ваш getter вызвать другую функцию и вместо этого заглянуть туда.
var o = {
_foo: function(){
return 'foo';
},
get foo(){
return this._foo();
}
};
spyOn(o, '_foo').and.returnValue('bar');
Ответ 6
Вы можете сделать это, если не сможете использовать последний жасмин (2.6.1)
const getSpy = jasmine.createSpy().and.returnValue('bar')
Object.defineProperty(o, 'foo', { get: getSpy });
Документация для defineProperty, здесь