Spaces:
Paused
Paused
import { vi, it, expect } from 'vitest' | |
import { createProxy } from './createProxy' | |
it('does not interfere with default constructors', () => { | |
const ProxyClass = createProxy( | |
class { | |
constructor(public name: string) {} | |
}, | |
{} | |
) | |
const instance = new ProxyClass('John') | |
expect(instance.name).toBe('John') | |
}) | |
it('does not interfere with default getters', () => { | |
const proxy = createProxy({ foo: 'initial' }, {}) | |
expect(proxy.foo).toBe('initial') | |
}) | |
it('does not interfere with default setters', () => { | |
const proxy = createProxy({ foo: 'initial' }, {}) | |
proxy.foo = 'next' | |
expect(proxy.foo).toBe('next') | |
}) | |
it('does not interfere with default methods', () => { | |
const proxy = createProxy({ getValue: () => 'initial' }, {}) | |
expect(proxy.getValue()).toBe('initial') | |
}) | |
it('does not interfere with existing descriptors', () => { | |
const target = {} as { foo: string; bar: number } | |
let internalBar = 0 | |
Object.defineProperties(target, { | |
foo: { | |
get: () => 'initial', | |
}, | |
bar: { | |
set: (value) => { | |
internalBar = value + 10 | |
}, | |
}, | |
}) | |
const proxy = createProxy(target, { | |
getProperty(data, next) { | |
return next() | |
}, | |
}) | |
expect(proxy.foo).toBe('initial') | |
proxy.bar = 5 | |
expect(proxy.bar).toBeUndefined() | |
expect(internalBar).toBe(15) | |
}) | |
it('infer prototype descriptors', () => { | |
class Child { | |
ok: boolean | |
set status(nextStatus: number) { | |
this.ok = nextStatus >= 200 && nextStatus < 300 | |
} | |
} | |
Object.defineProperties(Child.prototype, { | |
status: { enumerable: true }, | |
}) | |
const scope = {} as { child: typeof Child } | |
Object.defineProperty(scope, 'child', { | |
enumerable: true, | |
value: Child, | |
}) | |
const ProxyClass = createProxy(scope.child, {}) | |
const instance = new ProxyClass() | |
instance.status = 201 | |
expect(instance.ok).toBe(true) | |
}) | |
it('spies on the constructor', () => { | |
const OriginalClass = class { | |
constructor(public name: string, public age: number) {} | |
} | |
const constructorCall = vi.fn< | |
[ConstructorParameters<typeof OriginalClass>, Function], | |
typeof OriginalClass | |
>((args, next) => next()) | |
const ProxyClass = createProxy(OriginalClass, { | |
constructorCall, | |
}) | |
new ProxyClass('John', 32) | |
expect(constructorCall).toHaveBeenCalledTimes(1) | |
expect(constructorCall).toHaveBeenCalledWith( | |
['John', 32], | |
expect.any(Function) | |
) | |
}) | |
it('spies on property getters', () => { | |
const getProperty = vi.fn((args, next) => next()) | |
const proxy = createProxy({ foo: 'initial' }, { getProperty }) | |
proxy.foo | |
expect(getProperty).toHaveBeenCalledTimes(1) | |
expect(getProperty).toHaveBeenCalledWith(['foo', proxy], expect.any(Function)) | |
}) | |
it('spies on property setters', () => { | |
const setProperty = vi.fn((args, next) => next()) | |
const proxy = createProxy({ foo: 'initial' }, { setProperty }) | |
proxy.foo = 'next' | |
expect(setProperty).toHaveBeenCalledTimes(1) | |
expect(setProperty).toHaveBeenCalledWith( | |
['foo', 'next'], | |
expect.any(Function) | |
) | |
}) | |
it('spies on method calls', () => { | |
const methodCall = vi.fn((args, next) => next()) | |
const proxy = createProxy( | |
{ | |
greet: (name: string) => `hello ${name}`, | |
}, | |
{ methodCall } | |
) | |
proxy.greet('Clair') | |
expect(methodCall).toHaveBeenCalledTimes(1) | |
expect(methodCall).toHaveBeenCalledWith( | |
['greet', ['Clair']], | |
expect.any(Function) | |
) | |
}) | |
it('proxies properties on the prototype level', () => { | |
const method = vi.fn() | |
const prototype = { method } | |
const proxy = createProxy(Object.create(prototype), {}) | |
const proxyMethod = vi.fn() | |
proxy.method = proxyMethod | |
prototype.method() | |
expect(method).toHaveBeenCalledTimes(0) | |
expect(proxyMethod).toHaveBeenCalledTimes(1) | |
}) | |