From 4896b09c995943553c324ed4e66531e2ace96eff Mon Sep 17 00:00:00 2001 From: K-itKat20 Date: Mon, 21 Sep 2020 12:05:56 +0100 Subject: [PATCH 01/12] Delete Graph button --- ui/src/components/ViewGraph/ViewGraph.tsx | 48 ++++++++++----- .../components/view-graph/ViewGraph.test.tsx | 58 ++++++++++++------- 2 files changed, 70 insertions(+), 36 deletions(-) diff --git a/ui/src/components/ViewGraph/ViewGraph.tsx b/ui/src/components/ViewGraph/ViewGraph.tsx index e30b1d5..9911d14 100644 --- a/ui/src/components/ViewGraph/ViewGraph.tsx +++ b/ui/src/components/ViewGraph/ViewGraph.tsx @@ -1,16 +1,31 @@ import React from 'react'; import { makeStyles } from '@material-ui/core/styles'; -import { Button, Container, Grid, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Tooltip, IconButton, Toolbar, Zoom } from '@material-ui/core' +import { + Button, + Container, + Grid, + Table, + TableBody, + TableCell, + TableContainer, + TableHead, + TableRow, + Tooltip, + IconButton, + Toolbar, + Zoom, +} from '@material-ui/core'; import { Graph } from '../../domain/graph'; import { GetAllGraphsRepo } from '../../rest/repositories/get-all-graphs-repo'; import DeleteOutlineOutlinedIcon from '@material-ui/icons/DeleteOutlineOutlined'; import RefreshOutlinedIcon from '@material-ui/icons/RefreshOutlined'; import { NotificationAlert, AlertType } from '../Errors/NotificationAlert'; +import { DeleteGraphRepo } from '../../rest/repositories/delete-graph-repo'; interface IState { - graphs: Graph[], - selectedRow: any, - errorMessage: string, + graphs: Graph[]; + selectedRow: any; + errorMessage: string; } export default class ViewGraph extends React.Component<{}, IState> { @@ -20,7 +35,7 @@ export default class ViewGraph extends React.Component<{}, IState> { graphs: [], selectedRow: '', errorMessage: '', - } + }; } public async componentDidMount() { @@ -30,7 +45,7 @@ export default class ViewGraph extends React.Component<{}, IState> { private async getGraphs() { try { const graphs: Graph[] = await new GetAllGraphsRepo().getAll(); - this.setState({ graphs }) + this.setState({ graphs }); } catch (e) { this.setState({ errorMessage: `Failed to get all graphs: ${e.message}` }); } @@ -39,7 +54,7 @@ export default class ViewGraph extends React.Component<{}, IState> { private classes: any = makeStyles({ root: { width: '100%', - marginTop: 40 + marginTop: 40, }, table: { minWidth: 650, @@ -47,7 +62,6 @@ export default class ViewGraph extends React.Component<{}, IState> { }); public render() { - const { graphs, errorMessage } = this.state; return ( @@ -57,8 +71,7 @@ export default class ViewGraph extends React.Component<{}, IState> { {errorMessage && } - - +
Graph Name @@ -70,11 +83,18 @@ export default class ViewGraph extends React.Component<{}, IState> { {graphs.map((graph: Graph, index) => ( - {graph.getId()} + + {graph.getId()} + {graph.getStatus()} - + { + await new DeleteGraphRepo().delete(graph.getId()); + }} + > @@ -87,7 +107,7 @@ export default class ViewGraph extends React.Component<{}, IState> { + diff --git a/ui/test/components/view-graph/ViewGraph.test.tsx b/ui/test/components/view-graph/ViewGraph.test.tsx index d9a1458..19a7169 100644 --- a/ui/test/components/view-graph/ViewGraph.test.tsx +++ b/ui/test/components/view-graph/ViewGraph.test.tsx @@ -3,28 +3,30 @@ import { mount } from 'enzyme'; import ViewGraph from '../../../src/components/ViewGraph/ViewGraph'; import { GetAllGraphsRepo } from '../../../src/rest/repositories/get-all-graphs-repo'; import { Graph } from '../../../src/domain/graph'; +import {DeleteGraphRepo} from '../../../src/rest/repositories/delete-graph-repo' jest.mock('../../../src/rest/repositories/get-all-graphs-repo'); +jest.mock('../../../src/rest/repositories/delete-graph-repo') describe('When ExampleTable mounts', () => { it('should display Table Headers and Graphs when GetGraphs successful', async () => { mockGetGraphsToReturn([new Graph('testId1', 'deployed')]); - const wrapper = mount(); - await wrapper.update(); - await wrapper.update(); + const component = mount(); + await component.update(); + await component.update(); - expect(wrapper.find('thead').text()).toBe('Graph NameCurrent StateActions'); - expect(wrapper.find('tbody').text()).toBe('testId1deployed'); - expect(wrapper.find('caption').length).toBe(0); + expect(component.find('thead').text()).toBe('Graph NameCurrent StateActions'); + expect(component.find('tbody').text()).toBe('testId1deployed'); + expect(component.find('caption').length).toBe(0); }); it('should display No Graphs caption when ', async () => { mockGetGraphsToReturn([]); - const wrapper = mount(); - await wrapper.update(); + const component = mount(); + await component.update(); - expect(wrapper.find('caption').text()).toBe('No Graphs.'); + expect(component.find('caption').text()).toBe('No Graphs.'); }); it('should display Error Message in AlertNotification when GetGraphs request fails', () => { GetAllGraphsRepo.mockImplementationOnce(() => { @@ -33,36 +35,48 @@ describe('When ExampleTable mounts', () => { }; }); - const wrapper = mount(); + const component = mount(); - expect(wrapper.find('#notification-alert').text()).toBe('Failed to get all graphs: 404 Not Found'); + expect(component.find('#notification-alert').text()).toBe('Failed to get all graphs: 404 Not Found'); }); it('should not display Error AlertNotification when GetGraphs request successful', async () => { mockGetGraphsToReturn([new Graph('roadTraffic', 'DEPLOYED')]); - const wrapper = mount(); - await wrapper.update(); + const component = mount(); + await component.update(); - const table = wrapper.find('table'); + const table = component.find('table'); expect(table).toHaveLength(1); expect(table.find('tbody').text()).toBe('roadTrafficDEPLOYED'); - expect(wrapper.find('#notification-alert').length).toBe(0); + expect(component.find('#notification-alert').length).toBe(0); }); it('should call GetGraphs again when refresh button clicked', async () => { mockGetGraphsToReturn([new Graph('roadTraffic', 'DEPLOYING')]); - const wrapper = mount(); - await wrapper.update(); - expect(wrapper.find('tbody').text()).toBe('roadTrafficDEPLOYING'); + const component = mount(); + await component.update(); + expect(component.find('tbody').text()).toBe('roadTrafficDEPLOYING'); mockGetGraphsToReturn([new Graph('roadTraffic', 'FINISHED DEPLOYMENT')]); - wrapper.find('button#view-graphs-refresh-button').simulate('click'); - await wrapper.update(); + component.find('button#view-graphs-refresh-button').simulate('click'); + await component.update(); - expect(wrapper.find('tbody').text()).toBe('roadTrafficFINISHED DEPLOYMENT'); + expect(component.find('tbody').text()).toBe('roadTrafficFINISHED DEPLOYMENT'); }); -}); + it('should send a delete request when the delete button has been clicked', async() => { + mockGetGraphsToReturn([new Graph('peaches', 'ACTIVE')]); + const component = mount(); + await component.update(); + await component.update(); + expect(component.find('tbody').text()).toBe('peachesACTIVE'); + + component.find('tbody').find('button#view-graphs-delete-button-0').simulate('click'); + await component.update(); + + expect(DeleteGraphRepo).toHaveBeenCalledTimes(1); + }) +}); function mockGetGraphsToReturn(graphs: Graph[]):void { GetAllGraphsRepo.mockImplementationOnce(() => { return { From b686c4cabef7caf9de7d4207297451de7fe0406c Mon Sep 17 00:00:00 2001 From: macenturalxl1 Date: Mon, 21 Sep 2020 12:26:17 +0100 Subject: [PATCH 02/12] Many graphs test --- .../components/view-graph/ViewGraph.test.tsx | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/ui/test/components/view-graph/ViewGraph.test.tsx b/ui/test/components/view-graph/ViewGraph.test.tsx index 19a7169..24ccef8 100644 --- a/ui/test/components/view-graph/ViewGraph.test.tsx +++ b/ui/test/components/view-graph/ViewGraph.test.tsx @@ -3,10 +3,10 @@ import { mount } from 'enzyme'; import ViewGraph from '../../../src/components/ViewGraph/ViewGraph'; import { GetAllGraphsRepo } from '../../../src/rest/repositories/get-all-graphs-repo'; import { Graph } from '../../../src/domain/graph'; -import {DeleteGraphRepo} from '../../../src/rest/repositories/delete-graph-repo' +import { DeleteGraphRepo } from '../../../src/rest/repositories/delete-graph-repo' jest.mock('../../../src/rest/repositories/get-all-graphs-repo'); -jest.mock('../../../src/rest/repositories/delete-graph-repo') +// jest.mock('../../../src/rest/repositories/delete-graph-repo'); describe('When ExampleTable mounts', () => { it('should display Table Headers and Graphs when GetGraphs successful', async () => { @@ -60,29 +60,45 @@ describe('When ExampleTable mounts', () => { mockGetGraphsToReturn([new Graph('roadTraffic', 'FINISHED DEPLOYMENT')]); component.find('button#view-graphs-refresh-button').simulate('click'); await component.update(); - + expect(component.find('tbody').text()).toBe('roadTrafficFINISHED DEPLOYMENT'); }); - it('should send a delete request when the delete button has been clicked', async() => { + it('should send a delete request when the delete button has been clicked', async () => { + DeleteGraphRepo.prototype.delete = jest.fn(); mockGetGraphsToReturn([new Graph('peaches', 'ACTIVE')]); const component = mount(); await component.update(); await component.update(); expect(component.find('tbody').text()).toBe('peachesACTIVE'); - + component.find('tbody').find('button#view-graphs-delete-button-0').simulate('click'); await component.update(); - - expect(DeleteGraphRepo).toHaveBeenCalledTimes(1); - }) + + expect(DeleteGraphRepo.prototype.delete).toHaveBeenLastCalledWith('peaches'); + }); + it('should send a delete request for correct graphId from many graphs when the delete button has been clicked', async () => { + DeleteGraphRepo.prototype.delete = jest.fn(); + mockGetGraphsToReturn([new Graph('apples', 'ACTIVE'), new Graph('pears', 'INACTIVE')]); + + const component = mount(); + await component.update(); + await component.update(); + expect(component.find('tbody').text()).toBe('applesACTIVEpearsINACTIVE'); + + component.find('tbody').find('button#view-graphs-delete-button-1').simulate('click'); + await component.update(); + + expect(DeleteGraphRepo.prototype.delete).toHaveBeenLastCalledWith('pears'); + }); }); -function mockGetGraphsToReturn(graphs: Graph[]):void { + +function mockGetGraphsToReturn(graphs: Graph[]): void { GetAllGraphsRepo.mockImplementationOnce(() => { return { getAll: () => { return new Promise((resolve, reject) => { - resolve(graphs) + resolve(graphs); }) }, }; From 19320c67ef1730b684c6d1f4dee350ffccd27feb Mon Sep 17 00:00:00 2001 From: macenturalxl1 Date: Mon, 21 Sep 2020 12:41:15 +0100 Subject: [PATCH 03/12] Delete graph button handles error --- ui/src/components/ViewGraph/ViewGraph.tsx | 12 +++++++--- .../components/view-graph/ViewGraph.test.tsx | 24 ++++++++++++++++++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/ui/src/components/ViewGraph/ViewGraph.tsx b/ui/src/components/ViewGraph/ViewGraph.tsx index 9911d14..076e661 100644 --- a/ui/src/components/ViewGraph/ViewGraph.tsx +++ b/ui/src/components/ViewGraph/ViewGraph.tsx @@ -51,6 +51,14 @@ export default class ViewGraph extends React.Component<{}, IState> { } } + private async deleteGraph(graphName: string) { + try { + await new DeleteGraphRepo().delete(graphName); + } catch (e) { + this.setState({ errorMessage: `Failed to get all graphs: ${e.message}` }); + } + } + private classes: any = makeStyles({ root: { width: '100%', @@ -91,9 +99,7 @@ export default class ViewGraph extends React.Component<{}, IState> { { - await new DeleteGraphRepo().delete(graph.getId()); - }} + onClick={async () => await this.deleteGraph(graph.getId())} > diff --git a/ui/test/components/view-graph/ViewGraph.test.tsx b/ui/test/components/view-graph/ViewGraph.test.tsx index 24ccef8..90b9604 100644 --- a/ui/test/components/view-graph/ViewGraph.test.tsx +++ b/ui/test/components/view-graph/ViewGraph.test.tsx @@ -6,7 +6,7 @@ import { Graph } from '../../../src/domain/graph'; import { DeleteGraphRepo } from '../../../src/rest/repositories/delete-graph-repo' jest.mock('../../../src/rest/repositories/get-all-graphs-repo'); -// jest.mock('../../../src/rest/repositories/delete-graph-repo'); +jest.mock('../../../src/rest/repositories/delete-graph-repo'); describe('When ExampleTable mounts', () => { it('should display Table Headers and Graphs when GetGraphs successful', async () => { @@ -91,8 +91,30 @@ describe('When ExampleTable mounts', () => { expect(DeleteGraphRepo.prototype.delete).toHaveBeenLastCalledWith('pears'); }); + it('should ... when delete request returns server error', async () => { + mockDeleteGraphRepoToThrowError('500 Server Error'); + mockGetGraphsToReturn([new Graph('bananas', 'INACTIVE')]); + + const component = mount(); + await component.update(); + await component.update(); + expect(component.find('tbody').text()).toBe('bananasINACTIVE'); + + component.find('tbody').find('button#view-graphs-delete-button-0').simulate('click'); + await component.update(); + + expect(component.find('#notification-alert').text()).toBe('Failed to get all graphs: 500 Server Error'); + }); }); +function mockDeleteGraphRepoToThrowError(errorMessage: string) { + DeleteGraphRepo.mockImplementationOnce(() => { + return { + delete: () => { throw new Error(errorMessage); }, + }; + }); +} + function mockGetGraphsToReturn(graphs: Graph[]): void { GetAllGraphsRepo.mockImplementationOnce(() => { return { From 2526411736a67a02dbb20a45ad72e808989bda3b Mon Sep 17 00:00:00 2001 From: K-itKat20 Date: Mon, 21 Sep 2020 16:08:26 +0100 Subject: [PATCH 04/12] Delete button update status --- ui/src/components/ViewGraph/ViewGraph.tsx | 14 +++++++++++++- .../components/view-graph/ViewGraph.test.tsx | 19 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/ui/src/components/ViewGraph/ViewGraph.tsx b/ui/src/components/ViewGraph/ViewGraph.tsx index 076e661..337d8ad 100644 --- a/ui/src/components/ViewGraph/ViewGraph.tsx +++ b/ui/src/components/ViewGraph/ViewGraph.tsx @@ -58,6 +58,14 @@ export default class ViewGraph extends React.Component<{}, IState> { this.setState({ errorMessage: `Failed to get all graphs: ${e.message}` }); } } + private async updateGraph(index: number,graphName: string) { + const oldGraphs = this.state.graphs; + const newGraph =[new Graph(graphName, "DELETION IN PROGRESS")]; + const updatedGraphs =oldGraphs.map(obj => newGraph.find(o => o.getId() === obj.getId()) || obj); + this.setState({graphs: updatedGraphs}) + + + } private classes: any = makeStyles({ root: { @@ -99,7 +107,11 @@ export default class ViewGraph extends React.Component<{}, IState> { await this.deleteGraph(graph.getId())} + onClick={ + async () => {await this.deleteGraph(graph.getId()); + this.updateGraph(index,graph.getId()) + } + } > diff --git a/ui/test/components/view-graph/ViewGraph.test.tsx b/ui/test/components/view-graph/ViewGraph.test.tsx index 90b9604..9ae42b5 100644 --- a/ui/test/components/view-graph/ViewGraph.test.tsx +++ b/ui/test/components/view-graph/ViewGraph.test.tsx @@ -105,6 +105,25 @@ describe('When ExampleTable mounts', () => { expect(component.find('#notification-alert').text()).toBe('Failed to get all graphs: 500 Server Error'); }); + it('should change the current status of the graph when the delete button is clicked', async() => { + //given that I have a table + //when I click teh delete button + //then the current status of teh graph should be updated + DeleteGraphRepo.prototype.delete = jest.fn(); + mockGetGraphsToReturn([new Graph('apples', 'ACTIVE'), new Graph('pears', 'INACTIVE')]); + + const component = mount(); + await component.update(); + await component.update(); + expect(component.find('tbody').text()).toBe('applesACTIVEpearsINACTIVE'); + + component.find('tbody').find('button#view-graphs-delete-button-1').simulate('click'); + await component.update(); + await component.update(); + + expect(component.find('tbody').text()).toBe('applesACTIVEpearsDELETION IN PROGRESS') + + }) }); function mockDeleteGraphRepoToThrowError(errorMessage: string) { From 54279b17b9fadc1fe5c8f8c0afa08d9e209aa79e Mon Sep 17 00:00:00 2001 From: K-itKat20 Date: Mon, 21 Sep 2020 16:18:01 +0100 Subject: [PATCH 05/12] Code cleanup --- ui/src/components/ViewGraph/ViewGraph.tsx | 52 +++++++++---------- .../components/view-graph/ViewGraph.test.tsx | 40 +++++++------- 2 files changed, 46 insertions(+), 46 deletions(-) diff --git a/ui/src/components/ViewGraph/ViewGraph.tsx b/ui/src/components/ViewGraph/ViewGraph.tsx index 337d8ad..dd29c58 100644 --- a/ui/src/components/ViewGraph/ViewGraph.tsx +++ b/ui/src/components/ViewGraph/ViewGraph.tsx @@ -1,26 +1,26 @@ import React from 'react'; -import { makeStyles } from '@material-ui/core/styles'; +import {makeStyles} from '@material-ui/core/styles'; import { Button, Container, Grid, + IconButton, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, - Tooltip, - IconButton, Toolbar, + Tooltip, Zoom, } from '@material-ui/core'; -import { Graph } from '../../domain/graph'; -import { GetAllGraphsRepo } from '../../rest/repositories/get-all-graphs-repo'; +import {Graph} from '../../domain/graph'; +import {GetAllGraphsRepo} from '../../rest/repositories/get-all-graphs-repo'; import DeleteOutlineOutlinedIcon from '@material-ui/icons/DeleteOutlineOutlined'; import RefreshOutlinedIcon from '@material-ui/icons/RefreshOutlined'; -import { NotificationAlert, AlertType } from '../Errors/NotificationAlert'; -import { DeleteGraphRepo } from '../../rest/repositories/delete-graph-repo'; +import {AlertType, NotificationAlert} from '../Errors/NotificationAlert'; +import {DeleteGraphRepo} from '../../rest/repositories/delete-graph-repo'; interface IState { graphs: Graph[]; @@ -45,9 +45,9 @@ export default class ViewGraph extends React.Component<{}, IState> { private async getGraphs() { try { const graphs: Graph[] = await new GetAllGraphsRepo().getAll(); - this.setState({ graphs }); + this.setState({graphs}); } catch (e) { - this.setState({ errorMessage: `Failed to get all graphs: ${e.message}` }); + this.setState({errorMessage: `Failed to get all graphs: ${e.message}`}); } } @@ -55,16 +55,15 @@ export default class ViewGraph extends React.Component<{}, IState> { try { await new DeleteGraphRepo().delete(graphName); } catch (e) { - this.setState({ errorMessage: `Failed to get all graphs: ${e.message}` }); + this.setState({errorMessage: `Failed to get all graphs: ${e.message}`}); } } - private async updateGraph(index: number,graphName: string) { + + private async updateGraph(graphName: string) { const oldGraphs = this.state.graphs; - const newGraph =[new Graph(graphName, "DELETION IN PROGRESS")]; - const updatedGraphs =oldGraphs.map(obj => newGraph.find(o => o.getId() === obj.getId()) || obj); + const newGraph = [new Graph(graphName, "DELETION IN PROGRESS")]; + const updatedGraphs = oldGraphs.map(obj => newGraph.find(o => o.getId() === obj.getId()) || obj); this.setState({graphs: updatedGraphs}) - - } private classes: any = makeStyles({ @@ -78,18 +77,18 @@ export default class ViewGraph extends React.Component<{}, IState> { }); public render() { - const { graphs, errorMessage } = this.state; + const {graphs, errorMessage} = this.state; return ( -
- +
+ - {errorMessage && } + {errorMessage && }
- + Graph Name Current State Actions @@ -108,12 +107,13 @@ export default class ViewGraph extends React.Component<{}, IState> { {await this.deleteGraph(graph.getId()); - this.updateGraph(index,graph.getId()) - } + async () => { + await this.deleteGraph(graph.getId()); + this.updateGraph(graph.getId()) + } } > - + @@ -123,11 +123,11 @@ export default class ViewGraph extends React.Component<{}, IState> { {graphs.length === 0 && }
No Graphs.
- +