UNPKG

@deepkit/core

Version:
538 lines (454 loc) 14.9 kB
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(public name: string) { } } test('helper getClassName', () => { class User { constructor(public readonly name: string) { } } class MyError extends Error { } 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() { } const foo2 = () => { }; expect(isPromise(foo1())).toBe(false); expect(isPromise(foo2())).toBe(false); async function foo3() { } function foo4() { return new Promise((resolve) => { resolve(1); }); } 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 { } 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: any = {}; setPathValue(obj, 'bla2', 5); expect(obj['bla2']).toBe(5); } { const obj: any = {}; setPathValue(obj, 'bla.mowla', 6); expect(obj['bla']['mowla']).toBe(6); } }); test('asyncOperation maintain error stack trace', async () => { class MyError extends Error { } let fetched = false; try { async function doIt() { await asyncOperation((resolve, reject) => { setTimeout(() => { reject(new MyError('MyError1')); }); }); } await doIt(); } catch (error: any) { 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 { } let fetched = false; try { async function doIt() { await asyncOperation(async (resolve) => { await sleep(0.2); throw new MyError('MyError1'); }); } await doIt(); } catch (error: any) { 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(async (resolve) => { await sleep(0.2); async function doIt2() { await asyncOperation(async (resolve) => { await sleep(0.2); throw new Error('MyError2'); }); }; await doIt2(); }); } await doIt1(); } catch (error: any) { 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 { } class Child1 extends Base { } class Child2 extends Base { } class Child1_1 extends Child1 { } class Child1_1_1 extends Child1_1 { } 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', () => { expect(isConstructable(class { })).toBe(true); expect(isConstructable(class { }.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: string[] = []; const collected = (strings: string[]) => { got.length = 0; got.push(...strings); }; 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 { id = 1; } 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(function Peter() { })).toBe(`function Peter`); }); test('getClassTypeFromInstance', async () => { class Peter { } 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 { } 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 { id: number = 0; } class Base { } class Model2 extends Base { id: number = 0; model2() { return true; } } 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 { } 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 {} class Admin extends User {} class SuperAdmin extends Admin {} expect(getParentClass({} as any)).toBe(undefined); expect(getParentClass(Object)).toBe(undefined); expect(getParentClass(User)).toBe(undefined); expect(getParentClass(Admin)).toBe(User); expect(getParentClass(SuperAdmin)).toBe(Admin); });