qiankun-fit/src/sandbox/__tests__/common.test.ts
叡山电车 e807cbcfb6 🐛 keep toString always return original value for function in sandbox (#1785)
* fix: correct toString for functions

* Update src/sandbox/common.ts

* Update src/sandbox/common.ts

* handle getter in toString descriptor

* toString function predict

Co-authored-by: Kuitos <kuitos.lau@gmail.com>
2021-11-04 17:19:36 +08:00

83 lines
3.0 KiB
TypeScript

/**
* @author Kuitos
* @since 2021-04-12
*/
import { getTargetValue } from '../common';
describe('getTargetValue', () => {
it('should work well', () => {
const a1 = getTargetValue(window, undefined);
expect(a1).toEqual(undefined);
const a2 = getTargetValue(window, null);
expect(a2).toEqual(null);
const a3 = getTargetValue(window, function bindThis(this: any) {
return this;
});
const a3returns = a3();
expect(a3returns).toEqual(window);
});
it('should work well while function added prototype methods after first running', () => {
function prototypeAddedAfterFirstInvocation(this: any, field: string) {
this.field = field;
}
const notConstructableFunction = getTargetValue(window, prototypeAddedAfterFirstInvocation);
// `this` of not constructable function will be bound automatically, and it can not be changed by calling with special `this`
const result = {};
notConstructableFunction.call(result, '123');
expect(result).toStrictEqual({});
expect(window.field).toEqual('123');
prototypeAddedAfterFirstInvocation.prototype.addedFn = () => {};
const constructableFunction = getTargetValue(window, prototypeAddedAfterFirstInvocation);
// `this` coule be available if it be predicated as a constructable function
const result2 = {};
constructableFunction.call(result2, '456');
expect(result2).toStrictEqual({ field: '456' });
// window.field not be affected
expect(window.field).toEqual('123');
// reference should be stable after first running
expect(constructableFunction).toBe(getTargetValue(window, prototypeAddedAfterFirstInvocation));
});
it('should work well while value have a readonly prototype on its prototype chain', () => {
function callableFunction() {}
const functionWithReadonlyPrototype = () => {};
Object.defineProperty(functionWithReadonlyPrototype, 'prototype', {
writable: false,
enumerable: false,
configurable: false,
value: 123,
});
Object.setPrototypeOf(callableFunction, functionWithReadonlyPrototype);
const boundFn = getTargetValue(window, callableFunction);
expect(boundFn.prototype).toBe(callableFunction.prototype);
});
it("should work well while function's toString()'s return value keeps the same as the origin", () => {
function callableFunction1() {}
function callableFunction2() {}
function callableFunction3() {}
callableFunction2.toString = () => 'instance toString';
Object.defineProperty(callableFunction3, 'toString', {
get() {
return () => 'instance toString';
},
});
const boundFn1 = getTargetValue(window, callableFunction1);
const boundFn2 = getTargetValue(window, callableFunction2);
const boundFn3 = getTargetValue(window, callableFunction3);
expect(boundFn1.toString()).toBe(callableFunction1.toString());
expect(boundFn2.toString()).toBe(callableFunction2.toString());
expect(boundFn3.toString()).toBe(callableFunction3.toString());
});
});