diff options
author | 2020-06-17 21:40:35 -0400 | |
---|---|---|
committer | 2020-07-14 02:41:57 -0400 | |
commit | b80ded057a71f33f5d3365ba5393880a4296a229 (patch) | |
tree | 8e456ef4c0ca42a04579ec39a3b7522a41d27bb1 | |
parent | a717dcd2aa3ff3938c9adf0994936009c351948d (diff) |
Add many jests tests and implement block on element type and
subdictionary fields for subdictionary elements
Issue-ID: CLAMP-849
Change-Id: Ic6c4c06ee3b41e2e4dfe1913b7ecf57a951d9993
Signed-off-by: Ted Humphrey <Thomas.Humphrey@att.com>
-rw-r--r-- | ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.js | 437 | ||||
-rw-r--r-- | ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.test.js | 463 |
2 files changed, 599 insertions, 301 deletions
diff --git a/ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.js b/ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.js index 58cb9c6c3..90bbc887c 100644 --- a/ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.js +++ b/ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.js @@ -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> + ); + } } diff --git a/ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.test.js b/ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.test.js index d1d4aa662..a4c1335d8 100644 --- a/ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.test.js +++ b/ui-react/src/components/dialogs/ManageDictionaries/ManageDictionaries.test.js @@ -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')(); |