mirror of
https://github.com/tenrok/OverlayScrollbars.git
synced 2026-06-23 01:10:37 +03:00
introduce plugin system and split option validation into a plugin
This commit is contained in:
@@ -1,9 +1,252 @@
|
||||
import { validateOptions } from 'support/options';
|
||||
import { defaultOptions, optionsTemplate } from 'options';
|
||||
import { defaultOptions, getOptionsDiff } from 'options';
|
||||
|
||||
describe('options', () => {
|
||||
test('default options matching the options template', () => {
|
||||
const { _validated } = validateOptions(defaultOptions, optionsTemplate);
|
||||
expect(_validated).toEqual(defaultOptions);
|
||||
test('defaultOptions', () => {
|
||||
expect(defaultOptions).toEqual({
|
||||
resize: 'none',
|
||||
paddingAbsolute: false,
|
||||
updating: {
|
||||
elementEvents: [['img', 'load']],
|
||||
attributes: null,
|
||||
debounce: [0, 33],
|
||||
},
|
||||
overflow: {
|
||||
x: 'scroll',
|
||||
y: 'scroll',
|
||||
},
|
||||
scrollbars: {
|
||||
visibility: 'auto',
|
||||
autoHide: 'never',
|
||||
autoHideDelay: 800,
|
||||
dragScroll: true,
|
||||
clickScroll: false,
|
||||
touch: true,
|
||||
},
|
||||
textarea: {
|
||||
dynWidth: false,
|
||||
dynHeight: false,
|
||||
inheritedAttrs: ['style', 'class'],
|
||||
},
|
||||
nativeScrollbarsOverlaid: {
|
||||
show: false,
|
||||
initialize: false,
|
||||
},
|
||||
callbacks: {
|
||||
onUpdated: null,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
describe('getOptionsDiff', () => {
|
||||
test('diff simple options', () => {
|
||||
const options = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3,
|
||||
d: 4,
|
||||
e: 5,
|
||||
};
|
||||
const changed = {
|
||||
a: 0,
|
||||
b: 0,
|
||||
};
|
||||
|
||||
expect(getOptionsDiff(options, changed)).toEqual(changed);
|
||||
|
||||
expect(
|
||||
getOptionsDiff(options, {
|
||||
...options,
|
||||
...changed,
|
||||
})
|
||||
).toEqual(changed);
|
||||
});
|
||||
|
||||
test('diff nested options', () => {
|
||||
const options = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3,
|
||||
d: 4,
|
||||
e: 5,
|
||||
deep: {
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3,
|
||||
d: 4,
|
||||
},
|
||||
};
|
||||
const changed = {
|
||||
a: 0,
|
||||
b: 0,
|
||||
deep: {
|
||||
a: 0,
|
||||
b: 0,
|
||||
},
|
||||
};
|
||||
|
||||
expect(getOptionsDiff(options, changed)).toEqual(changed);
|
||||
|
||||
expect(
|
||||
getOptionsDiff(options, {
|
||||
...options,
|
||||
...changed,
|
||||
})
|
||||
).toEqual(changed);
|
||||
|
||||
expect(
|
||||
getOptionsDiff(options, {
|
||||
...options,
|
||||
...changed,
|
||||
deep: {
|
||||
...options.deep,
|
||||
...changed.deep,
|
||||
},
|
||||
})
|
||||
).toEqual(changed);
|
||||
});
|
||||
|
||||
test('diff foreign options', () => {
|
||||
const options = {
|
||||
a: 1,
|
||||
b: 2,
|
||||
c: 3,
|
||||
};
|
||||
const changed = {
|
||||
a: 0,
|
||||
d: 4,
|
||||
e: 5,
|
||||
};
|
||||
|
||||
expect(getOptionsDiff(options, changed)).toEqual(changed);
|
||||
|
||||
expect(
|
||||
getOptionsDiff(options, {
|
||||
...options,
|
||||
...changed,
|
||||
})
|
||||
).toEqual(changed);
|
||||
});
|
||||
|
||||
describe('diff arrays', () => {
|
||||
test('dont diff same looking arrays with primitve values', () => {
|
||||
const options = {
|
||||
a: [],
|
||||
b: [1, 2, 3],
|
||||
c: ['1', '2', '3'],
|
||||
d: [true, false, false],
|
||||
};
|
||||
const changed = {
|
||||
a: [],
|
||||
b: [1, 2, 3],
|
||||
c: ['1', '2', '3'],
|
||||
d: [true, false, false],
|
||||
};
|
||||
|
||||
expect(
|
||||
getOptionsDiff(options, {
|
||||
...options,
|
||||
...changed,
|
||||
})
|
||||
).toEqual({});
|
||||
|
||||
expect(getOptionsDiff(options, changed)).toEqual({});
|
||||
});
|
||||
|
||||
test('dont diff same looking arrays with non-primitve values', () => {
|
||||
const options = {
|
||||
a: [],
|
||||
b: [{ a: 1 }, { b: 2 }, { c: 3 }, ['tuple1', 'tuple2'], []],
|
||||
c: [
|
||||
['tuple1', 'tuple2'],
|
||||
['tuple1', 'tuple2'],
|
||||
['tuple1', 'tuple2'],
|
||||
],
|
||||
};
|
||||
const changed = {
|
||||
a: [],
|
||||
b: [{ a: 1 }, { b: 2 }, { c: 3 }, ['tuple1', 'tuple2'], []],
|
||||
c: [
|
||||
['tuple1', 'tuple2'],
|
||||
['tuple1', 'tuple2'],
|
||||
['tuple1', 'tuple2'],
|
||||
],
|
||||
};
|
||||
|
||||
expect(
|
||||
getOptionsDiff(options, {
|
||||
...options,
|
||||
...changed,
|
||||
})
|
||||
).toEqual({});
|
||||
|
||||
expect(getOptionsDiff(options, changed)).toEqual({});
|
||||
});
|
||||
|
||||
test('diff arrays with primitve values', () => {
|
||||
const options = {
|
||||
a: [] as string[],
|
||||
b: [1, 2, 3],
|
||||
c: ['1', '2', '3'],
|
||||
d: [true, false, false],
|
||||
};
|
||||
const changed = {
|
||||
a: ['hello'],
|
||||
b: [1, 2, 3, 4],
|
||||
c: ['1', '2', '3', '4'],
|
||||
d: [true, false, false, true],
|
||||
};
|
||||
|
||||
expect(
|
||||
getOptionsDiff(options, {
|
||||
...options,
|
||||
...changed,
|
||||
})
|
||||
).toEqual(changed);
|
||||
|
||||
expect(getOptionsDiff(options, changed)).toEqual(changed);
|
||||
});
|
||||
|
||||
test('diff arrays with mixed values', () => {
|
||||
const options = {
|
||||
a: [] as Record<string, unknown>[],
|
||||
b: [1, 2, 3] as Array<number | (() => void)>,
|
||||
c: ['1', '2', '3'] as Array<string | Record<string, unknown>>,
|
||||
d: [true, false, false],
|
||||
};
|
||||
const changed = {
|
||||
a: [{}],
|
||||
b: [1, 2, 3, () => {}],
|
||||
c: ['1', '2', '3', {}],
|
||||
};
|
||||
|
||||
expect(getOptionsDiff(options, changed)).toEqual(changed);
|
||||
|
||||
expect(
|
||||
getOptionsDiff(options, {
|
||||
...options,
|
||||
...changed,
|
||||
})
|
||||
).toEqual(changed);
|
||||
});
|
||||
|
||||
test('diff same looking arrays with not serializable values', () => {
|
||||
const fn = () => {};
|
||||
const options = {
|
||||
c: [fn, fn, () => {}],
|
||||
};
|
||||
const changed = {
|
||||
c: [fn, fn, () => {}],
|
||||
};
|
||||
|
||||
expect(
|
||||
getOptionsDiff(options, {
|
||||
...options,
|
||||
...changed,
|
||||
})
|
||||
).toEqual(changed);
|
||||
|
||||
expect(getOptionsDiff(options, changed)).toEqual(changed);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
import { defaultOptions } from 'options';
|
||||
import { optionsValidationPlugin, optionsValidationPluginName } from 'plugins/optionsValidation';
|
||||
|
||||
const getValidationFn = () => {
|
||||
const [name, instance] = optionsValidationPlugin;
|
||||
const validationFn = instance._;
|
||||
|
||||
expect(name).toBe(optionsValidationPluginName);
|
||||
expect(typeof validationFn).toBe('function');
|
||||
return validationFn;
|
||||
};
|
||||
|
||||
describe('optionsValidationPlugin', () => {
|
||||
test('default options matching the options template', () => {
|
||||
const validationFn = getValidationFn();
|
||||
|
||||
expect(validationFn(defaultOptions)).toEqual(defaultOptions);
|
||||
});
|
||||
|
||||
test('foreign options are in the result', () => {
|
||||
const validationFn = getValidationFn();
|
||||
const foreignOps = {
|
||||
someOption: true,
|
||||
someDeepOption: {
|
||||
someDeepOption: false,
|
||||
},
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
expect(validationFn(foreignOps)).toEqual(foreignOps);
|
||||
});
|
||||
});
|
||||
+10
-3
@@ -1,5 +1,12 @@
|
||||
import { PlainObject } from 'typings';
|
||||
import { optionsTemplateTypes as oTypes, transformOptions, OptionsTemplate, OptionsWithOptionsTemplate } from 'support/options';
|
||||
import {
|
||||
optionsTemplateTypes as oTypes,
|
||||
OptionsTemplate,
|
||||
} from 'plugins/optionsValidation/validation';
|
||||
import {
|
||||
transformOptions,
|
||||
OptionsWithOptionsTemplate,
|
||||
} from 'plugins/optionsValidation/transformation';
|
||||
|
||||
type TestOptionsObj = { propA: 'propA'; null: null };
|
||||
type TestOptionsEnum = 'A' | 'B' | 'C';
|
||||
@@ -36,7 +43,7 @@ const options: DeepRequired<TestOptions> = {
|
||||
func: () => {},
|
||||
};
|
||||
|
||||
const optionsTemplate: OptionsTemplate<Required<TestOptions>> = {
|
||||
const optionsTemplate: OptionsTemplate<DeepRequired<TestOptions>> = {
|
||||
str: oTypes.string,
|
||||
strArrNull: [oTypes.string, oTypes.array, oTypes.null],
|
||||
nullbool: [oTypes.boolean, oTypes.null],
|
||||
@@ -51,7 +58,7 @@ const optionsTemplate: OptionsTemplate<Required<TestOptions>> = {
|
||||
func: oTypes.function,
|
||||
};
|
||||
|
||||
const TestOptionsWithOptionsTemplate: OptionsWithOptionsTemplate<Required<TestOptions>> = {
|
||||
const TestOptionsWithOptionsTemplate: OptionsWithOptionsTemplate<DeepRequired<TestOptions>> = {
|
||||
str: [options.str, optionsTemplate.str],
|
||||
strArrNull: [options.strArrNull, optionsTemplate.strArrNull],
|
||||
nullbool: [options.nullbool, optionsTemplate.nullbool],
|
||||
@@ -0,0 +1,303 @@
|
||||
import {
|
||||
validateOptions,
|
||||
optionsTemplateTypes as oTypes,
|
||||
OptionsTemplate,
|
||||
} from 'plugins/optionsValidation/validation';
|
||||
import { assignDeep } from 'support/utils';
|
||||
|
||||
type TestOptionsObj = { propA: 'propA'; null: null };
|
||||
type TestOptionsEnum = 'A' | 'B' | 'C';
|
||||
type TestOptions = {
|
||||
str: string;
|
||||
strArrNull: string | Array<string> | null;
|
||||
nullbool: boolean | null;
|
||||
nested: {
|
||||
num: number;
|
||||
switch: boolean;
|
||||
abc: TestOptionsEnum;
|
||||
};
|
||||
obj: TestOptionsObj | null;
|
||||
abc: TestOptionsEnum;
|
||||
arr: Array<any>;
|
||||
func: () => void;
|
||||
};
|
||||
|
||||
const options: TestOptions = {
|
||||
str: 'hi',
|
||||
strArrNull: null,
|
||||
nullbool: true,
|
||||
nested: {
|
||||
num: 1,
|
||||
switch: false,
|
||||
abc: 'B',
|
||||
},
|
||||
obj: { propA: 'propA', null: null },
|
||||
abc: 'A',
|
||||
arr: [1, 2, 3],
|
||||
func: () => {},
|
||||
};
|
||||
|
||||
const template: OptionsTemplate<TestOptions> = {
|
||||
str: oTypes.string,
|
||||
strArrNull: [oTypes.string, oTypes.array, oTypes.null],
|
||||
nullbool: [oTypes.boolean, oTypes.null],
|
||||
nested: {
|
||||
num: oTypes.number,
|
||||
switch: oTypes.boolean,
|
||||
abc: 'A B C',
|
||||
},
|
||||
obj: [oTypes.object, oTypes.null],
|
||||
abc: 'A B C',
|
||||
arr: oTypes.array,
|
||||
func: oTypes.function,
|
||||
};
|
||||
|
||||
describe('options validation', () => {
|
||||
describe('object return & mutation', () => {
|
||||
test('foreign properties wont affect validated object', () => {
|
||||
const foreignObj = {
|
||||
foreignProp: 'foreign',
|
||||
foreignDeep: { a: 'A', b: 'B' },
|
||||
};
|
||||
const modifiedOptions = assignDeep({}, options, { nested: foreignObj }, foreignObj);
|
||||
const [validated, foreign] = validateOptions(template, modifiedOptions);
|
||||
|
||||
expect(validated).toEqual(options);
|
||||
expect(foreign).toEqual({ ...foreignObj, nested: foreignObj });
|
||||
});
|
||||
|
||||
test('passed object isnt returned object', () => {
|
||||
const clonedOptions = assignDeep({}, options);
|
||||
const [validated, foreign] = validateOptions(template, clonedOptions);
|
||||
|
||||
expect(validated).not.toBe(clonedOptions);
|
||||
expect(foreign).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('foreign property return', () => {
|
||||
test('return no foreign property', () => {
|
||||
const [, foreign] = validateOptions(template, options);
|
||||
|
||||
expect(foreign).toEqual({});
|
||||
});
|
||||
|
||||
test('return signle non-object foreign property', () => {
|
||||
const foreignObj = { foreignProp: 'foreign' };
|
||||
const modifiedOptions = assignDeep({}, options, foreignObj);
|
||||
const [, foreign] = validateOptions(template, modifiedOptions);
|
||||
|
||||
expect(foreign).toEqual(foreignObj);
|
||||
});
|
||||
|
||||
test('return complex foreign properties', () => {
|
||||
const foreignObj = {
|
||||
foreignProp: 'foreign',
|
||||
foreignDeep: { a: 'A', b: 'B' },
|
||||
};
|
||||
const modifiedOptions = assignDeep({}, options, foreignObj);
|
||||
const [, foreign] = validateOptions(template, modifiedOptions);
|
||||
|
||||
expect(foreign).toEqual(foreignObj);
|
||||
});
|
||||
|
||||
test('return nested complex foreign properties', () => {
|
||||
const foreignObj = {
|
||||
foreignProp: 'foreign',
|
||||
foreignDeep: { a: 'A', b: 'B' },
|
||||
};
|
||||
const modifiedOptions = assignDeep({}, options, { nested: foreignObj }, foreignObj);
|
||||
const [, foreign] = validateOptions(template, modifiedOptions);
|
||||
|
||||
expect(foreign.nested).toEqual(foreignObj);
|
||||
delete foreign.nested;
|
||||
expect(foreign).toEqual(foreignObj);
|
||||
});
|
||||
});
|
||||
|
||||
describe('value validity', () => {
|
||||
test('single value doesnt match template', () => {
|
||||
const modifiedOptions = assignDeep({}, options, { str: 1 });
|
||||
const [validated] = validateOptions(template, modifiedOptions);
|
||||
|
||||
expect(validated).not.toHaveProperty('str');
|
||||
});
|
||||
|
||||
test('single enum value doesnt match template', () => {
|
||||
const modifiedOptions = assignDeep({}, options, { abc: 'testval' });
|
||||
const [validated] = validateOptions(template, modifiedOptions);
|
||||
|
||||
expect(validated).not.toHaveProperty('abc');
|
||||
});
|
||||
|
||||
test('multiple values dont match template', () => {
|
||||
const modifiedOptions = assignDeep({}, options, {
|
||||
str: 1,
|
||||
abc: 'testval',
|
||||
nullbool: 'string',
|
||||
});
|
||||
const [validated] = validateOptions(template, modifiedOptions);
|
||||
|
||||
expect(validated).not.toHaveProperty('str');
|
||||
expect(validated).not.toHaveProperty('abc');
|
||||
expect(validated).not.toHaveProperty('nullbool');
|
||||
});
|
||||
|
||||
test('single nested value dont match template', () => {
|
||||
const modifiedOptions = assignDeep({}, options, { nested: { num: 'hi' } });
|
||||
const [validated] = validateOptions(template, modifiedOptions);
|
||||
|
||||
expect(validated.nested).not.toHaveProperty('num');
|
||||
});
|
||||
|
||||
test('single nested enum value dont match template', () => {
|
||||
const modifiedOptions = assignDeep({}, options, {
|
||||
nested: { abc: 'testabc' },
|
||||
});
|
||||
const [validated] = validateOptions(template, modifiedOptions);
|
||||
|
||||
expect(validated.nested).not.toHaveProperty('abc');
|
||||
});
|
||||
|
||||
test('multiple nested values dont match template', () => {
|
||||
const modifiedOptions = assignDeep({}, options, {
|
||||
nested: { num: 'hi', abc: 'testabc' },
|
||||
});
|
||||
const [validated] = validateOptions(template, modifiedOptions);
|
||||
|
||||
expect(validated.nested).not.toHaveProperty('num');
|
||||
expect(validated.nested).not.toHaveProperty('abc');
|
||||
});
|
||||
|
||||
test('all nested values dont match template', () => {
|
||||
const modifiedOptions = assignDeep({}, options, {
|
||||
nested: { num: 'hi', abc: 'testabc', switch: 1 },
|
||||
});
|
||||
const [validated] = validateOptions(template, modifiedOptions);
|
||||
|
||||
expect(validated).not.toHaveProperty('nested');
|
||||
});
|
||||
|
||||
test('all nested values dont match template with foreign property', () => {
|
||||
const modifiedOptions = assignDeep({}, options, {
|
||||
nested: {
|
||||
foreign: 'foreign',
|
||||
num: 'hi',
|
||||
abc: 'testabc',
|
||||
switch: 1,
|
||||
},
|
||||
});
|
||||
const [validated] = validateOptions(template, modifiedOptions);
|
||||
|
||||
expect(validated).not.toHaveProperty('nested');
|
||||
});
|
||||
|
||||
test('various values dont match template', () => {
|
||||
const modifiedOptions = assignDeep({}, options, {
|
||||
nested: { switch: null },
|
||||
obj: 1,
|
||||
abc: 'testest',
|
||||
func: {},
|
||||
});
|
||||
const [validated] = validateOptions(template, modifiedOptions);
|
||||
|
||||
expect(validated.nested).not.toHaveProperty('switch');
|
||||
expect(validated).not.toHaveProperty('obj');
|
||||
expect(validated).not.toHaveProperty('abc');
|
||||
expect(validated).not.toHaveProperty('func');
|
||||
});
|
||||
|
||||
test('various values dont match template with foreign properties', () => {
|
||||
const foreignObj = {
|
||||
foreignProp: 'foreign',
|
||||
foreignDeep: { a: 'A', b: 'B' },
|
||||
};
|
||||
const modifiedOptions = assignDeep(
|
||||
{},
|
||||
options,
|
||||
{
|
||||
nested: { switch: null },
|
||||
obj: 1,
|
||||
abc: 'testest',
|
||||
func: {},
|
||||
},
|
||||
foreignObj,
|
||||
{ nested: foreignObj }
|
||||
);
|
||||
const [validated, foreign] = validateOptions(template, modifiedOptions);
|
||||
|
||||
expect(foreign.nested).toEqual(foreignObj);
|
||||
delete foreign.nested;
|
||||
expect(foreign).toEqual(foreignObj);
|
||||
|
||||
expect(validated.nested).not.toHaveProperty('switch');
|
||||
expect(validated).not.toHaveProperty('obj');
|
||||
expect(validated).not.toHaveProperty('abc');
|
||||
expect(validated).not.toHaveProperty('func');
|
||||
});
|
||||
|
||||
test('nested object is string', () => {
|
||||
const modifiedOptions = assignDeep({}, options, { nested: 'string' });
|
||||
const [validated] = validateOptions(template, modifiedOptions);
|
||||
|
||||
expect(validated).not.toHaveProperty('nested');
|
||||
});
|
||||
|
||||
test('nested object is null', () => {
|
||||
const modifiedOptions = assignDeep({}, options, { nested: null });
|
||||
const [validated] = validateOptions(template, modifiedOptions);
|
||||
|
||||
expect(validated).not.toHaveProperty('nested');
|
||||
});
|
||||
|
||||
test('nested object is undefined', () => {
|
||||
const modifiedOptions: Partial<TestOptions> = assignDeep({}, options);
|
||||
modifiedOptions.nested = undefined;
|
||||
const [validated] = validateOptions(template, modifiedOptions);
|
||||
|
||||
expect(validated).not.toHaveProperty('nested');
|
||||
});
|
||||
});
|
||||
|
||||
describe('error logging', () => {
|
||||
test('dont log error if nothing is wrong', () => {
|
||||
const { warn } = console;
|
||||
console.warn = jest.fn();
|
||||
|
||||
validateOptions(template, options, true);
|
||||
expect(console.warn).not.toBeCalled();
|
||||
|
||||
console.warn = warn;
|
||||
});
|
||||
|
||||
test('dont log error if something is wrong and flag is false', () => {
|
||||
const { warn } = console;
|
||||
console.warn = jest.fn();
|
||||
|
||||
const modifiedOptions = assignDeep({}, options, { str: 1 });
|
||||
validateOptions(template, modifiedOptions, false);
|
||||
expect(console.warn).not.toBeCalled();
|
||||
|
||||
console.warn = warn;
|
||||
});
|
||||
|
||||
test('log error if something is wrong and flag is true', () => {
|
||||
const { warn } = console;
|
||||
console.warn = jest.fn();
|
||||
|
||||
// str must be string
|
||||
validateOptions(template, assignDeep({}, options, { str: 1 }), true);
|
||||
expect(console.warn).toBeCalledTimes(1);
|
||||
|
||||
// abc must be A | B | C
|
||||
validateOptions(template, assignDeep({}, options, { abc: 'some string' }), true);
|
||||
expect(console.warn).toBeCalledTimes(2);
|
||||
|
||||
// everthing OK
|
||||
validateOptions(template, assignDeep({}, options, { abc: 'C' }), true);
|
||||
expect(console.warn).toBeCalledTimes(2);
|
||||
|
||||
console.warn = warn;
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -8,11 +8,9 @@ import { createStructureSetup, StructureSetup } from 'setups/structureSetup';
|
||||
import { isHTMLElement } from 'support';
|
||||
|
||||
const mockGetEnvironment = jest.fn();
|
||||
jest.mock('environment', () => {
|
||||
return {
|
||||
getEnvironment: jest.fn().mockImplementation(() => mockGetEnvironment()),
|
||||
};
|
||||
});
|
||||
jest.mock('environment', () => ({
|
||||
getEnvironment: jest.fn().mockImplementation(() => mockGetEnvironment()),
|
||||
}));
|
||||
|
||||
interface StructureSetupProxy {
|
||||
input: OSTarget | StructureInitialization;
|
||||
@@ -377,9 +375,11 @@ describe('structureSetup', () => {
|
||||
describe('complex', () => {
|
||||
describe('single assigned', () => {
|
||||
test('padding', () => {
|
||||
const snapshot = fillBody(isTextarea, (content, hostId) => {
|
||||
return `<div id="${hostId}"><div id="padding">${content}</div></div>`;
|
||||
});
|
||||
const snapshot = fillBody(
|
||||
isTextarea,
|
||||
(content, hostId) =>
|
||||
`<div id="${hostId}"><div id="padding">${content}</div></div>`
|
||||
);
|
||||
const setup = assertCorrectSetup(
|
||||
isTextarea,
|
||||
createStructureSetupProxy({
|
||||
@@ -394,9 +394,11 @@ describe('structureSetup', () => {
|
||||
});
|
||||
|
||||
test('viewport', () => {
|
||||
const snapshot = fillBody(isTextarea, (content, hostId) => {
|
||||
return `<div id="${hostId}"><div id="viewport">${content}</div></div>`;
|
||||
});
|
||||
const snapshot = fillBody(
|
||||
isTextarea,
|
||||
(content, hostId) =>
|
||||
`<div id="${hostId}"><div id="viewport">${content}</div></div>`
|
||||
);
|
||||
const setup = assertCorrectSetup(
|
||||
isTextarea,
|
||||
createStructureSetupProxy({
|
||||
@@ -411,9 +413,11 @@ describe('structureSetup', () => {
|
||||
});
|
||||
|
||||
test('content', () => {
|
||||
const snapshot = fillBody(isTextarea, (content, hostId) => {
|
||||
return `<div id="${hostId}"><div id="content">${content}</div></div>`;
|
||||
});
|
||||
const snapshot = fillBody(
|
||||
isTextarea,
|
||||
(content, hostId) =>
|
||||
`<div id="${hostId}"><div id="content">${content}</div></div>`
|
||||
);
|
||||
const setup = assertCorrectSetup(
|
||||
isTextarea,
|
||||
createStructureSetupProxy({
|
||||
@@ -430,9 +434,11 @@ describe('structureSetup', () => {
|
||||
|
||||
describe('multiple assigned', () => {
|
||||
test('padding viewport content', () => {
|
||||
const snapshot = fillBody(isTextarea, (content, hostId) => {
|
||||
return `<div id="${hostId}"><div id="padding"><div id="viewport"><div id="content">${content}</div></div></div></div>`;
|
||||
});
|
||||
const snapshot = fillBody(
|
||||
isTextarea,
|
||||
(content, hostId) =>
|
||||
`<div id="${hostId}"><div id="padding"><div id="viewport"><div id="content">${content}</div></div></div></div>`
|
||||
);
|
||||
const setup = assertCorrectSetup(
|
||||
isTextarea,
|
||||
createStructureSetupProxy({
|
||||
@@ -449,9 +455,11 @@ describe('structureSetup', () => {
|
||||
});
|
||||
|
||||
test('padding viewport', () => {
|
||||
const snapshot = fillBody(isTextarea, (content, hostId) => {
|
||||
return `<div id="${hostId}"><div id="padding"><div id="viewport">${content}</div></div></div>`;
|
||||
});
|
||||
const snapshot = fillBody(
|
||||
isTextarea,
|
||||
(content, hostId) =>
|
||||
`<div id="${hostId}"><div id="padding"><div id="viewport">${content}</div></div></div>`
|
||||
);
|
||||
const setup = assertCorrectSetup(
|
||||
isTextarea,
|
||||
createStructureSetupProxy({
|
||||
@@ -467,9 +475,11 @@ describe('structureSetup', () => {
|
||||
});
|
||||
|
||||
test('padding content', () => {
|
||||
const snapshot = fillBody(isTextarea, (content, hostId) => {
|
||||
return `<div id="${hostId}"><div id="padding"><div id="content">${content}</div></div></div>`;
|
||||
});
|
||||
const snapshot = fillBody(
|
||||
isTextarea,
|
||||
(content, hostId) =>
|
||||
`<div id="${hostId}"><div id="padding"><div id="content">${content}</div></div></div>`
|
||||
);
|
||||
const setup = assertCorrectSetup(
|
||||
isTextarea,
|
||||
createStructureSetupProxy({
|
||||
@@ -485,9 +495,11 @@ describe('structureSetup', () => {
|
||||
});
|
||||
|
||||
test('viewport content', () => {
|
||||
const snapshot = fillBody(isTextarea, (content, hostId) => {
|
||||
return `<div id="${hostId}"><div id="viewport"><div id="content">${content}</div></div></div>`;
|
||||
});
|
||||
const snapshot = fillBody(
|
||||
isTextarea,
|
||||
(content, hostId) =>
|
||||
`<div id="${hostId}"><div id="viewport"><div id="content">${content}</div></div></div>`
|
||||
);
|
||||
const setup = assertCorrectSetup(
|
||||
isTextarea,
|
||||
createStructureSetupProxy({
|
||||
@@ -599,9 +611,11 @@ describe('structureSetup', () => {
|
||||
|
||||
describe('mixed', () => {
|
||||
test('false: padding & content | assigned: viewport', () => {
|
||||
const snapshot = fillBody(isTextarea, (content, hostId) => {
|
||||
return `<div id="${hostId}"><div id="viewport">${content}</div></div>`;
|
||||
});
|
||||
const snapshot = fillBody(
|
||||
isTextarea,
|
||||
(content, hostId) =>
|
||||
`<div id="${hostId}"><div id="viewport">${content}</div></div>`
|
||||
);
|
||||
const setup = assertCorrectSetup(
|
||||
isTextarea,
|
||||
createStructureSetupProxy({
|
||||
@@ -618,9 +632,11 @@ describe('structureSetup', () => {
|
||||
});
|
||||
|
||||
test('true: padding & content | assigned: viewport', () => {
|
||||
const snapshot = fillBody(isTextarea, (content, hostId) => {
|
||||
return `<div id="${hostId}"><div id="viewport">${content}</div></div>`;
|
||||
});
|
||||
const snapshot = fillBody(
|
||||
isTextarea,
|
||||
(content, hostId) =>
|
||||
`<div id="${hostId}"><div id="viewport">${content}</div></div>`
|
||||
);
|
||||
const setup = assertCorrectSetup(
|
||||
isTextarea,
|
||||
createStructureSetupProxy({
|
||||
@@ -637,9 +653,11 @@ describe('structureSetup', () => {
|
||||
});
|
||||
|
||||
test('true: content | false: padding | assigned: viewport', () => {
|
||||
const snapshot = fillBody(isTextarea, (content, hostId) => {
|
||||
return `<div id="${hostId}"><div id="viewport">${content}</div></div>`;
|
||||
});
|
||||
const snapshot = fillBody(
|
||||
isTextarea,
|
||||
(content, hostId) =>
|
||||
`<div id="${hostId}"><div id="viewport">${content}</div></div>`
|
||||
);
|
||||
const setup = assertCorrectSetup(
|
||||
isTextarea,
|
||||
createStructureSetupProxy({
|
||||
@@ -656,9 +674,11 @@ describe('structureSetup', () => {
|
||||
});
|
||||
|
||||
test('true: padding | false: content | assigned: viewport', () => {
|
||||
const snapshot = fillBody(isTextarea, (content, hostId) => {
|
||||
return `<div id="${hostId}"><div id="viewport">${content}</div></div>`;
|
||||
});
|
||||
const snapshot = fillBody(
|
||||
isTextarea,
|
||||
(content, hostId) =>
|
||||
`<div id="${hostId}"><div id="viewport">${content}</div></div>`
|
||||
);
|
||||
const setup = assertCorrectSetup(
|
||||
isTextarea,
|
||||
createStructureSetupProxy({
|
||||
@@ -675,9 +695,11 @@ describe('structureSetup', () => {
|
||||
});
|
||||
|
||||
test('false: padding | assigned: content', () => {
|
||||
const snapshot = fillBody(isTextarea, (content, hostId) => {
|
||||
return `<div id="${hostId}"><div id="content">${content}</div></div>`;
|
||||
});
|
||||
const snapshot = fillBody(
|
||||
isTextarea,
|
||||
(content, hostId) =>
|
||||
`<div id="${hostId}"><div id="content">${content}</div></div>`
|
||||
);
|
||||
const setup = assertCorrectSetup(
|
||||
isTextarea,
|
||||
createStructureSetupProxy({
|
||||
@@ -693,9 +715,11 @@ describe('structureSetup', () => {
|
||||
});
|
||||
|
||||
test('true: padding | assigned: content', () => {
|
||||
const snapshot = fillBody(isTextarea, (content, hostId) => {
|
||||
return `<div id="${hostId}"><div id="content">${content}</div></div>`;
|
||||
});
|
||||
const snapshot = fillBody(
|
||||
isTextarea,
|
||||
(content, hostId) =>
|
||||
`<div id="${hostId}"><div id="content">${content}</div></div>`
|
||||
);
|
||||
const setup = assertCorrectSetup(
|
||||
isTextarea,
|
||||
createStructureSetupProxy({
|
||||
@@ -711,9 +735,11 @@ describe('structureSetup', () => {
|
||||
});
|
||||
|
||||
test('false: padding | assigned: viewport', () => {
|
||||
const snapshot = fillBody(isTextarea, (content, hostId) => {
|
||||
return `<div id="${hostId}"><div id="viewport">${content}</div></div>`;
|
||||
});
|
||||
const snapshot = fillBody(
|
||||
isTextarea,
|
||||
(content, hostId) =>
|
||||
`<div id="${hostId}"><div id="viewport">${content}</div></div>`
|
||||
);
|
||||
const setup = assertCorrectSetup(
|
||||
isTextarea,
|
||||
createStructureSetupProxy({
|
||||
@@ -729,9 +755,11 @@ describe('structureSetup', () => {
|
||||
});
|
||||
|
||||
test('true: padding | assigned: viewport', () => {
|
||||
const snapshot = fillBody(isTextarea, (content, hostId) => {
|
||||
return `<div id="${hostId}"><div id="viewport">${content}</div></div>`;
|
||||
});
|
||||
const snapshot = fillBody(
|
||||
isTextarea,
|
||||
(content, hostId) =>
|
||||
`<div id="${hostId}"><div id="viewport">${content}</div></div>`
|
||||
);
|
||||
const setup = assertCorrectSetup(
|
||||
isTextarea,
|
||||
createStructureSetupProxy({
|
||||
@@ -747,9 +775,11 @@ describe('structureSetup', () => {
|
||||
});
|
||||
|
||||
test('false: padding | assigned: viewport & content', () => {
|
||||
const snapshot = fillBody(isTextarea, (content, hostId) => {
|
||||
return `<div id="${hostId}"><div id="viewport"><div id="content">${content}</div></div></div>`;
|
||||
});
|
||||
const snapshot = fillBody(
|
||||
isTextarea,
|
||||
(content, hostId) =>
|
||||
`<div id="${hostId}"><div id="viewport"><div id="content">${content}</div></div></div>`
|
||||
);
|
||||
const setup = assertCorrectSetup(
|
||||
isTextarea,
|
||||
createStructureSetupProxy({
|
||||
@@ -766,9 +796,11 @@ describe('structureSetup', () => {
|
||||
});
|
||||
|
||||
test('true: padding | assigned: viewport & content', () => {
|
||||
const snapshot = fillBody(isTextarea, (content, hostId) => {
|
||||
return `<div id="${hostId}"><div id="viewport"><div id="content">${content}</div></div></div>`;
|
||||
});
|
||||
const snapshot = fillBody(
|
||||
isTextarea,
|
||||
(content, hostId) =>
|
||||
`<div id="${hostId}"><div id="viewport"><div id="content">${content}</div></div></div>`
|
||||
);
|
||||
const setup = assertCorrectSetup(
|
||||
isTextarea,
|
||||
createStructureSetupProxy({
|
||||
@@ -785,9 +817,11 @@ describe('structureSetup', () => {
|
||||
});
|
||||
|
||||
test('false: content | assigned: padding', () => {
|
||||
const snapshot = fillBody(isTextarea, (content, hostId) => {
|
||||
return `<div id="${hostId}"><div id="padding">${content}</div></div>`;
|
||||
});
|
||||
const snapshot = fillBody(
|
||||
isTextarea,
|
||||
(content, hostId) =>
|
||||
`<div id="${hostId}"><div id="padding">${content}</div></div>`
|
||||
);
|
||||
const setup = assertCorrectSetup(
|
||||
isTextarea,
|
||||
createStructureSetupProxy({
|
||||
@@ -803,9 +837,11 @@ describe('structureSetup', () => {
|
||||
});
|
||||
|
||||
test('true: content | assigned: padding', () => {
|
||||
const snapshot = fillBody(isTextarea, (content, hostId) => {
|
||||
return `<div id="${hostId}"><div id="padding">${content}</div></div>`;
|
||||
});
|
||||
const snapshot = fillBody(
|
||||
isTextarea,
|
||||
(content, hostId) =>
|
||||
`<div id="${hostId}"><div id="padding">${content}</div></div>`
|
||||
);
|
||||
const setup = assertCorrectSetup(
|
||||
isTextarea,
|
||||
createStructureSetupProxy({
|
||||
@@ -821,9 +857,11 @@ describe('structureSetup', () => {
|
||||
});
|
||||
|
||||
test('false: content | assigned: viewport', () => {
|
||||
const snapshot = fillBody(isTextarea, (content, hostId) => {
|
||||
return `<div id="${hostId}"><div id="viewport">${content}</div></div>`;
|
||||
});
|
||||
const snapshot = fillBody(
|
||||
isTextarea,
|
||||
(content, hostId) =>
|
||||
`<div id="${hostId}"><div id="viewport">${content}</div></div>`
|
||||
);
|
||||
const setup = assertCorrectSetup(
|
||||
isTextarea,
|
||||
createStructureSetupProxy({
|
||||
@@ -839,9 +877,11 @@ describe('structureSetup', () => {
|
||||
});
|
||||
|
||||
test('true: content | assigned: viewport', () => {
|
||||
const snapshot = fillBody(isTextarea, (content, hostId) => {
|
||||
return `<div id="${hostId}"><div id="viewport">${content}</div></div>`;
|
||||
});
|
||||
const snapshot = fillBody(
|
||||
isTextarea,
|
||||
(content, hostId) =>
|
||||
`<div id="${hostId}"><div id="viewport">${content}</div></div>`
|
||||
);
|
||||
const setup = assertCorrectSetup(
|
||||
isTextarea,
|
||||
createStructureSetupProxy({
|
||||
@@ -857,9 +897,11 @@ describe('structureSetup', () => {
|
||||
});
|
||||
|
||||
test('false: content | assigned: padding & viewport', () => {
|
||||
const snapshot = fillBody(isTextarea, (content, hostId) => {
|
||||
return `<div id="${hostId}"><div id="padding"><div id="viewport">${content}</div></div></div>`;
|
||||
});
|
||||
const snapshot = fillBody(
|
||||
isTextarea,
|
||||
(content, hostId) =>
|
||||
`<div id="${hostId}"><div id="padding"><div id="viewport">${content}</div></div></div>`
|
||||
);
|
||||
const setup = assertCorrectSetup(
|
||||
isTextarea,
|
||||
createStructureSetupProxy({
|
||||
@@ -876,9 +918,11 @@ describe('structureSetup', () => {
|
||||
});
|
||||
|
||||
test('true: content | assigned: padding & viewport', () => {
|
||||
const snapshot = fillBody(isTextarea, (content, hostId) => {
|
||||
return `<div id="${hostId}"><div id="padding"><div id="viewport">${content}</div></div></div>`;
|
||||
});
|
||||
const snapshot = fillBody(
|
||||
isTextarea,
|
||||
(content, hostId) =>
|
||||
`<div id="${hostId}"><div id="padding"><div id="viewport">${content}</div></div></div>`
|
||||
);
|
||||
const setup = assertCorrectSetup(
|
||||
isTextarea,
|
||||
createStructureSetupProxy({
|
||||
|
||||
@@ -1,438 +0,0 @@
|
||||
import { validateOptions, optionsTemplateTypes as oTypes, OptionsTemplate } from 'support/options';
|
||||
import { assignDeep, isEmptyObject } from 'support/utils';
|
||||
|
||||
type TestOptionsObj = { propA: 'propA'; null: null };
|
||||
type TestOptionsEnum = 'A' | 'B' | 'C';
|
||||
type TestOptions = {
|
||||
str: string;
|
||||
strArrNull: string | Array<string> | null;
|
||||
nullbool: boolean | null;
|
||||
nested: {
|
||||
num: number;
|
||||
switch: boolean;
|
||||
abc: TestOptionsEnum;
|
||||
};
|
||||
obj: TestOptionsObj | null;
|
||||
abc: TestOptionsEnum;
|
||||
arr: Array<any>;
|
||||
func: () => void;
|
||||
};
|
||||
|
||||
const options: TestOptions = {
|
||||
str: 'hi',
|
||||
strArrNull: null,
|
||||
nullbool: true,
|
||||
nested: {
|
||||
num: 1,
|
||||
switch: false,
|
||||
abc: 'B',
|
||||
},
|
||||
obj: { propA: 'propA', null: null },
|
||||
abc: 'A',
|
||||
arr: [1, 2, 3],
|
||||
func: () => {},
|
||||
};
|
||||
|
||||
const template: OptionsTemplate<TestOptions> = {
|
||||
str: oTypes.string,
|
||||
strArrNull: [oTypes.string, oTypes.array, oTypes.null],
|
||||
nullbool: [oTypes.boolean, oTypes.null],
|
||||
nested: {
|
||||
num: oTypes.number,
|
||||
switch: oTypes.boolean,
|
||||
abc: 'A B C',
|
||||
},
|
||||
obj: [oTypes.object, oTypes.null],
|
||||
abc: 'A B C',
|
||||
arr: oTypes.array,
|
||||
func: oTypes.function,
|
||||
};
|
||||
|
||||
describe('options validation', () => {
|
||||
describe('object return & mutation', () => {
|
||||
test('foreign properties wont affect validated object', () => {
|
||||
const foreignObj = {
|
||||
foreignProp: 'foreign',
|
||||
foreignDeep: { a: 'A', b: 'B' },
|
||||
};
|
||||
const modifiedOptions = assignDeep({}, options, { nested: foreignObj }, foreignObj);
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(_validated).toEqual(options);
|
||||
});
|
||||
|
||||
test('passed objects arent mutated', () => {
|
||||
const clonedOptions = assignDeep({}, options);
|
||||
validateOptions(clonedOptions, template, clonedOptions);
|
||||
|
||||
expect(clonedOptions).toEqual(options);
|
||||
});
|
||||
|
||||
test('passed object isnt returned object', () => {
|
||||
const clonedOptions = assignDeep({}, options);
|
||||
const result = validateOptions(clonedOptions, template);
|
||||
|
||||
expect(result._validated).not.toBe(clonedOptions);
|
||||
});
|
||||
});
|
||||
|
||||
describe('foreign property return', () => {
|
||||
test('return no foreign property', () => {
|
||||
const result = validateOptions(options, template);
|
||||
|
||||
expect(isEmptyObject(result._foreign)).toBe(true);
|
||||
});
|
||||
|
||||
test('return signle non-object foreign property', () => {
|
||||
const foreignObj = { foreignProp: 'foreign' };
|
||||
const modifiedOptions = assignDeep({}, options, foreignObj);
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _foreign } = result;
|
||||
|
||||
expect(_foreign).toEqual(foreignObj);
|
||||
});
|
||||
|
||||
test('return complex foreign properties', () => {
|
||||
const foreignObj = {
|
||||
foreignProp: 'foreign',
|
||||
foreignDeep: { a: 'A', b: 'B' },
|
||||
};
|
||||
const modifiedOptions = assignDeep({}, options, foreignObj);
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _foreign } = result;
|
||||
|
||||
expect(_foreign).toEqual(foreignObj);
|
||||
});
|
||||
|
||||
test('return nested complex foreign properties', () => {
|
||||
const foreignObj = {
|
||||
foreignProp: 'foreign',
|
||||
foreignDeep: { a: 'A', b: 'B' },
|
||||
};
|
||||
const modifiedOptions = assignDeep({}, options, { nested: foreignObj }, foreignObj);
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _foreign } = result;
|
||||
|
||||
expect(_foreign.nested).toEqual(foreignObj);
|
||||
delete _foreign.nested;
|
||||
expect(_foreign).toEqual(foreignObj);
|
||||
});
|
||||
});
|
||||
|
||||
describe('diff property return', () => {
|
||||
test('one value changed', () => {
|
||||
const modifiedOptions = assignDeep({}, options, { str: 'newvaluetest' });
|
||||
const result = validateOptions(modifiedOptions, template, options);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(_validated.str).toBe('newvaluetest');
|
||||
delete _validated.str;
|
||||
expect(isEmptyObject(_validated)).toBe(true);
|
||||
});
|
||||
|
||||
test('multiple values changed', () => {
|
||||
const modifiedOptions = assignDeep({}, options, {
|
||||
str: 'newvaluetest',
|
||||
nullbool: null,
|
||||
});
|
||||
const result = validateOptions(modifiedOptions, template, options);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(_validated.str).toBe('newvaluetest');
|
||||
expect(_validated.nullbool).toBe(null);
|
||||
delete _validated.str;
|
||||
delete _validated.nullbool;
|
||||
expect(isEmptyObject(_validated)).toBe(true);
|
||||
});
|
||||
|
||||
test('one nested value changed', () => {
|
||||
const modifiedOptions = assignDeep({}, options, { nested: { num: -1293 } });
|
||||
const result = validateOptions(modifiedOptions, template, options);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(_validated.nested?.num).toBe(-1293);
|
||||
delete _validated.nested?.num;
|
||||
expect(isEmptyObject(_validated.nested)).toBe(true);
|
||||
delete _validated.nested;
|
||||
expect(isEmptyObject(_validated)).toBe(true);
|
||||
});
|
||||
|
||||
test('multiple nested values changed', () => {
|
||||
const modifiedOptions = assignDeep({}, options, {
|
||||
nested: { num: -1293, abc: 'C' },
|
||||
});
|
||||
const result = validateOptions(modifiedOptions, template, options);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(_validated.nested?.num).toBe(-1293);
|
||||
expect(_validated.nested?.abc).toBe('C');
|
||||
delete _validated.nested?.num;
|
||||
delete _validated.nested?.abc;
|
||||
expect(isEmptyObject(_validated.nested)).toBe(true);
|
||||
delete _validated.nested;
|
||||
expect(isEmptyObject(_validated)).toBe(true);
|
||||
});
|
||||
|
||||
test('various values changed', () => {
|
||||
const newFunc = () => {};
|
||||
const modifiedOptions = assignDeep({}, options, {
|
||||
str: 'newstrvalue',
|
||||
func: newFunc,
|
||||
abc: 'C',
|
||||
nested: { num: -1293, abc: 'C' },
|
||||
});
|
||||
const result = validateOptions(modifiedOptions, template, options);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(_validated.str).toBe('newstrvalue');
|
||||
expect(_validated.func).toBe(newFunc);
|
||||
expect(_validated.abc).toBe('C');
|
||||
delete _validated.str;
|
||||
delete _validated.func;
|
||||
delete _validated.abc;
|
||||
expect(_validated.nested?.num).toBe(-1293);
|
||||
expect(_validated.nested?.abc).toBe('C');
|
||||
delete _validated.nested?.num;
|
||||
delete _validated.nested?.abc;
|
||||
expect(isEmptyObject(_validated.nested)).toBe(true);
|
||||
delete _validated.nested;
|
||||
expect(isEmptyObject(_validated)).toBe(true);
|
||||
});
|
||||
|
||||
test('various values changed with foreign properties', () => {
|
||||
const foreignObj = {
|
||||
foreignProp: 'foreign',
|
||||
foreignDeep: { a: 'A', b: 'B' },
|
||||
};
|
||||
const newFunc = () => {};
|
||||
const modifiedOptions = assignDeep(
|
||||
{},
|
||||
options,
|
||||
{
|
||||
str: 'newstrvalue',
|
||||
func: newFunc,
|
||||
abc: 'C',
|
||||
nested: { num: -1293, abc: 'C' },
|
||||
},
|
||||
foreignObj,
|
||||
{ nested: foreignObj }
|
||||
);
|
||||
const result = validateOptions(modifiedOptions, template, options);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(_validated.str).toBe('newstrvalue');
|
||||
expect(_validated.func).toBe(newFunc);
|
||||
expect(_validated.abc).toBe('C');
|
||||
delete _validated.str;
|
||||
delete _validated.func;
|
||||
delete _validated.abc;
|
||||
expect(_validated.nested?.num).toBe(-1293);
|
||||
expect(_validated.nested?.abc).toBe('C');
|
||||
delete _validated.nested?.num;
|
||||
delete _validated.nested?.abc;
|
||||
expect(isEmptyObject(_validated.nested)).toBe(true);
|
||||
delete _validated.nested;
|
||||
expect(isEmptyObject(_validated)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('value validity', () => {
|
||||
test('single value doesnt match template', () => {
|
||||
const modifiedOptions = assignDeep({}, options, { str: 1 });
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(_validated).not.toHaveProperty('str');
|
||||
});
|
||||
|
||||
test('single enum value doesnt match template', () => {
|
||||
const modifiedOptions = assignDeep({}, options, { abc: 'testval' });
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(_validated).not.toHaveProperty('abc');
|
||||
});
|
||||
|
||||
test('multiple values dont match template', () => {
|
||||
const modifiedOptions = assignDeep({}, options, {
|
||||
str: 1,
|
||||
abc: 'testval',
|
||||
nullbool: 'string',
|
||||
});
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(_validated).not.toHaveProperty('str');
|
||||
expect(_validated).not.toHaveProperty('abc');
|
||||
expect(_validated).not.toHaveProperty('nullbool');
|
||||
});
|
||||
|
||||
test('single nested value dont match template', () => {
|
||||
const modifiedOptions = assignDeep({}, options, { nested: { num: 'hi' } });
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(_validated.nested).not.toHaveProperty('num');
|
||||
});
|
||||
|
||||
test('single nested enum value dont match template', () => {
|
||||
const modifiedOptions = assignDeep({}, options, {
|
||||
nested: { abc: 'testabc' },
|
||||
});
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(_validated.nested).not.toHaveProperty('abc');
|
||||
});
|
||||
|
||||
test('multiple nested values dont match template', () => {
|
||||
const modifiedOptions = assignDeep({}, options, {
|
||||
nested: { num: 'hi', abc: 'testabc' },
|
||||
});
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(_validated.nested).not.toHaveProperty('num');
|
||||
expect(_validated.nested).not.toHaveProperty('abc');
|
||||
});
|
||||
|
||||
test('all nested values dont match template', () => {
|
||||
const modifiedOptions = assignDeep({}, options, {
|
||||
nested: { num: 'hi', abc: 'testabc', switch: 1 },
|
||||
});
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(_validated).not.toHaveProperty('nested');
|
||||
});
|
||||
|
||||
test('all nested values dont match template with foreign property', () => {
|
||||
const modifiedOptions = assignDeep({}, options, {
|
||||
nested: {
|
||||
foreign: 'foreign',
|
||||
num: 'hi',
|
||||
abc: 'testabc',
|
||||
switch: 1,
|
||||
},
|
||||
});
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(_validated).not.toHaveProperty('nested');
|
||||
});
|
||||
|
||||
test('various values dont match template', () => {
|
||||
const modifiedOptions = assignDeep({}, options, {
|
||||
nested: { switch: null },
|
||||
obj: 1,
|
||||
abc: 'testest',
|
||||
func: {},
|
||||
});
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(_validated.nested).not.toHaveProperty('switch');
|
||||
expect(_validated).not.toHaveProperty('obj');
|
||||
expect(_validated).not.toHaveProperty('abc');
|
||||
expect(_validated).not.toHaveProperty('func');
|
||||
});
|
||||
|
||||
test('various values dont match template with foreign properties', () => {
|
||||
const foreignObj = {
|
||||
foreignProp: 'foreign',
|
||||
foreignDeep: { a: 'A', b: 'B' },
|
||||
};
|
||||
const modifiedOptions = assignDeep(
|
||||
{},
|
||||
options,
|
||||
{
|
||||
nested: { switch: null },
|
||||
obj: 1,
|
||||
abc: 'testest',
|
||||
func: {},
|
||||
},
|
||||
foreignObj,
|
||||
{ nested: foreignObj }
|
||||
);
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated, _foreign } = result;
|
||||
|
||||
expect(_foreign.nested).toEqual(foreignObj);
|
||||
delete _foreign.nested;
|
||||
expect(_foreign).toEqual(foreignObj);
|
||||
|
||||
expect(_validated.nested).not.toHaveProperty('switch');
|
||||
expect(_validated).not.toHaveProperty('obj');
|
||||
expect(_validated).not.toHaveProperty('abc');
|
||||
expect(_validated).not.toHaveProperty('func');
|
||||
});
|
||||
|
||||
test('nested object is string', () => {
|
||||
const modifiedOptions = assignDeep({}, options, { nested: 'string' });
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(_validated).not.toHaveProperty('nested');
|
||||
});
|
||||
|
||||
test('nested object is null', () => {
|
||||
const modifiedOptions = assignDeep({}, options, { nested: null });
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(_validated).not.toHaveProperty('nested');
|
||||
});
|
||||
|
||||
test('nested object is undefined', () => {
|
||||
const modifiedOptions: Partial<TestOptions> = assignDeep({}, options);
|
||||
modifiedOptions.nested = undefined;
|
||||
const result = validateOptions(modifiedOptions, template);
|
||||
const { _validated } = result;
|
||||
|
||||
expect(_validated).not.toHaveProperty('nested');
|
||||
});
|
||||
});
|
||||
|
||||
describe('error logging', () => {
|
||||
test('dont log error if nothing is wrong', () => {
|
||||
const { warn } = console;
|
||||
console.warn = jest.fn();
|
||||
|
||||
validateOptions(options, template, null, true);
|
||||
expect(console.warn).not.toBeCalled();
|
||||
|
||||
console.warn = warn;
|
||||
});
|
||||
|
||||
test('dont log error if something is wrong and flag is false', () => {
|
||||
const { warn } = console;
|
||||
console.warn = jest.fn();
|
||||
|
||||
const modifiedOptions = assignDeep({}, options, { str: 1 });
|
||||
validateOptions(modifiedOptions, template, null, false);
|
||||
expect(console.warn).not.toBeCalled();
|
||||
|
||||
console.warn = warn;
|
||||
});
|
||||
|
||||
test('log error if something is wrong and flag is true', () => {
|
||||
const { warn } = console;
|
||||
console.warn = jest.fn();
|
||||
|
||||
// str must be string
|
||||
validateOptions(assignDeep({}, options, { str: 1 }), template, null, true);
|
||||
expect(console.warn).toBeCalledTimes(1);
|
||||
|
||||
// abc must be A | B | C
|
||||
validateOptions(assignDeep({}, options, { abc: 'some string' }), template, null, true);
|
||||
expect(console.warn).toBeCalledTimes(2);
|
||||
|
||||
// everthing OK
|
||||
validateOptions(assignDeep({}, options, { abc: 'C' }), template, null, true);
|
||||
expect(console.warn).toBeCalledTimes(2);
|
||||
|
||||
console.warn = warn;
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user