Add many jests tests and implement block on element type and 81/109281/3
authorTed Humphrey <Thomas.Humphrey@att.com>
Thu, 18 Jun 2020 01:40:35 +0000 (21:40 -0400)
committerTed Humphrey <Thomas.Humphrey@att.com>
Tue, 14 Jul 2020 06:41:57 +0000 (02:41 -0400)
subdictionary fields for subdictionary elements

Issue-ID: CLAMP-849
Change-Id: Ic6c4c06ee3b41e2e4dfe1913b7ecf57a951d9993
Signed-off-by: Ted Humphrey <Thomas.Humphrey@att.com>
ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.js
ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.test.js

index 58cb9c6..90bbc88 100644 (file)
@@ -74,7 +74,9 @@ const ColPullLeftStyled = styled(Col)`
 const cellStyle = { border: '1px solid black' };
 const headerStyle = { backgroundColor: '#ddd', border: '2px solid black'       };
 const rowHeaderStyle = {backgroundColor:'#ddd',  fontSize: '15pt', text: 'bold', border: '1px solid black'};
+
 let dictList = [];
+let subDictFlag = false;
 
 function SelectSubDictType(props) {
        const {onChange} = props;
@@ -90,9 +92,10 @@ function SelectSubDictType(props) {
                SelectedDictTypes = SelectedDictTypes.slice(0,-1);
                onChange(SelectedDictTypes);
        }
+       // When the subDictFlag is true, we need to disable selection of element "type"
        return(
                <div>
-                       <select multiple={true}  onChange={selectedValues}>
+                       <select disabled={subDictFlag} multiple={true} onChange={selectedValues}>
                                <option value="string">string</option>
                                <option value="number">number</option>
                                <option value="datetime">datetime</option>
@@ -100,66 +103,75 @@ function SelectSubDictType(props) {
                                <option value="json">json</option>
                        </select>
                </div>
-       )
+       );
 }
 
 function SubDict(props) {
        const {onChange} = props;
        const subDicts = [];
-       subDicts.push('Default');
+       subDicts.push('none');
        if (dictList !== undefined  && dictList.length > 0) {
-       let item;
-        for(item in dictList) {
-            if(dictList[item].secondLevelDictionary === 1) {
-                subDicts.push(dictList[item].name);
-            }
-        };
+               let item;
+               for(item in dictList) {
+                       if(dictList[item].secondLevelDictionary === 1) {
+                               subDicts.push(dictList[item].name);
+                       }
+               }
+       }
+       let optionItems = [];
+       for (let i=0; i<subDicts.length; ++i) {
+               if (i === 0) {
+                       optionItems.push(<option selected key={subDicts[i]}>{subDicts[i]}</option>);
+               } else {
+                       optionItems.push(<option key={subDicts[i]}>{subDicts[i]}</option>);
+               }
        }
-       subDicts.push('');
-       let optionItems = subDicts.map(
-               (item) => <option key={item}>{item}</option>
-         );
+
        function selectedValue (e) {
                onChange(e.target.value);
        }
+       // When the subDictFlag is true, we need to disable selection of
+       // the sub-dictionary flag
        return(
-               <select onChange={selectedValue} >
-                       {optionItems}
-               </select>
-       )
+                       <select disabled={subDictFlag} onChange={selectedValue} >
+                               {optionItems}
+                       </select>
+       );
 }
 
 export default class ManageDictionaries extends React.Component {
        constructor(props, context) {
                super(props, context);
-               this.handleClose = this.handleClose.bind(this);
+               this.addDictionaryElementRow = this.addDictionaryElementRow.bind(this);
+               this.addDictionaryRow = this.addDictionaryRow.bind(this);
+               this.addReplaceDictionaryRequest = this.addReplaceDictionaryRequest.bind(this);
                this.clickHandler = this.clickHandler.bind(this);
+               this.deleteDictionaryElementRow = this.deleteDictionaryElementRow.bind(this);
+               this.deleteDictionaryRequest = this.deleteDictionaryRequest.bind(this);
+               this.deleteDictionaryRow = this.deleteDictionaryRow.bind(this);
+               this.fileSelectedHandler = this.fileSelectedHandler.bind(this);
                this.getDictionaries = this.getDictionaries.bind(this);
                this.getDictionaryElements = this.getDictionaryElements.bind(this);
-               this.addReplaceDictionaryRequest = this.addReplaceDictionaryRequest.bind(this);
-               this.deleteDictionaryRequest = this.deleteDictionaryRequest.bind(this);
+               this.handleClose = this.handleClose.bind(this);
+               this.handleDictionaryRowClick = this.handleDictionaryRowClick.bind(this);
+               this.importCsvData = this.importCsvData.bind(this);
+               this.updateDictionaryElementRow = this.updateDictionaryElementRow.bind(this);
                this.updateDictionaryElementsRequest = this.updateDictionaryElementsRequest.bind(this);
-               this.addDictionaryRow = this.addDictionaryRow.bind(this);
                this.updateDictionaryRow = this.updateDictionaryRow.bind(this);
-               this.deleteDictionaryRow = this.deleteDictionaryRow.bind(this);
-               this.addDictionaryElementRow = this.addDictionaryElementRow.bind(this);
-               this.deleteDictionaryElementRow = this.deleteDictionaryElementRow.bind(this);
-               this.updateDictionaryElementRow = this.updateDictionaryElementRow.bind(this);
-               this.fileSelectedHandler = this.fileSelectedHandler.bind(this);
+               this.readOnly = props.readOnly !== undefined ? props.readOnly : false;
                this.state = {
                        show: true,
-                       selectedFile: '',
                        currentSelectedDictionary: null,
                        exportFilename: '',
                        content: null,
                        dictionaryElements: [],
                        tableIcons: {
                                Add: forwardRef((props, ref) => <AddBox {...props} ref={ref} />),
-                               Check: forwardRef((props, ref) => <Check {...props} ref={ref} />),
-                               Clear: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
                                Delete: forwardRef((props, ref) => <DeleteOutline {...props} ref={ref} />),
                                DetailPanel: forwardRef((props, ref) => <ChevronRight {...props} ref={ref} />),
                                Edit: forwardRef((props, ref) => <Edit {...props} ref={ref} />),
+                               Check: forwardRef((props, ref) => <Check {...props} ref={ref} />),
+                               Clear: forwardRef((props, ref) => <Clear {...props} ref={ref} />),
                                Export: forwardRef((props, ref) => <VerticalAlignBottomIcon {...props} ref={ref} />),
                                Filter: forwardRef((props, ref) => <FilterList {...props} ref={ref} />),
                                FirstPage: forwardRef((props, ref) => <FirstPage {...props} ref={ref} />),
@@ -226,10 +238,10 @@ export default class ManageDictionaries extends React.Component {
                                        headerStyle: headerStyle
                                },
                                {
-                                   title: "Sub-Dictionary", field: "subDictionary",
-                                     editComponent: props => (
+                                       title: "Sub-Dictionary", field: "subDictionary",
+                                       editComponent: props => (
                                                 <div>
-                                                        <SubDict  value={props.value} onChange={props.onChange} />
+                                                        <SubDict value={props.value} onChange={props.onChange} />
                                                 </div>
                                      ),
                                    cellStyle: cellStyle,
@@ -256,14 +268,19 @@ export default class ManageDictionaries extends React.Component {
        getDictionaries() {
                TemplateMenuService.getDictionary().then(arrayOfdictionaries => {
                        this.setState({ dictionaries: arrayOfdictionaries, currentSelectedDictionary: null })
+                       // global variable setting used functional components in this file
+                       dictList = arrayOfdictionaries;
+               }).catch(() => {
+                       console.error('Failed to retrieve dictionaries');
+                       this.setState({ dictionaries: [], currentSelectedDictionary: null })
                });
        }
 
        getDictionaryElements(dictionaryName) {
                TemplateMenuService.getDictionaryElements(dictionaryName).then(dictionaryElements => {
-                       dictList = this.state.dictionaries;
                        this.setState({ dictionaryElements: dictionaryElements.dictionaryElements} );
-               });
+                       this.setState({ currentSelectDictionary: dictionaryName });
+               }).catch(() => console.error('Failed to retrieve dictionary elements'))
        }
 
        clickHandler(rowData) {
@@ -277,27 +294,33 @@ export default class ManageDictionaries extends React.Component {
 
        addReplaceDictionaryRequest(dictionaryEntry) {
                TemplateMenuService.insDictionary(dictionaryEntry)
-               .then(resp => {})
-               .then(() => {this.getDictionaries()});
+               .then(resp => {
+                       this.getDictionaries();
+               })
+               .catch(() => console.error('Failed to insert new dictionary elements'));
        }
 
        updateDictionaryElementsRequest(dictElements) {
                let reqData = { "name": this.state.currentSelectedDictionary, 'dictionaryElements': dictElements };
                TemplateMenuService.insDictionaryElements(reqData)
-               .then(resp => {})
-               .then(() => { this.getDictionaryElements(this.state.currentSelectedDictionary) });
+               .then(resp => { this.getDictionaryElements(this.state.currentSelectedDictionary) })
+               .catch(() => console.error('Failed to update dictionary elements'));
        }
 
        deleteDictionaryRequest(dictionaryName) {
                TemplateMenuService.deleteDictionary(dictionaryName)
-               .then(resp => { this.getDictionaries() });
+               .then(resp => {
+                       this.getDictionaries();
+               })
+               .catch(() => console.error('Failed to delete dictionary'));
        }
 
        deleteDictionaryElementRequest(dictionaryName, elemenetShortName) {
                TemplateMenuService.deleteDictionaryElements({ 'name': dictionaryName, 'shortName': elemenetShortName })
                .then(resp => {
                        this.getDictionaryElements(dictionaryName);
-               });
+               })
+               .catch(() => console.error('Failed to delete dictionary elements'));
        }
 
        fileSelectedHandler = (event) => {
@@ -306,83 +329,94 @@ export default class ManageDictionaries extends React.Component {
                        if (event.target.files && event.target.files[0]) {
                                const reader = new FileReader();
                                reader.onload = (e) => {
+                                       let errorMessages = this.importCsvData(reader.result);
+                                       if (errorMessages !== '') {
+                                               alert(errorMessages);
+                                       }
+                               }
+                               reader.readAsText(event.target.files[0]);
+                       }
+               } else {
+                       alert('Please upload .csv extention files only.');
+               }
+       }
 
-                               const jsonKeyNames = [ 'shortName', 'name', 'description', 'type', 'subDictionary' ];
-                               const userHeaderNames = [ 'Element Short Name', 'Element Name', 'Element Description', 'Element Type', 'Sub-Dictionary'  ];
-                               const mandatory = [ true, true, true, true, false ];
-                               const validTypes = ['string','number','datetime','json','map'];
+       importCsvData(rawCsvData) {
 
-                               let result = CsvToJson(reader.result, ',', '||||', userHeaderNames, jsonKeyNames, mandatory);
+               const jsonKeyNames = [ 'shortName', 'name', 'description', 'type', 'subDictionary' ];
+               const userHeaderNames = [ 'Element Short Name', 'Element Name', 'Element Description', 'Element Type', 'Sub-Dictionary'  ];
+               const validTypes = ['string','number','datetime','json','map'];
 
-                               let errorMessages = result.errorMessages;
-                               let jsonObjArray = result.jsonObjArray;
+               let mandatory;
 
-                               let validTypesErrorMesg = '';
+               if (subDictFlag) {
+                       mandatory = [ true, true, true, false, false ];
+               } else {
+                       mandatory = [ true, true, true, true, false ];
+               }
 
-                               for (let i=0; i < validTypes.length; ++i) {
-                                       if (i === 0) {
-                                               validTypesErrorMesg = validTypes[i];
-                                       } else {
-                                               validTypesErrorMesg += ',' + validTypes[i];
-                                       }
-                               }
+               let result = CsvToJson(rawCsvData, ',', '||||', userHeaderNames, jsonKeyNames, mandatory);
 
-                               if (errorMessages !== '') {
-                                       alert(errorMessages);
-                                       return;
-                               }
+               let errorMessages = result.errorMessages;
+               let jsonObjArray = result.jsonObjArray;
 
-                               // Perform further checks on data that is now in JSON form
-                               let subDictionaries = [];
+               let validTypesErrorMesg = '';
 
-                               // NOTE: dictList is a global variable  maintained faithfully
-                               //       by the getDictionaries() method outside this import
-                               //       functionality.
-                               let item;
-                               for (item in dictList) {
-                                       if (dictList[item].secondLevelDictionary === 1) {
-                                               subDictionaries.push(dictList[item].name);
-                                       }
-                               };
-
-                               // Check for valid Sub-Dictionary and Element Type values
-                               subDictionaries = subDictionaries.toString();
-                               let row = 2;
-                               let dictElem;
-                               for (dictElem of jsonObjArray) {
-                                       let itemKey;
-                                       for (itemKey in dictElem){
-                                               let value = dictElem[itemKey].trim();
-                                               let keyIndex = jsonKeyNames.indexOf(itemKey);
-                                               if (itemKey === 'shortName' && /[^a-zA-Z0-9-_.]/.test(value)) {
-                                                       errorMessages += '\n' + userHeaderNames[keyIndex] +
-                                                               ' at row #' + row +
-                                                               ' can only contain alphanumeric characters and periods, hyphens or underscores';
-                                               }
-                                               if (itemKey === 'type' && validTypes.indexOf(value) < 0) {
-                                                       errorMessages += '\nInvalid value of "' + value + '" for "' + userHeaderNames[keyIndex] + '" at row #' + row;
-                                                       errorMessages += '\nValid types are: ' + validTypesErrorMesg;
-                                               }
-                                               if (value !== "" && itemKey === 'subDictionary' && subDictionaries.indexOf(value) < 0) {
-                                                       errorMessages += '\nInvalid Sub-Dictionary value of "' + value + '" at row #' + row;
-                            }
-                        }
-                                       ++row;
-                    }
-                                       if (errorMessages) {
-                                               alert(errorMessages);
-                                               return;
-                                       }
+               for (let i=0; i < validTypes.length; ++i) {
+                       if (i === 0) {
+                               validTypesErrorMesg = validTypes[i];
+                       } else {
+                               validTypesErrorMesg += ',' + validTypes[i];
+                       }
+               }
+
+               if (errorMessages !== '') {
+                       return errorMessages;
+               }
+
+               // Perform further checks on data that is now in JSON form
+               let subDictionaries = [];
 
-                                       // We made it through all the checks. Send it to back end
-                                       this.updateDictionaryElementsRequest(jsonObjArray);
+               // NOTE: dictList is a global variable  maintained faithfully
+               //       by the getDictionaries() method outside this import
+               //       functionality.
+               let item;
+               for (item in dictList) {
+                       if (dictList[item].secondLevelDictionary === 1) {
+                               subDictionaries.push(dictList[item].name);
+                       }
+               };
+
+               // Check for valid Sub-Dictionary and Element Type values
+               subDictionaries = subDictionaries.toString();
+               let row = 2;
+               let dictElem;
+               for (dictElem of jsonObjArray) {
+                       let itemKey;
+                       for (itemKey in dictElem){
+                               let value = dictElem[itemKey].trim();
+                               let keyIndex = jsonKeyNames.indexOf(itemKey);
+                               if (itemKey === 'shortName' && /[^a-zA-Z0-9-_.]/.test(value)) {
+                                       errorMessages += '\n' + userHeaderNames[keyIndex] +
+                                               ' at row #' + row +
+                                               ' can only contain alphanumeric characters and periods, hyphens or underscores';
+                               }
+                               if (itemKey === 'type' && validTypes.indexOf(value) < 0) {
+                                       errorMessages += '\nInvalid value of "' + value + '" for "' + userHeaderNames[keyIndex] + '" at row #' + row;
+                                       errorMessages += '\nValid types are: ' + validTypesErrorMesg;
+                               }
+                               if (value !== "" && itemKey === 'subDictionary' && subDictionaries.indexOf(value) < 0) {
+                                       errorMessages += '\nInvalid Sub-Dictionary value of "' + value + '" at row #' + row;
                                }
-                               reader.readAsText(event.target.files[0]);
                        }
-                       this.setState({selectedFile: event.target.files[0]})
-               } else {
-                       alert('Please upload .csv extention files only.');
+                       ++row;
+               }
+               if (errorMessages === '') {
+                       // We made it through all the checks. Send it to back end
+                       this.updateDictionaryElementsRequest(jsonObjArray);
                }
+
+               return errorMessages;
        }
 
        addDictionaryRow(newData) {
@@ -392,13 +426,13 @@ export default class ManageDictionaries extends React.Component {
                                        if (/[^a-zA-Z0-9-_.]/.test(newData.name)) {
                                                validData = false;
                                                alert('Please enter alphanumeric input. Only allowed special characters are:(period, hyphen, underscore)');
-                                               reject(() => {});
+                                               reject();
                                        }
                                        for (let i = 0; i < this.state.dictionaries.length; i++) {
                                                if (this.state.dictionaries[i].name === newData.name) {
                                                        validData = false;
                                                        alert(newData.name + ' dictionary name already exists')
-                                                       reject(() => {});
+                                                       reject();
                                                }
                                        }
                                        if (validData) {
@@ -410,13 +444,14 @@ export default class ManageDictionaries extends React.Component {
        }
 
 
-       updateDictionaryRow(oldData, newData) {
+       updateDictionaryRow(newData, oldData) {
                let validData = true;
-               return new Promise((resolve) => {
+               return new Promise((resolve, reject) => {
                        setTimeout(() => {
                                if (/[^a-zA-Z0-9-_.]/.test(newData.name)) {
                                        validData = false;
                                        alert('Please enter alphanumberic input. Only allowed special characters are:(period, hyphen, underscore)');
+                                       reject();
                                }
                                if (validData) {
                                        this.addReplaceDictionaryRequest(newData);
@@ -427,7 +462,7 @@ export default class ManageDictionaries extends React.Component {
        }
 
        deleteDictionaryRow(oldData) {
-               return new Promise((resolve) => {
+               return new Promise((resolve, reject) => {
                        setTimeout(() => {
                                this.deleteDictionaryRequest(oldData.name);
                                resolve();
@@ -439,53 +474,63 @@ export default class ManageDictionaries extends React.Component {
                return new Promise((resolve, reject) => {
                        setTimeout(() => {
                                let dictionaryElements = this.state.dictionaryElements;
-                               let errorMessage = '';
+                               let errorMessages = '';
                                for (let i = 0; i < this.state.dictionaryElements.length; i++) {
                                        if (this.state.dictionaryElements[i].shortName === newData.shortName) {
                                                alert('Short Name "' + newData.shortName + '" already exists');
-                                               reject(() => {});
+                                               reject("");
                                        }
                                }
-                               if (newData.shortName !== '' && /[^a-zA-Z0-9-_.]/.test(newData.shortName)) {
-                                       errorMessage += '\nShort Name is limited to alphanumeric characters and also period, hyphen, and underscore';
+                               // MaterialTable returns no property at all if the user has not touched a
+                               // new column, so we want to add the property with an emptry string
+                               // for several cases if that is the case to simplify other checks.
+                               if (newData.description === undefined) {
+                                       newData.description = "";
+                               }
+                               if (newData.subDictionary === undefined) {
+                                       newData.subDictionary = null;
+                               }
+                               if (newData.type === undefined) {
+                                       newData.type = "";
+                               }
+                               if (!newData.shortName && /[^a-zA-Z0-9-_.]/.test(newData.shortName)) {
+                                       errorMessages += '\nShort Name is limited to alphanumeric characters and also period, hyphen, and underscore';
                                }
                                if (!newData.shortName){
-                                       errorMessage += '\nShort Name must be specified';
+                                       errorMessages += '\nShort Name must be specified';
                                }
                                if (!newData.name){
-                                       errorMessage += '\nElement Name must be specified';
+                                       errorMessages += '\nElement Name must be specified';
                                }
-                               if (!newData.type){
-                                       errorMessage += '\nElement Type must be specified';
+                               if (!newData.type && !subDictFlag){
+                                       errorMessages += '\nElement Type must be specified';
                                }
-                               if (!newData.description){
-                                       errorMessage += '\nElement Description must be specified';
-                               }
-                               if (errorMessage === '') {
+                               if (errorMessages === '') {
                                        dictionaryElements.push(newData);
-                                       this.updateDictionaryElementsRequest(dictionaryElements);
+                                       this.updateDictionaryElementsRequest([newData]);
                                        resolve();
                                } else {
-                                       alert(errorMessage);
-                                       reject(() => {});
+                                       alert(errorMessages);
+                                       reject("");
                                }
                        }, 1000);
                });
        }
 
        updateDictionaryElementRow(newData, oldData) {
-               return new Promise((resolve) => {
+               return new Promise((resolve, reject) => {
                        setTimeout(() => {
                                let dictionaryElements = this.state.dictionaryElements;
                                let validData =  true;
                                if (!newData.type) {
                                        validData = false;
                                        alert('Element Type cannot be null');
+                                       reject();
                                }
                                if (validData) {
                                        const index = dictionaryElements.indexOf(oldData);
                                        dictionaryElements[index] = newData;
-                                       this.updateDictionaryElementsRequest(dictionaryElements);
+                                       this.updateDictionaryElementsRequest([newData]);
                                }
                                resolve();
                        }, 1000);
@@ -502,6 +547,15 @@ export default class ManageDictionaries extends React.Component {
                });
        }
 
+       handleDictionaryRowClick(event, rowData) {
+               subDictFlag = rowData.secondLevelDictionary === 1 ? true : false;
+               this.setState({
+                       currentSelectedDictionary : rowData.name,
+                       exportFilename: rowData.name
+               })
+               this.getDictionaryElements(rowData.name);
+       }
+
        render() {
                return (
                        <ModalStyled size="xl" show={this.state.show} onHide={this.handleClose} backdrop="static" keyboard={false} >
@@ -509,70 +563,69 @@ export default class ManageDictionaries extends React.Component {
                                        <Modal.Title>Manage Dictionaries</Modal.Title>
                                </Modal.Header>
                                <Modal.Body>
-                                       {this.state.currentSelectedDictionary === null ? <MaterialTable
-                               title={"Dictionary List"}
-                               data={this.state.dictionaries}
-                               columns={this.state.dictColumns}
-                               icons={this.state.tableIcons}
-                               onRowClick={(event, rowData) => {
-                                                               this.setState({
-                                                                       currentSelectedDictionary : rowData.name,
-                                                                       exportFilename: rowData.name
-                                                               })
-                                                               this.getDictionaryElements(rowData.name);
-                                                       }}
-                               options={{
-                               headerStyle: rowHeaderStyle,
-                               }}
-                               editable={{
-                               onRowAdd: this.addDictionaryRow,
-                               onRowUpdate: this.updateDictionaryRow,
-                               onRowDelete: this.deleteDictionaryRow
-                                                       }}
+                                       {this.state.currentSelectedDictionary === null ?
+                                               <MaterialTable
+                                                       title={"Dictionary List"}
+                                                       data={this.state.dictionaries}
+                                                       columns={this.state.dictColumns}
+                                                       icons={this.state.tableIcons}
+                                                       onRowClick={this.handleDictionaryRowClick}
+                                                       options={{
+                                                               headerStyle: rowHeaderStyle,
+                                                       }}
+                                                       editable={!this.readOnly ?
+                                                               {
+                                                                       onRowAdd: this.addDictionaryRow,
+                                                                       onRowUpdate: this.updateDictionaryRow,
+                                                                       onRowDelete: this.deleteDictionaryRow
+                                                               } : undefined }
+                                               /> : null
+                                       }
+                                       {this.state.currentSelectedDictionary !== null ?
+                                               <MaterialTable
+                                                       title={'Dictionary Elements List for ' + (subDictFlag ? 'Sub-Dictionary "' : '"') + this.state.currentSelectedDictionary + '"'}
+                                                       data={this.state.dictionaryElements}
+                                                       columns={this.state.dictElementColumns}
+                                                       icons={this.state.tableIcons}
+                                                       options={{
+                                                               exportAllData: true,
+                                                               exportButton: true,
+                                                               exportFileName: this.state.exportFilename,
+                                                               headerStyle:{backgroundColor:'white',  fontSize: '15pt', text: 'bold', border: '1px solid black'}
+                                                       }}
+                                                       components={{
+                                                               Toolbar: props => (
+                                                                       <Row>
+                                                                               <Col sm="11">
+                                                                                       <MTableToolbarStyled {...props} />
+                                                                               </Col>
+                                                                               <ColPullLeftStyled sm="1">
+                                                                                       <Tooltip title="Import" placement = "bottom">
+                                                                                               <IconButton aria-label="import" disabled={this.readOnly} onClick={() => this.fileUpload.click()}>
+                                                                                                       <VerticalAlignTopIcon />
+                                                                                               </IconButton>
+                                                                                       </Tooltip>
+                                                                                       <input type="file" ref={(fileUpload) => {this.fileUpload = fileUpload;}}
+                                                                                               style={{ visibility: 'hidden', width: '1px' }} onChange={this.fileSelectedHandler} />
+                                                                               </ColPullLeftStyled>
+                                                                       </Row>
+                                                               )
+                                                       }}
+                                                       editable={!this.readOnly ?
+                                                               {
+                                                                       onRowAdd: this.addDictionaryElementRow,
+                                                                       onRowUpdate: this.updateDictionaryElementRow,
+                                                                       onRowDelete: this.deleteDictionaryElementRow
+                                                               } : undefined
+                                                        }
                                                /> : null
-                    }
-                    {this.state.currentSelectedDictionary !== null ? <MaterialTable
-                        title={'Dictionary Elements List for "' + this.state.currentSelectedDictionary + '"'}
-                        data={this.state.dictionaryElements}
-                        columns={this.state.dictElementColumns}
-                        icons={this.state.tableIcons}
-                        options={{
-                                                       exportAllData: true,
-                            exportButton: true,
-                            exportFileName: this.state.exportFilename,
-                            headerStyle:{backgroundColor:'white',  fontSize: '15pt', text: 'bold', border: '1px solid black'}
-                        }}
-                        components={{
-                            Toolbar: props => (
-                                                               <Row>
-                                                                       <Col sm="11">
-                                       <MTableToolbarStyled {...props} />
-                                                                       </Col>
-                                                                       <ColPullLeftStyled sm="1">
-                                        <Tooltip title="Import" placement = "bottom">
-                                        <IconButton aria-label="import" onClick={() => this.fileUpload.click()}>
-                                               <VerticalAlignTopIcon />
-                                        </IconButton>
-                                        </Tooltip>
-                                               <input type="file" ref={(fileUpload) => {this.fileUpload = fileUpload;}}
-                                                                                       style={{ visibility: 'hidden', width: '1px' }} onChange={this.fileSelectedHandler} />
-                                                                       </ColPullLeftStyled>
-                                </Row>
-                            )
-                        }}
-                        editable={{
-                            onRowAdd: this.addDictionaryElementRow,
-                            onRowUpdate: this.updateDictionaryElementRow,
-                            onRowDelete: this.deleteDictionaryElementRow
-                        }}
-                        /> : null
-                    }
-                    {this.state.currentSelectedDictionary !== null ? <button onClick={this.clickHandler} style={{marginTop: '25px'}}>Go Back to Dictionaries List</button>:""}
-                </Modal.Body>
-                <Modal.Footer>
-                    <Button variant="secondary" type="null" onClick={this.handleClose}>Close</Button>
-                </Modal.Footer>
-            </ModalStyled>
-        );
-    }
+                                       }
+                                       {this.state.currentSelectedDictionary !== null ? <button onClick={this.clickHandler} style={{marginTop: '25px'}}>Go Back to Dictionaries List</button>:""}
+                               </Modal.Body>
+                               <Modal.Footer>
+                                       <Button variant="secondary" type="null" onClick={this.handleClose}>Close</Button>
+                               </Modal.Footer>
+                       </ModalStyled>
+               );
+       }
 }
index d1d4aa6..a4c1335 100644 (file)
@@ -27,7 +27,94 @@ import { render } from 'enzyme';
 import ManageDictionaries from './ManageDictionaries';
 import TemplateMenuService from '../../../api/TemplateService'
 
+const TestDictionaryElements = {
+    name: "test",
+    secondLevelDictionary: 0,
+    subDictionaryType: "", 
+    dictionaryElements: [
+      {
+        shortName: "alertType",
+        name: "Alert Type",
+        description: "Type of Alert",
+        type: "string",
+        subDictionary: "", 
+        createdDate: "2020-06-12T13:58:51.443931Z",
+        updatedDate: "2020-06-13T16:27:57.084870Z",
+        updatedBy: "admin",
+        createdBy: "admin"
+      }
+    ]
+};
+
+const TestDictionaries =
+[
+  {
+    name: "test",
+    secondLevelDictionary: 0,
+    subDictionaryType: "string",
+    dictionaryElements: [ TestDictionaryElements ],
+    createdDate: "2020-06-14T21:00:33.231166Z",
+    updatedDate: "2020-06-14T21:00:33.231166Z",
+    updatedBy: "admin",
+    createdBy: "admin"
+  },
+  {
+    name: "testSub1",
+    secondLevelDictionary: 1,
+    subDictionaryType: "string",
+    dictionaryElements: [
+      {
+        shortName: "subElem",
+        name: "Sub Element",
+        description: "Sub Element Description",
+        type: "string",
+        createdDate: "2020-06-14T21:04:44.402287Z",
+        updatedDate: "2020-06-14T21:04:44.402287Z",
+        updatedBy: "admin",
+        createdBy: "admin"
+      }
+    ],
+    createdDate: "2020-06-14T21:01:16.390250Z",
+    updatedDate: "2020-06-14T21:01:16.390250Z",
+    updatedBy: "admin",
+    createdBy: "admin"
+  }
+];
+
+
+const historyMock = { push: jest.fn() };
+
+let errorMessage = '';
+
+window.alert = jest.fn().mockImplementation((mesg) => { errorMessage = mesg ; return });
+
+TemplateMenuService.getDictionary = jest.fn().mockImplementation(() => {
+       return Promise.resolve(TestDictionaries);
+});
+
+TemplateMenuService.insDictionary = jest.fn().mockImplementation(() => {
+       return Promise.resolve({ ok: true, status: 200 });
+});
+
+TemplateMenuService.deleteDictionary = jest.fn().mockImplementation(() => {
+       return Promise.resolve("200");
+});
+
+TemplateMenuService.getDictionaryElements = jest.fn().mockImplementation(() => {
+       return Promise.resolve(TestDictionaryElements);
+});
+
+TemplateMenuService.deleteDictionaryElements = jest.fn().mockImplementation(() => {
+       return Promise.resolve("200");
+});
+
+TemplateMenuService.insDictionaryElements = jest.fn().mockImplementation(() => {
+       return Promise.resolve("200");
+});
+
+
 describe('Verify ManageDictionaries', () => {
+
        beforeEach(() => {
                fetch.resetMocks();
        });
@@ -40,7 +127,7 @@ describe('Verify ManageDictionaries', () => {
                                json: () => {
                                        return Promise.resolve({
                                                "name": "vtest",
-                                               "secondLevelDictionary": "1",
+                                               "secondLevelDictionary": 1,
                                                "subDictionaryType": "string",
                                                "updatedBy": "test",
                                                "updatedDate": "05-07-2019 19:09:42"
@@ -60,7 +147,7 @@ describe('Verify ManageDictionaries', () => {
                                json: () => {
                                        return Promise.resolve({
                                                "name": "vtest",
-                                               "secondLevelDictionary": "1",
+                                               "secondLevelDictionary": 1,
                                                "subDictionaryType": "string",
                                                "updatedBy": "test",
                                                "updatedDate": "05-07-2019 19:09:42"
@@ -71,124 +158,283 @@ describe('Verify ManageDictionaries', () => {
                const component = shallow(<ManageDictionaries />);
        });
 
-       it('Test API Rejection', () => {
-               const myMockFunc  = fetch.mockImplementationOnce(() => Promise.reject('error'));
-               setTimeout( () => myMockFunc().catch(e => {
-                       console.info(e);
-               }),
-               100
-               );
-               const component = shallow(<ManageDictionaries />);
-               expect(myMockFunc.mock.calls.length).toBe(1);
-       });
-
        it('Test Table icons', () => {
-               fetch.mockImplementationOnce(() => {
-                       return Promise.resolve({
-                               ok: true,
-                               status: 200,
-                               json: () => {
-                                       return Promise.resolve({
-                                               "name": "vtest",
-                                               "secondLevelDictionary": "1",
-                                               "subDictionaryType": "string",
-                                               "updatedBy": "test",
-                                               "updatedDate": "05-07-2019 19:09:42"
-                                       });
-                               }
-                       });
-               });
+
                const component = mount(<ManageDictionaries />);
                expect(component.find('[className="MuiSelect-icon MuiTablePagination-selectIcon"]')).toBeTruthy();
        });
 
-       test('Test get dictionaryNames/dictionaryElements, add/delete dictionary functions', async () => {
-               const dictionaries = [
-                       {
-                               name: "DefaultActors",
-                               secondLevelDictionary: 0,
-                               subDictionaryType: "",
-                               dictionaryElements: [
-                                       {
-                                               "shortName": "SDNR",
-                                               "name": "SDNR Change",
-                                               "description": "SDNR component",
-                                               "type": "string",
-                                               "createdDate": "2020-06-07T18:57:18.130858Z",
-                                               "updatedDate": "2020-06-11T13:10:52.239282Z",
-                                               "updatedBy": "admin"
-                                       }
-                               ],
-                               createdDate: "2020-06-07T22:21:08.428742Z",
-                               updatedDate: "2020-06-10T00:41:49.122908Z",
-                               updatedBy: "Not found"
-                       }
-               ];
-               const historyMock = { push: jest.fn() };
-               TemplateMenuService.getDictionary = jest.fn().mockImplementation(() => {
-                       return Promise.resolve(dictionaries);
-               });
-               TemplateMenuService.getDictionaryElements = jest.fn().mockImplementation(() => {
-                       return Promise.resolve(dictionaries[0]);
-               });
-               TemplateMenuService.insDictionary = jest.fn().mockImplementation(() => {
-                       return Promise.resolve(200);
-               });
-               TemplateMenuService.deleteDictionary = jest.fn().mockImplementation(() => {
-                       return Promise.resolve(200);
-               });
-               const flushPromises = () => new Promise(setImmediate);
-               const component = shallow(<ManageDictionaries history={historyMock} />)
+       test('Test add/replace and delete dictionary requests', async () => {
+
+               const component = shallow(<ManageDictionaries history={historyMock}/>)
                const instance = component.instance();
-               instance.getDictionaryElements("DefaultActors");
-               instance.clickHandler();
-               instance.addReplaceDictionaryRequest();
-               instance.deleteDictionaryRequest();
+
+               const flushPromises = () => new Promise(setImmediate);
+
+               instance.addReplaceDictionaryRequest({name: "newdict", secondLevelDictionary: 0, subDictionaryType: "string"});
+               instance.deleteDictionaryRequest("test");
+
                await flushPromises();
-               expect(component.state('dictionaries')).toEqual(dictionaries);
+
+               expect(component.state('currentSelectedDictionary')).toEqual(null);
+               expect(component.state('dictionaries')).toEqual(TestDictionaries);
        });
 
-       test('Test adding and deleting dictionaryelements', async () => {
-               const historyMock = { push: jest.fn() };
-               const dictionaries = [
-                       {
-                               name: "DefaultActors",
-                               secondLevelDictionary: 0,
-                               subDictionaryType: "",
-                               dictionaryElements: [
-                                       {
-                                               "shortName": "SDNR",
-                                               "name": "SDNR Change",
-                                               "description": "SDNR component",
-                                               "type": "string",
-                                               "createdDate": "2020-06-07T18:57:18.130858Z",
-                                               "updatedDate": "2020-06-11T13:10:52.239282Z",
-                                               "updatedBy": "admin"
-                                       }
-                               ],
-                               createdDate: "2020-06-07T22:21:08.428742Z",
-                               updatedDate: "2020-06-10T00:41:49.122908Z",
-                               updatedBy: "Not found"
-                       }
-               ];
-               TemplateMenuService.getDictionary = jest.fn().mockImplementation(() => {
-                       return Promise.resolve(dictionaries);
-               });
-               TemplateMenuService.insDictionaryElements = jest.fn().mockImplementation(() => {
-                       return Promise.resolve(200);
-               });
-               TemplateMenuService.deleteDictionaryElements = jest.fn().mockImplementation(() => {
-                       return Promise.resolve(200);
-               });
-               const flushPromises = () => new Promise(setImmediate);
+       test('Test update dictionary row', async () => {
+
                const component = shallow(<ManageDictionaries history={historyMock}/>)
                const instance = component.instance();
-               instance.addReplaceDictionaryRequest({ name: "EventDictionary", secondLevelDictionary: "0", subDictionaryType: "string"} );
-               instance.deleteDictionaryRequest('EventDictionary');
-               await flushPromises();
-               expect(component.state('currentSelectedDictionary')).toEqual(null);
+               const rowData = { name: "newdict", secondLevelDictionary: 0, subDictionaryType: "string" };
+
+               await expect(instance.updateDictionaryRow(rowData, rowData)).resolves.toEqual(undefined);
+
+       }, 2000);
+
+       test('Test add dictionary row', async () => {
+
+               const addReplaceRequest = jest.spyOn(ManageDictionaries.prototype,'addReplaceDictionaryRequest');
+               const component = shallow(<ManageDictionaries />)
+               const instance = component.instance();
+               const rowData = { name: "newdict", secondLevelDictionary: 0, subDictionaryType: "string" };
+
+               await instance.addDictionaryRow(rowData);
+                expect(addReplaceRequest).toHaveBeenCalledWith(rowData);
+
+       }, 2000);
+
+       test('Test add dictionary row with errors name already exists', async () => {
+
+               const component = shallow(<ManageDictionaries />)
+               const instance = component.instance();
+               let  rowData = { name: "test", secondLevelDictionary: 0, subDictionaryType: "" };
+
+               await expect(instance.addDictionaryRow(rowData)).rejects.toEqual(undefined);
+
+       }, 2000);
+
+       test('Test add dictionary row with errors illegal chars in name', async () => {
+
+               const component = shallow(<ManageDictionaries />)
+               const instance = component.instance();
+               let  rowData = { name: "test@@", secondLevelDictionary: 0, subDictionaryType: "" };
+
+               await expect(instance.addDictionaryRow(rowData)).rejects.toEqual(undefined);
+
+       }, 2000);
+
+       test('Test update dictionary row with errors illegal chars in name', async () => {
+
+               const component = shallow(<ManageDictionaries />)
+               const instance = component.instance();
+               let  rowData = { name: "test@@", secondLevelDictionary: 0, subDictionaryType: "" };
+
+               await expect(instance.updateDictionaryRow(rowData)).rejects.toEqual(undefined);
+       });
+
+
+       test('Test add dictionary row with errors (illegal chars)', async () => {
+
+               const addReplaceRequest = jest.spyOn(ManageDictionaries.prototype,'addReplaceDictionaryRequest');
+               const component = shallow(<ManageDictionaries />)
+               const instance = component.instance();
+               let  rowData = { name: "test@@", secondLevelDictionary: 0, subDictionaryType: "" };
+
+               await expect(instance.addDictionaryRow(rowData)).rejects.toEqual(undefined);
+
+       }, 2000);
+
+
+       test('Test delete dictionary row', async () => {
+
+               const deleteRequest = jest.spyOn(ManageDictionaries.prototype,'deleteDictionaryRequest');
+               const component = shallow(<ManageDictionaries />)
+               const instance = component.instance();
+               const rowData = { name: "newdict", secondLevelDictionary: 0, subDictionaryType: "string" };
+
+               await instance.deleteDictionaryRow(rowData);
+                expect(deleteRequest).toHaveBeenCalledWith("newdict");
+
+       }, 2000);
+
+       test('Test handle select dictionary row click', async () => {
+
+               const component = shallow(<ManageDictionaries />)
+               const instance = component.instance();
+               const rowData = { name: "newdict", secondLevelDictionary: 0, subDictionaryType: "string" };
+
+               instance.handleDictionaryRowClick("event", rowData);
+               expect(component.state('currentSelectedDictionary')).toEqual("newdict");
+       }, 2000);
+
+       test('Test dictionary element row add, update, delete', async () => {
+
+               const rowData = {
+                       createdBy: "admin",
+                       createdDate: "2020-06-15T13:59:20.467381Z",
+                       description: "Description",
+                       name: "Some Elem",
+                       shortName: "someElem",
+                       type: "string",
+                       updatedBy: "admin",
+                       updatedDate: "2020-06-15T13:59:20.467381Z"
+               };
+
+               const component = shallow(<ManageDictionaries/>)
+               const instance = component.instance();
+
+               const badRowData = {
+                       description: "Description",
+                       name: "Some Elem",
+                       shortName: "someElem",
+                       type: "string"
+               };
+
+                await instance.clickHandler();
+                await instance.getDictionaryElements("test");
+
+               await expect(instance.addDictionaryElementRow(rowData)).resolves.toEqual(undefined);
+               await expect(instance.updateDictionaryElementRow(rowData, rowData)).resolves.toEqual(undefined);
+               await expect(instance.deleteDictionaryElementRow(rowData)).resolves.toEqual(undefined);
+       });
+
+       test('Test dictionary element row add with errors', async () => {
+
+               const badRowData = {
+                       description: "",
+                       name: "",
+                       shortName: "some#Elem",
+                       type: ""
+               };
+
+               const component = shallow(<ManageDictionaries/>)
+               const instance = component.instance();
+
+               await expect(instance.addDictionaryElementRow(badRowData)).rejects.toEqual("");
+       });
+
+       test('Test dictionary element update with error illegal name', async () => {
+
+               const badRowData = {
+                       description: "",
+                       name: "test@@",
+                       shortName: "some#Elem",
+                       type: ""
+               };
+
+               const component = shallow(<ManageDictionaries/>)
+               const instance = component.instance();
+
+               await expect(instance.updateDictionaryElementRow(badRowData)).rejects.toEqual(undefined);
+       });
+
+       test('Test dictionary element addition with duplicate name error', async () => {
+
+               const badRowData = {
+                       description: "description",
+                       name: "Alert Type",
+                       shortName: "alertType",
+                       type: "string"
+               };
+
+               const component = shallow(<ManageDictionaries/>)
+               const instance = component.instance();
+
+               component.setState({ currentSelectedDictionary: 'test' });
+
+               await instance.getDictionaryElements();
+               await expect(instance.addDictionaryElementRow(badRowData)).rejects.toEqual("");
+       });
+
+       test('Test dictionary element addition with empty name error', async () => {
+
+               const badRowData = {
+                       description: "description",
+                       name: "Alert Type",
+                       shortName: "",
+                       type: "string"
+               };
+
+               const component = shallow(<ManageDictionaries/>)
+               const instance = component.instance();
+
+               component.setState({ currentSelectedDictionary: 'test' });
+
+               await instance.getDictionaryElements();
+               await expect(instance.addDictionaryElementRow(badRowData)).rejects.toEqual("");
+       });
+
+
+       it('Test Import CSV Sunny Day', async () => {
+
+                TemplateMenuService.insDictionaryElements = jest.fn().mockImplementation(() => {
+                        return Promise.resolve({ ok: true, status: 200 });
+                });
+
+                let rawCsvData = '"Element Short Name","Element Name","Element Description","Element Type","Sub-Dictionary"\n';
+                rawCsvData += '"alertType","Alert Type","Alert Type Description","string","","admin","2020-06-11T13:56:14.927437Z"';
+
+                let expectedResult = [
+                                {
+                                        description: "Alert Type Description",
+                                        name: "Alert Type",
+                                        shortName: "alertType",
+                                        subDictionary: "",
+                                        type: "string"
+                                }
+               ];
+
+               const updateDictionaryElementsRequest = jest.spyOn(ManageDictionaries.prototype,'updateDictionaryElementsRequest');
+
+               const component = shallow(<ManageDictionaries />)
+               const instance = component.instance();
+
+               await expect(instance.importCsvData(rawCsvData)).toEqual('');
+                expect(updateDictionaryElementsRequest).toHaveBeenCalledWith(expectedResult);
+       });
+
+       it('Test Import CSV Mandatory Field Check Errors', () => {
+
+                let rawCsvData = '"Element Short Name","Element Name","Element Description","Element Type","Sub-Dictionary"\n';
+                rawCsvData += '"","","","","","",""';
+
+               // The empty values for all the fields in row 1 of the rawCsvData will trigger a bunch of errors.
+               // Getting Enzyme to properly match them with embedded newlines turned out to be impossible
+               // and maybe not desirable anyway; so our test for "success" here is simply that the
+               // routine returns a non-empty error string.
+
+               const component = shallow(<ManageDictionaries />)
+               const instance = component.instance();
+               expect(instance.importCsvData(rawCsvData)).not.toEqual('');
+       });
+
+       it('Test Import CSV Errors in Row Data', async () => {
+
+                TemplateMenuService.insDictionaryElements = jest.fn().mockImplementation(() => {
+                        return Promise.resolve({ ok: true, status: 200 });
+                });
+
+                let rawCsvData = '"Element Short Name","Element Name","Element Description","Element Type","Sub-Dictionary"\n';
+                rawCsvData += '"alert@Type","Alert Type","Alert Type Description","strin","subby","admin","2020-06-11T13:56:14.927437Z"';
+
+                let expectedResult = [
+                                {
+                                        description: "Alert Type Description",
+                                        name: "Alert Type",
+                                        shortName: "alertType",
+                                        subDictionary: "",
+                                        type: "string"
+                                }
+               ];
+
+               const updateDictionaryElementsRequest = jest.spyOn(ManageDictionaries.prototype,'updateDictionaryElementsRequest');
+
+               const component = shallow(<ManageDictionaries />)
+               const instance = component.instance();
+
+               await expect(instance.importCsvData(rawCsvData)).not.toEqual('');
        });
 
+
        it('Test handleClose', () => {
                fetch.mockImplementationOnce(() => {
                        return Promise.resolve({
@@ -197,7 +443,7 @@ describe('Verify ManageDictionaries', () => {
                                json: () => {
                                        return Promise.resolve({
                                                "name": "vtest",
-                                               "secondLevelDictionary": "1",
+                                               "secondLevelDictionary": 1,
                                                "subDictionaryType": "string",
                                                "updatedBy": "test",
                                                "updatedDate": "05-07-2019 19:09:42"
@@ -205,7 +451,6 @@ describe('Verify ManageDictionaries', () => {
                                }
                        });
                });
-               const historyMock = { push: jest.fn() };
                const handleClose = jest.spyOn(ManageDictionaries.prototype,'handleClose');
                const component = shallow(<ManageDictionaries history={historyMock} />)
                component.find('[variant="secondary"]').prop('onClick')();