Remove unused validateProps module and tests
This commit is contained in:
parent
aaae1fd1ef
commit
0490441d09
|
@ -1,4 +1,3 @@
|
||||||
import { recursivelyValidate } from "./validateProps";
|
|
||||||
import {
|
import {
|
||||||
isString,
|
isString,
|
||||||
keys,
|
keys,
|
||||||
|
@ -15,11 +14,11 @@ export const validatePage = (page, getComponent) => {
|
||||||
const error = message => errors.push(message);
|
const error = message => errors.push(message);
|
||||||
|
|
||||||
const noIndex = !page.index;
|
const noIndex = !page.index;
|
||||||
if(noIndex) {
|
if (noIndex) {
|
||||||
error("Page does not define an index member");
|
error("Page does not define an index member");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!page.appBody
|
if (!page.appBody
|
||||||
|| !isString(page.appBody)
|
|| !isString(page.appBody)
|
||||||
|| !page.appBody.endsWith(".json")) {
|
|| !page.appBody.endsWith(".json")) {
|
||||||
error("App body must be set toa valid JSON file");
|
error("App body must be set toa valid JSON file");
|
||||||
|
@ -44,15 +43,15 @@ export const validatePages = (pages, getComponent) => {
|
||||||
let errors = [];
|
let errors = [];
|
||||||
const error = message => errors.push(message);
|
const error = message => errors.push(message);
|
||||||
|
|
||||||
if(!pages.main) {
|
if (!pages.main) {
|
||||||
error("must have a 'main' page");
|
error("must have a 'main' page");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!pages.unauthenticated) {
|
if (!pages.unauthenticated) {
|
||||||
error("must have a 'unauthenticated' (login) page");
|
error("must have a 'unauthenticated' (login) page");
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!pages.componentLibraries
|
if (!pages.componentLibraries
|
||||||
|| !isArray(pages.componentLibraries)
|
|| !isArray(pages.componentLibraries)
|
||||||
|| pages.componentLibraries.length === 0) {
|
|| pages.componentLibraries.length === 0) {
|
||||||
|
|
||||||
|
|
|
@ -1,143 +0,0 @@
|
||||||
import { types } from "./types";
|
|
||||||
import {
|
|
||||||
createProps, arrayElementComponentName
|
|
||||||
} from "./createProps";
|
|
||||||
import { isString } from "util";
|
|
||||||
import {
|
|
||||||
includes, filter, map, keys,
|
|
||||||
flatten, flattenDeep, each,
|
|
||||||
indexOf, isUndefined
|
|
||||||
} from "lodash/fp";
|
|
||||||
import { common } from "../../../../core/src";
|
|
||||||
import {
|
|
||||||
isBinding
|
|
||||||
} from "../../common/binding";
|
|
||||||
|
|
||||||
const pipe = common.$;
|
|
||||||
|
|
||||||
const makeError = (errors, propName, stack) => (message) =>
|
|
||||||
errors.push({
|
|
||||||
stack,
|
|
||||||
propName,
|
|
||||||
error: message
|
|
||||||
});
|
|
||||||
|
|
||||||
export const recursivelyValidate = (rootProps, getComponent, stack = []) => {
|
|
||||||
|
|
||||||
if (!rootProps._component) {
|
|
||||||
const errs = [];
|
|
||||||
makeError(errs, "_component", stack)("Component is not set");
|
|
||||||
return errs;
|
|
||||||
// this would break everything else anyway
|
|
||||||
}
|
|
||||||
|
|
||||||
const componentDef = getComponent(
|
|
||||||
rootProps._component);
|
|
||||||
|
|
||||||
|
|
||||||
const errors = validateProps(
|
|
||||||
componentDef,
|
|
||||||
rootProps,
|
|
||||||
stack,
|
|
||||||
true);
|
|
||||||
|
|
||||||
const validateChildren = (_props, _stack) =>
|
|
||||||
!_props._children
|
|
||||||
? []
|
|
||||||
: pipe(_props._children, [
|
|
||||||
map(child => recursivelyValidate(
|
|
||||||
child,
|
|
||||||
getComponent,
|
|
||||||
[..._stack, _props._children.indexOf(child)]))
|
|
||||||
]);
|
|
||||||
|
|
||||||
const childErrors = validateChildren(
|
|
||||||
rootProps, stack);
|
|
||||||
|
|
||||||
return flattenDeep([errors, ...childErrors]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const expandPropDef = propDef =>
|
|
||||||
isString(propDef)
|
|
||||||
? types[propDef].defaultDefinition()
|
|
||||||
: propDef;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const validateProps = (componentDefinition, props, stack = [], isFinal = true) => {
|
|
||||||
|
|
||||||
const errors = [];
|
|
||||||
|
|
||||||
if (isFinal && !props._component) {
|
|
||||||
makeError(errors, "_component", stack)("Component is not set");
|
|
||||||
return errors;
|
|
||||||
// this would break everything else anyway
|
|
||||||
}
|
|
||||||
|
|
||||||
const propsDefinition = componentDefinition.props;
|
|
||||||
|
|
||||||
for (let propDefName in props) {
|
|
||||||
|
|
||||||
const ignore = ['_component', "_children", '_layout', 'name', 'description', 'location'];
|
|
||||||
|
|
||||||
if (ignore.includes(propDefName)) continue;
|
|
||||||
|
|
||||||
const propDef = expandPropDef(propsDefinition[propDefName]);
|
|
||||||
|
|
||||||
const type = types[propDef.type];
|
|
||||||
|
|
||||||
const error = makeError(errors, propDefName, stack);
|
|
||||||
|
|
||||||
const propValue = props[propDefName];
|
|
||||||
|
|
||||||
// component declarations dont need to define al props.
|
|
||||||
if (!isFinal && isUndefined(propValue)) continue;
|
|
||||||
|
|
||||||
if (isFinal && propDef.required && propValue) {
|
|
||||||
error(`Property ${propDefName} is required`);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isBinding(propValue)) {
|
|
||||||
if (propDef.type === "event") {
|
|
||||||
error(`Cannot apply binding to type ${propDef.type}`);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!type.isOfType(propValue)) {
|
|
||||||
error(`Property ${propDefName} is not of type ${propDef.type}. Actual value ${propValue}`)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (propDef.type === "options"
|
|
||||||
&& propValue
|
|
||||||
&& !isBinding(propValue)
|
|
||||||
&& !includes(propValue)(propDef.options)) {
|
|
||||||
error(`Property ${propDefName} is not one of allowed options. Acutal value is ${propValue}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const validateComponentDefinition = (componentDefinition) => {
|
|
||||||
const { errors } = createProps(componentDefinition);
|
|
||||||
|
|
||||||
const propDefinitions = expandPropDef(componentDefinition.props);
|
|
||||||
|
|
||||||
pipe(propDefinitions, [
|
|
||||||
keys,
|
|
||||||
map(k => ({
|
|
||||||
propDef: propDefinitions[k],
|
|
||||||
propName: k
|
|
||||||
})),
|
|
||||||
filter(d => d.propDef.type === "options"
|
|
||||||
&& (!d.propDef.options || d.propDef.options.length === 0)),
|
|
||||||
each(d => makeError(errors, d.propName)(`${d.propName} does not have any options`))
|
|
||||||
]);
|
|
||||||
|
|
||||||
return errors;
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,232 +0,0 @@
|
||||||
import {
|
|
||||||
validateComponentDefinition,
|
|
||||||
validateProps,
|
|
||||||
recursivelyValidate
|
|
||||||
} from "../src/userInterface/pagesParsing/validateProps";
|
|
||||||
import { createProps } from "../src/userInterface/pagesParsing/createProps";
|
|
||||||
import {
|
|
||||||
setBinding
|
|
||||||
} from "../src/common/binding";
|
|
||||||
|
|
||||||
// not that allot of this functionality is covered
|
|
||||||
// in createDefaultProps - as validate props uses that.
|
|
||||||
|
|
||||||
describe("validateComponentDefinition", () => {
|
|
||||||
|
|
||||||
|
|
||||||
it("should return error when no options for options field", () => {
|
|
||||||
|
|
||||||
const compDef = {
|
|
||||||
name:"some_component",
|
|
||||||
props: {
|
|
||||||
size: {
|
|
||||||
type: "options",
|
|
||||||
options: []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const errors = validateComponentDefinition(compDef);
|
|
||||||
|
|
||||||
expect(errors.length).toEqual(1);
|
|
||||||
expect(errors[0].propName).toBe("size");
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not return error when options field has options", () => {
|
|
||||||
|
|
||||||
const compDef = {
|
|
||||||
name: "some_component",
|
|
||||||
props: {
|
|
||||||
size: {
|
|
||||||
type: "options",
|
|
||||||
options: ["small", "medium", "large"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const errors = validateComponentDefinition(compDef);
|
|
||||||
|
|
||||||
expect(errors).toEqual([]);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
const validComponentDef = {
|
|
||||||
name: "some_component",
|
|
||||||
props: {
|
|
||||||
size: {
|
|
||||||
type: "options",
|
|
||||||
options: ["small", "medium", "large"],
|
|
||||||
default:"medium"
|
|
||||||
},
|
|
||||||
rowCount : "number"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const childComponentDef = {
|
|
||||||
name: "child_component",
|
|
||||||
props: {
|
|
||||||
width: "number",
|
|
||||||
units: {
|
|
||||||
type: "string",
|
|
||||||
default: "px"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const validProps = () => {
|
|
||||||
|
|
||||||
const { props } = createProps(validComponentDef);
|
|
||||||
props._children.push(
|
|
||||||
createProps(childComponentDef));
|
|
||||||
return props;
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("validateProps", () => {
|
|
||||||
|
|
||||||
it("should have no errors with a big list of valid props", () => {
|
|
||||||
|
|
||||||
const errors = validateProps(validComponentDef, validProps(), [], true);
|
|
||||||
expect(errors).toEqual([]);
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return error with invalid value", () => {
|
|
||||||
|
|
||||||
const props = validProps();
|
|
||||||
props.rowCount = "1";
|
|
||||||
const errors = validateProps(validComponentDef, props, [], true);
|
|
||||||
expect(errors.length).toEqual(1);
|
|
||||||
expect(errors[0].propName).toBe("rowCount");
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return error with invalid option", () => {
|
|
||||||
|
|
||||||
const props = validProps();
|
|
||||||
props.size = "really_small";
|
|
||||||
const errors = validateProps(validComponentDef, props, [], true);
|
|
||||||
expect(errors.length).toEqual(1);
|
|
||||||
expect(errors[0].propName).toBe("size");
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should not return error when has binding", () => {
|
|
||||||
const props = validProps();
|
|
||||||
props._children[0].width = setBinding({path:"some_path"});
|
|
||||||
props.size = setBinding({path:"other path", fallback:"small"});
|
|
||||||
const errors = validateProps(validComponentDef, props, [], true);
|
|
||||||
expect(errors.length).toEqual(0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("recursivelyValidateProps", () => {
|
|
||||||
|
|
||||||
const rootComponent = {
|
|
||||||
name: "rootComponent",
|
|
||||||
children: true,
|
|
||||||
props: {
|
|
||||||
width: "number"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const todoListComponent = {
|
|
||||||
name: "todoListComponent",
|
|
||||||
props:{
|
|
||||||
showTitle: "bool"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const headerComponent = {
|
|
||||||
name: "headerComponent",
|
|
||||||
props: {
|
|
||||||
text: "string"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const iconComponent = {
|
|
||||||
name: "iconComponent",
|
|
||||||
props: {
|
|
||||||
iconName: "string"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const navItemComponent = {
|
|
||||||
name: "navItemComponent",
|
|
||||||
props: {
|
|
||||||
text: "string"
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getComponent = name => ({
|
|
||||||
rootComponent,
|
|
||||||
todoListComponent,
|
|
||||||
headerComponent,
|
|
||||||
iconComponent,
|
|
||||||
navItemComponent
|
|
||||||
})[name];
|
|
||||||
|
|
||||||
const rootProps = () => ({
|
|
||||||
_component: "rootComponent",
|
|
||||||
width: 100,
|
|
||||||
_children: [{
|
|
||||||
_component: "todoListComponent",
|
|
||||||
showTitle: true,
|
|
||||||
_children : [
|
|
||||||
{
|
|
||||||
_component: "navItemComponent",
|
|
||||||
text: "todos"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
_component: "headerComponent",
|
|
||||||
text: "Your todo list"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
_component: "iconComponent",
|
|
||||||
iconName: "fa fa-list"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
_component: "iconComponent",
|
|
||||||
iconName:"fa fa-cog"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return no errors for valid structure", () => {
|
|
||||||
const result = recursivelyValidate(
|
|
||||||
rootProps(),
|
|
||||||
getComponent);
|
|
||||||
|
|
||||||
expect(result).toEqual([]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return error on root component", () => {
|
|
||||||
const root = rootProps();
|
|
||||||
root.width = "yeeeoooo";
|
|
||||||
const result = recursivelyValidate(root, getComponent);
|
|
||||||
expect(result.length).toBe(1);
|
|
||||||
expect(result[0].propName).toBe("width");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return error on first nested child component", () => {
|
|
||||||
const root = rootProps();
|
|
||||||
root._children[0].showTitle = "yeeeoooo";
|
|
||||||
const result = recursivelyValidate(root, getComponent);
|
|
||||||
expect(result.length).toBe(1);
|
|
||||||
expect(result[0].stack).toEqual([0]);
|
|
||||||
expect(result[0].propName).toBe("showTitle");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should return error on second nested child component", () => {
|
|
||||||
const root = rootProps();
|
|
||||||
root._children[0]._children[0].text = false;
|
|
||||||
const result = recursivelyValidate(root, getComponent);
|
|
||||||
expect(result.length).toBe(1);
|
|
||||||
expect(result[0].stack).toEqual([0,0]);
|
|
||||||
expect(result[0].propName).toBe("text");
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
Loading…
Reference in New Issue