-
-
Notifications
You must be signed in to change notification settings - Fork 187
Description
Description
I was recently mocked a CanvasRenderingContext2D, and I used let obj = createSpyObject(CanvasRenderingContext2D); to create the Spy for me. It works great for all the methods on the class, but properties aren't spyable.
So while the test succeeds because the property values are assignable and readable, I can't spy that a property was set three times with three different colors, just inspect the property value for the last one.
Proposed solution
I did a quick experiment in my project and implemented this
export type SpyObjectEx<T> = T & { [P in keyof T]: T[P] extends UnknownFunction ? T[P] & CompatibleSpy<T[P]> : T[P] } & {
/**
* Casts to type without readonly properties
*/
castToWritable(): Writable<T>
propertySpy: {
[P in keyof T]: T[P] extends UnknownFunction ? undefined : {
'get': jasmine.Spy<(this: T) => P>
'set': jasmine.Spy<(this: T, value: T[P]) => void>
}
}
};
export function installPropertySpies<T>(spy: SpyObject<T>): SpyObjectEx<T> {
const propertySpy: any = {};
Object.getOwnPropertyNames(spy).forEach((key) => {
const descriptor = Object.getOwnPropertyDescriptor(spy, key);
if (!descriptor)
return;
let propertySpies: {
get?: jasmine.Spy<(this: T) => T[keyof T]> | undefined
set?: jasmine.Spy<(this: T, value: T[keyof T]) => void> | undefined
} = {
};
if (descriptor.get || descriptor.set) {
if (descriptor.get) {
propertySpies.get = spyOnProperty<T>(spy, key as any, 'get');
propertySpies.get.and.callThrough();
}
if (descriptor.set) {
propertySpies.set = spyOnProperty<T>(spy, key as any, 'set');
propertySpies.set.and.callThrough();
}
}
propertySpy[key] = propertySpies;
});
(spy as SpyObjectEx<T>).propertySpy = propertySpy;
return spy as SpyObjectEx<T>;
}I'm thinking it could be something added to either installProtoMethods<T> or createSpyObject<T>.
It shouldn't conflict with users use are providing properties via the template, since they're not defined as properties with getters/setters.
There is some leakage for the type casing, in that Typescript won't error if a user tried spy.propertySpy['methodName'], but it should throw a compiler error on spy.propertySpy['methodName'].and as the type should be undefined.
Alternatives considered
Leaving this in my project, since it appears to do what I need it to do. And someone could copy/paste this into their's if needed.
Do you want to create a pull request?
Yes