From e5a760cfe2b65868472a2a8593dc482ce8db5f00 Mon Sep 17 00:00:00 2001 From: Arturo Riveron Borodovisina Date: Wed, 16 Mar 2022 15:12:03 +0100 Subject: [PATCH] test(utils): increase test coverage chunk 2 --- src/util.js | 5 +- test/tests/global.js | 1 + test/tests/util/awaitKey.js | 28 ++ test/tests/util/base64encode.js | 17 -- test/tests/util/commons.js | 372 +++++++++++++++++++++++ test/tests/util/defineLazyProp.js | 54 ++++ test/tests/util/deserializePrimitive.js | 38 +++ test/tests/util/dotify.js | 21 +- test/tests/util/eventEmitter.js | 66 ++++ test/tests/util/extend.js | 22 ++ test/tests/util/get.js | 54 ++++ test/tests/util/index.js | 17 +- test/tests/util/isPlainObject.js | 57 ++++ test/tests/util/match.js | 13 + test/tests/util/memoize.js | 23 +- test/tests/util/patch.js | 23 ++ test/tests/util/promiseDebounce.js | 50 +++ test/tests/util/regex.js | 45 +++ test/tests/util/replaceObject.js | 45 +++ test/tests/util/safeInterval.js | 15 + test/tests/util/serialize.js | 80 +++++ test/tests/util/stringify.js | 13 + test/tests/util/stringifyError.js | 108 +++++++ test/tests/util/stringifyErrorMessage.js | 8 +- test/tests/util/values.js | 25 ++ 25 files changed, 1172 insertions(+), 28 deletions(-) create mode 100644 test/tests/util/awaitKey.js delete mode 100644 test/tests/util/base64encode.js create mode 100644 test/tests/util/commons.js create mode 100644 test/tests/util/defineLazyProp.js create mode 100644 test/tests/util/deserializePrimitive.js create mode 100644 test/tests/util/eventEmitter.js create mode 100644 test/tests/util/get.js create mode 100644 test/tests/util/isPlainObject.js create mode 100644 test/tests/util/match.js create mode 100644 test/tests/util/patch.js create mode 100644 test/tests/util/promiseDebounce.js create mode 100644 test/tests/util/regex.js create mode 100644 test/tests/util/replaceObject.js create mode 100644 test/tests/util/safeInterval.js create mode 100644 test/tests/util/stringify.js create mode 100644 test/tests/util/stringifyError.js create mode 100644 test/tests/util/values.js diff --git a/src/util.js b/src/util.js index 30af21b4..8b256dcf 100644 --- a/src/util.js +++ b/src/util.js @@ -1,4 +1,3 @@ - /* @flow */ /* eslint max-lines: 0 */ @@ -557,7 +556,7 @@ export function objFilter(obj : { [string] : T }, filter? : (T, ?string) = const result = {}; for (const key in obj) { - if (!obj.hasOwnProperty(key) || !filter(obj[key], key)) { + if (!obj.hasOwnProperty(key) || (filter && !filter(obj[key], key))) { continue; } @@ -687,7 +686,7 @@ export function undotify(obj : { [string] : string }) : Object { } else { value = deserializePrimitive(value); } - + let keyResult = result; const parts = key.split('.'); for (let i = 0; i < parts.length; i++) { diff --git a/test/tests/global.js b/test/tests/global.js index 86cda84a..1daa84e8 100644 --- a/test/tests/global.js +++ b/test/tests/global.js @@ -12,6 +12,7 @@ describe('experiment', () => { } delete window.__goku__latest_global__; }); + it('should return default value from the namespace', () => { const { get } = getGlobalNameSpace({ name: 'goku' }); const res = get('vegeta', 'testingDatDefaultValue'); diff --git a/test/tests/util/awaitKey.js b/test/tests/util/awaitKey.js new file mode 100644 index 00000000..ccd82121 --- /dev/null +++ b/test/tests/util/awaitKey.js @@ -0,0 +1,28 @@ +/* @flow */ + +import { awaitKey } from '../../../src'; + +describe('awaitKey cases', () => { + it('awaitKey should return the value when existing', () => { + const obj = { + custom: true + }; + const result = awaitKey(obj, 'custom'); + + if (!result) { + throw new Error(`should return "true", but got: ${ result }`); + } + }); + + it('awaitKey should return the configured value when does not exists', () => { + const obj = {}; + + awaitKey(obj, 'custom'); + obj.custom = 'result'; + const result = obj.custom; + + if (result !== 'result') { + throw new Error(`should return "result", but got: ${ result }`); + } + }); +}); diff --git a/test/tests/util/base64encode.js b/test/tests/util/base64encode.js deleted file mode 100644 index f80c9e56..00000000 --- a/test/tests/util/base64encode.js +++ /dev/null @@ -1,17 +0,0 @@ -/* @flow */ - -import { base64encode } from '../../../src'; - -describe('domainMatches', () => { - - it('should return true when domain matches', () => { - const original = 'ewewgweg'; - const expected = 'ZXdld2d3ZWc'; - - const result = base64encode(original); - - if (result !== expected) { - throw new Error(`Expected base64 of ${ original } to be ${ expected }, got ${ result }`); - } - }); -}); diff --git a/test/tests/util/commons.js b/test/tests/util/commons.js new file mode 100644 index 00000000..6088b3a2 --- /dev/null +++ b/test/tests/util/commons.js @@ -0,0 +1,372 @@ +/* @flow */ + +import { ZalgoPromise } from '@krakenjs/zalgo-promise/dist/zalgo-promise'; + +import { + perc, min, max, roundUp, regexMap, svgToBase64, + objFilter, regexTokenize, camelToDasherize, dasherizeToCamel, + capitalizeFirstLetter, arrayFrom, isObject, isObjectObject, + copyProp, cycle, weakMapMemoize, weakMapMemoizePromise, + tryCatch, assertExists, unique, constHas, promiseIdentity, + isElement, getObjectID, hashStr, safeTimeout, cleanup, + dedupeErrors, ExtendableError +} from '../../../src/util'; + +describe('util cases', () => { + const sourceValues = [ 7, 30, 1 ]; + + it('perc', () => { + const result = perc(1000, 50); + + if (result !== 500) { + throw new Error(`should return the value "500", but got: ${ result }`); + } + }); + + it('min', () => { + const result = min(...sourceValues); + + if (result !== 1) { + throw new Error(`should return the minimum value "1", but got: ${ result }`); + } + }); + + it('max', () => { + const result = max(...sourceValues); + + if (result !== 30) { + throw new Error(`should return the maximum value "30", but got: ${ result }`); + } + }); + + it('roundUp', () => { + const result = roundUp(10, 5); + + if (result !== 10) { + throw new Error(`should return the roundUp value "10", but got: ${ result }`); + } + }); + + it('roundUp', () => { + const result = roundUp(10, 6); + + if (result !== 12) { + throw new Error(`should return the roundUp value "12", but got: ${ result }`); + } + }); + + it('regexMap', () => { + const expectedResult = 'test'; + // $FlowFixMe[incompatible-call] + const result = regexMap(expectedResult, /[a-z]*/); + + if (result[0] !== expectedResult) { + throw new Error(`should get the value "${ expectedResult }", but got: ${ String(result) }`); + } + }); + + it('svgToBase64', () => { + const expectedResult = 'data:image/svg+xml;base64,YQ'; + // $FlowFixMe[incompatible-call] + const result = svgToBase64('a'); + + if (result !== expectedResult) { + throw new Error(`should get the value "${ expectedResult }", but got: ${ String(result) }`); + } + }); + + it('objFilter', () => { + const result = objFilter({ value: true, value1: false }, value => value); + + if (!result.value) { + throw new Error(`should get the value "true" from key, but got: ${ String(result) }`); + } + }); + + it('regexTokenize', () => { + const expectedResult = 'test'; + const result = regexTokenize(expectedResult, /[a-z]+/); + + if (result[0] !== expectedResult) { + throw new Error(`should get the value "${ expectedResult }" from key, but got: ${ String(result) }`); + } + }); + + it('camelToDasherize and dasherizeToCamel', () => { + const dasherize = camelToDasherize('TestCase'); + const undasherize = dasherizeToCamel(dasherize); + + if (dasherize !== '-test-case' || undasherize !== 'TestCase') { + throw new Error(`should dasherize and undasherize values, but got dasherize: ${ String(dasherize) } and undasherize: ${ undasherize }`); + } + }); + + it('capitalizeFirstLetter', () => { + const expectedResult = 'Test'; + const result = capitalizeFirstLetter('test'); + + if (result !== expectedResult) { + throw new Error(`should return the value "${ expectedResult }", but got ${ String(result) }`); + } + }); + + it('arrayFrom', () => { + const result = arrayFrom([ 1, 2, 3 ]); + + if (result.length !== 3) { + throw new Error(`should return an array with length "3", but got ${ String(result) }`); + } + }); + + it('isObject', () => { + const result = isObject({}); + + if (!result) { + throw new Error(`should return the value "true", but got ${ String(result) }`); + } + }); + + it('isObjectObject', () => { + const result = isObjectObject({}); + + if (!result) { + throw new Error(`should return the value "true", but got ${ String(result) }`); + } + }); + + it('copyProp should copy the name property from source object', () => { + const target = {}; + copyProp({ value: 1 }, target, 'value'); + + if (!target.value) { + throw new Error(`should copy the property "value" in the target object`); + } + }); + + it('copyProp should copy the name property from default value', () => { + const target = {}; + copyProp({}, target, 'value', 1); + + if (!target.value) { + throw new Error(`should copy the property "value" in the target object`); + } + }); + + it('cycle', () => { + const expectedErrorMessage = 'unexpected'; + try { + cycle(() => { + throw new Error(expectedErrorMessage); + }); + } catch (err) { + if (err.message !== expectedErrorMessage) { + throw new Error(`should throw the error message "${ expectedErrorMessage }", but got: ${ err.message }`); + } + } + }); + + it('weakMapMemoize', () => { + const result = weakMapMemoize(() => true)('value'); + + if (!result) { + throw new Error(`should return the value "true", but got: ${ result }`); + } + }); + + it('weakMapMemoizePromise', async () => { + const customMethod = () => { + return new ZalgoPromise(resolve => { + resolve(true); + }); + }; + const result = await weakMapMemoizePromise(customMethod)('value'); + + if (!result) { + throw new Error(`should return the value "true", but got: ${ result }`); + } + }); + + it('tryCatch should return the method execution', () => { + const { result, error } = tryCatch(() => true); + + if (!result || error) { + throw new Error(`should execute the method with no errors, but got: ${ String(error) }`); + } + }); + + it('tryCatch should return the method execution', () => { + const expectedErrorMessage = 'unexpected'; + // eslint-disable-next-line no-unused-vars + const { result, error } = tryCatch(() => { + throw new Error(expectedErrorMessage); + }); + // $FlowFixMe[incompatible-type] + if (error.message !== expectedErrorMessage) { + // $FlowFixMe[incompatible-use] + throw new Error(`should return error message "${ expectedErrorMessage }", but got: ${ error.message }`); + } + }); + + it('assertExists should thrown an error', () => { + const expectedErrorMessage = 'Expected value to be present'; + try { + assertExists('value', null); + } catch (err) { + if (err.message !== expectedErrorMessage) { + throw new Error(`should return error message "${ expectedErrorMessage }", but got: ${ err.message }`); + } + } + }); + + it('assertExists should return second argument', () => { + const thing = {}; + const result = assertExists('value', thing); + + if (!Object.is(thing, result)) { + throw new Error('should return the exact same oject, but got a different reference'); + } + }); + + it('unique', () => { + const result = unique([ '1', '1', '1' ]); + + if (result.length > 1 || result[0] !== '1') { + throw new Error(`should return unique values, but got: ${ String(result) }`); + } + }); + + it('constHas', () => { + const result = constHas({ 'test': 'test' }, 'test'); + + if (!result) { + throw new Error(`should return value "true", but got: ${ String(result) }`); + } + }); + + it('promiseIdentity', async () => { + const result = await promiseIdentity(true); + + if (!result) { + throw new Error(`should return value "true", but got: ${ String(result) }`); + } + }); + + it('isElement', () => { + function NodeElement() { + this.style = { + color: 'red' + }; + } + NodeElement.prototype = Node.prototype; + const element = new NodeElement(); + Reflect.defineProperty(element, 'nodeType', { value: 1 }); + Reflect.defineProperty(element, 'ownerDocument', { value: {} }); + const result = isElement(element); + + if (!result) { + throw new Error(`should return is an Element with value "true", but got: ${ String(result) }`); + } + }); + + it('getObjectID should return the object id', () => { + const expectedResult = 'object:uid_'; + const result = getObjectID({ key: 'value' }); + + if (!result.startsWith(expectedResult)) { + throw new Error(`should return value starting with "${ expectedResult }", but got: ${ result }`); + } + }); + + it('getObjectID should throw an error', () => { + const expectedErrorMessage = 'Invalid object'; + try { + getObjectID(); + } catch (err) { + if (err.message !== expectedErrorMessage) { + throw new Error(`should throw the error message "${ expectedErrorMessage }", but got: ${ err.message }`); + } + } + }); + + it('hashStr', () => { + const expectedResult = 8725400074294; + const result = hashStr('test'); + + if (result !== expectedResult) { + throw new Error(`should return value ${ expectedResult }, but got: ${ result }`); + } + }); + + it('safeTimeout', () => { + let result; + const executeFunction = () => { + result = true; + }; + + safeTimeout(executeFunction, 0); + safeTimeout(() => { + if (!result) { + throw new Error(`should return value "true", but got: ${ result }`); + } + }, 100); + }); + + it('cleanup should send a register method to a queue', () => { + const item = 'value'; + const cleaner = cleanup({}); + const result = cleaner.set('test', item); + const register = cleaner.register(() => true); + register.cancel(); + cleaner.all('error'); + + if (result !== 'value') { + throw new Error(`should get the value "${ item }", but got ${ String(result) }`); + } + }); + + it('cleanup should directly execute a register method', () => { + const item = 'value'; + const cleaner = cleanup({}); + const result = cleaner.set('test', item); + cleaner.all('error'); + cleaner.register(() => true); + + if (result !== 'value') { + throw new Error(`should get the value "${ item }", but got ${ String(result) }`); + } + }); + + it('dedupeErrors', () => { + const expectedResult = 'errorMessage'; + const error = new Error(expectedResult); + // $FlowFixMe[incompatible-use] + const result = dedupeErrors(err => err.message)(error); + + if (result !== expectedResult) { + throw new Error(`should get the value "${ expectedResult }", but got ${ String(result) }`); + } + }); + + it('ExtendableError with default stack', () => { + const expectedErrorMessage = 'customError'; + const error = new ExtendableError(expectedErrorMessage); + + if (error.message !== expectedErrorMessage) { + throw new Error(`should get the value "${ expectedErrorMessage }", but got ${ String(error.message) }`); + } + }); + + it('ExtendableError with custom stack', () => { + const original = Error.captureStackTrace; + // $FlowFixMe[cannot-write] + Error.captureStackTrace = undefined; + const expectedErrorMessage = 'customError'; + const error = new ExtendableError(expectedErrorMessage); + + if (error.message !== expectedErrorMessage) { + throw new Error(`should get the value "${ expectedErrorMessage }", but got ${ String(error.message) }`); + } + // $FlowFixMe[cannot-write] + Error.captureStackTrace = original; + }); +}); diff --git a/test/tests/util/defineLazyProp.js b/test/tests/util/defineLazyProp.js new file mode 100644 index 00000000..ca78b0e2 --- /dev/null +++ b/test/tests/util/defineLazyProp.js @@ -0,0 +1,54 @@ +/* @flow */ + +import { defineLazyProp } from '../../../src/util'; + +describe('defineLazyProp cases', () => { + let source; + + beforeEach(() => { + source = {}; + }); + + it('defineLazyProp should throw error message when typeof is array and key is not a number', () => { + const expectedErrorMessage = 'Array key must be number'; + try { + defineLazyProp([ 1 ], 'key', () => 'key'); + } catch (err) { + if (err.message !== expectedErrorMessage) { + throw new Error(`should throw the error "${ expectedErrorMessage }", but got: ${ err.message }`); + } + } + }); + + it('defineLazyProp should throw error message when typeof is object and key is not a string', () => { + const expectedErrorMessage = 'Object key must be string'; + try { + defineLazyProp({}, 2, () => 'key'); + } catch (err) { + if (err.message !== expectedErrorMessage) { + throw new Error(`should throw the error "${ expectedErrorMessage }", but got: ${ err.message }`); + } + } + }); + + it('defineLazyProp should get the property', () => { + defineLazyProp(source, 'test', () => 1); + const result = source.test; + + + // $FlowFixMe[incompatible-type] + if (result !== 1) { + throw new Error(`should return the value "1", but got: ${ String(result) }`); + } + }); + + it('defineLazyProp should set the property', () => { + defineLazyProp(source, 'test', () => true); + source.test = 30; + + // $FlowFixMe[incompatible-type] + if (source.test !== 30) { + throw new Error(`should return the an object with key "value", but got: ${ JSON.stringify(source.test) }`); + } + }); +}); diff --git a/test/tests/util/deserializePrimitive.js b/test/tests/util/deserializePrimitive.js new file mode 100644 index 00000000..08b12966 --- /dev/null +++ b/test/tests/util/deserializePrimitive.js @@ -0,0 +1,38 @@ +/* @flow */ + +import { deserializePrimitive } from '../../../src'; + +describe('deserializePrimitive cases', () => { + it('deserializePrimitive should return true', () => { + const result = deserializePrimitive('true'); + + if (result !== true) { + throw new Error(`should return "true", but got: ${ String(result) }`); + } + }); + + it('deserializePrimitive should return false', () => { + const result = deserializePrimitive('false'); + + if (result !== false) { + throw new Error(`should return "true", but got: ${ String(result) }`); + } + }); + + it('deserializePrimitive should return numeric value', () => { + const result = deserializePrimitive('10'); + + if (result !== 10) { + throw new Error(`should return "true", but got: ${ String(result) }`); + } + }); + + + it('deserializePrimitive should return float value', () => { + const result = deserializePrimitive('10.57'); + + if (result !== 10.57) { + throw new Error(`should return "true", but got: ${ String(result) }`); + } + }); +}); diff --git a/test/tests/util/dotify.js b/test/tests/util/dotify.js index d146e667..d62f9de4 100644 --- a/test/tests/util/dotify.js +++ b/test/tests/util/dotify.js @@ -5,7 +5,6 @@ import { dotify, undotify } from '../../../src'; describe('dotify cases', () => { it('should dotify and undotify to give the same result', () => { - const data = { foo: 'bar', baz: [ 1, 2, 3 ], @@ -18,7 +17,8 @@ describe('dotify cases', () => { }, zorg: 'zerg', berk: 'me,erk' - } + }, + func: () => true }; const dotified = dotify(data); @@ -28,4 +28,21 @@ describe('dotify cases', () => { throw new Error(`Does not match. Original data:\n\n${ JSON.stringify(data, null, 4) }\n\nDotified:\n\n${ JSON.stringify(dotified, null, 4) }\n\nUndotified:\n\n${ JSON.stringify(undotified, null, 4) }`); } }); + + it('undotify should throw an error', () => { + const expectedErrorMessage = 'Disallowed key: constructor'; + const data = { + 'test': Object.prototype, + 'constructor.part': 'error' + }; + + try { + // $FlowFixMe[incompatible-call] + undotify(data); + } catch (err) { + if (err.message !== expectedErrorMessage) { + throw new Error(`should throw the error message "${ expectedErrorMessage }", but got: ${ err.message }`); + } + } + }); }); diff --git a/test/tests/util/eventEmitter.js b/test/tests/util/eventEmitter.js new file mode 100644 index 00000000..c93f33c8 --- /dev/null +++ b/test/tests/util/eventEmitter.js @@ -0,0 +1,66 @@ + +/* @flow */ + +import { eventEmitter } from '../../../src/util'; + +describe('eventEmitter cases', () => { + const eventName = 'click'; + let click = false; + const handler = () => { + click = true; + }; + + beforeEach(() => { + click = false; + }); + + it('eventEmitter should return the emitter object', () => { + const emitter = eventEmitter(); + + if (typeof emitter !== 'object') { + throw new TypeError(`should get the emitter object, but got ${ JSON.stringify(emitter) }`); + } + }); + + it('eventEmitter should resolve the handler when on event', async () => { + const emitter = eventEmitter(); + const emitterOnEvent = emitter.on(eventName, handler); + await emitter.trigger(eventName); + emitterOnEvent.cancel(); + if (!click) { + throw new Error(`should call the event "${ eventName }" with the result "true", but got ${ String(click) }`); + } + }); + + it('eventEmitter should resolve the handler when calling trigger', async () => { + const emitter = eventEmitter(); + emitter.once(eventName, handler); + await emitter.trigger(eventName); + + if (!click) { + throw new Error(`should call once the event "${ eventName }" with the result "true", but got ${ String(click) }`); + } + }); + + it('eventEmitter should resolve the handler once when calling triggerOnce', async () => { + const emitter = eventEmitter(); + emitter.once(eventName, handler); + emitter.triggerOnce(eventName); + await emitter.triggerOnce(eventName); + + if (!click) { + throw new Error(`should trigger once the event "${ eventName }" with the result "true", but got ${ String(click) }`); + } + }); + + it('eventEmitter should reset all registered handlers', async () => { + const emitter = eventEmitter(); + emitter.on(eventName, handler); + emitter.reset(); + await emitter.trigger(eventName); + + if (click !== false) { + throw new Error(`should not found the event "${ eventName }" and the result should be "undefined", but got ${ String(click) }`); + } + }); +}); diff --git a/test/tests/util/extend.js b/test/tests/util/extend.js index 28036e02..9e84e88e 100644 --- a/test/tests/util/extend.js +++ b/test/tests/util/extend.js @@ -4,6 +4,15 @@ import { extend } from '../../../src'; describe('extend cases', () => { + it('should return same object when second argument is empty', () => { + const result = extend({ a: true }); + const arrayResult = Object.entries(result).flat(); + + if (arrayResult[0] !== 'a' || !arrayResult[1]) { + throw new Error(`should return the exact same first argument object, but got: ${ String(result) }`); + } + }); + it('should add keys from one object to another', () => { const obj1 : Object = { 'foo': 1, @@ -31,4 +40,17 @@ describe('extend cases', () => { throw new Error(`Expected obj1.bloop to equal 6, got ${ obj1.bloop }`); } }); + + it('should return the extend object when Object.assign is not valid', () => { + const originalFunc = Object.assign; + Reflect.deleteProperty(Object, 'assign'); + const result = extend({ a: true }, { b: false }); + const arrayResult = Object.entries(result).flat(); + + if (arrayResult[0] !== 'a' || !arrayResult[1] || + arrayResult[2] !== 'b' || arrayResult[3]) { + throw new Error(`should return the extended object, but got: ${ String(result) }`); + } + Reflect.defineProperty(Object, 'assign', originalFunc); + }); }); diff --git a/test/tests/util/get.js b/test/tests/util/get.js new file mode 100644 index 00000000..f5ab4aea --- /dev/null +++ b/test/tests/util/get.js @@ -0,0 +1,54 @@ +/* @flow */ + +import { get, getOrSet } from '../../../src'; + +describe('get cases', () => { + const expectedResult = 10; + it('get should return default value', () => { + const result = get({}, '', expectedResult); + + if (result !== expectedResult) { + throw new Error(`should return value "10", but got: ${ String(result) }`); + } + }); + + it('get should get deep keys', () => { + const result = get({ value: { result: expectedResult } }, 'value.result'); + + if (result !== expectedResult) { + throw new Error(`should return value "true", but got: ${ String(result) }`); + } + }); + + it('get should get deep keys', () => { + const result = get({ value: { result: expectedResult } }, 'value.result'); + + if (result !== expectedResult) { + throw new Error(`should return value "true", but got: ${ String(result) }`); + } + }); + + it('get should get deep keys with default value', () => { + const result = get({}, 'value.result', expectedResult); + + if (result !== expectedResult) { + throw new Error(`should return value "true", but got: ${ String(result) }`); + } + }); + + it('getOrSet should get value when exists in object', () => { + const result = getOrSet({ value: true }, 'value', () => true); + + if (!result) { + throw new Error(`should return value "true", but got: ${ String(result) }`); + } + }); + + it('getOrSet should set ad get value when not exists in object', () => { + const result = getOrSet({ }, 'value', () => true); + + if (!result) { + throw new Error(`should return value "true", but got: ${ String(result) }`); + } + }); +}); diff --git a/test/tests/util/index.js b/test/tests/util/index.js index db9658a8..46107594 100644 --- a/test/tests/util/index.js +++ b/test/tests/util/index.js @@ -7,7 +7,22 @@ import './extend'; import './serialize'; import './domainMatches'; import './identity'; +import './stringify'; +import './stringifyError'; import './stringifyErrorMessage'; import './isRegex'; import './isDefined'; -import './base64encode'; +import './patch'; +import './match'; +import './awayKey'; +import './values'; +import './commons'; +import './promiseDebounce'; +import './safeInterval'; +import './deserializePrimitive'; +import './get'; +import './isPlainObject'; +import './defineLazyProp'; +import './eventEmitter'; +import './replaceObject'; +import './regex'; diff --git a/test/tests/util/isPlainObject.js b/test/tests/util/isPlainObject.js new file mode 100644 index 00000000..c0d6c9ca --- /dev/null +++ b/test/tests/util/isPlainObject.js @@ -0,0 +1,57 @@ +/* @flow */ + +import { isPlainObject } from '../../../src'; + +describe('isPlainObject cases', () => { + let entity; + + beforeEach(() => { + function Entity() { + this.description = 'test'; + } + entity = new Entity(); + }); + + it('isPlainObject should return false', () => { + const result = isPlainObject(2); + + if (result) { + throw new Error(`should return is not a plain object, but got: ${ String(result) }`); + } + }); + + it('isPlainObject should return false when constructor is not a function', () => { + entity.constructor = false; + const result = isPlainObject(entity); + + if (result) { + throw new Error(`should return is not a plain object, but got: ${ String(result) }`); + } + }); + + it('isPlainObject should return false when prototype is not an object', () => { + entity.constructor.prototype = null; + const result = isPlainObject(entity); + + if (result) { + throw new Error(`should return is not a plain object, but got: ${ String(result) }`); + } + }); + + it('isPlainObject should return false when prototype is not an object', () => { + Reflect.deleteProperty(entity.constructor.prototype, 'isPrototypeOf'); + const result = isPlainObject(entity); + + if (result) { + throw new Error(`should return is not a plain object, but got: ${ String(result) }`); + } + }); + + it('isPlainObject should return false when prototype is not an object', () => { + const result = isPlainObject({}); + + if (!result) { + throw new Error(`should return is a valid plain object, but got: ${ String(result) }`); + } + }); +}); diff --git a/test/tests/util/match.js b/test/tests/util/match.js new file mode 100644 index 00000000..4aeaa8fb --- /dev/null +++ b/test/tests/util/match.js @@ -0,0 +1,13 @@ +/* @flow */ + +import { match } from '../../../src'; + +describe('match cases', () => { + it('match should return original function', () => { + const result = match('letters', /(t[a-z]*)/i); + + if (result !== 'tters') { + throw new Error(`should return "tters", but got: ${ String(result) }`); + } + }); +}); diff --git a/test/tests/util/memoize.js b/test/tests/util/memoize.js index 71144ae4..0d97a913 100644 --- a/test/tests/util/memoize.js +++ b/test/tests/util/memoize.js @@ -1,7 +1,9 @@ /* @flow */ /* eslint max-lines: off */ -import { memoize, inlineMemoize } from '../../../src'; +import { ZalgoPromise } from '@krakenjs/zalgo-promise/dist/zalgo-promise'; + +import { memoize, inlineMemoize, memoizePromise } from '../../../src'; describe('memoize cases', () => { @@ -529,4 +531,23 @@ describe('memoize cases', () => { throw new Error(`Expected counter to be 4, got ${ counter }`); } }); + + it('inlineMemoize should execute serializeArgs with function type', () => { + const result = inlineMemoize(() => true, () => true, [ () => true ]); + + if (!result) { + throw new Error(`should return the value "true", but got: ${ result }`); + } + }); + + it('memoizePromise', async () => { + const memoizeFunction = memoizePromise(() => ZalgoPromise.resolve(true)); + // $FlowFixMe[prop-missing] + memoizeFunction.reset(); + const result = await memoizeFunction(); + + if (!result) { + throw new Error(`should return the value "true", but got: ${ result }`); + } + }); }); diff --git a/test/tests/util/patch.js b/test/tests/util/patch.js new file mode 100644 index 00000000..a07ec47e --- /dev/null +++ b/test/tests/util/patch.js @@ -0,0 +1,23 @@ +/* @flow */ + +import { patchMethod } from '../../../src'; + +describe('patchMethod cases', () => { + it('patchMethod should return original function', () => { + const obj = { + custom() : string { + return 'first'; + } + }; + const handler = ({ callOriginal }) => { + return callOriginal(); + }; + + patchMethod(obj, 'custom', handler); + const result = obj.custom(); + + if (result !== 'first') { + throw new Error(`should return "first", but got: ${ result }`); + } + }); +}); diff --git a/test/tests/util/promiseDebounce.js b/test/tests/util/promiseDebounce.js new file mode 100644 index 00000000..44ca9c78 --- /dev/null +++ b/test/tests/util/promiseDebounce.js @@ -0,0 +1,50 @@ +/* @flow */ +import { debounce, promiseDebounce, promisify } from '../../../src'; + +describe('promiseDebounce cases', () => { + it('debounce', () => { + let result; + + debounce(() => { + result = true; + }, 0)(); + debounce(() => { + if (!result) { + throw new Error(`should return the value "true", but got: ${ String(result) }`); + } + }, 100); + }); + + it('promiseDebounce should return original function', () => { + const debouncedFunc = promiseDebounce(() => true); + const result = debouncedFunc(); + + if (!debouncedFunc()) { + throw new Error(`should return the value "true", but got: ${ String(result) }`); + } + }); + + it('promiseDebounce should throw and error', () => { + const debouncedFunc = promiseDebounce(() => { + throw new Error('unexpected'); + }); + + debouncedFunc() + .catch(err => { + // $FlowFixMe[incompatible-type] + if (err.message !== 'unexpected') { + throw new Error(`should throw the error message "unexpected", but got: ${ err.message }`); + } + }); + }); + + it('promisify should execute the function as a promise', () => { + [ undefined, { name: 'method' } ].forEach(async testCase => { + const result = await promisify(() => true, testCase)(); + + if (!result) { + throw new Error(` should return value "true", but got: ${ result }`); + } + }); + }); +}); diff --git a/test/tests/util/regex.js b/test/tests/util/regex.js new file mode 100644 index 00000000..08d51b8f --- /dev/null +++ b/test/tests/util/regex.js @@ -0,0 +1,45 @@ + +/* @flow */ + +import { regex } from '../../../src/util'; + +describe('regex cases', () => { + it('regex should return "undefined" when a regex does not match', () => { + const result = regex('regex', 'source'); + + if (result !== undefined) { + throw new Error(`should get the value "undefined", but got ${ String(result) }`); + } + }); + + it('regex should return the result object when a match was found', () => { + const source = 'source'; + const result = regex('[a-z]+', source); + + if (result?.text !== source) { + throw new Error(`should get the value "source", but got ${ String(result?.text) }`); + } + }); + + it('regex should replace the resulting matching text', () => { + const source = 'source'; + const result = regex('rce', source); + // $FlowFixMe[incompatible-use] + const text = result.replace('a'); + + if (text !== 'rcea') { + throw new Error(`should get the value "rcea", but got ${ text }`); + } + }); + + it('regex should replace and return an empty string', () => { + const source = 'source'; + const result = regex('', source); + // $FlowFixMe[incompatible-use] + const text = result.replace(''); + + if (text !== '') { + throw new Error(`should get the an empty string, but got ${ text }`); + } + }); +}); diff --git a/test/tests/util/replaceObject.js b/test/tests/util/replaceObject.js new file mode 100644 index 00000000..2ea59652 --- /dev/null +++ b/test/tests/util/replaceObject.js @@ -0,0 +1,45 @@ + +/* @flow */ + +import { replaceObject } from '../../../src/util'; + +describe('replaceObject cases', () => { + + it('replaceObject should replace the array', () => { + const source = [ 1, 2, [ 3, 4 ] ]; + const result = replaceObject(source, el => el); + + if (result[0] !== 1 || result[2][1] !== 4) { + throw new Error(`should get the exact same array, but got ${ JSON.stringify(source) }`); + } + }); + + it('replaceObject should replace the object', () => { + const source = { + a: 1, + b: 2, + c: { + d: 3 + }, + __proto__: { + ignore: 1 + } + }; + const result = replaceObject(source, el => el); + + if (result.a !== 1 || result.c.d !== 3) { + throw new Error(`should get the exact same object, but got ${ JSON.stringify(source) }`); + } + }); + + it('replaceObject should replace the object', () => { + const expectedErrorMessage = 'Pass an object or array'; + try { + replaceObject(1, el => el); + } catch (err) { + if (err.message !== expectedErrorMessage) { + throw new Error(`should throw the error message "${ expectedErrorMessage }", but got ${ err.message }`); + } + } + }); +}); diff --git a/test/tests/util/safeInterval.js b/test/tests/util/safeInterval.js new file mode 100644 index 00000000..96bf6003 --- /dev/null +++ b/test/tests/util/safeInterval.js @@ -0,0 +1,15 @@ +/* @flow */ + +import { safeInterval } from '../../../src'; + +describe('safeInterval cases', () => { + it('safeInterval should safely debounce the function', () => { + safeInterval(() => true, 50); + }); + + it('safeInterval should cancel the debounced function', () => { + const result = safeInterval(() => true, 50); + + result.cancel(); + }); +}); diff --git a/test/tests/util/serialize.js b/test/tests/util/serialize.js index 55927174..2931451a 100644 --- a/test/tests/util/serialize.js +++ b/test/tests/util/serialize.js @@ -44,4 +44,84 @@ describe('serialization cases', () => { cases.forEach(encodedecode); }); + + it('base64encode should return true when domain matches', () => { + const original = 'ewewgweg'; + const expected = 'ZXdld2d3ZWc'; + + const result = base64encode(original); + + if (result !== expected) { + throw new Error(`Expected base64 of ${ original } to be ${ expected }, got ${ result }`); + } + }); + + it('base64encode should return true when domain matches and btoa is not available', () => { + const originalFn = window.btoa; + Reflect.deleteProperty(window, 'btoa'); + window.Buffer = { + from() : string { + return 'ZXdld2d3ZWc'; + } + }; + + const original = 'ewewgweg'; + const expected = 'ZXdld2d3ZWc'; + + const result = base64encode(original); + + if (result !== expected) { + throw new Error(`Expected base64 of ${ original } to be ${ expected }, got ${ result }`); + } + Reflect.deleteProperty(window, 'Buffer'); + window.btoa = originalFn; + }); + + it('base64encode should throw an error when btoa and Buffer are not available', () => { + const expectedErrorMessage = 'Can not find window.btoa or Buffer'; + const originalFn = window.btoa; + Reflect.deleteProperty(window, 'btoa'); + + try { + base64encode('ewewgweg'); + } catch (err) { + if (err.message !== expectedErrorMessage) { + throw new Error(`should throw the error message "${ expectedErrorMessage }", but got: ${ err.message }`); + } + } + window.btoa = originalFn; + }); + + it('base64decode should return decode value when btoa is not available', () => { + const expectedResult = 'test'; + const originalFn = window.atob; + Reflect.deleteProperty(window, 'atob'); + window.Buffer = { + from() : string { + return expectedResult; + } + }; + + const result = base64decode('dGVzdA=='); + if (result !== expectedResult) { + throw new Error(`should return the value "${ expectedResult }", but got: ${ expectedResult }`); + } + Reflect.deleteProperty(window, 'Buffer'); + window.atob = originalFn; + }); + + it('base64decode should throw an error when atob and Buffer are not available', () => { + const expectedErrorMessage = 'Can not find window.atob or Buffer'; + const originalFn = window.atob; + Reflect.deleteProperty(window, 'atob'); + + try { + base64decode('dGVzdA=='); + } catch (err) { + if (err.message !== expectedErrorMessage) { + throw new Error(`should throw the error message "${ expectedErrorMessage }", but got: ${ err.message }`); + } + } + window.atob = originalFn; + }); }); diff --git a/test/tests/util/stringify.js b/test/tests/util/stringify.js new file mode 100644 index 00000000..d3b09a8f --- /dev/null +++ b/test/tests/util/stringify.js @@ -0,0 +1,13 @@ +/* @flow */ + +import { stringify } from '../../../src'; + +describe('stringify cases', () => { + it('stringify should return the exact same value when is a string value', () => { + const result = stringify('1'); + + if (result !== '1') { + throw new Error(`should return value "1", but got: ${ result }`); + } + }); +}); diff --git a/test/tests/util/stringifyError.js b/test/tests/util/stringifyError.js new file mode 100644 index 00000000..53f3dfd8 --- /dev/null +++ b/test/tests/util/stringifyError.js @@ -0,0 +1,108 @@ +/* @flow */ + +import { stringifyError } from '../../../src'; + +describe('stringifyError cases', () => { + it('stringifyError should return stack overflow error message', () => { + const expectedResult = 'stringifyError stack overflow'; + const result = stringifyError('custom error', 4); + + if (result !== expectedResult) { + throw new Error(`should throw the error message "${ expectedResult }", but got: ${ result }`); + } + }); + + it('stringifyError should return unknown error message', () => { + const expectedResult = ``; + const result = stringifyError(0, 1); + + if (result !== expectedResult) { + throw new Error(`should throw the error messagee "${ expectedResult }", but got: ${ result }`); + } + }); + + it('stringifyError should return the exact same error message when is a string type', () => { + const expectedResult = `my error`; + const result = stringifyError(expectedResult, 1); + + if (result !== expectedResult) { + throw new Error(`should throw the error message "${ expectedResult }", but got: ${ result }`); + } + }); + + it('stringifyError should return only the stack when is an Error instance', () => { + const expectedResult = `custom`; + const error = new Error(expectedResult); + const result = stringifyError(error, 1); + + if (!result.startsWith(`Error: ${ expectedResult }`)) { + throw new Error(`should throw the error message starting with "Error: ${ expectedResult }", but got: ${ result }`); + } + }); + + it('stringifyError should return the only the stack when is an Error instance with empty message', () => { + const expectedResult = `at Context.`; + const error = new Error('anything not important'); + + error.message = ''; + const result = stringifyError(error, 1); + + if (!result.includes(expectedResult)) { + throw new Error(`should throw the error message starting with "${ expectedResult }", but got: ${ result }`); + } + }); + + it('stringifyError should return the only the message when is an Error instance with empty stack', () => { + const expectedResult = `error instance`; + const error = new Error(expectedResult); + + error.stack = ''; + const result = stringifyError(error, 1); + + if (result !== expectedResult) { + throw new Error(`should throw the error message "${ expectedResult }", but got: ${ result }`); + } + }); + + it('stringifyError should return the message and stack when is and Error instance and message is not include in the stack', () => { + const expectedErrorMessage = 'Error: custom at line whatever'; + const error = new Error('custom'); + + error.message = 'message'; + error.stack = expectedErrorMessage; + const result = stringifyError(error, 1); + + if (!result.endsWith(expectedErrorMessage)) { + throw new Error(`should throw the error message ending with "${ expectedErrorMessage }", but got: ${ result }`); + } + }); + + it('stringifyError should return call toString when error message is an object', () => { + const expectedErrorMessage = '[object Object]'; + const result = stringifyError({}, 1); + + if (result !== expectedErrorMessage) { + throw new Error(`should throw the error message "${ expectedErrorMessage }", but got: ${ result }`); + } + }); + + it('stringifyError should return call toString from Object.prototype when error message is object', () => { + const expectedErrorMessage = '[object Object]'; + const result = stringifyError({ toString: null }, 1); + + if (result !== expectedErrorMessage) { + throw new Error(`should throw the error message "${ expectedErrorMessage }", but got: ${ result }`); + } + }); + + it('stringifyError should handle error when something when wrong', () => { + const expectedErrorMessage = 'Error while stringifying error'; + const result = stringifyError({ toString: () => { + throw new Error('unexpected error'); + } }, 2); + + if (!result.startsWith(expectedErrorMessage)) { + throw new Error(`should throw the error message starting wit "${ expectedErrorMessage }", but got: ${ result }`); + } + }); +}); diff --git a/test/tests/util/stringifyErrorMessage.js b/test/tests/util/stringifyErrorMessage.js index 2da9fc80..cc2b1852 100644 --- a/test/tests/util/stringifyErrorMessage.js +++ b/test/tests/util/stringifyErrorMessage.js @@ -5,7 +5,7 @@ import { stringifyErrorMessage } from '../../../src'; describe('stringifyErrorMessage', () => { it('should return default error message when argument is falsy', () => { - // $FlowFixMe method-unbinding + // $FlowFixMe[method-unbinding] const defaultMessage = ``; const message = stringifyErrorMessage(); if (message !== defaultMessage) { @@ -24,7 +24,7 @@ describe('stringifyErrorMessage', () => { it('should return default message if Error instance without a message is passed', () => { // eslint-disable-next-line unicorn/error-message const error = new Error(); - // $FlowFixMe method-unbinding + // $FlowFixMe[method-unbinding] const expectedMessage = ``; const message = stringifyErrorMessage(error); if (message !== expectedMessage) { @@ -43,7 +43,7 @@ describe('stringifyErrorMessage', () => { it('should return default message if argument passed has a empty string message field', () => { const error = { message: '' }; - // $FlowFixMe method-unbinding + // $FlowFixMe[method-unbinding] const expectedMessage = ``; const message = stringifyErrorMessage(error); if (message !== expectedMessage) { @@ -53,7 +53,7 @@ describe('stringifyErrorMessage', () => { it('should return default message if a primitive argument is passed or argument has non-string value in message field', () => { const error = 42; - // $FlowFixMe method-unbinding + // $FlowFixMe[method-unbinding] const expectedMessage = ``; const message = stringifyErrorMessage(error); if (message !== expectedMessage) { diff --git a/test/tests/util/values.js b/test/tests/util/values.js new file mode 100644 index 00000000..238676a0 --- /dev/null +++ b/test/tests/util/values.js @@ -0,0 +1,25 @@ +/* @flow */ + +import { values } from '../../../src'; + +describe('values cases', () => { + + it('should return object values when Object.values is available', () => { + const result = values({ a: true }); + + if (!result[0]) { + throw new Error(`should return the value from the original object, but got: ${ String(result) }`); + } + }); + + it('should return object values when Object.values is unavailable', () => { + const originalFunc = Object.values; + Reflect.deleteProperty(Object, 'values'); + const result = values({ a: true }); + + if (!result[0]) { + throw new Error(`should return the value from the original object, but got: ${ String(result) }`); + } + Reflect.defineProperty(Object, 'values', originalFunc); + }); +});