Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@
],
"author": "Vinoth",
"license": "ISC",
"repository": {
"type": "git",
"url": "https://github.com/vinothdevelop/HTMLReport4Jest"
},
"repository": {
"type": "git",
"url": "https://github.com/vinothdevelop/HTMLReport4Jest"
},
"bugs": {
"url": "https://github.com/vinothdevelop/HTMLReport4Jest/issues"
},
Expand Down
57 changes: 46 additions & 11 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,27 @@ import Header from './Components/Header/Header';
import Sidebar from './Components/Sidebar/Sidebar';
import Main from './Components/Main/Main';
let data;
const statusList = [];
class App extends Component {
constructor(props) {
data = window.resultData;
super(props);
this.state = {
menuState: 'close',
testResults: data,
treeViewData: this.formatTreeViewData(data),
treeViewData: this.formatTreeViewData(data, []),
information: this.getInformation(data),
};
this.onTreeNodeClick = this.onTreeNodeClick.bind(this);
this.state.gridData = this.state.treeViewData;
this.menuStateChange = this.menuStateChange.bind(this);
this.onStatusChecked = this.onStatusChecked.bind(this);
}
formatTreeViewData(testResults) {
getStatusList() {
return statusList;
}

formatTreeViewData(testResults, statusFilter) {
const testResultData = {};
Object.assign(testResultData, testResults);
let treeViewData = [];
Expand All @@ -40,13 +46,14 @@ class App extends Component {
testResultData.testResults,
[],
id,
statusFilter,
);
}
treeViewData = rootElement;
return treeViewData;
}

parseTreeData(testResults, parentArray, id) {
parseTreeData(testResults, parentArray, id, statusFilter) {
let subArray = [];
testResults.forEach(element => {
if (element.testFilePath || element.fullName) {
Expand All @@ -70,15 +77,30 @@ class App extends Component {
element.testResults,
[],
id,
statusFilter,
);
parentArray.push(nodeValue);
if (
statusFilter.length === 0 ||
nodeValue.children.length > 0
) {
parentArray.push(nodeValue);
}
} else if (element.ancestorTitles) {
[subArray, id] = this.parseAncestor(
element.ancestorTitles,
element,
subArray,
id,
);
if (statusList.indexOf(element.status) < 0) {
statusList.push(element.status);
}
if (
statusFilter.length === 0 ||
statusFilter.indexOf(element.status) >= 0
) {
[subArray, id] = this.parseAncestor(
element.ancestorTitles,
element,
subArray,
id,
statusFilter,
);
}
}
}
});
Expand All @@ -88,7 +110,7 @@ class App extends Component {
return [parentArray, id];
}

parseAncestor(ancestors, testCase, parentArray, id) {
parseAncestor(ancestors, testCase, parentArray, id, statusFilter) {
const ancestorCopy = [...ancestors];
if (ancestors.length > 0) {
const itemTitle = ancestors[0];
Expand All @@ -113,6 +135,7 @@ class App extends Component {
testCase,
[],
id,
statusFilter,
);
parentArray.push(nodeValue);
} else {
Expand All @@ -139,6 +162,7 @@ class App extends Component {
testCase,
parentArray[elementIndex].children,
id,
statusFilter,
);
}
} else {
Expand Down Expand Up @@ -197,6 +221,15 @@ class App extends Component {
return information;
}

onStatusChecked = checkedStatuses => {
this.setState({
gridData: this.formatTreeViewData(
this.state.testResults,
checkedStatuses,
),
});
};

render() {
return (
<div className="App">
Expand All @@ -219,6 +252,8 @@ class App extends Component {
this.state.testResults?.reporterOptions?.expandResults
}
information={this.state.information}
statusList={this.getStatusList()}
onStatusChecked={this.onStatusChecked}
/>
</div>
);
Expand Down
17 changes: 17 additions & 0 deletions src/App.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,20 @@ describe('Tree click', () => {
expect(container.querySelector('.main')).toMatchSnapshot();
});
});

describe('Status filter', () => {
test('Should have checkboxes', () => {
window.resultData = sampleData;
const { container } = render(<App></App>);
expect(container.querySelectorAll('.checkboxLabel').length).toEqual(4);
});
test('Should filter on checkbox click', () => {
window.resultData = sampleData;
const { container } = render(<App></App>);
const statusCheckboxes = container.querySelectorAll('.checkboxLabel');
fireEvent.click(statusCheckboxes[3]);
expect(container.querySelectorAll('.tab-content').length).toEqual(2);
fireEvent.click(statusCheckboxes[3]);
expect(container.querySelectorAll('.tab-content').length).toEqual(40);
});
});
51 changes: 51 additions & 0 deletions src/Components/FilterToggler/CheckBox.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
.checkboxLabel {
text-transform: capitalize;
position: relative;
padding-left: 35px;
margin-bottom: 5px;
cursor: pointer;
display: 'inline';
}

/* Hide the default checkbox */
.checkboxLabel input[type='checkbox'] {
visibility: hidden;
}

/* creating a custom checkbox based
on demand */
.checkboxSpan {
position: absolute;
top: 0;
left: 0;
height: 1em;
width: 1em;
background-color: white;
border: solid black;
border-width: 1px 1px 1px 1px;
}

/* specify the background color to be
shown when checkbox is checked */
.checkboxLabel input:checked ~ .checkboxSpan {
background-color: #333334;
}

/* checkmark to be shown in checkbox */
/* It is not be shown when not checked */
.checkboxSpan:after {
position: absolute;
display: none;
}

/* styling the checkmark using webkit */
/* creating a square to be the sign of
checkmark */
.checkboxLabel .checkboxSpan:after {
left: 6px;
bottom: 5px;
width: 6px;
height: 6px;
border: solid black;
border-width: 4px 4px 4px 4px;
}
25 changes: 25 additions & 0 deletions src/Components/FilterToggler/CheckBox.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import PropTypes from 'prop-types';
import './CheckBox.css';
export const CheckBox = props => {
return (
<label className="checkboxLabel">
{props.value}
<input
key={props.value}
onChange={props.handleCheck}
type="checkbox"
checked={props.isChecked}
value={props.value}
id={props.value}
/>
<span className="checkboxSpan"></span>
</label>
);
};
CheckBox.propTypes = {
handleCheck: PropTypes.func.isRequired,
isChecked: PropTypes.bool,
value: PropTypes.string.isRequired,
};
export default CheckBox;
50 changes: 50 additions & 0 deletions src/Components/FilterToggler/CheckBox.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';
import CheckBox from './CheckBox';
import { render, fireEvent } from '@testing-library/react';
test('Should contain value', () => {
const { container } = render(
<CheckBox
value="Test"
isChecked={false}
handleCheck={function () {}}
></CheckBox>,
);
expect(container).toHaveTextContent('Test');
});

test('Should not be checked', () => {
const { container } = render(
<CheckBox
value="Test"
isChecked={false}
handleCheck={function () {}}
></CheckBox>,
);
expect(container.firstChild.lastChild.previousSibling).not.toBeChecked();
});

test('Should be checked', () => {
const { container } = render(
<CheckBox
value="Test"
isChecked={true}
handleCheck={function () {}}
></CheckBox>,
);
expect(container.firstChild.lastChild.previousSibling).toBeChecked();
});

test('Should call function on change', () => {
const mockCallback = jest.fn();
const { container } = render(
<CheckBox
value="Test"
isChecked={false}
handleCheck={mockCallback}
></CheckBox>,
);
fireEvent.click(container.firstChild);
expect(mockCallback.mock.calls.length).toBe(1);
fireEvent.click(container.firstChild);
expect(mockCallback.mock.calls.length).toBe(2);
});
61 changes: 61 additions & 0 deletions src/Components/FilterToggler/FilterToggler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React from 'react';
import CheckBox from './CheckBox';
import PropTypes from 'prop-types';
export default class FilterToggler extends React.Component {
constructor(props) {
super(props);
this.state = {
statusList: this.init(this.props.statusList),
};
}

init(statusList) {
if (statusList && statusList.length > 0) {
return statusList.map(status => {
return { value: status, isChecked: false };
});
} else {
return [];
}
}

handleChecked = event => {
const checkStatuses = [];
this.state.statusList.forEach(status => {
if (status.value === event.target.value) {
status.isChecked = event.target.checked;
}
if (status.isChecked) {
checkStatuses.push(status.value);
}
});
this.setState(this.state.statusList);
this.props.onStatusChecked(checkStatuses);
};
render() {
if (this.props.statusList && this.props.statusList.length > 0) {
return (
<div>
<p>
Filter:{' '}
{this.state.statusList.map(status => {
return (
<CheckBox
key={status.value}
handleCheck={this.handleChecked}
{...status}
/>
);
})}
</p>
</div>
);
} else {
return null;
}
}
}
FilterToggler.propTypes = {
statusList: PropTypes.array,
onStatusChecked: PropTypes.func.isRequired,
};
Loading