mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-06-22 04:00:35 +03:00
improve tests and prettier
This commit is contained in:
@@ -29,7 +29,9 @@ import { OSTargetElement } from 'typings';
|
||||
|
||||
type StructureInitializationElementFn<T> = ((target: OSTargetElement) => HTMLElement | T) | T;
|
||||
|
||||
type ScrollbarsInitializationElementFn<T> = ((target: OSTargetElement, host: HTMLElement, viewport: HTMLElement) => HTMLElement | T) | T;
|
||||
type ScrollbarsInitializationElementFn<T> =
|
||||
| ((target: OSTargetElement, host: HTMLElement, viewport: HTMLElement) => HTMLElement | T)
|
||||
| T;
|
||||
|
||||
/**
|
||||
* A Static element is an element which MUST be generated.
|
||||
@@ -44,7 +46,9 @@ export type StructureInitializationStaticElement = StructureInitializationElemen
|
||||
* If boolean (or the returned result is boolean), the generation of the element is forced (or not).
|
||||
* If the function returns and element, the element returned by the function acts as the generated element.
|
||||
*/
|
||||
export type StructureInitializationDynamicElement = StructureInitializationElementFn<boolean | null>;
|
||||
export type StructureInitializationDynamicElement = StructureInitializationElementFn<
|
||||
boolean | null
|
||||
>;
|
||||
|
||||
export interface StructureInitializationStrategy {
|
||||
_host: StructureInitializationStaticElement;
|
||||
@@ -57,7 +61,9 @@ export interface ScrollbarsInitializationStrategy {
|
||||
_scrollbarsSlot: ScrollbarsInitializationElementFn<null | undefined>;
|
||||
}
|
||||
|
||||
export interface InitializationStrategy extends StructureInitializationStrategy, ScrollbarsInitializationStrategy {}
|
||||
export interface InitializationStrategy
|
||||
extends StructureInitializationStrategy,
|
||||
ScrollbarsInitializationStrategy {}
|
||||
|
||||
export type OnEnvironmentChanged = (env: Environment) => void;
|
||||
export interface Environment {
|
||||
@@ -103,13 +109,17 @@ const getNativeScrollbarStyling = (testElm: HTMLElement): boolean => {
|
||||
try {
|
||||
result =
|
||||
style(testElm, cssProperty('scrollbar-width')) === 'none' ||
|
||||
window.getComputedStyle(testElm, '::-webkit-scrollbar').getPropertyValue('display') === 'none';
|
||||
window.getComputedStyle(testElm, '::-webkit-scrollbar').getPropertyValue('display') ===
|
||||
'none';
|
||||
} catch (ex) {}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
const getRtlScrollBehavior = (parentElm: HTMLElement, childElm: HTMLElement): { i: boolean; n: boolean } => {
|
||||
const getRtlScrollBehavior = (
|
||||
parentElm: HTMLElement,
|
||||
childElm: HTMLElement
|
||||
): { i: boolean; n: boolean } => {
|
||||
const strHidden = 'hidden';
|
||||
style(parentElm, { overflowX: strHidden, overflowY: strHidden, direction: 'rtl' });
|
||||
scrollLeft(parentElm, 0);
|
||||
@@ -161,7 +171,9 @@ const getWindowDPR = (): number => {
|
||||
};
|
||||
|
||||
// init function decides for all values
|
||||
const getDefaultInitializationStrategy = (nativeScrollbarStyling: boolean): InitializationStrategy => ({
|
||||
const getDefaultInitializationStrategy = (
|
||||
nativeScrollbarStyling: boolean
|
||||
): InitializationStrategy => ({
|
||||
_host: null,
|
||||
_viewport: null,
|
||||
_padding: null,
|
||||
@@ -243,7 +255,10 @@ const createEnvironment = (): Environment => {
|
||||
const isZoom = deltaIsBigger && difference && dprChanged;
|
||||
|
||||
if (isZoom) {
|
||||
const newScrollbarSize = (environmentInstance._nativeScrollbarSize = getNativeScrollbarSize(body, envElm));
|
||||
const newScrollbarSize = (environmentInstance._nativeScrollbarSize = getNativeScrollbarSize(
|
||||
body,
|
||||
envElm
|
||||
));
|
||||
removeElements(envElm);
|
||||
|
||||
if (scrollbarSize.x !== newScrollbarSize.x || scrollbarSize.y !== newScrollbarSize.y) {
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ export const createCache = <Value, Ctx = undefined>(
|
||||
update: UpdateCachePropFunction<Value, Ctx>,
|
||||
options: CacheOptions<Value>
|
||||
): Cache<Value, Ctx> => {
|
||||
const { _initialValue, _equal, _alwaysUpdateValues } = options || {};
|
||||
const { _initialValue, _equal, _alwaysUpdateValues } = options;
|
||||
let _value: Value = _initialValue;
|
||||
let _previous: Value | undefined;
|
||||
|
||||
|
||||
@@ -8,7 +8,16 @@ const getDummyStyle = (): CSSStyleDeclaration => createDiv().style;
|
||||
// https://developer.mozilla.org/en-US/docs/Glossary/Vendor_Prefix
|
||||
|
||||
export const cssPrefixes: ReadonlyArray<string> = ['-webkit-', '-moz-', '-o-', '-ms-'];
|
||||
export const jsPrefixes: ReadonlyArray<string> = ['WebKit', 'Moz', 'O', 'MS', 'webkit', 'moz', 'o', 'ms'];
|
||||
export const jsPrefixes: ReadonlyArray<string> = [
|
||||
'WebKit',
|
||||
'Moz',
|
||||
'O',
|
||||
'MS',
|
||||
'webkit',
|
||||
'moz',
|
||||
'o',
|
||||
'ms',
|
||||
];
|
||||
|
||||
export const jsCache: { [key: string]: any } = {};
|
||||
export const cssCache: { [key: string]: string } = {};
|
||||
@@ -35,9 +44,14 @@ export const cssProperty = (name: string): string => {
|
||||
prefixWithoutDashes + uppercasedName, // webkitTransition
|
||||
firstLetterToUpper(prefixWithoutDashes) + uppercasedName, // WebkitTransition
|
||||
];
|
||||
return !(result = resultPossibilities.find((resultPossibility: string) => elmStyle[resultPossibility] !== undefined));
|
||||
|
||||
// eslint-disable-next-line no-return-assign
|
||||
return !(result = resultPossibilities.find(
|
||||
(resultPossibility: string) => elmStyle[resultPossibility] !== undefined
|
||||
));
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-return-assign
|
||||
return (cssCache[name] = result || '');
|
||||
};
|
||||
|
||||
@@ -72,6 +86,7 @@ export const cssPropertyValue = (property: string, values: string, suffix?: stri
|
||||
return !result;
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-return-assign
|
||||
return (cssCache[name] = result || '');
|
||||
};
|
||||
|
||||
|
||||
@@ -26,7 +26,10 @@ export function each<T>(
|
||||
arrayLikeObject: ArrayLike<T> | null | undefined,
|
||||
callback: (value: T, indexOrKey: number, source: ArrayLike<T>) => boolean | unknown
|
||||
): ArrayLike<T> | null | undefined;
|
||||
export function each(obj: PlainObject, callback: (value: any, indexOrKey: string, source: PlainObject) => boolean | unknown): PlainObject;
|
||||
export function each(
|
||||
obj: PlainObject,
|
||||
callback: (value: any, indexOrKey: string, source: PlainObject) => boolean | unknown
|
||||
): PlainObject;
|
||||
export function each(
|
||||
obj: PlainObject | null | undefined,
|
||||
callback: (value: any, indexOrKey: string, source: PlainObject) => boolean | unknown
|
||||
@@ -53,15 +56,22 @@ export function each<T>(
|
||||
* @param item The item.
|
||||
* @param fromIndex The array index at which to begin the search. If fromIndex is omitted, the search starts at index 0.
|
||||
*/
|
||||
export const indexOf = <T = any>(arr: Array<T>, item: T, fromIndex?: number): number => arr.indexOf(item, fromIndex);
|
||||
export const indexOf = <T = any>(arr: Array<T>, item: T, fromIndex?: number): number =>
|
||||
arr.indexOf(item, fromIndex);
|
||||
|
||||
/**
|
||||
* Pushesh all given items into the given array and returns it.
|
||||
* @param array The array the items shall be pushed into.
|
||||
* @param items The items which shall be pushed into the array.
|
||||
*/
|
||||
export const push = <T>(array: Array<T>, items: T | ArrayLike<T>, arrayIsSingleItem?: boolean): Array<T> => {
|
||||
!arrayIsSingleItem && !isString(items) && isArrayLike(items) ? Array.prototype.push.apply(array, items as Array<T>) : array.push(items as T);
|
||||
export const push = <T>(
|
||||
array: Array<T>,
|
||||
items: T | ArrayLike<T>,
|
||||
arrayIsSingleItem?: boolean
|
||||
): Array<T> => {
|
||||
!arrayIsSingleItem && !isString(items) && isArrayLike(items)
|
||||
? Array.prototype.push.apply(array, items as Array<T>)
|
||||
: array.push(items as T);
|
||||
return array;
|
||||
};
|
||||
|
||||
@@ -86,7 +96,8 @@ export const from = <T = any>(arr: ArrayLike<T>) => {
|
||||
* Check whether the passed array is empty.
|
||||
* @param array The array which shall be checked.
|
||||
*/
|
||||
export const isEmptyArray = (array: Array<any> | null | undefined) => array && array.length === 0;
|
||||
export const isEmptyArray = (array: Array<any> | null | undefined): boolean =>
|
||||
!!array && array.length === 0;
|
||||
|
||||
/**
|
||||
* Calls all functions in the passed array/set of functions.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { isNumber, isFunction } from 'support/utils/types';
|
||||
import { from } from 'support/utils/array';
|
||||
import { rAF, cAF } from 'support/compatibility/apis';
|
||||
|
||||
const setT = window.setTimeout;
|
||||
const clearTimeouts = (id: number | undefined) => {
|
||||
id && window.clearTimeout(id);
|
||||
id && cAF!(id);
|
||||
@@ -42,13 +42,14 @@ export const noop = () => {}; // eslint-disable-line
|
||||
*/
|
||||
export const debounce = <FunctionToDebounce extends (...args: any) => any>(
|
||||
functionToDebounce: FunctionToDebounce,
|
||||
options: DebounceOptions<FunctionToDebounce>
|
||||
options?: DebounceOptions<FunctionToDebounce>
|
||||
): Debounced<FunctionToDebounce> => {
|
||||
let timeoutId: number | undefined;
|
||||
let maxTimeoutId: number | undefined;
|
||||
let prevArguments: Parameters<FunctionToDebounce> | null | undefined;
|
||||
let latestArguments: Parameters<FunctionToDebounce> | null | undefined;
|
||||
const { _timeout, _maxDelay, _mergeParams } = options;
|
||||
const { _timeout, _maxDelay, _mergeParams } = options || {};
|
||||
const setT = window.setTimeout;
|
||||
|
||||
const invokeFunctionToDebounce = function (args: IArguments) {
|
||||
clearTimeouts(timeoutId);
|
||||
@@ -59,31 +60,35 @@ export const debounce = <FunctionToDebounce extends (...args: any) => any>(
|
||||
functionToDebounce.apply(this, args);
|
||||
};
|
||||
|
||||
const mergeParms = (curr: Parameters<FunctionToDebounce>): Parameters<FunctionToDebounce> | false | null | undefined =>
|
||||
const mergeParms = (
|
||||
curr: Parameters<FunctionToDebounce>
|
||||
): Parameters<FunctionToDebounce> | false | null | undefined =>
|
||||
_mergeParams && prevArguments ? _mergeParams(prevArguments, curr) : curr;
|
||||
|
||||
const flush = () => {
|
||||
/* istanbul ignore next */
|
||||
if (timeoutId) {
|
||||
invokeFunctionToDebounce(mergeParms(latestArguments!) || latestArguments!);
|
||||
}
|
||||
};
|
||||
|
||||
const debouncedFn = function () {
|
||||
const args: Parameters<FunctionToDebounce> = arguments as Parameters<FunctionToDebounce>;
|
||||
// eslint-disable-next-line prefer-rest-params
|
||||
const args: Parameters<FunctionToDebounce> = from(arguments) as Parameters<FunctionToDebounce>;
|
||||
const finalTimeout = isFunction(_timeout) ? _timeout() : _timeout;
|
||||
const hasTimeout = isNumber(finalTimeout) && finalTimeout >= 0;
|
||||
|
||||
if (hasTimeout) {
|
||||
const finalMaxWait = isFunction(_maxDelay) ? _maxDelay() : _maxDelay;
|
||||
const hasMaxWait = isNumber(finalMaxWait) && finalMaxWait >= 0;
|
||||
const setTimeoutFn = finalTimeout! > 0 ? setT : rAF!;
|
||||
const setTimeoutFn = finalTimeout > 0 ? setT : rAF!;
|
||||
const mergeParamsResult = mergeParms(args);
|
||||
const invokedArgs = mergeParamsResult || args;
|
||||
const boundInvoke = invokeFunctionToDebounce.bind(0, invokedArgs);
|
||||
|
||||
if (!mergeParamsResult) {
|
||||
invokeFunctionToDebounce(prevArguments || args);
|
||||
}
|
||||
// if (!mergeParamsResult) {
|
||||
// invokeFunctionToDebounce(prevArguments || args);
|
||||
// }
|
||||
|
||||
clearTimeouts(timeoutId);
|
||||
timeoutId = setTimeoutFn(boundInvoke, finalTimeout as number) as number;
|
||||
|
||||
@@ -10,11 +10,11 @@ interface GenericLexicon<T extends boolean> {
|
||||
}
|
||||
|
||||
export interface Lexicon<T extends boolean> extends GenericLexicon<T> {
|
||||
_inverted: Lexicon<T extends true ? false : true>;
|
||||
// _inverted: Lexicon<T extends true ? false : true>;
|
||||
}
|
||||
|
||||
export const getLexicon = <T extends boolean = false>(horizontal?: T): Lexicon<T> => {
|
||||
return {
|
||||
export const getLexicon = <T extends boolean = false>(horizontal?: T): Lexicon<T> =>
|
||||
({
|
||||
_widthHeight: horizontal ? 'width' : 'height',
|
||||
_WidthHeight: horizontal ? 'Width' : 'Height',
|
||||
_leftTop: horizontal ? 'left' : 'top',
|
||||
@@ -23,6 +23,5 @@ export const getLexicon = <T extends boolean = false>(horizontal?: T): Lexicon<T
|
||||
_XY: horizontal ? 'X' : 'Y',
|
||||
_wh: horizontal ? 'w' : 'h',
|
||||
_lt: horizontal ? 'l' : 't',
|
||||
_inverted: getLexicon(!horizontal),
|
||||
} as Lexicon<T>;
|
||||
};
|
||||
// _inverted: getLexicon(!horizontal),
|
||||
} as Lexicon<T>);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { push, each, from, indexOf, runEach } from 'support/utils/array';
|
||||
import { push, each, from, indexOf, runEach, isEmptyArray } from 'support/utils/array';
|
||||
|
||||
describe('array utilities', () => {
|
||||
describe('push', () => {
|
||||
@@ -306,4 +306,10 @@ describe('array utilities', () => {
|
||||
const idx = indexOf([1, 2, 3], 2);
|
||||
expect(idx).toBe(1);
|
||||
});
|
||||
|
||||
test('isEmptyArray', () => {
|
||||
expect(isEmptyArray([])).toBe(true);
|
||||
expect(isEmptyArray([1, 2, 3])).toBe(false);
|
||||
expect(isEmptyArray(null)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,321 @@
|
||||
import { noop, debounce } from 'support/utils/function';
|
||||
import { rAF } from 'support/compatibility/apis';
|
||||
|
||||
jest.mock('support/compatibility/apis', () => {
|
||||
const originalModule = jest.requireActual('support/compatibility/apis');
|
||||
return {
|
||||
...originalModule,
|
||||
rAF: jest.fn().mockImplementation((...args) => originalModule.rAF(...args)),
|
||||
};
|
||||
});
|
||||
|
||||
const mockSetTimeout = () => {
|
||||
const original = window.setTimeout;
|
||||
// @ts-ignore
|
||||
const setT = (window.setTimeout = jest.fn((...args) => original(...args)));
|
||||
return [
|
||||
setT,
|
||||
() => {
|
||||
window.setTimeout = original;
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-return-await
|
||||
const timeout = async (timeout = 100) => await new Promise((r) => setTimeout(r, timeout));
|
||||
|
||||
describe('function', () => {
|
||||
test('noop', () => {
|
||||
expect(typeof noop).toBe('function');
|
||||
expect(noop()).toBe(undefined);
|
||||
});
|
||||
|
||||
describe('debounce', () => {
|
||||
describe('timeout', () => {
|
||||
test('without timeout', () => {
|
||||
let i = 0;
|
||||
const [setT, unmockSetTimeout] = mockSetTimeout();
|
||||
const debouncedFn = debounce(() => {
|
||||
i += 1;
|
||||
});
|
||||
expect(rAF).not.toHaveBeenCalled();
|
||||
expect(setT).not.toHaveBeenCalled();
|
||||
debouncedFn();
|
||||
expect(rAF).not.toHaveBeenCalled();
|
||||
expect(setT).not.toHaveBeenCalled();
|
||||
expect(i).toBe(1);
|
||||
unmockSetTimeout();
|
||||
});
|
||||
|
||||
test('with timeout 0', async () => {
|
||||
let i = 0;
|
||||
const [setT, unmockSetTimeout] = mockSetTimeout();
|
||||
const debouncedFn = debounce(
|
||||
() => {
|
||||
i += 1;
|
||||
},
|
||||
{ _timeout: 0 }
|
||||
);
|
||||
|
||||
expect(rAF).not.toHaveBeenCalled();
|
||||
expect(setT).not.toHaveBeenCalled();
|
||||
debouncedFn();
|
||||
expect(rAF).toHaveBeenCalledTimes(1);
|
||||
expect(setT).not.toHaveBeenCalled();
|
||||
expect(i).toBe(0);
|
||||
|
||||
await timeout();
|
||||
|
||||
expect(i).toBe(1);
|
||||
unmockSetTimeout();
|
||||
});
|
||||
|
||||
test('with timeout > 0', async () => {
|
||||
let i = 0;
|
||||
const [setT, unmockSetTimeout] = mockSetTimeout();
|
||||
const debouncedFn = debounce(
|
||||
() => {
|
||||
i += 1;
|
||||
},
|
||||
{ _timeout: 1 }
|
||||
);
|
||||
|
||||
expect(rAF).not.toHaveBeenCalled();
|
||||
expect(setT).not.toHaveBeenCalled();
|
||||
debouncedFn();
|
||||
expect(rAF).not.toHaveBeenCalled();
|
||||
expect(setT).toHaveBeenCalledTimes(1);
|
||||
|
||||
expect(i).toBe(0);
|
||||
await timeout();
|
||||
expect(i).toBe(1);
|
||||
|
||||
unmockSetTimeout();
|
||||
});
|
||||
|
||||
test('with timeout > 0 and multiple calls', async () => {
|
||||
let i = 0;
|
||||
const debouncedFn = debounce(
|
||||
() => {
|
||||
i += 1;
|
||||
},
|
||||
{ _timeout: 200 }
|
||||
);
|
||||
|
||||
debouncedFn();
|
||||
await timeout();
|
||||
expect(i).toBe(0);
|
||||
|
||||
debouncedFn();
|
||||
await timeout();
|
||||
expect(i).toBe(0);
|
||||
|
||||
debouncedFn();
|
||||
await timeout();
|
||||
expect(i).toBe(0);
|
||||
|
||||
debouncedFn();
|
||||
await timeout();
|
||||
expect(i).toBe(0);
|
||||
|
||||
debouncedFn();
|
||||
await timeout(300);
|
||||
expect(i).toBe(1);
|
||||
});
|
||||
|
||||
test('with timeout function', async () => {
|
||||
let i = 0;
|
||||
let timeoutMs = 200;
|
||||
const debouncedFn = debounce(
|
||||
() => {
|
||||
i += 1;
|
||||
},
|
||||
{ _timeout: () => timeoutMs }
|
||||
);
|
||||
|
||||
debouncedFn();
|
||||
await timeout();
|
||||
expect(i).toBe(0);
|
||||
|
||||
timeoutMs = 1000;
|
||||
|
||||
debouncedFn();
|
||||
await timeout(500);
|
||||
expect(i).toBe(0);
|
||||
|
||||
await timeout(500);
|
||||
expect(i).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('maxDelay', () => {
|
||||
test('without maxDelay', async () => {
|
||||
let i = 0;
|
||||
const debouncedFn = debounce(
|
||||
() => {
|
||||
i += 1;
|
||||
},
|
||||
{ _timeout: 100 }
|
||||
);
|
||||
debouncedFn();
|
||||
expect(i).toBe(0);
|
||||
|
||||
await timeout(150);
|
||||
|
||||
expect(i).toBe(1);
|
||||
});
|
||||
|
||||
test('with maxDelay and longer timeout', async () => {
|
||||
let i = 0;
|
||||
const debouncedFn = debounce(
|
||||
() => {
|
||||
i += 1;
|
||||
},
|
||||
{ _timeout: 10000, _maxDelay: 100 }
|
||||
);
|
||||
debouncedFn();
|
||||
expect(i).toBe(0);
|
||||
|
||||
await timeout(150);
|
||||
|
||||
expect(i).toBe(1);
|
||||
});
|
||||
|
||||
test('with maxDelay and shorter timeout with multiple calls', async () => {
|
||||
let i = 0;
|
||||
const debouncedFn = debounce(
|
||||
() => {
|
||||
i += 1;
|
||||
},
|
||||
{ _timeout: 200, _maxDelay: 500 }
|
||||
);
|
||||
debouncedFn();
|
||||
await timeout(150);
|
||||
expect(i).toBe(0);
|
||||
|
||||
debouncedFn();
|
||||
await timeout(150);
|
||||
|
||||
debouncedFn();
|
||||
await timeout(150);
|
||||
expect(i).toBe(0);
|
||||
|
||||
debouncedFn();
|
||||
await timeout(150);
|
||||
expect(i).toBe(1);
|
||||
});
|
||||
|
||||
test('with maxDelay function', async () => {
|
||||
let i = 0;
|
||||
let maxDelayMs = 300;
|
||||
const debouncedFn = debounce(
|
||||
() => {
|
||||
i += 1;
|
||||
},
|
||||
{ _timeout: 400, _maxDelay: () => maxDelayMs }
|
||||
);
|
||||
debouncedFn();
|
||||
expect(i).toBe(0);
|
||||
|
||||
await timeout();
|
||||
|
||||
debouncedFn();
|
||||
expect(i).toBe(0);
|
||||
|
||||
await timeout();
|
||||
|
||||
maxDelayMs = 800; // this delay will be applied in the next cycle, not instantly
|
||||
|
||||
debouncedFn();
|
||||
expect(i).toBe(0);
|
||||
|
||||
await timeout();
|
||||
|
||||
debouncedFn();
|
||||
expect(i).toBe(1); // max delay 300 invoked here
|
||||
|
||||
await timeout(300);
|
||||
|
||||
debouncedFn();
|
||||
expect(i).toBe(1);
|
||||
|
||||
await timeout(300);
|
||||
|
||||
debouncedFn();
|
||||
expect(i).toBe(1);
|
||||
|
||||
await timeout(300);
|
||||
|
||||
debouncedFn();
|
||||
expect(i).toBe(2); // max delay 800 invoked here
|
||||
});
|
||||
});
|
||||
|
||||
describe('mergeParams', () => {
|
||||
test('with correct mergeParams function', async () => {
|
||||
let i = 0;
|
||||
const _mergeParams = jest.fn((prev: [number, number], curr: [number, number]) => {
|
||||
const [prevA, prevB] = prev;
|
||||
const [currA, currB] = curr;
|
||||
|
||||
return [prevA + currA, prevB + currB] as [number, number];
|
||||
});
|
||||
const debouncedFn = debounce(
|
||||
(a: number, b: number) => {
|
||||
i += a * b;
|
||||
},
|
||||
{ _timeout: 200, _mergeParams }
|
||||
);
|
||||
debouncedFn(1, 1);
|
||||
expect(i).toBe(0);
|
||||
expect(_mergeParams).not.toHaveBeenCalled();
|
||||
|
||||
await timeout();
|
||||
|
||||
debouncedFn(4, 4);
|
||||
expect(i).toBe(0);
|
||||
expect(_mergeParams).toHaveBeenLastCalledWith([1, 1], [4, 4]);
|
||||
|
||||
await timeout();
|
||||
|
||||
debouncedFn(10, 10);
|
||||
expect(i).toBe(0);
|
||||
expect(_mergeParams).toHaveBeenLastCalledWith([5, 5], [10, 10]);
|
||||
|
||||
await timeout(250);
|
||||
|
||||
expect(i).toBe(15 * 15);
|
||||
});
|
||||
|
||||
test('without correct mergeParams function', async () => {
|
||||
let i = 0;
|
||||
const _mergeParams = jest.fn(() => null);
|
||||
const debouncedFn = debounce(
|
||||
(a, b) => {
|
||||
i += a * b;
|
||||
},
|
||||
{ _timeout: 200, _mergeParams }
|
||||
);
|
||||
debouncedFn(1, 1);
|
||||
expect(i).toBe(0);
|
||||
expect(_mergeParams).not.toHaveBeenCalled();
|
||||
|
||||
await timeout();
|
||||
|
||||
debouncedFn(2, 2);
|
||||
expect(i).toBe(0);
|
||||
expect(_mergeParams).toHaveBeenLastCalledWith([1, 1], [2, 2]);
|
||||
|
||||
await timeout();
|
||||
|
||||
debouncedFn(3, 3);
|
||||
expect(i).toBe(0);
|
||||
expect(_mergeParams).toHaveBeenLastCalledWith([2, 2], [3, 3]);
|
||||
|
||||
await timeout(250);
|
||||
|
||||
expect(i).toBe(3 * 3);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
import { getLexicon } from 'support/utils/lexicon';
|
||||
|
||||
describe('getLexicon', () => {
|
||||
test('Get vertical Lexicon', () => {
|
||||
const lexicon = getLexicon();
|
||||
expect(lexicon._widthHeight).toBe('height');
|
||||
expect(lexicon._WidthHeight).toBe('Height');
|
||||
expect(lexicon._leftTop).toBe('top');
|
||||
expect(lexicon._LeftTop).toBe('Top');
|
||||
expect(lexicon._xy).toBe('y');
|
||||
expect(lexicon._XY).toBe('Y');
|
||||
expect(lexicon._wh).toBe('h');
|
||||
expect(lexicon._lt).toBe('t');
|
||||
});
|
||||
|
||||
test('Get horizontal Lexicon', () => {
|
||||
const lexicon = getLexicon(true);
|
||||
expect(lexicon._widthHeight).toBe('width');
|
||||
expect(lexicon._WidthHeight).toBe('Width');
|
||||
expect(lexicon._leftTop).toBe('left');
|
||||
expect(lexicon._LeftTop).toBe('Left');
|
||||
expect(lexicon._xy).toBe('x');
|
||||
expect(lexicon._XY).toBe('X');
|
||||
expect(lexicon._wh).toBe('w');
|
||||
expect(lexicon._lt).toBe('l');
|
||||
});
|
||||
});
|
||||
@@ -154,8 +154,8 @@ const targetDomObserver = createDOMObserver(
|
||||
|
||||
const createContentDomOserver = (
|
||||
eventContentChange: Array<[string?, string?] | null | undefined>
|
||||
) => {
|
||||
return createDOMObserver(
|
||||
) =>
|
||||
createDOMObserver(
|
||||
trargetContentElm!,
|
||||
true,
|
||||
(contentChangedTroughEvent: boolean) => {
|
||||
@@ -188,7 +188,7 @@ const createContentDomOserver = (
|
||||
? liesBetween(target as Element, hostSelector, '.content')
|
||||
: false;
|
||||
},
|
||||
_ignoreNestedTargetChange: (target, attrName, oldValue, newValue) => {
|
||||
_ignoreNestedTargetChange: (_target, attrName, oldValue, newValue) => {
|
||||
if (attrName === 'class' && oldValue && newValue) {
|
||||
const diff = diffClass(oldValue, newValue);
|
||||
const ignore = diff.length === 1 && diff[0].startsWith(ignorePrefix);
|
||||
@@ -204,7 +204,6 @@ const createContentDomOserver = (
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
let contentDomObserver = createContentDomOserver(contentChange);
|
||||
|
||||
@@ -229,12 +228,10 @@ const changedThrough = <ChangeThrough extends DOMContentObserverResult | DOMTarg
|
||||
observationLists = [observationLists] as Array<ChangeThrough[]>;
|
||||
}
|
||||
|
||||
const getStats = (): Stat => {
|
||||
return {
|
||||
total: getTotalObservations(),
|
||||
lists: (observationLists as Array<ChangeThrough[]>).map((list) => [list, list.length]),
|
||||
};
|
||||
};
|
||||
const getStats = (): Stat => ({
|
||||
total: getTotalObservations(),
|
||||
lists: (observationLists as Array<ChangeThrough[]>).map((list) => [list, list.length]),
|
||||
});
|
||||
|
||||
return {
|
||||
before: () => {
|
||||
|
||||
Reference in New Issue
Block a user