import {validateAll} from "../src/templateApi/validate"; import createNodes from "../src/templateApi/createNodes"; import {some} from "lodash"; import {getNewField, addField} from "../src/templateApi/fields"; import {getNewRecordValidationRule, commonRecordValidationRules, addRecordValidationRule} from "../src/templateApi/recordValidationRules"; import { findField } from "../src/templateApi/hierarchy"; import {findCollectionDefaultIndex} from "./specHelpers"; const createValidHierarchy = () => { const root = createNodes.getNewRootLevel(); const customerRecord = createNodes.getNewRecordTemplate(root, "customer"); customerRecord.collectionName = "customers"; const customersDefaultIndex = findCollectionDefaultIndex(customerRecord); const customersNoGroupaggregateGroup = createNodes.getNewAggregateGroupTemplate(customersDefaultIndex); customersNoGroupaggregateGroup.name = "Customers Summary"; const allCustomersOwedFunctions = createNodes.getNewAggregateTemplate(customersNoGroupaggregateGroup); allCustomersOwedFunctions.aggregatedValue = "return record.owed"; allCustomersOwedFunctions.name = "all customers owed amount"; const partnerRecord = createNodes.getNewRecordTemplate(root, "partner"); partnerRecord.collectionName = "partners"; partnerRecord.name = "partner"; const businessName = getNewField("string"); businessName.name = "businessname"; businessName.label = "bn"; addField(partnerRecord,businessName); customerRecord.name = "customer"; const surnameField = getNewField("string"); surnameField.name = "surname"; surnameField.label = "surname"; const isaliveField = getNewField("bool"); isaliveField.name = "isalive"; const createddateField = getNewField("datetime"); createddateField.name = "createddate"; const ageField = getNewField("number"); ageField.name = "age"; const partnerField = getNewField("reference"); partnerField.name = "partner"; partnerField.typeOptions.indexNodeKey = "l"; partnerField.typeOptions.reverseIndexNodeKeys = ["l"]; partnerField.typeOptions.displayValue = "l"; const otherNamesField = getNewField("array"); otherNamesField.name = "othernames"; addField(customerRecord, surnameField); addField(customerRecord, isaliveField); addField(customerRecord, createddateField); addField(customerRecord, ageField); addField(customerRecord, partnerField); addField(customerRecord, otherNamesField); addRecordValidationRule(customerRecord) (commonRecordValidationRules.fieldNotEmpty("surname")); return { root, customerRecord, customersDefaultIndex, customersNoGroupaggregateGroup, allCustomersOwedFunctions } }; describe("hierarchy validation", () => { const expectInvalidField = (validationResult, fieldName, expectedNode, count = 1) => { expect(validationResult.length).toBe(count); expect(some(validationResult, r => r.field === fieldName && r.item === expectedNode)).toBe(true); } it("should return no errors when hierarchy is valid", () => { const hierarchy = createValidHierarchy(); const validationResult = validateAll(hierarchy.root); expect(validationResult).toEqual([]); }); it("should return an error on name field, when name not set, on all nodes types", () => { let hierarchy = createValidHierarchy(); const expectInvalidName = (node) => expectInvalidField(validationResult, "name", node, 1); hierarchy = createValidHierarchy(); hierarchy.customerRecord.name = ""; let validationResult = validateAll(hierarchy.root); expectInvalidName(hierarchy.customerRecord); hierarchy.customerRecord.name = "customers"; hierarchy = createValidHierarchy(); hierarchy.customerRecord.name = ""; validationResult = validateAll(hierarchy.root); expectInvalidName(hierarchy.customerRecord); hierarchy.customerRecord.name = "customer"; }); it("record > should return an error on fields member if empty", () => { const hierarchy = createValidHierarchy(); hierarchy.customerRecord.fields = []; const validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "fields", hierarchy.customerRecord); }); it("record > should return an error on unrecognised type", () => { const hierarchy = createValidHierarchy(); hierarchy.customerRecord.type = "notatype"; const validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "type", hierarchy.customerRecord); }); it("record > should return an error when validation rules do not have correct members", () => { let hierarchy = createValidHierarchy(); delete hierarchy.customerRecord.validationRules[0].expressionWhenValid; let validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "validationRules", hierarchy.customerRecord); hierarchy = createValidHierarchy(); delete hierarchy.customerRecord.validationRules[0].messageWhenInvalid; validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "validationRules", hierarchy.customerRecord); }); it("collection > should return error when duplicate names", () => { const hierarchy = createValidHierarchy(); hierarchy.customerRecord.collectionName = "partners" hierarchy.customerRecord.name = "partner" const validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "name", hierarchy.customerRecord, 2); }); it("index > should return error when index has no map", () => { const hierarchy = createValidHierarchy(); hierarchy.customersDefaultIndex.map = ""; const validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "map", hierarchy.customersDefaultIndex); }); it("index > should return error when index map function does not compile", () => { const hierarchy = createValidHierarchy(); hierarchy.customersDefaultIndex.map = "invalid js!!"; const validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "map", hierarchy.customersDefaultIndex); }); it("index > should return error when index filter function does not compile", () => { const hierarchy = createValidHierarchy(); hierarchy.customersDefaultIndex.filter = "invalid js!!"; const validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "filter", hierarchy.customersDefaultIndex); }); it("index > should return error when index type is not one of allowed values", () => { const hierarchy = createValidHierarchy(); hierarchy.customersDefaultIndex.indexType = ""; const validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "indexType", hierarchy.customersDefaultIndex); hierarchy.customersDefaultIndex.indexType = "should not be allowed"; const validationResult2 = validateAll(hierarchy.root); expectInvalidField(validationResult2, "indexType", hierarchy.customersDefaultIndex); }); it("index > should return error when reference index's parent is not a record", () => { const hierarchy = createValidHierarchy(); hierarchy.customersDefaultIndex.indexType = "reference"; const validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "indexType", hierarchy.customersDefaultIndex); }); it("field > should return error when a field is invalid", () => { const hierarchy = createValidHierarchy(); const invalidField =hierarchy.customerRecord.fields[0]; invalidField.name = ""; const validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "name", invalidField); }); it("aggregateGroup > should return error when name is not supplied", () => { const hierarchy = createValidHierarchy(); hierarchy.customersNoGroupaggregateGroup.name = ""; const validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "name", hierarchy.customersNoGroupaggregateGroup); }); it("aggregate > should return error when name note set", () => { const hierarchy = createValidHierarchy(); hierarchy.allCustomersOwedFunctions.name = ""; const validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "name", hierarchy.allCustomersOwedFunctions); }); it("aggregate > should return error when condition does not compile", () => { const hierarchy = createValidHierarchy(); hierarchy.customersNoGroupaggregateGroup.condition = "invalid condition"; const validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "condition", hierarchy.customersNoGroupaggregateGroup); }); it("aggregate > should return error when aggregatedValue does not compile", () => { const hierarchy = createValidHierarchy(); hierarchy.allCustomersOwedFunctions.aggregatedValue = "invalid value"; const validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "aggregatedValue", hierarchy.allCustomersOwedFunctions); }); it("aggregate > should be valid when valid condition and aggregatedValue supplied", () => { const hierarchy = createValidHierarchy(); hierarchy.allCustomersOwedFunctions.aggregatedValue = "return record.owed;"; hierarchy.allCustomersOwedFunctions.condition = "record.owed > 0;"; const validationResult = validateAll(hierarchy.root); expect(validationResult.length).toBe(0); }); it("field.typeOptions > string > should return error when maxLength <= 0", () => { const hierarchy = createValidHierarchy(); const invalidField = findField(hierarchy.customerRecord, "surname"); invalidField.typeOptions.maxLength = -1; let validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.maxLength", invalidField); invalidField.typeOptions.maxLength = 0; validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.maxLength", invalidField); invalidField.typeOptions.maxLength = 1; validationResult = validateAll(hierarchy.root); validationResult.length === 0; }); it("field.typeOptions > string > should return error allowDeclaredValues only is not a bool", () => { const hierarchy = createValidHierarchy(); const invalidField = findField(hierarchy.customerRecord, "surname"); invalidField.typeOptions.allowDeclaredValuesOnly = null; let validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.allowDeclaredValuesOnly", invalidField); invalidField.typeOptions.allowDeclaredValuesOnly = ""; validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.allowDeclaredValuesOnly", invalidField); }); it("field.typeOptions > string > should return error when values contains non-string", () => { const hierarchy = createValidHierarchy(); const invalidField = findField(hierarchy.customerRecord, "surname"); invalidField.typeOptions.values = [1]; const validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.values", invalidField); }); it("field.typeOptions > bool > should return error when allowNulls is not a bool", () => { const hierarchy = createValidHierarchy(); const invalidField = findField(hierarchy.customerRecord, "isalive"); invalidField.typeOptions.allowNulls = "1"; let validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.allowNulls", invalidField); invalidField.typeOptions.allowNulls = null; validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.allowNulls", invalidField); }); it("field.typeOptions > datetime > should return error when maxValue is not a date", () => { const hierarchy = createValidHierarchy(); const invalidField = findField(hierarchy.customerRecord, "createddate"); invalidField.typeOptions.maxValue = "1"; let validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.maxValue", invalidField); invalidField.typeOptions.maxValue = null; validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.maxValue", invalidField); }); it("field.typeOptions > datetime > should return error when minValue is not a date", () => { const hierarchy = createValidHierarchy(); const invalidField = findField(hierarchy.customerRecord, "createddate"); invalidField.typeOptions.minValue = "1"; let validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.minValue", invalidField); invalidField.typeOptions.minValue = null; validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.minValue", invalidField); }); it("field.typeOptions > number > should return error when minValue is not an integer", () => { const hierarchy = createValidHierarchy(); const invalidField = findField(hierarchy.customerRecord, "age"); invalidField.typeOptions.minValue = "hello"; let validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.minValue", invalidField); invalidField.typeOptions.minValue = null; validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.minValue", invalidField); invalidField.typeOptions.minValue = 1.1; validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.minValue", invalidField); }); it("field.typeOptions > number > should return error when maxValue is not an integer", () => { const hierarchy = createValidHierarchy(); const invalidField = findField(hierarchy.customerRecord, "age"); invalidField.typeOptions.maxValue = "hello"; let validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.maxValue", invalidField); invalidField.typeOptions.maxValue = null; validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.maxValue", invalidField); invalidField.typeOptions.maxValue = 1.1; validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.maxValue", invalidField); }); it("field.typeOptions > number > should return error when decimal places is not a positive integer", () => { const hierarchy = createValidHierarchy(); const invalidField = findField(hierarchy.customerRecord, "age"); invalidField.typeOptions.decimalPlaces = "hello"; let validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.decimalPlaces", invalidField); invalidField.typeOptions.decimalPlaces = null; validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.decimalPlaces", invalidField); invalidField.typeOptions.decimalPlaces = -1; validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.decimalPlaces", invalidField); invalidField.typeOptions.decimalPlaces = 1.1; validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.decimalPlaces", invalidField); }); it("field.typeOptions > reference > should return error when indexNodeKey is not a compmleted string", () => { const hierarchy = createValidHierarchy(); const invalidField = findField(hierarchy.customerRecord, "partner"); invalidField.typeOptions.indexNodeKey = null; let validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.indexNodeKey", invalidField); invalidField.typeOptions.indexNodeKey = ""; validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.indexNodeKey", invalidField); invalidField.typeOptions.indexNodeKey = 1; validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.indexNodeKey", invalidField); }); it("field.typeOptions > reference > should return error when reverseIndexNodeKeys is not a string array of >0 length", () => { const hierarchy = createValidHierarchy(); const invalidField = findField(hierarchy.customerRecord, "partner"); invalidField.typeOptions.reverseIndexNodeKeys = null; let validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.reverseIndexNodeKeys", invalidField); invalidField.typeOptions.reverseIndexNodeKeys = ""; validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.reverseIndexNodeKeys", invalidField); invalidField.typeOptions.reverseIndexNodeKeys = []; validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.reverseIndexNodeKeys", invalidField); invalidField.typeOptions.reverseIndexNodeKeys = "/not/an/array"; validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.reverseIndexNodeKeys", invalidField); invalidField.typeOptions.reverseIndexNodeKeys = ["/some/key/here"]; validationResult = validateAll(hierarchy.root); expect(validationResult.length).toBe(0); }); it("field.typeOptions > reference > should return error when displayValue is not a compmleted string", () => { const hierarchy = createValidHierarchy(); const invalidField = findField(hierarchy.customerRecord, "partner"); invalidField.typeOptions.displayValue = null; let validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.displayValue", invalidField); invalidField.typeOptions.displayValue = ""; validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.displayValue", invalidField); invalidField.typeOptions.displayValue = 1; validationResult = validateAll(hierarchy.root); expectInvalidField(validationResult, "typeOptions.displayValue", invalidField); }); });