improve code and fix tests

This commit is contained in:
Rene Haas
2022-07-29 17:05:59 +02:00
parent 0fb35b5ae3
commit 2e587409a2
13 changed files with 374 additions and 268 deletions
@@ -1,4 +1,4 @@
import { assignDeep, each, isArray, keys } from 'support';
import { each, isArray, keys } from 'support';
import { OverlayScrollbars, OverlayScrollbarsStatic } from 'overlayscrollbars';
export type PluginInstance =
@@ -10,12 +10,11 @@ export type Plugin<T extends PluginInstance = PluginInstance> = {
const pluginRegistry: Record<string, PluginInstance> = {};
export const getPlugins = () => assignDeep({}, pluginRegistry);
export const getPlugins = () => pluginRegistry;
export const addPlugin = (addedPlugin: Plugin | Plugin[]) => {
each((isArray(addedPlugin) ? addedPlugin : [addedPlugin]) as Plugin[], (plugin) => {
each(keys(plugin), (pluginName) => {
pluginRegistry[pluginName] = plugin[pluginName];
});
const pluginName = keys(plugin)[0];
pluginRegistry[pluginName] = plugin[pluginName];
});
};
@@ -20,7 +20,7 @@ export type StructureDynamicInitializationElement = DynamicInitializationElement
* If element is provided, the provided element takes all its responsibilities.
* DOM hierarchy isn't checked in this case, its assumed that hieararchy is correct in such a case.
*
* Null or Undefined means that the environment initialization strategy is used.
* undefined means that the default initialization strategy is used.
*/
export interface StructureInitialization {
target: InitializationTargetElement;
@@ -1,7 +0,0 @@
export const mouseButton = (event: MouseEvent): number => {
const { button } = event;
if (!event.which && button !== undefined) {
return button & 1 ? 1 : button & 2 ? 3 : button & 4 ? 2 : 0; // eslint-disable-line no-bitwise
}
return event.which;
};
@@ -1,3 +1,2 @@
export * from 'support/compatibility/vendors';
export * from 'support/compatibility/apis';
export * from 'support/compatibility/events';
@@ -105,11 +105,15 @@ const liesBetween = (
): boolean => {
const closestHighBoundaryElm = elm && closest(elm, highBoundarySelector);
const closestDeepBoundaryElm = elm && findFirst(deepBoundarySelector, closestHighBoundaryElm);
const deepBoundaryIsValid =
closest(closestDeepBoundaryElm, highBoundarySelector) === closestHighBoundaryElm;
return closestHighBoundaryElm && closestDeepBoundaryElm
? closestHighBoundaryElm === elm ||
closestDeepBoundaryElm === elm ||
closest(closest(elm, deepBoundarySelector), highBoundarySelector) !== closestHighBoundaryElm
(deepBoundaryIsValid &&
closest(closest(elm, deepBoundarySelector), highBoundarySelector) !==
closestHighBoundaryElm)
: false;
};
@@ -3,36 +3,26 @@ import { defaultOptions, getOptionsDiff } from 'options';
describe('options', () => {
test('defaultOptions', () => {
expect(defaultOptions).toEqual({
resize: 'none',
paddingAbsolute: false,
showNativeOverlaidScrollbars: false,
updating: {
elementEvents: [['img', 'load']],
attributes: null,
debounce: [0, 33],
attributes: null,
ignoreMutation: null,
},
overflow: {
x: 'scroll',
y: 'scroll',
},
scrollbars: {
theme: 'os-theme-dark',
visibility: 'auto',
autoHide: 'never',
autoHideDelay: 800,
autoHideDelay: 1300,
dragScroll: true,
clickScroll: false,
touch: true,
},
textarea: {
dynWidth: false,
dynHeight: false,
inheritedAttrs: ['style', 'class'],
},
nativeScrollbarsOverlaid: {
show: false,
initialize: false,
},
callbacks: {
onUpdated: null,
pointers: ['mouse', 'touch', 'pen'],
},
});
});
@@ -1,8 +1,12 @@
import { defaultOptions } from 'options';
import { optionsValidationPlugin, optionsValidationPluginName } from 'plugins/optionsValidation';
import {
optionsValidationPlugin,
optionsValidationPluginName,
} from 'plugins/optionsValidationPlugin';
const getValidationFn = () => {
const [name, instance] = optionsValidationPlugin;
const name = Object.keys(optionsValidationPlugin)[0];
const instance = optionsValidationPlugin[name];
const validationFn = instance._;
expect(name).toBe(optionsValidationPluginName);
@@ -2,11 +2,11 @@ import { PlainObject } from 'typings';
import {
optionsTemplateTypes as oTypes,
OptionsTemplate,
} from 'plugins/optionsValidation/validation';
} from 'plugins/optionsValidationPlugin/validation';
import {
transformOptions,
OptionsWithOptionsTemplate,
} from 'plugins/optionsValidation/transformation';
} from 'plugins/optionsValidationPlugin/transformation';
type TestOptionsObj = { propA: 'propA'; null: null };
type TestOptionsEnum = 'A' | 'B' | 'C';
@@ -2,7 +2,7 @@ import {
validateOptions,
optionsTemplateTypes as oTypes,
OptionsTemplate,
} from 'plugins/optionsValidation/validation';
} from 'plugins/optionsValidationPlugin/validation';
import { assignDeep } from 'support/utils';
type TestOptionsObj = { propA: 'propA'; null: null };
@@ -0,0 +1,36 @@
import { addPlugin, getPlugins } from 'plugins';
describe('plugins', () => {
test('getPlugins', () => {
const plugins = getPlugins();
expect(plugins).toEqual({});
});
test('addPlugin single', () => {
const myPlugin = {};
const myPlugin2 = {};
addPlugin({
myPlugin,
myPlugin2,
});
const plugins = getPlugins();
expect(plugins.myPlugin).toBe(myPlugin);
expect(plugins.myPlugin2).toBe(undefined); // one plugin per object
});
test('addPlugin multiple', () => {
const myPlugin = {};
const myPlugin2 = {};
addPlugin([
{
myPlugin,
},
{
myPlugin2,
},
]);
const plugins = getPlugins();
expect(plugins.myPlugin).toBe(myPlugin);
expect(plugins.myPlugin2).toBe(myPlugin2);
});
});
@@ -1,4 +1,4 @@
import { hasClass, isFunction, isHTMLElement } from 'support';
import { hasClass, is, isFunction, isHTMLElement } from 'support';
import { dataAttributeHost } from 'classnames';
import { InternalEnvironment } from 'environment';
import {
@@ -34,27 +34,42 @@ interface StructureSetupElementsProxy {
destroy: () => void;
}
type TargetType = 'element' | 'textarea' | 'body';
const textareaId = 'textarea';
const textareaHostId = 'host';
const elementId = 'target';
const dynamicContent = 'text<p>paragraph</p>';
const textareaContent = `<textarea id="${textareaId}">text</textarea>`;
const getSnapshot = () => document.body.innerHTML;
const getTarget = (textarea?: boolean) =>
document.getElementById(textarea ? textareaId : elementId)!;
const fillBody = (textarea?: boolean, customDOM?: (content: string, hostId: string) => string) => {
document.body.innerHTML = `
const getSnapshot = () => document.documentElement.outerHTML;
const getTarget = (targetType: TargetType) => {
switch (targetType) {
case 'element':
return document.getElementById(elementId)!;
case 'textarea':
return document.getElementById(textareaId)!;
case 'body':
return document.body;
default:
throw new Error('Invalid Target');
}
};
const fillBody = (
targetType: TargetType,
customDOM?: (content: string, hostId: string) => string
) => {
const textarea = targetType === 'textarea';
const customDomResult =
customDOM &&
customDOM(textarea ? textareaContent : dynamicContent, textarea ? textareaHostId : elementId);
const normalDom = textarea ? textareaContent : `<div id="${elementId}">${dynamicContent}</div>`;
document.body.innerHTML =
targetType === 'body'
? dynamicContent
: `
<nav></nav>
${
customDOM
? customDOM(
textarea ? textareaContent : dynamicContent,
textarea ? textareaHostId : elementId
)
: textarea
? textareaContent
: `<div id="${elementId}">${dynamicContent}</div>`
}
${customDomResult || normalDom}
<footer></footer>
`;
return getSnapshot();
@@ -63,8 +78,8 @@ const clearBody = () => {
document.body.innerHTML = '';
};
const getElements = (textarea?: boolean) => {
const target = getTarget(textarea);
const getElements = (targetType: TargetType) => {
const target = getTarget(targetType);
const host = document.querySelector('[data-overlayscrollbars]')!;
const padding = document.querySelector('.os-padding')!;
const viewport = document.querySelector('.os-viewport')!;
@@ -79,8 +94,8 @@ const getElements = (textarea?: boolean) => {
};
};
const assertCorrectDOMStructure = (textarea: boolean, viewportIsTarget: boolean) => {
const { target, host, padding, viewport, content } = getElements(textarea);
const assertCorrectDOMStructure = (targetType: TargetType, viewportIsTarget: boolean) => {
const { target, host, padding, viewport, content } = getElements(targetType);
if (viewportIsTarget) {
expect(target).toBe(host);
@@ -100,12 +115,14 @@ const assertCorrectDOMStructure = (textarea: boolean, viewportIsTarget: boolean)
expect(padding.parentElement).toBe(host);
}
expect(host.parentElement).toBe(document.body);
expect(host.previousElementSibling).toBe(document.querySelector('nav'));
expect(host.nextElementSibling).toBe(document.querySelector('footer'));
if (targetType !== 'body') {
expect(host.parentElement).toBe(document.body);
expect(host.previousElementSibling).toBe(document.querySelector('nav'));
expect(host.nextElementSibling).toBe(document.querySelector('footer'));
}
const contentElm = content || viewport;
if (textarea) {
if (targetType === 'textarea') {
expect(target.parentElement).toBe(contentElm);
expect(contentElm.innerHTML).toBe(textareaContent);
} else {
@@ -128,7 +145,7 @@ const createStructureSetupProxy = (
};
const assertCorrectSetupElements = (
textarea: boolean,
targetType: TargetType,
setupElementsProxy: StructureSetupElementsProxy,
environment: InternalEnvironment
): [StructureSetupElementsObj, () => void] => {
@@ -143,11 +160,13 @@ const assertCorrectSetupElements = (
_viewportHasClass,
_viewportAddRemoveClass,
} = elements;
const { target, host, padding, viewport, content } = getElements(textarea);
const { target, host, padding, viewport, content } = getElements(targetType);
const isTextarea = target.matches('textarea');
const isBody = target.matches('body');
expect(textarea).toBe(isTextarea);
if (targetType !== 'element') {
expect(target.matches(targetType)).toBe(true);
}
expect(_target).toBe(target);
expect(_host).toBe(host);
@@ -222,52 +241,36 @@ const assertCorrectSetupElements = (
if (input === undefined) {
if (isStaticStrategy) {
strategy = strategy as StructureStaticInitializationElement;
if (typeof strategy === 'function') {
const result = strategy(target);
if (_viewportIsTarget) {
if (kind === 'host') {
expect(elm).toBeTruthy();
} else {
expect(elm).toBeFalsy();
}
} else if (result && !isTextarea) {
expect(result).toBe(elm);
} else {
const resultingStrategy = typeof strategy === 'function' ? strategy(target) : strategy;
if (_viewportIsTarget) {
if (kind === 'host') {
expect(elm).toBeTruthy();
} else {
expect(elm).toBeFalsy();
}
} else if (resultingStrategy && !isTextarea) {
expect(resultingStrategy).toBe(elm);
} else {
expect(elm).toBeTruthy();
}
} else {
strategy = strategy as StructureDynamicInitializationElement;
if (typeof strategy === 'function') {
const result = strategy(target);
const resultIsBoolean = typeof result === 'boolean';
if (_viewportIsTarget) {
if (kind === 'host') {
expect(elm).toBeTruthy();
} else {
expect(elm).toBeFalsy();
}
} else if (resultIsBoolean) {
if (result) {
expect(elm).toBeTruthy();
} else {
expect(elm).toBeFalsy();
}
} else if (result) {
expect(elm).toBe(result);
const resultingStrategy = typeof strategy === 'function' ? strategy(target) : strategy;
const resultIsBoolean = typeof resultingStrategy === 'boolean';
if (_viewportIsTarget) {
if (kind === 'host') {
expect(elm).toBeTruthy();
} else {
expect(elm).toBeFalsy();
}
} else {
const strategyIsBoolean = typeof strategy === 'boolean';
if (strategyIsBoolean) {
if (strategy) {
expect(elm).toBeTruthy();
} else {
expect(elm).toBeFalsy();
}
} else if (resultIsBoolean) {
if (resultingStrategy) {
expect(elm).toBeTruthy();
} else {
expect(elm).toBeFalsy();
}
} else if (resultingStrategy) {
expect(elm).toBe(resultingStrategy);
}
}
}
@@ -345,7 +348,7 @@ const envNativeScrollbarStyling = {
name: 'native scrollbar styling',
env: {
...env,
_nativeScrollbarStyling: true,
_nativeScrollbarsHiding: true,
},
};
const envCssCustomProperties = {
@@ -359,11 +362,12 @@ const envInitStrategyMin = {
name: 'initialization strategy min',
env: {
...env,
_getInitializationStrategy: () => ({
_host: null,
_viewport: () => null,
_content: () => false,
_padding: false,
_getDefaultInitialization: () => ({
...env._staticDefaultInitialization,
host: null,
viewport: () => null,
content: () => false,
padding: false,
}),
},
};
@@ -371,11 +375,12 @@ const envInitStrategyMax = {
name: 'initialization strategy max',
env: {
...env,
_getInitializationStrategy: () => ({
_host: null,
_viewport: null,
_content: true,
_padding: () => true,
_getDefaultInitialization: () => ({
...env._staticDefaultInitialization,
host: null,
viewport: null,
content: true,
padding: () => true,
}),
},
};
@@ -383,21 +388,23 @@ const envInitStrategyAssigned = {
name: 'initialization strategy assigned',
env: {
...env,
_getInitializationStrategy: () => ({
_host: () => document.querySelector('#host1') as HTMLElement,
_viewport: (target: HTMLElement) => target.querySelector('#viewport') as HTMLElement,
_content: (target: HTMLElement) => target.querySelector<HTMLElement>('#content'),
_padding: (target: HTMLElement) => target.querySelector<HTMLElement>('#padding'),
_getDefaultInitialization: () => ({
...env._staticDefaultInitialization,
host: () => document.querySelector('#host1') as HTMLElement,
viewport: (target: HTMLElement) => target.querySelector('#viewport') as HTMLElement,
content: (target: HTMLElement) => target.querySelector<HTMLElement>('#content'),
padding: (target: HTMLElement) => target.querySelector<HTMLElement>('#padding'),
}),
},
};
const envInitStrategyViewportIsTarget = {
name: 'initialization strategy assigned',
name: 'initialization strategy viewport is target',
env: {
...env,
_nativeScrollbarStyling: true,
_getInitializationStrategy: () => ({
_viewport: (target: HTMLElement) => target,
_nativeScrollbarsHiding: true,
_getDefaultInitialization: () => ({
...env._staticDefaultInitialization,
viewport: (target: HTMLElement) => !is(target, 'textarea') && target,
}),
},
};
@@ -420,28 +427,28 @@ describe('structureSetup', () => {
mockGetEnvironment.mockImplementation(() => currEnv);
});
[false, true].forEach((isTextarea) => {
describe(isTextarea ? 'textarea' : 'element', () => {
(['element', 'textarea', 'body'] as TargetType[]).forEach((targetType) => {
describe(targetType, () => {
describe('basic', () => {
test('Element', () => {
const snapshot = fillBody(isTextarea);
const snapshot = fillBody(targetType);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
createStructureSetupProxy(getTarget(isTextarea)),
targetType,
createStructureSetupProxy(getTarget(targetType)),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
test('Object', () => {
const snapshot = fillBody(isTextarea);
const snapshot = fillBody(targetType);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
createStructureSetupProxy({ target: getTarget(isTextarea) }),
targetType,
createStructureSetupProxy({ target: getTarget(targetType) }),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
});
@@ -450,58 +457,58 @@ describe('structureSetup', () => {
describe('single assigned', () => {
test('padding', () => {
const snapshot = fillBody(
isTextarea,
targetType,
(content, hostId) =>
`<div id="${hostId}"><div id="padding">${content}</div></div>`
);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
host: document.querySelector<HTMLElement>('#host')!,
target: getTarget(isTextarea),
target: getTarget(targetType),
padding: () => document.querySelector<HTMLElement>('#padding')!,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
test('viewport', () => {
const snapshot = fillBody(
isTextarea,
targetType,
(content, hostId) =>
`<div id="${hostId}"><div id="viewport">${content}</div></div>`
);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
host: () => document.querySelector<HTMLElement>('#host')!,
target: getTarget(isTextarea),
target: getTarget(targetType),
viewport: document.querySelector<HTMLElement>('#viewport')!,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
test('content', () => {
const snapshot = fillBody(
isTextarea,
targetType,
(content, hostId) =>
`<div id="${hostId}"><div id="content">${content}</div></div>`
);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
host: document.querySelector<HTMLElement>('#host')!,
target: getTarget(isTextarea),
target: getTarget(targetType),
content: document.querySelector<HTMLElement>('#content')!,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
});
@@ -509,176 +516,176 @@ describe('structureSetup', () => {
describe('multiple assigned', () => {
test('padding viewport content', () => {
const snapshot = fillBody(
isTextarea,
targetType,
(content, hostId) =>
`<div id="${hostId}"><div id="padding"><div id="viewport"><div id="content">${content}</div></div></div></div>`
);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
host: document.querySelector<HTMLElement>('#host')!,
target: getTarget(isTextarea),
target: getTarget(targetType),
padding: document.querySelector<HTMLElement>('#padding')!,
viewport: document.querySelector<HTMLElement>('#viewport')!,
content: () => document.querySelector<HTMLElement>('#content')!,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
test('padding viewport', () => {
const snapshot = fillBody(
isTextarea,
targetType,
(content, hostId) =>
`<div id="${hostId}"><div id="padding"><div id="viewport">${content}</div></div></div>`
);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
host: () => document.querySelector<HTMLElement>('#host')!,
target: getTarget(isTextarea),
target: getTarget(targetType),
padding: document.querySelector<HTMLElement>('#padding')!,
viewport: document.querySelector<HTMLElement>('#viewport')!,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
test('padding content', () => {
const snapshot = fillBody(
isTextarea,
targetType,
(content, hostId) =>
`<div id="${hostId}"><div id="padding"><div id="content">${content}</div></div></div>`
);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
host: document.querySelector<HTMLElement>('#host')!,
target: getTarget(isTextarea),
target: getTarget(targetType),
padding: () => document.querySelector<HTMLElement>('#padding')!,
content: document.querySelector<HTMLElement>('#content')!,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
test('viewport content', () => {
const snapshot = fillBody(
isTextarea,
targetType,
(content, hostId) =>
`<div id="${hostId}"><div id="viewport"><div id="content">${content}</div></div></div>`
);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
host: document.querySelector<HTMLElement>('#host')!,
target: getTarget(isTextarea),
target: getTarget(targetType),
viewport: document.querySelector<HTMLElement>('#viewport')!,
content: () => document.querySelector<HTMLElement>('#content')!,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
});
describe('single false', () => {
test('padding', () => {
const snapshot = fillBody(isTextarea);
const snapshot = fillBody(targetType);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
target: getTarget(isTextarea),
target: getTarget(targetType),
padding: false,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
test('content', () => {
const snapshot = fillBody(isTextarea);
const snapshot = fillBody(targetType);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
target: getTarget(isTextarea),
target: getTarget(targetType),
content: () => false,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
});
describe('single true', () => {
test('padding', () => {
const snapshot = fillBody(isTextarea);
const snapshot = fillBody(targetType);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
target: getTarget(isTextarea),
target: getTarget(targetType),
padding: () => true,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
test('content', () => {
const snapshot = fillBody(isTextarea);
const snapshot = fillBody(targetType);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
target: getTarget(isTextarea),
target: getTarget(targetType),
content: true,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
});
describe('multiple false', () => {
test('padding & content', () => {
const snapshot = fillBody(isTextarea);
const snapshot = fillBody(targetType);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
target: getTarget(isTextarea),
target: getTarget(targetType),
padding: false,
content: false,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
});
describe('multiple true', () => {
test('padding & content', () => {
const snapshot = fillBody(isTextarea);
const snapshot = fillBody(targetType);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
target: getTarget(isTextarea),
target: getTarget(targetType),
padding: true,
content: true,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
});
@@ -686,329 +693,329 @@ describe('structureSetup', () => {
describe('mixed', () => {
test('false: padding & content | assigned: viewport', () => {
const snapshot = fillBody(
isTextarea,
targetType,
(content, hostId) =>
`<div id="${hostId}"><div id="viewport">${content}</div></div>`
);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
host: document.querySelector<HTMLElement>('#host')!,
target: getTarget(isTextarea),
target: getTarget(targetType),
padding: false,
viewport: document.querySelector<HTMLElement>('#viewport')!,
content: false,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
test('true: padding & content | assigned: viewport', () => {
const snapshot = fillBody(
isTextarea,
targetType,
(content, hostId) =>
`<div id="${hostId}"><div id="viewport">${content}</div></div>`
);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
host: document.querySelector<HTMLElement>('#host')!,
target: getTarget(isTextarea),
target: getTarget(targetType),
padding: true,
viewport: document.querySelector<HTMLElement>('#viewport')!,
content: true,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
test('true: content | false: padding | assigned: viewport', () => {
const snapshot = fillBody(
isTextarea,
targetType,
(content, hostId) =>
`<div id="${hostId}"><div id="viewport">${content}</div></div>`
);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
host: document.querySelector<HTMLElement>('#host')!,
target: getTarget(isTextarea),
target: getTarget(targetType),
padding: () => false,
viewport: document.querySelector<HTMLElement>('#viewport')!,
content: () => true,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
test('true: padding | false: content | assigned: viewport', () => {
const snapshot = fillBody(
isTextarea,
targetType,
(content, hostId) =>
`<div id="${hostId}"><div id="viewport">${content}</div></div>`
);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
host: document.querySelector<HTMLElement>('#host')!,
target: getTarget(isTextarea),
target: getTarget(targetType),
padding: true,
viewport: () => document.querySelector<HTMLElement>('#viewport')!,
content: false,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
test('false: padding | assigned: content', () => {
const snapshot = fillBody(
isTextarea,
targetType,
(content, hostId) =>
`<div id="${hostId}"><div id="content">${content}</div></div>`
);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
host: document.querySelector<HTMLElement>('#host')!,
target: getTarget(isTextarea),
target: getTarget(targetType),
padding: false,
content: document.querySelector<HTMLElement>('#content')!,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
test('true: padding | assigned: content', () => {
const snapshot = fillBody(
isTextarea,
targetType,
(content, hostId) =>
`<div id="${hostId}"><div id="content">${content}</div></div>`
);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
host: document.querySelector<HTMLElement>('#host')!,
target: getTarget(isTextarea),
target: getTarget(targetType),
padding: true,
content: document.querySelector<HTMLElement>('#content')!,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
test('false: padding | assigned: viewport', () => {
const snapshot = fillBody(
isTextarea,
targetType,
(content, hostId) =>
`<div id="${hostId}"><div id="viewport">${content}</div></div>`
);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
host: document.querySelector<HTMLElement>('#host')!,
target: getTarget(isTextarea),
target: getTarget(targetType),
padding: () => false,
viewport: document.querySelector<HTMLElement>('#viewport')!,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
test('true: padding | assigned: viewport', () => {
const snapshot = fillBody(
isTextarea,
targetType,
(content, hostId) =>
`<div id="${hostId}"><div id="viewport">${content}</div></div>`
);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
host: document.querySelector<HTMLElement>('#host')!,
target: getTarget(isTextarea),
target: getTarget(targetType),
padding: true,
viewport: document.querySelector<HTMLElement>('#viewport')!,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
test('false: padding | assigned: viewport & content', () => {
const snapshot = fillBody(
isTextarea,
targetType,
(content, hostId) =>
`<div id="${hostId}"><div id="viewport"><div id="content">${content}</div></div></div>`
);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
host: document.querySelector<HTMLElement>('#host')!,
target: getTarget(isTextarea),
target: getTarget(targetType),
viewport: document.querySelector<HTMLElement>('#viewport')!,
padding: false,
content: () => document.querySelector<HTMLElement>('#content')!,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
test('true: padding | assigned: viewport & content', () => {
const snapshot = fillBody(
isTextarea,
targetType,
(content, hostId) =>
`<div id="${hostId}"><div id="viewport"><div id="content">${content}</div></div></div>`
);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
host: document.querySelector<HTMLElement>('#host')!,
target: getTarget(isTextarea),
target: getTarget(targetType),
viewport: () => document.querySelector<HTMLElement>('#viewport')!,
padding: true,
content: document.querySelector<HTMLElement>('#content')!,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
test('false: content | assigned: padding', () => {
const snapshot = fillBody(
isTextarea,
targetType,
(content, hostId) =>
`<div id="${hostId}"><div id="padding">${content}</div></div>`
);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
host: document.querySelector<HTMLElement>('#host')!,
target: getTarget(isTextarea),
target: getTarget(targetType),
padding: document.querySelector<HTMLElement>('#padding')!,
content: false,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
test('true: content | assigned: padding', () => {
const snapshot = fillBody(
isTextarea,
targetType,
(content, hostId) =>
`<div id="${hostId}"><div id="padding">${content}</div></div>`
);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
host: () => document.querySelector<HTMLElement>('#host')!,
target: getTarget(isTextarea),
target: getTarget(targetType),
padding: document.querySelector<HTMLElement>('#padding')!,
content: true,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
test('false: content | assigned: viewport', () => {
const snapshot = fillBody(
isTextarea,
targetType,
(content, hostId) =>
`<div id="${hostId}"><div id="viewport">${content}</div></div>`
);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
host: document.querySelector<HTMLElement>('#host')!,
target: getTarget(isTextarea),
target: getTarget(targetType),
viewport: () => document.querySelector<HTMLElement>('#viewport')!,
content: false,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
test('true: content | assigned: viewport', () => {
const snapshot = fillBody(
isTextarea,
targetType,
(content, hostId) =>
`<div id="${hostId}"><div id="viewport">${content}</div></div>`
);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
host: document.querySelector<HTMLElement>('#host')!,
target: getTarget(isTextarea),
target: getTarget(targetType),
viewport: document.querySelector<HTMLElement>('#viewport')!,
content: true,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
test('false: content | assigned: padding & viewport', () => {
const snapshot = fillBody(
isTextarea,
targetType,
(content, hostId) =>
`<div id="${hostId}"><div id="padding"><div id="viewport">${content}</div></div></div>`
);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
host: document.querySelector<HTMLElement>('#host')!,
target: getTarget(isTextarea),
target: getTarget(targetType),
padding: () => document.querySelector<HTMLElement>('#padding')!,
viewport: document.querySelector<HTMLElement>('#viewport')!,
content: () => false,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
test('true: content | assigned: padding & viewport', () => {
const snapshot = fillBody(
isTextarea,
targetType,
(content, hostId) =>
`<div id="${hostId}"><div id="padding"><div id="viewport">${content}</div></div></div>`
);
const [elements, destroy] = assertCorrectSetupElements(
isTextarea,
targetType,
createStructureSetupProxy({
host: () => document.querySelector<HTMLElement>('#host')!,
target: getTarget(isTextarea),
target: getTarget(targetType),
padding: document.querySelector<HTMLElement>('#padding')!,
viewport: () => document.querySelector<HTMLElement>('#viewport')!,
content: true,
}),
currEnv
);
assertCorrectDOMStructure(isTextarea, elements._viewportIsTarget);
assertCorrectDOMStructure(targetType, elements._viewportIsTarget);
assertCorrectDestroy(snapshot, destroy);
});
});
@@ -1,7 +1,6 @@
import { isEmptyObject } from 'support/utils/object';
import { isString, isPlainObject } from 'support/utils/types';
import { style, hide, show, topRightBottomLeft } from 'support/dom/style';
import { StyleObject } from 'typings';
import { style, hide, show, topRightBottomLeft, directionIsRTL } from 'support/dom/style';
describe('dom style', () => {
afterEach(() => {
@@ -36,8 +35,6 @@ describe('dom style', () => {
style(document.body, { width: '123px' });
expect(document.body.style.width).toBe('123px');
interface O {}
expect(document.body.style.getPropertyValue('--custom')).toBe('');
style<'--custom'>(document.body, { '--custom': '123px' });
expect(document.body.style.getPropertyValue('--custom')).toBe('123px');
@@ -62,7 +59,13 @@ describe('dom style', () => {
expect(document.body.style.zIndex).toBe('');
expect(document.body.style.lineHeight).toBe('');
expect(document.body.style.getPropertyValue('--custom')).toBe('');
style<'--custom'>(document.body, { width: '123px', height: 321, opacity: '0.5', zIndex: 1, '--custom': '123px' });
style<'--custom'>(document.body, {
width: '123px',
height: 321,
opacity: '0.5',
zIndex: 1,
'--custom': '123px',
});
expect(document.body.style.width).toBe('123px');
expect(document.body.style.height).toBe('321px');
expect(document.body.style.opacity).toBe('0.5');
@@ -138,4 +141,18 @@ describe('dom style', () => {
});
});
});
describe('directionIsRTL', () => {
test('normal', () => {
document.body.setAttribute('style', 'direction: rtl');
expect(directionIsRTL(document.body)).toBe(true);
document.body.setAttribute('style', 'direction: ltr');
expect(directionIsRTL(document.body)).toBe(false);
});
test('null', () => {
expect(directionIsRTL(null)).toBe(false);
});
});
});
@@ -1,7 +1,18 @@
import { find, findFirst, is, children, contents, parent, createDiv, liesBetween, createDOM } from 'support/dom';
import {
find,
findFirst,
is,
children,
contents,
parent,
createDiv,
liesBetween,
createDOM,
} from 'support/dom';
const slotElm = document.body;
const testHTML = '<div id="parent" class="div-class"><div id="child" class="div-class"></div></div><p>2</p><input type="text" value="3"></input>abc';
const testHTML =
'<div id="parent" class="div-class"><div id="child" class="div-class"></div></div><p>2</p><input type="text" value="3"></input>abc';
describe('dom traversal', () => {
beforeEach(() => {
@@ -225,10 +236,18 @@ describe('dom traversal', () => {
});
describe('liesBetween', () => {
const elmsBetween = ['.host', '.something', '.something-a', '.something-b', '.padding', '.viewport', '.content'];
const elmsBetween = [
'.host',
'.something',
'.something-a',
'.something-b',
'.padding',
'.viewport',
'.content',
];
const elmsOutside = ['.allowed-a', '.allowed-b', '.allowed-c', '.deeper-a', '.deeper-b'];
const elmsToTest = [...elmsBetween, ...elmsOutside];
const domPart = (id: string, content?: string) => `
const nestedDomPart = (id: string, content?: string) => `
<div id="${id}" class="host">
<div class="something">
<div class="something-a">
@@ -244,17 +263,39 @@ describe('dom traversal', () => {
</div>
</div>
</div>
</div>
`;
const createTestDOM = (nestings = 0) => {
</div>`;
const createNestedTestDOM = (nestings = 0) => {
let part = '';
for (let i = 0; i < nestings + 1; i++) {
part = domPart(`host-${nestings - i}`, part);
part = nestedDomPart(`host-${nestings - i}`, part);
}
return part;
};
const genericTest = (nestings: number) => {
const createSpecialTestDOM = () => `
<div class="host">
<div class="allowed-a">
<div class="allowed-b">
<div class="allowed-c">
</div>
</div>
</div>
<div class="host">
<div class="something">
<div class="something-a">
</div>
</div>
<div class="padding">
<div class="something-b"></div>
<div class="viewport">
<div class="content">
<div class="deeper-a"><div class="deeper-b"></div></div>
</div>
</div>
</div>
</div>
</div>`;
const genericTest = (nestings = 0) => {
const allHostIds = Array(nestings)
.fill(0)
.map((_, index) => `#host-${index}`);
@@ -263,11 +304,19 @@ describe('dom traversal', () => {
const runExpectance = (id: string) => {
const isRemainingId = remainingIds.includes(id);
elmsToTest.forEach((elm) => {
const hostElm = findFirst(`${id}`);
const searchElm = hostElm?.classList.contains(elm.substring(1)) ? hostElm : findFirst(`${id} ${elm}`);
const hostElm = findFirst(`${id}`) as HTMLElement;
const searchElm = hostElm?.classList.contains(elm.substring(1))
? hostElm
: findFirst(`${id} ${elm}`);
expect(liesBetween(searchElm, `${hostId}`, '.content')).toBe(
isRemainingId ? false : elmsBetween.includes(elm) ? true : elmsOutside.includes(elm) ? false : undefined
isRemainingId
? false
: elmsBetween.includes(elm)
? true
: elmsOutside.includes(elm)
? false
: undefined
);
});
};
@@ -295,24 +344,32 @@ describe('dom traversal', () => {
}
};
test('with native closest', () => {
slotElm.innerHTML = createTestDOM(3);
test('nested with native closest', () => {
slotElm.innerHTML = createNestedTestDOM(3);
genericTest(3);
});
test('with polyfill closest', () => {
test('nested with polyfill closest', () => {
const original = Element.prototype.closest;
// @ts-ignore
Element.prototype.closest = undefined;
slotElm.innerHTML = createTestDOM(3);
slotElm.innerHTML = createNestedTestDOM(3);
genericTest(3);
Element.prototype.closest = original;
});
test('special with polyfill closest', () => {
slotElm.innerHTML = createSpecialTestDOM();
genericTest();
});
test('text node', () => {
expect(liesBetween(createDOM('<div>textnodehere</div>')[0].firstChild, '.a', '.b')).toEqual(false);
slotElm.innerHTML = createNestedTestDOM(3);
expect(liesBetween(createDOM('<div>textnodehere</div>')[0].firstChild, '.a', '.b')).toEqual(
false
);
});
});
});