mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-05-17 05:49:39 +03:00
improve tests and code
This commit is contained in:
@@ -37,7 +37,7 @@ export interface OverlayScrollbarsStatic {
|
||||
): OverlayScrollbars;
|
||||
|
||||
plugin(plugin: Plugin | Plugin[]): void;
|
||||
valid(osInstance: any): boolean;
|
||||
valid(osInstance: any): osInstance is OverlayScrollbars;
|
||||
env(): Environment;
|
||||
}
|
||||
|
||||
@@ -94,19 +94,19 @@ export interface OverlayScrollbars {
|
||||
options(): Options;
|
||||
options(newOptions: DeepPartial<Options>): Options;
|
||||
|
||||
update(force?: boolean): OverlayScrollbars;
|
||||
|
||||
destroy(): void;
|
||||
|
||||
state(): State;
|
||||
|
||||
elements(): Elements;
|
||||
|
||||
on<N extends keyof EventListenerMap>(name: N, listener: EventListener<N>): () => void;
|
||||
on<N extends keyof EventListenerMap>(name: N, listener: EventListener<N>[]): () => void;
|
||||
|
||||
off<N extends keyof EventListenerMap>(name: N, listener: EventListener<N>): void;
|
||||
off<N extends keyof EventListenerMap>(name: N, listener: EventListener<N>[]): void;
|
||||
|
||||
update(force?: boolean): boolean;
|
||||
|
||||
state(): State;
|
||||
|
||||
elements(): Elements;
|
||||
|
||||
destroy(): void;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-redeclare
|
||||
@@ -115,11 +115,7 @@ export const OverlayScrollbars: OverlayScrollbarsStatic = (
|
||||
options?: DeepPartial<Options>,
|
||||
eventListeners?: InitialEventListeners
|
||||
) => {
|
||||
const {
|
||||
_getDefaultOptions,
|
||||
_getDefaultInitialization,
|
||||
_addListener: addEnvListener,
|
||||
} = getEnvironment();
|
||||
const { _getDefaultOptions, _getDefaultInitialization, _addListener } = getEnvironment();
|
||||
const plugins = getPlugins();
|
||||
const targetIsElement = isHTMLElement(target);
|
||||
const instanceTarget = targetIsElement ? target : target.target;
|
||||
@@ -149,10 +145,9 @@ export const OverlayScrollbars: OverlayScrollbarsStatic = (
|
||||
currentOptions,
|
||||
structureState
|
||||
);
|
||||
const update = (changedOptions: DeepPartial<Options>, force?: boolean) => {
|
||||
const update = (changedOptions: DeepPartial<Options>, force?: boolean): boolean =>
|
||||
updateStructure(changedOptions, !!force);
|
||||
};
|
||||
const removeEnvListener = addEnvListener(update.bind(0, {}, true));
|
||||
const removeEnvListener = _addListener(update.bind(0, {}, true));
|
||||
const destroy = (canceled?: boolean) => {
|
||||
removeInstance(instanceTarget);
|
||||
removeEnvListener();
|
||||
@@ -257,10 +252,7 @@ export const OverlayScrollbars: OverlayScrollbarsStatic = (
|
||||
}
|
||||
);
|
||||
},
|
||||
update(force?: boolean) {
|
||||
update({}, force);
|
||||
return instance;
|
||||
},
|
||||
update: (force?: boolean) => update({}, force),
|
||||
destroy: destroy.bind(0),
|
||||
};
|
||||
|
||||
@@ -323,13 +315,15 @@ export const OverlayScrollbars: OverlayScrollbarsStatic = (
|
||||
]);
|
||||
});
|
||||
|
||||
return instance.update(true);
|
||||
instance.update(true);
|
||||
|
||||
return instance;
|
||||
}
|
||||
return potentialInstance!;
|
||||
};
|
||||
|
||||
OverlayScrollbars.plugin = addPlugin;
|
||||
OverlayScrollbars.valid = (osInstance: any) => {
|
||||
OverlayScrollbars.valid = (osInstance: any): osInstance is OverlayScrollbars => {
|
||||
const hasElmsFn = osInstance && (osInstance as OverlayScrollbars).elements;
|
||||
const elements = isFunction(hasElmsFn) && hasElmsFn();
|
||||
return isPlainObject(elements) && !!getInstance(elements.target);
|
||||
|
||||
@@ -4,11 +4,11 @@ import type { DeepPartial } from 'typings';
|
||||
|
||||
export type SetupElements<T extends Record<string, any>> = [elements: T, destroy: () => void];
|
||||
|
||||
export type SetupUpdate<T extends any[]> = (
|
||||
export type SetupUpdate<Args extends any[], R> = (
|
||||
changedOptions: DeepPartial<Options>,
|
||||
force: boolean,
|
||||
...args: T
|
||||
) => void;
|
||||
...args: Args
|
||||
) => R;
|
||||
|
||||
export type SetupUpdateCheckOption = <T>(path: string) => [value: T, changed: boolean];
|
||||
|
||||
@@ -26,8 +26,9 @@ export type SetupState<T extends Record<string, any>> = [
|
||||
export type Setup<
|
||||
DynamicState,
|
||||
StaticState extends Record<string, any> = Record<string, any>,
|
||||
A extends any[] = []
|
||||
> = [update: SetupUpdate<A>, state: (() => DynamicState) & StaticState, destroy: () => void];
|
||||
Args extends any[] = [],
|
||||
R = void
|
||||
> = [update: SetupUpdate<Args, R>, state: (() => DynamicState) & StaticState, destroy: () => void];
|
||||
|
||||
const getPropByPath = <T>(obj: any, path: string): T =>
|
||||
obj
|
||||
|
||||
@@ -68,34 +68,33 @@ const initialStructureSetupUpdateState: StructureSetupState = {
|
||||
export const createStructureSetup = (
|
||||
target: InitializationTarget,
|
||||
options: ReadonlyOptions
|
||||
): Setup<StructureSetupState, StructureSetupStaticState> => {
|
||||
): Setup<StructureSetupState, StructureSetupStaticState, [], boolean> => {
|
||||
const checkOptionsFallback = createOptionCheck(options, {});
|
||||
const state = createState(initialStructureSetupUpdateState);
|
||||
const [addEvent, removeEvent, triggerEvent] = createEventListenerHub<StructureSetupEventMap>();
|
||||
const [getState] = state;
|
||||
const [elements, appendStructureElements, destroyElements] = createStructureSetupElements(target);
|
||||
const updateStructure = createStructureSetupUpdate(elements, state);
|
||||
const triggerUpdateEvent: (...args: StructureSetupEventMap['u']) => void = (
|
||||
const triggerUpdateEvent: (...args: StructureSetupEventMap['u']) => boolean = (
|
||||
updateHints,
|
||||
changedOptions,
|
||||
force
|
||||
) => {
|
||||
const truthyUpdateHints = keys(updateHints).some((key) => updateHints[key]);
|
||||
|
||||
if (truthyUpdateHints || !isEmptyObject(changedOptions) || force) {
|
||||
const changed = truthyUpdateHints || !isEmptyObject(changedOptions) || force;
|
||||
if (changed) {
|
||||
triggerEvent('u', [updateHints, changedOptions, force]);
|
||||
}
|
||||
return changed;
|
||||
};
|
||||
const [destroyObservers, appendObserverElements, updateObservers, updateObserversOptions] =
|
||||
createStructureSetupObservers(elements, state, (updateHints) => {
|
||||
triggerUpdateEvent(updateStructure(checkOptionsFallback, updateHints), {}, false);
|
||||
});
|
||||
createStructureSetupObservers(elements, state, (updateHints) =>
|
||||
triggerUpdateEvent(updateStructure(checkOptionsFallback, updateHints), {}, false)
|
||||
);
|
||||
|
||||
const structureSetupState = getState.bind(0) as (() => StructureSetupState) &
|
||||
StructureSetupStaticState;
|
||||
structureSetupState._addOnUpdatedListener = (listener) => {
|
||||
addEvent('u', listener);
|
||||
};
|
||||
structureSetupState._addOnUpdatedListener = (listener) => addEvent('u', listener);
|
||||
structureSetupState._appendElements = () => {
|
||||
const { _target, _viewport } = elements;
|
||||
const initialScrollLeft = scrollLeft(_target);
|
||||
@@ -113,7 +112,7 @@ export const createStructureSetup = (
|
||||
(changedOptions, force?) => {
|
||||
const checkOption = createOptionCheck(options, changedOptions, force);
|
||||
updateObserversOptions(checkOption);
|
||||
triggerUpdateEvent(
|
||||
return triggerUpdateEvent(
|
||||
updateStructure(checkOption, updateObservers(), force),
|
||||
changedOptions,
|
||||
!!force
|
||||
|
||||
@@ -0,0 +1,408 @@
|
||||
import { DeepPartial } from 'typings';
|
||||
import { defaultOptions, Options } from 'options';
|
||||
import { assignDeep } from 'support';
|
||||
import { OverlayScrollbars as originalOverlayScrollbars } from '../../src/overlayscrollbars';
|
||||
|
||||
const bodyElm = document.body;
|
||||
const div = document.createElement('div');
|
||||
|
||||
bodyElm.append(div);
|
||||
|
||||
let OverlayScrollbars = originalOverlayScrollbars;
|
||||
|
||||
describe('overlayscrollbars', () => {
|
||||
beforeEach(async () => {
|
||||
jest.resetModules();
|
||||
({ OverlayScrollbars } = await import('../../src/overlayscrollbars'));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
const instance = OverlayScrollbars(div);
|
||||
if (OverlayScrollbars.valid(instance)) {
|
||||
instance.destroy();
|
||||
}
|
||||
});
|
||||
|
||||
describe('instance', () => {
|
||||
describe('initialization', () => {
|
||||
describe('initialization completed', () => {
|
||||
[div, { target: div }].forEach((init) => {
|
||||
describe(`as ${init === div ? 'element' : 'object'}`, () => {
|
||||
test('without options', () => {
|
||||
const osInstance = OverlayScrollbars(init);
|
||||
|
||||
expect(OverlayScrollbars.valid(osInstance)).toBe(false);
|
||||
expect(div.children.length).toBe(0);
|
||||
});
|
||||
|
||||
test('with empty options', () => {
|
||||
const osInstance = OverlayScrollbars(init, {});
|
||||
|
||||
expect(OverlayScrollbars.valid(osInstance)).toBe(true);
|
||||
expect(div.children.length).not.toBe(0);
|
||||
|
||||
expect(osInstance.options()).not.toBe(defaultOptions);
|
||||
expect(osInstance.options()).toEqual(defaultOptions);
|
||||
});
|
||||
|
||||
test('with custom options', () => {
|
||||
const customOptions: DeepPartial<Options> = {
|
||||
paddingAbsolute: false,
|
||||
showNativeOverlaidScrollbars: true,
|
||||
overflow: {
|
||||
x: 'hidden',
|
||||
},
|
||||
update: {
|
||||
ignoreMutation: () => true,
|
||||
elementEvents: null,
|
||||
},
|
||||
scrollbars: {
|
||||
pointers: null,
|
||||
autoHideDelay: 0,
|
||||
},
|
||||
};
|
||||
const osInstance = OverlayScrollbars(init, customOptions);
|
||||
|
||||
expect(OverlayScrollbars.valid(osInstance)).toBe(true);
|
||||
expect(div.children.length).not.toBe(0);
|
||||
|
||||
expect(osInstance.options()).toEqual(assignDeep({}, defaultOptions, customOptions));
|
||||
});
|
||||
|
||||
test('with event listeners', () => {
|
||||
const initialized = jest.fn();
|
||||
const updated = jest.fn();
|
||||
const destroyed = jest.fn();
|
||||
const osInstance = OverlayScrollbars(
|
||||
init,
|
||||
{},
|
||||
{
|
||||
initialized,
|
||||
updated,
|
||||
destroyed,
|
||||
}
|
||||
);
|
||||
|
||||
expect(OverlayScrollbars.valid(osInstance)).toBe(true);
|
||||
expect(div.children.length).not.toBe(0);
|
||||
|
||||
expect(initialized).toHaveBeenCalledTimes(1);
|
||||
expect(initialized).toHaveBeenCalledWith(osInstance);
|
||||
|
||||
expect(updated).toHaveBeenCalledTimes(1);
|
||||
expect(updated).toHaveBeenCalledWith(osInstance, expect.any(Object));
|
||||
|
||||
expect(destroyed).not.toHaveBeenCalled();
|
||||
|
||||
osInstance.destroy();
|
||||
|
||||
expect(destroyed).toHaveBeenCalledTimes(1);
|
||||
expect(destroyed).toHaveBeenCalledWith(osInstance, false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('initialization canceled', () => {
|
||||
test('without options', () => {
|
||||
const osInstance = OverlayScrollbars({
|
||||
target: div,
|
||||
cancel: { nativeScrollbarsOverlaid: true },
|
||||
});
|
||||
|
||||
expect(OverlayScrollbars.valid(osInstance)).toBe(false);
|
||||
expect(div.children.length).toBe(0);
|
||||
});
|
||||
|
||||
test('with empty options', () => {
|
||||
const osInstance = OverlayScrollbars(
|
||||
{
|
||||
target: div,
|
||||
cancel: { nativeScrollbarsOverlaid: true },
|
||||
},
|
||||
{}
|
||||
);
|
||||
|
||||
expect(OverlayScrollbars.valid(osInstance)).toBe(false);
|
||||
expect(div.children.length).toBe(0);
|
||||
});
|
||||
|
||||
test('with event listeners', () => {
|
||||
const initialized = jest.fn();
|
||||
const updated = jest.fn();
|
||||
const destroyed = jest.fn();
|
||||
const osInstance = OverlayScrollbars(
|
||||
{
|
||||
target: div,
|
||||
cancel: { nativeScrollbarsOverlaid: true },
|
||||
},
|
||||
{},
|
||||
{
|
||||
initialized,
|
||||
updated,
|
||||
destroyed,
|
||||
}
|
||||
);
|
||||
|
||||
expect(OverlayScrollbars.valid(osInstance)).toBe(false);
|
||||
expect(div.children.length).toBe(0);
|
||||
|
||||
expect(initialized).not.toHaveBeenCalled();
|
||||
expect(updated).not.toHaveBeenCalled();
|
||||
expect(destroyed).toHaveBeenCalledTimes(1);
|
||||
expect(destroyed).toHaveBeenCalledWith(osInstance, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('options', () => {
|
||||
const customOptions: DeepPartial<Options> = {
|
||||
paddingAbsolute: !defaultOptions.paddingAbsolute,
|
||||
overflow: { x: 'hidden' },
|
||||
};
|
||||
const osInstance = OverlayScrollbars(div, {});
|
||||
expect(osInstance.options()).not.toBe(defaultOptions);
|
||||
expect(osInstance.options()).toEqual(defaultOptions);
|
||||
OverlayScrollbars(div)!.destroy();
|
||||
|
||||
expect(OverlayScrollbars(div, customOptions).options()).toEqual(
|
||||
assignDeep({}, defaultOptions, customOptions)
|
||||
);
|
||||
OverlayScrollbars(div)!.destroy();
|
||||
|
||||
const osInstance2 = OverlayScrollbars(div, {});
|
||||
expect(osInstance2.options(customOptions)).toEqual(
|
||||
assignDeep({}, defaultOptions, customOptions)
|
||||
);
|
||||
expect(osInstance2.options()).toEqual(assignDeep({}, defaultOptions, customOptions));
|
||||
});
|
||||
|
||||
test('on', () => {
|
||||
const onInitialized = jest.fn();
|
||||
const onUpdated = jest.fn();
|
||||
const onUpdated2 = jest.fn();
|
||||
const onDestroyed = jest.fn();
|
||||
const osInstance = OverlayScrollbars(div, {});
|
||||
|
||||
osInstance.on('initialized', onInitialized);
|
||||
osInstance.on('updated', [onUpdated, onUpdated, onUpdated2]);
|
||||
osInstance.on('destroyed', onDestroyed);
|
||||
|
||||
expect(onInitialized).not.toHaveBeenCalled();
|
||||
|
||||
expect(onUpdated).not.toHaveBeenCalled();
|
||||
expect(onUpdated2).not.toHaveBeenCalled();
|
||||
|
||||
osInstance.update();
|
||||
expect(onUpdated).not.toHaveBeenCalled();
|
||||
expect(onUpdated2).not.toHaveBeenCalled();
|
||||
|
||||
osInstance.update(true);
|
||||
expect(onUpdated).toHaveBeenCalledTimes(1);
|
||||
expect(onUpdated2).toHaveBeenCalledTimes(1);
|
||||
expect(onUpdated).toHaveBeenLastCalledWith(osInstance, expect.any(Object));
|
||||
expect(onUpdated2).toHaveBeenLastCalledWith(osInstance, expect.any(Object));
|
||||
|
||||
expect(onDestroyed).not.toHaveBeenCalled();
|
||||
OverlayScrollbars(div)!.destroy();
|
||||
expect(onDestroyed).toHaveBeenCalledTimes(1);
|
||||
expect(onDestroyed).toHaveBeenLastCalledWith(osInstance, false);
|
||||
|
||||
// after destruction no further events are triggered
|
||||
osInstance.update(true);
|
||||
expect(onUpdated).toHaveBeenCalledTimes(1);
|
||||
expect(onUpdated2).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('off', () => {
|
||||
const onInitialized = jest.fn();
|
||||
const onUpdated = jest.fn();
|
||||
const onUpdated2 = jest.fn();
|
||||
const onDestroyed = jest.fn();
|
||||
|
||||
expect(onInitialized).not.toHaveBeenCalled();
|
||||
const osInstance = OverlayScrollbars(
|
||||
div,
|
||||
{},
|
||||
{
|
||||
initialized: onInitialized,
|
||||
updated: [onUpdated, onUpdated, onUpdated2],
|
||||
destroyed: onDestroyed,
|
||||
}
|
||||
);
|
||||
|
||||
expect(onInitialized).toHaveBeenCalledTimes(1);
|
||||
expect(onInitialized).toHaveBeenLastCalledWith(osInstance);
|
||||
|
||||
expect(onUpdated).toHaveBeenCalledTimes(1);
|
||||
expect(onUpdated2).toHaveBeenCalledTimes(1);
|
||||
|
||||
osInstance.update(true);
|
||||
|
||||
expect(onUpdated).toHaveBeenCalledTimes(2);
|
||||
expect(onUpdated2).toHaveBeenCalledTimes(2);
|
||||
|
||||
osInstance.off('updated', onUpdated2);
|
||||
osInstance.update(true);
|
||||
expect(onUpdated).toHaveBeenCalledTimes(3);
|
||||
expect(onUpdated2).toHaveBeenCalledTimes(2);
|
||||
|
||||
osInstance.on('updated', onUpdated2);
|
||||
osInstance.update(true);
|
||||
expect(onUpdated).toHaveBeenCalledTimes(4);
|
||||
expect(onUpdated2).toHaveBeenCalledTimes(3);
|
||||
|
||||
osInstance.off('updated', [onUpdated, onUpdated2]);
|
||||
osInstance.update(true);
|
||||
expect(onUpdated).toHaveBeenCalledTimes(4);
|
||||
expect(onUpdated2).toHaveBeenCalledTimes(3);
|
||||
|
||||
osInstance.off('destroyed', onDestroyed);
|
||||
expect(onDestroyed).not.toHaveBeenCalled();
|
||||
osInstance.destroy();
|
||||
expect(onDestroyed).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('state', () => {
|
||||
const osInstance = OverlayScrollbars(div, {});
|
||||
const state = osInstance.state();
|
||||
const stateObj = {
|
||||
overflowEdge: { x: 0, y: 0 },
|
||||
overflowAmount: { x: 0, y: 0 },
|
||||
overflowStyle: { x: '', y: '' },
|
||||
hasOverflow: { x: false, y: false },
|
||||
padding: { t: 0, r: 0, b: 0, l: 0 },
|
||||
paddingAbsolute: false,
|
||||
directionRTL: false,
|
||||
destroyed: false,
|
||||
};
|
||||
|
||||
expect(state).not.toBe(osInstance.state());
|
||||
expect(state).toEqual(osInstance.state());
|
||||
expect(state).toEqual(stateObj);
|
||||
|
||||
osInstance.options({ paddingAbsolute: true });
|
||||
expect(osInstance.state()).toEqual(
|
||||
expect.objectContaining({
|
||||
paddingAbsolute: true,
|
||||
})
|
||||
);
|
||||
|
||||
osInstance.destroy();
|
||||
expect(osInstance.state()).toEqual(
|
||||
expect.objectContaining({
|
||||
destroyed: true,
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
test('elements', () => {
|
||||
const osInstance = OverlayScrollbars(div, {});
|
||||
const elements = osInstance.elements();
|
||||
const elementsObj = {
|
||||
target: div,
|
||||
host: div,
|
||||
padding: expect.any(HTMLElement),
|
||||
viewport: expect.any(HTMLElement),
|
||||
content: expect.any(HTMLElement),
|
||||
scrollOffsetElement: expect.any(HTMLElement),
|
||||
scrollEventElement: expect.any(HTMLElement),
|
||||
scrollbarHorizontal: {
|
||||
scrollbar: expect.any(HTMLElement),
|
||||
track: expect.any(HTMLElement),
|
||||
handle: expect.any(HTMLElement),
|
||||
clone: expect.any(Function),
|
||||
},
|
||||
scrollbarVertical: {
|
||||
scrollbar: expect.any(HTMLElement),
|
||||
track: expect.any(HTMLElement),
|
||||
handle: expect.any(HTMLElement),
|
||||
clone: expect.any(Function),
|
||||
},
|
||||
};
|
||||
|
||||
expect(elements).not.toBe(osInstance.elements());
|
||||
// clone function identity is always different
|
||||
expect(
|
||||
assignDeep({}, elements, {
|
||||
scrollbarHorizontal: {
|
||||
clone: null,
|
||||
},
|
||||
scrollbarVertical: {
|
||||
clone: null,
|
||||
},
|
||||
})
|
||||
).toEqual(
|
||||
assignDeep({}, osInstance.elements(), {
|
||||
scrollbarHorizontal: {
|
||||
clone: null,
|
||||
},
|
||||
scrollbarVertical: {
|
||||
clone: null,
|
||||
},
|
||||
})
|
||||
);
|
||||
expect(elements).toEqual(elementsObj);
|
||||
|
||||
osInstance.destroy();
|
||||
|
||||
expect(elements).toEqual(elementsObj);
|
||||
});
|
||||
|
||||
test('update', () => {
|
||||
const osInstance = OverlayScrollbars(div, {});
|
||||
expect(osInstance.update()).toBe(false);
|
||||
expect(osInstance.update(false)).toBe(false);
|
||||
expect(osInstance.update(true)).toBe(true);
|
||||
|
||||
// host mutation
|
||||
div.style.cursor = 'pointer';
|
||||
expect(osInstance.update()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('static', () => {
|
||||
test('plugin', () => {
|
||||
expect(OverlayScrollbars.plugin).toEqual(expect.any(Function));
|
||||
});
|
||||
|
||||
test('env', () => {
|
||||
const env = OverlayScrollbars.env();
|
||||
const envObj = {
|
||||
scrollbarsSize: { x: 0, y: 0 },
|
||||
scrollbarsOverlaid: { x: true, y: true },
|
||||
scrollbarsHiding: false,
|
||||
rtlScrollBehavior: { i: true, n: false },
|
||||
flexboxGlue: true,
|
||||
cssCustomProperties: false,
|
||||
staticDefaultInitialization: expect.any(Object),
|
||||
staticDefaultOptions: expect.any(Object),
|
||||
getDefaultInitialization: expect.any(Function),
|
||||
setDefaultInitialization: expect.any(Function),
|
||||
getDefaultOptions: expect.any(Function),
|
||||
setDefaultOptions: expect.any(Function),
|
||||
};
|
||||
expect(env).not.toBe(OverlayScrollbars.env());
|
||||
expect(env).toEqual(OverlayScrollbars.env());
|
||||
expect(env).toEqual(envObj);
|
||||
});
|
||||
|
||||
test('valid', () => {
|
||||
expect(OverlayScrollbars.valid(true)).toBe(false);
|
||||
expect(OverlayScrollbars.valid(false)).toBe(false);
|
||||
expect(OverlayScrollbars.valid('')).toBe(false);
|
||||
expect(OverlayScrollbars.valid(123)).toBe(false);
|
||||
expect(OverlayScrollbars.valid({})).toBe(false);
|
||||
expect(OverlayScrollbars.valid(div)).toBe(false);
|
||||
expect(OverlayScrollbars.valid(setTimeout)).toBe(false);
|
||||
|
||||
expect(OverlayScrollbars.valid(OverlayScrollbars(div))).toBe(false);
|
||||
|
||||
const osInstance = OverlayScrollbars(div, {});
|
||||
expect(OverlayScrollbars.valid(osInstance)).toBe(true);
|
||||
|
||||
osInstance.destroy();
|
||||
expect(OverlayScrollbars.valid(osInstance)).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -2,6 +2,7 @@ import { createEventListenerHub } from 'support/eventListeners';
|
||||
|
||||
type EventMap = {
|
||||
onBoolean: [a: boolean, b: string];
|
||||
onString: [a: string];
|
||||
onUndefined: [];
|
||||
};
|
||||
|
||||
@@ -10,19 +11,27 @@ describe('eventListeners', () => {
|
||||
test('initialization', () => {
|
||||
const onBooleanA = jest.fn((a: boolean, b: string) => a + b);
|
||||
const onBooleanB = jest.fn();
|
||||
const onString = jest.fn();
|
||||
const onUndefined = jest.fn();
|
||||
const [, , triggerEvent] = createEventListenerHub<EventMap>({
|
||||
onBoolean: [onBooleanA, onBooleanB],
|
||||
onString: [onString, onString], // multiple equal listeners are treated as one
|
||||
onUndefined,
|
||||
});
|
||||
triggerEvent('onBoolean', [true, 'hi']);
|
||||
triggerEvent('onString', ['hi']);
|
||||
triggerEvent('onUndefined');
|
||||
|
||||
expect(onBooleanA).toHaveBeenCalledTimes(1);
|
||||
expect(onBooleanA).toHaveBeenLastCalledWith(true, 'hi');
|
||||
|
||||
expect(onBooleanB).toHaveBeenCalledTimes(1);
|
||||
expect(onBooleanB).toHaveBeenLastCalledWith(true, 'hi');
|
||||
|
||||
// even though onString was registered twice, its only called once
|
||||
expect(onString).toHaveBeenCalledTimes(1);
|
||||
expect(onString).toHaveBeenLastCalledWith('hi');
|
||||
|
||||
expect(onUndefined).toHaveBeenCalledTimes(1);
|
||||
expect(onUndefined).toHaveBeenLastCalledWith();
|
||||
});
|
||||
@@ -30,6 +39,7 @@ describe('eventListeners', () => {
|
||||
test('addEvent', () => {
|
||||
const onBooleanA = jest.fn((a: boolean, b: string) => a + b);
|
||||
const onBooleanB = jest.fn();
|
||||
const onString = jest.fn();
|
||||
const onUndefinedA = jest.fn();
|
||||
const onUndefinedB = jest.fn();
|
||||
const [addEvent, , triggerEvent] = createEventListenerHub<EventMap>();
|
||||
@@ -68,6 +78,14 @@ describe('eventListeners', () => {
|
||||
expect(onUndefinedB).toHaveBeenCalledTimes(2);
|
||||
expect(onUndefinedB).toHaveBeenLastCalledWith();
|
||||
|
||||
// multiple equal listeners are treated as one
|
||||
addEvent('onString', [onString, onString]);
|
||||
triggerEvent('onString', ['hi']);
|
||||
|
||||
// even though onString was registered twice, its only called once
|
||||
expect(onString).toHaveBeenCalledTimes(1);
|
||||
expect(onString).toHaveBeenLastCalledWith('hi');
|
||||
|
||||
const something = jest.fn();
|
||||
// @ts-ignore
|
||||
addEvent('something', something);
|
||||
@@ -79,6 +97,7 @@ describe('eventListeners', () => {
|
||||
test('removeEvent', () => {
|
||||
const onBooleanA = jest.fn();
|
||||
const onBooleanB = jest.fn();
|
||||
const onString = jest.fn();
|
||||
const onUndefinedA = jest.fn();
|
||||
const onUndefinedB = jest.fn();
|
||||
const [addEvent, removeEvent, triggerEvent] = createEventListenerHub<EventMap>({
|
||||
@@ -149,6 +168,17 @@ describe('eventListeners', () => {
|
||||
expect(onUndefinedA).toHaveBeenCalledTimes(4);
|
||||
expect(onUndefinedB).toHaveBeenCalledTimes(4);
|
||||
|
||||
addEvent('onString', [onString, onString]);
|
||||
triggerEvent('onString', ['hi']);
|
||||
|
||||
expect(onString).toHaveBeenCalledTimes(1);
|
||||
|
||||
// even though onString was registered twice, its treated as a single listener because multiple equal listeners are treated as one
|
||||
removeEvent('onString', onString);
|
||||
triggerEvent('onString', ['hi']);
|
||||
|
||||
expect(onString).toHaveBeenCalledTimes(1);
|
||||
|
||||
// @ts-ignore
|
||||
const something = jest.fn();
|
||||
// @ts-ignore
|
||||
|
||||
Reference in New Issue
Block a user