diff --git a/.babelrc b/.babelrc index c4aaa13..a9dd0f7 100644 --- a/.babelrc +++ b/.babelrc @@ -1,9 +1,4 @@ { - "presets": [ - "@babel/preset-env", - "@babel/preset-react" - ], - "plugins": [ - "@babel/plugin-proposal-class-properties" - ] -} \ No newline at end of file + "presets": [["@babel/preset-env"], "@babel/preset-react"], + "plugins": ["@babel/plugin-proposal-class-properties"] +} diff --git a/package.json b/package.json index d6c387f..e99800d 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,8 @@ "ansi-to-html": "^0.6.14", "babel-eslint": "^10.1.0", "babel-loader": "^8.1.0", + "babel-polyfill": "^6.26.0", + "chart.js": "^2.9.3", "clean-webpack-plugin": "^3.0.0", "css-loader": "^4.0.0", "eslint": "^7.4.0", @@ -73,6 +75,7 @@ "jest": "^26.1.0", "prettier": "^2.0.5", "react": "^16.13.1", + "react-chartjs-2": "^2.10.0", "react-dev-utils": "^10.2.1", "react-dom": "^16.13.1", "semantic-release": "^17.1.1", diff --git a/src/App.js b/src/App.js index 9d49747..002a66b 100644 --- a/src/App.js +++ b/src/App.js @@ -29,9 +29,16 @@ class App extends Component { title: 'All', numPassedTests: testResultData.numPassedTests, numFailedTests: testResultData.numFailedTests, - numTotalTests: testResultData.numTotalTests, numPendingTests: testResultData.numPendingTests, numTodoTests: testResultData.numTodoTests, + numFailedTestSuites: testResultData.numFailedTestSuites, + numPassedTestSuites: testResultData.numPassedTestSuites, + numPendingTestSuites: testResultData.numPendingTestSuites, + numRuntimeErrorTestSuites: testResultData.numRuntimeErrorTestSuites, + numMatchedSnapshot: testResultData.snapshot?.matched, + numAddedSnapshot: testResultData.snapshot?.added, + numUnmatchedSnapshot: testResultData.snapshot?.unmatched, + numUpdatedSnapshot: testResultData.snapshot?.updated, id: `id${1}`, }; id++; @@ -63,6 +70,16 @@ class App extends Component { nodeValue.numPendingTests = element.numPendingTests; nodeValue.numTodoTests = element.numTodoTests; nodeValue.failureMessages = element.failureMessage; + nodeValue.numFailedTestSuites = element.numFailedTestSuites; + nodeValue.numFailnumPassedTestSuitesedTests = + element.numPassedTestSuites; + nodeValue.numPendingTestSuites = element.numPendingTestSuites; + nodeValue.numRuntimeErrorTestSuites = + element.numRuntimeErrorTestSuites; + nodeValue.numMatchedSnapshot = element.snapshot?.matched; + nodeValue.numAddedSnapshot = element.snapshot?.added; + nodeValue.numUnmatchedSnapshot = element.snapshot?.unmatched; + nodeValue.numUpdatedSnapshot = element.snapshot?.updated; nodeValue.id = `id${id}`; id++; if (element.testResults) { @@ -105,6 +122,10 @@ class App extends Component { nodeValue.numPendingTests = testCase.status === 'pending' ? 1 : 0; nodeValue.numTodoTests = testCase.status === 'todo' ? 1 : 0; + nodeValue.numFailedTestSuites = 0; + nodeValue.numFailnumPassedTestSuitesedTests = 0; + nodeValue.numPendingTestSuites = 0; + nodeValue.numRuntimeErrorTestSuites = 0; nodeValue.id = `id${id}`; id++; ancestorCopy.shift(); @@ -219,6 +240,7 @@ class App extends Component { this.state.testResults?.reporterOptions?.expandResults } information={this.state.information} + menuState={this.state.menuState} /> ); diff --git a/src/Components/Grid/GridHeader.css b/src/Components/Grid/GridHeader.css index 6461a2c..6c011ba 100644 --- a/src/Components/Grid/GridHeader.css +++ b/src/Components/Grid/GridHeader.css @@ -1,28 +1,28 @@ .column { - box-sizing: border-box; + box-sizing: border-box; float: left; padding: 10px; - height: 40px; - } + height: 50px; +} - .testcase{ +.testcase { width: 40%; } -.result{ - width: 20%; +.result { + width: 20%; } -.time{ - width: 20%; +.time { + width: 15%; } -.information{ - width: 20%; +.information { + width: 25%; } - .tableheader{ - border-top-right-radius:8px; +.tableheader { + border-top-right-radius: 8px; text-align: left; background: #333334; color: #fff; @@ -30,15 +30,14 @@ border-collapse: collapse; border-spacing: 0; overflow-wrap: break-word; - /* padding: 1rem; */ } - - /* Clear floats after the columns */ - .row:after { - content: ""; + +/* Clear floats after the columns */ +.row:after { + content: ''; display: table; clear: both; - } - .row{ - box-sizing: border-box; - } \ No newline at end of file +} +.row { + box-sizing: border-box; +} diff --git a/src/Components/Main/Main.css b/src/Components/Main/Main.css index 122ef71..2bc6954 100644 --- a/src/Components/Main/Main.css +++ b/src/Components/Main/Main.css @@ -1,10 +1,35 @@ - .main { padding: 11vh 1vw 1vh 1vw; - } + position: absolute; + align-content: space-around; + transition: margin-left 0.5s; +} - @media screen and (max-width: 700px) { +@media screen and (max-width: 700px) { div.main { padding: 14vh 1vw 1vh 1vw; } - } +} + +.menuopen { + left: 32%; + width: 66%; + padding: 20px; + top: 50px; +} + +.menuclose { + left: 0px; +} + +@media screen and (min-width: 1024px) { + .menuclose { + width: 100%; + } +} + +@media screen and (min-width: 1280px) { + .menuclose { + width: 98%; + } +} diff --git a/src/Components/Main/Main.js b/src/Components/Main/Main.js index 9edfb54..b668cf9 100644 --- a/src/Components/Main/Main.js +++ b/src/Components/Main/Main.js @@ -10,16 +10,7 @@ import Information from '../Information/Information'; class Main extends Component { constructor(props) { super(props); - this.state = { - resultSummary: { - numFailedTests: this.props.testResults.numFailedTests ?? 0, - numPassedTests: this.props.testResults.numPassedTests ?? 0, - numTotalTests: this.props.testResults.numTotalTests ?? 0, - numPendingTests: this.props.testResults.numPendingTests ?? 0, - numTodoTests: this.props.testResults.numTodoTests ?? 0, - }, - showModel: false, - }; + this.state = { showModel: false }; this.onShowModel = this.onShowModel.bind(this); this.onModelClose = this.onModelClose.bind(this); } @@ -35,21 +26,42 @@ class Main extends Component { prevProps.testResults.numPendingTests !== this.props.testResults.numPendingTests || prevProps.testResults.numTodoTests !== - this.props.testResults.numTodoTests + this.props.testResults.numTodoTests || + prevProps.testResults.numFailedTestSuites !== + this.props.testResults.numFailedTestSuites || + prevProps.testResults.numPendingTestSuites !== + this.props.testResults.numPendingTestSuites || + prevProps.testResults.numPassedTestSuites !== + this.props.testResults.numPassedTestSuites || + prevProps.testResults.numRuntimeErrorTestSuites !== + this.props.testResults.numRuntimeErrorTestSuites ) { - this.setState({ - resultSummary: { - numFailedTests: this.props.testResults.numFailedTests ?? 0, - numPassedTests: this.props.testResults.numPassedTests ?? 0, - numTotalTests: this.props.testResults.numTotalTests ?? 0, - numPendingTests: - this.props.testResults.numPendingTests ?? 0, - numTodoTests: this.props.testResults.numTodoTests ?? 0, - }, - }); + return; } } + getSummary() { + return { + numFailedTests: this.props.testResults.numFailedTests ?? 0, + numPassedTests: this.props.testResults.numPassedTests ?? 0, + numPendingTests: this.props.testResults.numPendingTests ?? 0, + numTodoTests: this.props.testResults.numTodoTests ?? 0, + numFailedTestSuites: + this.props.testResults.numFailedTestSuites ?? 0, + numPassedTestSuites: + this.props.testResults.numPassedTestSuites ?? 0, + numPendingTestSuites: + this.props.testResults.numPendingTestSuites ?? 0, + numRuntimeErrorTestSuites: + this.props.testResults.numRuntimeErrorTestSuites ?? 0, + numAddedSnapshot: this.props.testResults.numAddedSnapshot ?? 0, + numMatchedSnapshot: this.props.testResults.numMatchedSnapshot ?? 0, + numUnmatchedSnapshot: + this.props.testResults.numUnmatchedSnapshot ?? 0, + numUpdatedSnapshot: this.props.testResults.numUpdatedSnapshot ?? 0, + }; + } + onModelClose() { this.setState({ showModel: false }); } @@ -60,8 +72,12 @@ class Main extends Component { } render() { return ( -
- +
+ .cards { + grid-template-columns: repeat(2, 1fr); + } +} + +/* Screen larger than 1360px? 3 columns */ +@media (min-width: 1360px) { + .menuclose > .cards { + grid-template-columns: repeat(3, 1fr); + } + .menuopen > .cards { + grid-template-columns: repeat(2, 1fr); + } +} + +.green { + background-color: green; +} + +.orange { + background-color: orange; +} +.red { + background-color: red; +} +.blue { + background-color: blue; +} +.gray { + background-color: gray; +} diff --git a/src/Components/Summary/Summary.js b/src/Components/Summary/Summary.js index 26ec985..5e82109 100644 --- a/src/Components/Summary/Summary.js +++ b/src/Components/Summary/Summary.js @@ -5,33 +5,88 @@ import './Summary.css'; import SummaryElement from './SummaryElement'; export default class Summary extends Component { + constructor(props) { + super(props); + this.state = { + testSummaryData: { + labels: ['Passed', 'Pending', 'Failed', 'Todo'], + datasets: [ + { + data: [ + this.props.resultSummary.numPassedTests, + this.props.resultSummary.numPendingTests, + this.props.resultSummary.numFailedTests, + this.props.resultSummary.numTodoTests, + ], + backgroundColor: ['green', 'orange', 'red', 'gray'], + hoverBackgroundColor: [ + 'green', + 'orange', + 'red', + 'gray', + ], + }, + ], + }, + testSuiteSummaryData: { + labels: ['Passed', 'Pending', 'Failed', 'Runtime Error'], + datasets: [ + { + data: [ + this.props.resultSummary.numPassedTestSuites, + this.props.resultSummary.numPendingTestSuites, + this.props.resultSummary.numFailedTestSuites, + this.props.resultSummary.numRuntimeErrorTestSuites, + ], + backgroundColor: ['green', 'orange', 'red', 'gray'], + hoverBackgroundColor: [ + 'green', + 'orange', + 'red', + 'gray', + ], + }, + ], + }, + snapshotSummaryData: { + labels: ['Matched', 'Updated', 'Unmatched', 'Added'], + datasets: [ + { + data: [ + this.props.resultSummary.numMatchedSnapshot, + this.props.resultSummary.numUpdatedSnapshot, + this.props.resultSummary.numUnmatchedSnapshot, + this.props.resultSummary.numAddedSnapshot, + ], + backgroundColor: ['green', 'orange', 'red', 'gray'], + hoverBackgroundColor: [ + 'green', + 'orange', + 'red', + 'gray', + ], + }, + ], + }, + }; + } render() { return ( -
- - +
); @@ -39,4 +94,5 @@ export default class Summary extends Component { } Summary.propTypes = { resultSummary: PropTypes.any.isRequired, + id: PropTypes.any.isRequired, }; diff --git a/src/Components/Summary/SummaryElement.css b/src/Components/Summary/SummaryElement.css index cfd3d90..2bfcc6e 100644 --- a/src/Components/Summary/SummaryElement.css +++ b/src/Components/Summary/SummaryElement.css @@ -1,51 +1,5 @@ -.dot a { - text-decoration: none; - font-size: calc(10vmin); - color: white; - display: block; - position: absolute; - transform: translate(-50%, -50%); - top: 50%; - left: 50%; - } - - .dot span{ - text-decoration: none; - font-size: calc(3vmin); - color: white; - display: block; - position: absolute; - transform: translate(-50%, -50%); - top: 80%; - left: 50%; - } - - .dot a:hover { - color: #f1f1f1; - } - .dot { - height: 100px; - width: 100px; - border-radius: 50%; - display: inline-block; - padding: 25px 25px 25px 25px; - margin: 15px 15px 15px 15px; +.card { + padding: 1rem; position: relative; - } - - .green{ - background-color: green; - } - - .orange{ - background-color: orange; - } - .red{ - background-color: red; - } - .blue{ - background-color: blue; - } - .gray{ - background-color:gray; - } \ No newline at end of file + max-width: 350px; +} diff --git a/src/Components/Summary/SummaryElement.js b/src/Components/Summary/SummaryElement.js index a78bd6b..502e820 100644 --- a/src/Components/Summary/SummaryElement.js +++ b/src/Components/Summary/SummaryElement.js @@ -2,19 +2,66 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import './SummaryElement.css'; +import { Pie, Chart } from 'react-chartjs-2'; export default class SummaryElement extends Component { + constructor(props) { + super(props); + this.state = { + data: this.props.data, + }; + } + + // eslint-disable-next-line no-unused-vars + static getDerivedStateFromProps(props, state) { + Chart.pluginService.register({ + afterRender: function (chart) { + let noData = true; + chart.data.datasets[0].data.forEach(element => { + if (element > 0) { + noData = false; + } + }); + if (noData) { + const ctx = chart.chart.ctx; + const width = chart.chart.width; + const height = chart.chart.height; + chart.clear(); + + ctx.save(); + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + ctx.font = "16px normal 'Helvetica Nueue'"; + ctx.fillText('No data to display', width / 2, height / 2); + ctx.restore(); + } + }, + }); + + return null; + } + render() { return ( - - {this.props.data} - {this.props.Category} - +
+ +
); } } SummaryElement.propTypes = { - Category: PropTypes.string.isRequired, - styleClass: PropTypes.string.isRequired, - data: PropTypes.number.isRequired, + data: PropTypes.object.isRequired, + title: PropTypes.string, }; diff --git a/src/Components/Summary/SummaryElement.test.js b/src/Components/Summary/SummaryElement.test.js new file mode 100644 index 0000000..b55a224 --- /dev/null +++ b/src/Components/Summary/SummaryElement.test.js @@ -0,0 +1,40 @@ +import React from 'react'; +import SummaryElement from './SummaryElement'; +import { render, waitFor } from '@testing-library/react'; +test('should contain chart', async () => { + const data = { + labels: ['Passed', 'Pending', 'Failed', 'Todo'], + datasets: [ + { + data: [1, 2, 3, 4], + backgroundColor: ['green', 'orange', 'red', 'gray'], + hoverBackgroundColor: ['green', 'orange', 'red', 'gray'], + }, + ], + }; + const { container } = render( + , + ); + const canvas = await waitFor(() => container.firstChild.firstChild); + const img = canvas.toDataURL(); + const imageData = img.replace(/^data:image\/\w+;base64,/, ''); + const buf = Buffer.from(imageData, 'base64'); + expect(buf).toMatchSnapshot(); +}); + +test('should contain no data found', () => { + const data = { + labels: ['Passed', 'Pending', 'Failed', 'Todo'], + datasets: [ + { + data: [0, 0, 0, 0], + backgroundColor: ['green', 'orange', 'red', 'gray'], + hoverBackgroundColor: ['green', 'orange', 'red', 'gray'], + }, + ], + }; + const { container } = render( + , + ); + expect(container.firstChild).toMatchSnapshot(); +}); diff --git a/src/Components/Summary/__snapshots__/SummaryElement.test.js.snap b/src/Components/Summary/__snapshots__/SummaryElement.test.js.snap new file mode 100644 index 0000000..7abcb28 --- /dev/null +++ b/src/Components/Summary/__snapshots__/SummaryElement.test.js.snap @@ -0,0 +1,23 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should contain chart 1`] = ` +
+ +
+`; + +exports[`should contain no data found 1`] = ` +
+ +
+`; diff --git a/src/__snapshots__/App.test.js.snap b/src/__snapshots__/App.test.js.snap index 21d77e6..0cc91ec 100644 --- a/src/__snapshots__/App.test.js.snap +++ b/src/__snapshots__/App.test.js.snap @@ -2,71 +2,35 @@ exports[`Tree click Should call function on tree node click 1`] = `
- - - 7 - - - Passed - - - - - 0 - - - Pending - - - - - 2 - - - Failed - - - +
+
- - 9 - - - Total - - - +
+
- - 0 - - - Todo - - + +