@deepkit/core
Version:
Deepkit core library
479 lines • 16.4 kB
JavaScript
import { expect, test } from '@jest/globals';
import { asyncOperation, changeClass, collectForMicrotask, createDynamicClass, getClassName, getClassTypeFromInstance, getObjectKeysSize, getParentClass, getPathValue, isArray, isAsyncFunction, isClass, isClassInstance, isConstructable, isFunction, isNumeric, isObject, isPlainObject, isPromise, isPrototypeOfBase, isUndefined, setPathValue, sleep, stringifyValueWithType } from '../src/core';
class SimpleClass {
constructor(name) {
this.name = name;
}
}
SimpleClass.__type = ['name', 'constructor', 'P&2!:"0"5'];
test('helper getClassName', () => {
class User {
constructor(name) {
this.name = name;
}
}
User.__type = ['name', 'constructor', 'P&2!:"0"5'];
class MyError extends Error {
}
MyError.__type = ['5'];
expect(getClassName(new User('peter'))).toBe('User');
expect(getClassName(User)).toBe('User');
expect(getClassName(MyError)).toBe('MyError');
expect(getClassName(new MyError)).toBe('MyError');
});
test('helper isObject', () => {
expect(isObject([])).toBe(false);
expect(isObject(false)).toBe(false);
expect(isObject(true)).toBe(false);
expect(isObject(null)).toBe(false);
expect(isObject(undefined)).toBe(false);
expect(isObject(() => {
})).toBe(false);
expect(isObject(function () {
})).toBe(false);
expect(isObject(1)).toBe(false);
expect(isObject('1')).toBe(false);
expect(isObject({})).toBe(true);
expect(isObject(new Date())).toBe(true);
expect(isObject(new SimpleClass('asd'))).toBe(true);
});
test('helper isPromise', async () => {
expect(isPromise([])).toBe(false);
expect(isPromise(false)).toBe(false);
expect(isPromise(true)).toBe(false);
expect(isPromise(null)).toBe(false);
expect(isPromise(undefined)).toBe(false);
expect(isPromise(() => {
})).toBe(false);
expect(isPromise(function () {
})).toBe(false);
expect(isPromise(1)).toBe(false);
expect(isPromise('1')).toBe(false);
function foo1() {
}
foo1.__type = ['foo1', 'P"/!'];
const foo2 = () => {
};
expect(isPromise(foo1())).toBe(false);
expect(isPromise(foo2())).toBe(false);
async function foo3() {
}
foo3.__type = ['foo3', 'P"/!'];
function foo4() {
return new Promise(Object.assign((resolve) => {
resolve(1);
}, { __type: ['resolve', '', 'P"2!"/"'] }));
}
foo4.__type = ['foo4', 'P"/!'];
expect(isObject(foo3())).toBe(true);
expect(isObject(foo4())).toBe(true);
expect(isObject(await foo4())).toBe(false);
expect(isObject((async () => {
})())).toBe(true);
});
test('helper isFunction', () => {
expect(isFunction([])).toBe(false);
expect(isFunction(false)).toBe(false);
expect(isFunction(true)).toBe(false);
expect(isFunction(null)).toBe(false);
expect(isFunction(undefined)).toBe(false);
expect(isFunction(1)).toBe(false);
expect(isFunction('1')).toBe(false);
expect(isFunction({})).toBe(false);
expect(isFunction(new Date())).toBe(false);
expect(isFunction(new SimpleClass('asd'))).toBe(false);
expect(isFunction(isFunction)).toBe(true);
expect(isFunction(() => {
})).toBe(true);
expect(isFunction(async () => {
})).toBe(true);
expect(isFunction(function () {
})).toBe(true);
expect(isFunction(async function () {
})).toBe(true);
});
test('helper isAsyncFunction', () => {
expect(isAsyncFunction([])).toBe(false);
expect(isAsyncFunction(false)).toBe(false);
expect(isAsyncFunction(true)).toBe(false);
expect(isAsyncFunction(null)).toBe(false);
expect(isAsyncFunction(undefined)).toBe(false);
expect(isAsyncFunction(1)).toBe(false);
expect(isAsyncFunction('1')).toBe(false);
expect(isAsyncFunction({})).toBe(false);
expect(isAsyncFunction(new Date())).toBe(false);
expect(isAsyncFunction(new SimpleClass('asd'))).toBe(false);
expect(isAsyncFunction(isFunction)).toBe(false);
expect(isAsyncFunction(() => {
})).toBe(false);
expect(isAsyncFunction(async () => {
})).toBe(true);
expect(isAsyncFunction(function () {
})).toBe(false);
expect(isAsyncFunction(async function () {
})).toBe(true);
});
test('helper isClass', () => {
expect(isClass([])).toBe(false);
expect(isClass(false)).toBe(false);
expect(isClass(true)).toBe(false);
expect(isClass(null)).toBe(false);
expect(isClass(undefined)).toBe(false);
expect(isClass(1)).toBe(false);
expect(isClass('1')).toBe(false);
expect(isClass({})).toBe(false);
expect(isClass(new Date())).toBe(false);
expect(isClass(new SimpleClass('asd'))).toBe(false);
expect(isClass(isFunction)).toBe(false);
expect(isClass(() => {
})).toBe(false);
expect(isClass(async () => {
})).toBe(false);
expect(isClass(function () {
})).toBe(false);
expect(isClass(async function () {
})).toBe(false);
expect(isClass(SimpleClass)).toBe(true);
});
test('helper isPlainObject', () => {
expect(isPlainObject([])).toBe(false);
expect(isPlainObject(false)).toBe(false);
expect(isPlainObject(true)).toBe(false);
expect(isPlainObject(null)).toBe(false);
expect(isPlainObject(undefined)).toBe(false);
expect(isPlainObject(1)).toBe(false);
expect(isPlainObject('1')).toBe(false);
expect(isPlainObject(() => {
})).toBe(false);
expect(isPlainObject(function () {
})).toBe(false);
expect(isPlainObject(new Date())).toBe(false);
expect(isPlainObject(new SimpleClass('asd'))).toBe(false);
class O extends Object {
}
O.__type = ['5'];
expect(isPlainObject(new O)).toBe(false);
expect(isPlainObject({})).toBe(true);
expect(isPlainObject(new Object)).toBe(true);
});
test('helper is array', () => {
expect(isArray({})).toBe(false);
expect(isArray(new Date())).toBe(false);
expect(isArray(new SimpleClass('asd'))).toBe(false);
expect(isArray(false)).toBe(false);
expect(isArray(true)).toBe(false);
expect(isArray(null)).toBe(false);
expect(isArray(undefined)).toBe(false);
expect(isArray(1)).toBe(false);
expect(isArray('1')).toBe(false);
expect(isArray([])).toBe(true);
});
test('helper is isUndefined', () => {
expect(isUndefined({})).toBe(false);
expect(isUndefined(new Date())).toBe(false);
expect(isUndefined(new SimpleClass('asd'))).toBe(false);
expect(isUndefined(false)).toBe(false);
expect(isUndefined(true)).toBe(false);
expect(isUndefined(null)).toBe(false);
expect(isUndefined(1)).toBe(false);
expect(isUndefined('1')).toBe(false);
expect(isUndefined([])).toBe(false);
expect(isUndefined(undefined)).toBe(true);
});
test('test getPathValue', () => {
expect(getPathValue({
bla: 3
}, 'bla')).toBe(3);
expect(getPathValue({
bla: 3
}, 'bla2', null)).toBe(null);
expect(getPathValue({}, 'bla', 'another')).toBe('another');
});
test('test getPathValue deep', () => {
expect(getPathValue({
bla: {
mowla: 5
}
}, 'bla.mowla')).toBe(5);
expect(getPathValue({
'bla.mowla': 5
}, 'bla.mowla')).toBe(5);
expect(getPathValue({
bla: {
mowla: {
evenDeeper: true
}
}
}, 'bla.mowla.evenDeeper')).toBe(true);
expect(getPathValue({
bla: {
mowla: {
evenDeeper: true
}
}
}, 'bla.mowla')['evenDeeper']).toBe(true);
});
test('test setPathValue ', () => {
{
const obj = {};
setPathValue(obj, 'bla2', 5);
expect(obj['bla2']).toBe(5);
}
{
const obj = {};
setPathValue(obj, 'bla.mowla', 6);
expect(obj['bla']['mowla']).toBe(6);
}
});
test('asyncOperation maintain error stack trace', async () => {
class MyError extends Error {
}
MyError.__type = ['5'];
let fetched = false;
try {
async function doIt() {
await asyncOperation(Object.assign((resolve, reject) => {
setTimeout(() => {
reject(new MyError('MyError1'));
});
}, { __type: ['resolve', 'reject', '', 'P"2!"2""/#'] }));
}
doIt.__type = ['doIt', 'P"/!'];
await doIt();
}
catch (error) {
fetched = true;
expect(error).toBeInstanceOf(MyError);
expect(error.stack).toContain('MyError1');
expect(error.stack).toContain('doIt');
}
expect(fetched).toBe(true);
});
test('asyncOperation catches async errors', async () => {
class MyError extends Error {
}
MyError.__type = ['5'];
let fetched = false;
try {
async function doIt() {
await asyncOperation(Object.assign(async (resolve) => {
await sleep(0.2);
throw new MyError('MyError1');
}, { __type: ['resolve', '', 'P"2!"/"'] }));
}
doIt.__type = ['doIt', 'P"/!'];
await doIt();
}
catch (error) {
fetched = true;
expect(error).toBeInstanceOf(MyError);
expect(error.stack).toContain('MyError1');
expect(error.stack).toContain('doIt');
}
expect(fetched).toBe(true);
});
test('asyncOperation deep', async () => {
let fetched = false;
try {
async function doIt1() {
await asyncOperation(Object.assign(async (resolve) => {
await sleep(0.2);
async function doIt2() {
await asyncOperation(Object.assign(async (resolve) => {
await sleep(0.2);
throw new Error('MyError2');
}, { __type: ['resolve', '', 'P"2!"/"'] }));
}
doIt2.__type = ['doIt2', 'P"/!'];
;
await doIt2();
}, { __type: ['resolve', '', 'P"2!"/"'] }));
}
doIt1.__type = ['doIt1', 'P"/!'];
await doIt1();
}
catch (error) {
fetched = true;
expect(error.stack).toContain('MyError2');
expect(error.stack).toContain('doIt1');
expect(error.stack).toContain('doIt2');
}
expect(fetched).toBe(true);
});
test('getObjectKeysSize', async () => {
expect(getObjectKeysSize({})).toBe(0);
expect(getObjectKeysSize({ a: true })).toBe(1);
expect(getObjectKeysSize({ a: 1, b: 1, c: 3, d: 4, e: {} })).toBe(5);
});
test('isPrototypeOfBase', () => {
class Base {
}
Base.__type = ['5'];
class Child1 extends Base {
}
Child1.__type = ['5'];
class Child2 extends Base {
}
Child2.__type = ['5'];
class Child1_1 extends Child1 {
}
Child1_1.__type = ['5'];
class Child1_1_1 extends Child1_1 {
}
Child1_1_1.__type = ['5'];
expect(isPrototypeOfBase(Base, Base)).toBe(true);
expect(isPrototypeOfBase(Child1, Base)).toBe(true);
expect(isPrototypeOfBase(Child2, Base)).toBe(true);
expect(isPrototypeOfBase(Child1_1, Base)).toBe(true);
expect(isPrototypeOfBase(Child1_1, Child1)).toBe(true);
expect(isPrototypeOfBase(Child1_1_1, Base)).toBe(true);
expect(isPrototypeOfBase(Child1_1_1, Child1_1)).toBe(true);
});
test('isConstructable', () => {
var _a, _b;
expect(isConstructable((_a = class {
},
_a.__type = ['5'],
_a))).toBe(true);
expect(isConstructable((_b = class {
},
_b.__type = ['5'],
_b).bind(undefined))).toBe(true);
expect(isConstructable(function () {
})).toBe(true);
expect(isConstructable(function () {
}.bind(undefined))).toBe(true);
expect(isConstructable(() => {
})).toBe(false);
expect(isConstructable((() => {
}).bind(undefined))).toBe(false);
expect(isConstructable(async () => {
})).toBe(false);
expect(isConstructable(async function () {
})).toBe(false);
expect(isConstructable(function* () {
})).toBe(false);
//the runtime type transformer converts this to `{foo: function() {}}.foo` which is constructable again :(
// expect(isConstructable({foo() {}}.foo)).toBe(false);
expect(isConstructable(URL)).toBe(true);
});
test('collectForMicrotask', async () => {
let got = [];
const collected = Object.assign((strings) => {
got.length = 0;
got.push(...strings);
}, { __type: ['strings', '', 'P&F2!"/"'] });
const fn = collectForMicrotask(collected);
fn('a');
fn('b');
fn('c');
await sleep(0.1);
expect(got).toEqual(['a', 'b', 'c']);
fn('d');
await sleep(0.1);
expect(got).toEqual(['d']);
});
test('stringifyValueWithType', async () => {
class Peter {
constructor() {
this.id = 1;
}
}
Peter.__type = ['5'];
expect(stringifyValueWithType(new Peter)).toBe(`Peter {id: number(1)}`);
expect(stringifyValueWithType({ id: 1 })).toBe(`object {id: number(1)}`);
expect(stringifyValueWithType('foo')).toBe(`string(foo)`);
expect(stringifyValueWithType(2)).toBe(`number(2)`);
expect(stringifyValueWithType(true)).toBe(`boolean(true)`);
expect(stringifyValueWithType(Object.assign(function Peter() {
}, { __type: ['Peter', 'P"/!'] }))).toBe(`function Peter`);
});
test('getClassTypeFromInstance', async () => {
class Peter {
}
Peter.__type = ['5'];
expect(getClassTypeFromInstance(new Peter)).toBe(Peter);
expect(() => getClassTypeFromInstance({})).toThrow('Value is not a class instance');
expect(() => getClassTypeFromInstance('asd')).toThrow('Value is not a class instance');
expect(() => getClassTypeFromInstance(23)).toThrow('Value is not a class instance');
expect(() => getClassTypeFromInstance(undefined)).toThrow('Value is not a class instance');
});
test('isClassInstance', async () => {
class Peter {
}
Peter.__type = ['5'];
expect(isClassInstance(new Peter)).toBe(true);
expect(isClassInstance({})).toBe(false);
expect(isClassInstance('asd')).toBe(false);
expect(isClassInstance(undefined)).toBe(false);
expect(isClassInstance(null)).toBe(false);
expect(isClassInstance(3223)).toBe(false);
});
test('isClassInstance', async () => {
class Model1 {
constructor() {
this.id = 0;
}
}
Model1.__type = ['id', function () { return 0; }, '\'3!>"5'];
class Base {
}
Base.__type = ['5'];
class Model2 extends Base {
constructor() {
super(...arguments);
this.id = 0;
}
model2() {
return true;
}
}
Model2.__type = ['id', function () { return 0; }, 'model2', '\'3!>"P"0#5'];
const model1 = new Model1;
model1.id = 22;
changeClass(model1, Model2);
expect(model1 instanceof Model1).toBe(true);
expect(changeClass(model1, Model2) instanceof Model2).toBe(true);
expect(changeClass(model1, Model2) instanceof Base).toBe(true);
expect(changeClass(model1, Model2) instanceof Model1).toBe(false);
expect(changeClass(model1, Model2).model2()).toBe(true);
});
test('createDynamicClass', () => {
const class1 = createDynamicClass('Model');
expect(getClassName(class1)).toBe('Model');
expect(getClassName(new class1)).toBe('Model');
expect(class1.toString()).toBe('class Model {}');
class Base {
}
Base.__type = ['5'];
const class2 = createDynamicClass('Model2', Base);
expect(getClassName(class2)).toBe('Model2');
expect(getClassName(new class2)).toBe('Model2');
expect(new class2).toBeInstanceOf(Base);
expect(class2.toString()).toBe('class Model2 extends Base {}');
});
test('isNumeric', () => {
expect(isNumeric(12)).toBe(true);
expect(isNumeric(12.2)).toBe(true);
expect(isNumeric('12')).toBe(true);
expect(isNumeric('12.2')).toBe(true);
expect(isNumeric('12.2 ')).toBe(false);
expect(isNumeric('12..2')).toBe(false);
});
test('getParentClass', () => {
class User {
}
User.__type = ['5'];
class Admin extends User {
}
Admin.__type = ['5'];
class SuperAdmin extends Admin {
}
SuperAdmin.__type = ['5'];
expect(getParentClass({})).toBe(undefined);
expect(getParentClass(Object)).toBe(undefined);
expect(getParentClass(User)).toBe(undefined);
expect(getParentClass(Admin)).toBe(User);
expect(getParentClass(SuperAdmin)).toBe(Admin);
});
//# sourceMappingURL=core.spec.js.map