Skip to content
This repository has been archived by the owner on Dec 7, 2019. It is now read-only.

Commit

Permalink
Text search in HTML Report (#70)
Browse files Browse the repository at this point in the history
  • Loading branch information
navstyachka authored and artem-zinnatullin committed Jun 19, 2017
1 parent 9d57f1a commit a7e8cc3
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 31 deletions.
10 changes: 1 addition & 9 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,5 @@ gradle/local.properties

# Html viewer rules
node_modules/
temp/
coverage/
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
composer/src/main/resources/html-report
test/
1 change: 1 addition & 0 deletions html-report/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"classnames": "^2.2.5",
"copy-webpack-plugin": "^4.0.1",
"cssnano": "^3.10.0",
"elasticlunr": "^0.9.5",
"extract-text-webpack-plugin": "^2.1.0",
"postcss": "^5.0.19",
"postcss-cli": "^4.0.0",
Expand Down
118 changes: 110 additions & 8 deletions html-report/src/components/SearchBar.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,123 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import elasticlunr from 'elasticlunr';

const SEARCH_FIELDS = ['package_name', 'class_name', 'name', 'id', 'status'];
const SEARCH_REF = 'id';
const EL_SEARCH = elasticlunr();
export default class SearchBar extends Component {
static propTypes = {
data: PropTypes.array,
setSearchResults: PropTypes.func,
filterByStatus: PropTypes.string
};

state = {
error: false,
searchLabel: null,
searchParams: null,
query: '',
status: null
};

componentWillMount() {
let { data } = this.props;
elasticlunr.clearStopWords();
SEARCH_FIELDS.forEach(f => EL_SEARCH.addField(f))
EL_SEARCH.setRef(SEARCH_REF);
if (data.length) {
data.forEach(item => EL_SEARCH.addDoc(item))
}
}

componentWillReceiveProps(nextProps) {
let status = nextProps.filterByStatus;
if (status !== this.state.status) {
this.setTagSearch('status');
this.performSearch(status);
this.setState({ status: status, query: status });
}
}

mapResults(results) {
return results.map(item => {
return EL_SEARCH.documentStore.docs[item.ref];
})
}

clearResults = () => {
this.props.setSearchResults(this.props.data);
this.setState({ searchLabel: null, searchParams: null, error: false, query: '', status: null });
};

setTagSearch = (field) => {
if (SEARCH_FIELDS.indexOf(field) < 0) {
this.setState({ error: true });
return;
}

let params = {};
params.fields = {};
SEARCH_FIELDS.forEach((f) => {
if (f === field) {
params.fields[f] = { boost: 1 }
} else {
params.fields[f] = { boost: 0 }
}
});

this.setState({ searchLabel: field, searchParams: params, query: '' })
};

performSearch = (query) => {
let searchParameters = { expand: true };
if (this.state.searchParams) {
Object.assign(searchParameters, this.state.searchParams)
}
let results = EL_SEARCH.search(query, searchParameters);
this.props.setSearchResults(this.mapResults(results))
};

setSearchQuery = (event) => {
let val = event.target.value;
this.setState({ query: val, error: false });

if (!val) {
if (this.state.searchLabel) return;
this.clearResults();
return;
}

if (val.indexOf(':') < 0) {
this.performSearch(val)
} else {
this.setTagSearch(val.split(':')[0])
}
};

render() {
let errorTextClasses = cx('form-item__error-text col-100', { visible: this.state.error });
let errorInputClasses = cx({ 'is-invalid-input': this.state.error });

return (
<div className="card">
<div className="form-container">
<form>
<div className="row search-params full">
<div className="row full-width-content input-group full">
<div className="form-item col-25">
<input type="text" placeholder="Search" />
<div className="row search-params full">
<div className="row full-width-content input-group full">
<div className="form-item">
<div className="vertical-aligned-content">
{ this.state.searchLabel && <div className="label margin-right-20">{ this.state.searchLabel }:</div> }
<input type="text" className={ errorInputClasses } placeholder="Search" value={ this.state.query }
onChange={ this.setSearchQuery } />
<button type="reset" className="button secondary margin-left-20" onClick={ this.clearResults }>
Reset
</button>
</div>
<div className={ errorTextClasses }>No such key exists!</div>
</div>
<button type="submit" className="button margin-left-20">Search</button>
<button type="reset" className="button secondary margin-left-20">Reset</button>
</div>
</form>
</div>
</div>
</div>
)
Expand Down
33 changes: 24 additions & 9 deletions html-report/src/components/Suite.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ import React, { Component } from 'react';
import cx from 'classnames';
import randomColor from 'randomcolor';
import convertTime from './../utils/convertTime'
// import SearchBar from './SearchBar';
import paths from './../utils/paths'
import SearchBar from './SearchBar';

export default class Suite extends Component {
state = {
colors: null
colors: null,
tests: window.suite.tests,
activeStatus: null
};

componentWillMount() {
Expand All @@ -26,21 +29,29 @@ export default class Suite extends Component {
this.setState({ colors });
}

getSearchResults(results) {
this.setState({ tests: results });
}

filterByStatus = (status) => {
this.setState({ activeStatus: status })
};

render() {
const data = window.suite;
return (
<div className="content margin-top-20">
<div className="title-common"><a href="../index.html">Suits list</a>/ Suite {data.id}</div>
<div className="title-common"><a href={ paths.fromSuiteToIndex }>Suits list</a>/ Suite {data.id}</div>
<div className="row justify-between">
<div className="card card-info">
<div className="card card-info filter-card" onClick={ () => this.filterByStatus('passed') }>
<div className="text-sub-title-light">Passed</div>
<div className="card-info__content status-passed">{ data.passed_count }</div>
</div>
<div className="card card-info">
<div className="card card-info filter-card" onClick={ () => this.filterByStatus('failed') }>
<div className="text-sub-title-light">Failed</div>
<div className="card-info__content status-failed">{ data.failed_count }</div>
</div>
<div className="card card-info">
<div className="card card-info filter-card" onClick={ () => this.filterByStatus('ignored') }>
<div className="text-sub-title-light">Ignored</div>
<div className="card-info__content status-ignored">{ data.ignored_count }</div>
</div>
Expand All @@ -50,12 +61,16 @@ export default class Suite extends Component {
</div>
</div>

{/*<SearchBar />*/}
<SearchBar data={ data.tests } setSearchResults={ (results) => this.getSearchResults(results) }
filterByStatus={ this.state.activeStatus } />

<div className="card">
<div className="title-common">Tests <span className="label">{ data.tests.length }</span></div>
<div className="vertical-aligned-content title-common">
<div className="margin-right-10">Tests</div>
<span className="label">{ this.state.tests.length }</span>
</div>
<div className="container-expanded list">
{ data.tests.map((test, i) => {
{ this.state.tests.map((test, i) => {
return (<a key={ i } href={`${data.id}/${test.deviceId}/${test.id}.html`}
className={ cx('list__item', 'row full justify-between', test.status) }>
<div>
Expand Down
3 changes: 2 additions & 1 deletion html-report/src/components/SuitesList.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { Component } from 'react';
import convertTime from './../utils/convertTime';
import paths from './../utils/paths';

export default class SuitesList extends Component {
render() {
Expand All @@ -10,7 +11,7 @@ export default class SuitesList extends Component {
{ window.mainData.suites.map((suite) => {
return (
<div key={ suite.id } className="suite-item card">
<a href={`./suites/${suite.id}.html`} className="title-common with-arrow">
<a href={ paths.fromIndexToSuite(suite.id) } className="title-common with-arrow">
Suite { suite.id }
</a>
<div className="row full margin-bottom-20 bounded">
Expand Down
9 changes: 5 additions & 4 deletions html-report/src/components/TestItem.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { Component } from 'react';
import cx from 'classnames';
import convertTime from './../utils/convertTime'
import paths from './../utils/paths'

export default class TestItem extends Component {
componentWillMount() {
Expand All @@ -26,8 +27,8 @@ export default class TestItem extends Component {
return (
<div className="content margin-top-20">
<div className="title-common vertical-aligned-content">
<a href="../../../index.html">Suits list</a> /
<a href={ `../../${data.suite_id}.html` }>Suite { data.suite_id }</a> /
<a href={ paths.fromTestToIndex }>Suits list</a> /
<a href={ paths.fromTestToSuite(data.suite_id) }>Suite { data.suite_id }</a> /
{ data.deviceId }
</div>
<div className='margin-top-20'>
Expand Down Expand Up @@ -62,15 +63,15 @@ export default class TestItem extends Component {
</div>) }
</div> }

<div className="card">
{ !!data.screenshots_paths.length && <div className="card">
<ul className="images row">
{ data.screenshots_paths.map((image) => {
return ( <li key={ image } className="images__item col-20">
<img src={ image } />
</li> )
}) }
</ul>
</div>
</div>}
</div>
</div>
);
Expand Down
6 changes: 6 additions & 0 deletions html-report/src/utils/paths.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
fromIndexToSuite: (suiteId) => `./suites/${suiteId}.html`,
fromSuiteToIndex: '../index.html',
fromTestToSuite: (suiteId) => `../../${suiteId}.html`,
fromTestToIndex: '../../../index.html',
};
12 changes: 12 additions & 0 deletions html-report/styles/_custom.scss
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,18 @@
text-align: right;
}

/* Filter card */

.filter-card {
cursor: pointer;
transition: transform $short-transition;
transform: translateY(0);

&:hover {
transform: translateY(-5px);
}
}

/* Log */

.log-wrapper {
Expand Down

0 comments on commit a7e8cc3

Please sign in to comment.