Unverified Commit f8699a39 authored by Ryan Lieu's avatar Ryan Lieu Committed by GitHub

Browse on home page (#199)

* tags stying

* fixed tests

* cleaned up some unecessary changes

* added tests for browsepage

* fixed naming

* added DocumentTitle test to BrowsePage

* fixed whitespacing in browsetags tests

* fixed styling issues

* refactored browsetags component into tagslist

* cleaned up extraneous components

* fixed test

* updated tests, styling

* fixed test name
parent 624959dd
import * as React from 'react';
import * as DocumentTitle from 'react-document-title';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import './styles.scss';
import AppConfig from 'config/config';
import LoadingSpinner from 'components/common/LoadingSpinner';
import TagInfo from 'components/Tags/TagInfo';
import { Tag } from 'interfaces';
import { GlobalState } from 'ducks/rootReducer';
import { getAllTags } from 'ducks/allTags/reducer';
import { GetAllTagsRequest } from 'ducks/allTags/types';
export interface StateFromProps {
allTags: Tag[];
isLoading: boolean;
}
export interface DispatchFromProps {
getAllTags: () => GetAllTagsRequest;
}
interface BrowsePageState {
curatedTags: Tag[];
otherTags: Tag[];
isLoading: boolean;
}
export type BrowsePageProps = StateFromProps & DispatchFromProps;
export class BrowsePage extends React.Component<BrowsePageProps, BrowsePageState> {
constructor(props) {
super(props);
this.state = {
curatedTags: [],
otherTags: [],
isLoading: this.props.isLoading,
};
}
static getDerivedStateFromProps(nextProps, prevState) {
const { allTags, isLoading } = nextProps;
if (isLoading) {
return {
...prevState,
isLoading,
};
}
const curatedTagsList = AppConfig.browse.curatedTags;
const curatedTags = allTags.filter((tag) => curatedTagsList.indexOf(tag.tag_name) !== -1);
let otherTags = [];
if (AppConfig.browse.showAllTags) {
otherTags = allTags.filter((tag) => curatedTagsList.indexOf(tag.tag_name) === -1);
}
return { curatedTags, otherTags, isLoading };
}
componentDidMount() {
this.props.getAllTags();
}
generateTagInfo(tagArray: Tag[]) {
return tagArray.map((tag, index) =>
<TagInfo data={ tag } compact={ false } key={ index }/>)
}
import TagsList from 'components/common/TagsList';
export class BrowsePage extends React.Component {
render() {
let innerContent;
if (this.state.isLoading) {
innerContent = <LoadingSpinner/>;
} else {
innerContent = (
return (
<DocumentTitle title="Browse - Amundsen">
<div className="container">
<div className="row">
<div className="col-xs-12">
<h3 id="browse-header">Browse Tags</h3>
<hr className="header-hr"/>
<div id="browse-body" className="browse-body">
{this.generateTagInfo(this.state.curatedTags)}
{
this.state.curatedTags.length > 0 && this.state.otherTags.length > 0 &&
<hr />
}
{this.generateTagInfo(this.state.otherTags)}
</div>
<h3 id="browse-header">Browse Tags</h3>
<hr className="header-hr"/>
<TagsList />
</div>
</div>
</div>
);
}
return (
<DocumentTitle title="Browse - Amundsen">
{ innerContent }
</DocumentTitle>
);
}
}
export const mapStateToProps = (state: GlobalState) => {
return {
allTags: state.allTags.allTags,
isLoading: state.allTags.isLoading,
};
};
export const mapDispatchToProps = (dispatch: any) => {
return bindActionCreators({ getAllTags } , dispatch);
};
export default connect<StateFromProps, DispatchFromProps>(mapStateToProps, mapDispatchToProps)(BrowsePage);
export default BrowsePage;
......@@ -3,142 +3,39 @@ import * as DocumentTitle from 'react-document-title';
import { shallow } from 'enzyme';
import LoadingSpinner from 'components/common/LoadingSpinner';
import TagInfo from 'components/Tags/TagInfo';
import { BrowsePage, BrowsePageProps, mapDispatchToProps, mapStateToProps } from '../';
import globalState from 'fixtures/globalState';
import AppConfig from 'config/config';
AppConfig.browse.curatedTags = ['test1'];
import { BrowsePage } from '../';
import TagsList from 'components/common/TagsList';
describe('BrowsePage', () => {
let props: BrowsePageProps;
let subject;
beforeEach(() => {
props = {
allTags: [
{
tag_count: 2,
tag_name: 'test1',
},
{
tag_count: 1,
tag_name: 'test2',
},
],
isLoading: false,
getAllTags: jest.fn(),
};
subject = shallow(<BrowsePage {...props} />);
});
describe('getDerivedStateFromProps', () => {
it('returns correct state if props.isLoading', () => {
const prevState = subject.state();
props.isLoading = true;
subject.setProps(props);
expect(subject.state()).toMatchObject({
...prevState,
isLoading: true,
});
});
it('returns correct state if !props.isLoading', () => {
props.isLoading = false;
subject.setProps(props);
expect(subject.state()).toMatchObject({
curatedTags: [{ tag_count: 2, tag_name: 'test1'}],
otherTags: [{ tag_count: 1, tag_name: 'test2'}],
isLoading: false,
});
});
it('returns correct state if !props.isLoading and !AppConfig.browse.showAllTags', () => {
AppConfig.browse.showAllTags = false;
subject = shallow(<BrowsePage {...props} />);
expect(subject.state()).toMatchObject({
curatedTags: [{tag_count: 2, tag_name: 'test1'}],
otherTags: [],
isLoading: false,
});
AppConfig.browse.showAllTags = true; // reset so other tests aren't affected
});
});
describe('componentDidMount', () => {
it('calls props.getAllTags', () => {
expect(props.getAllTags).toHaveBeenCalled();
});
});
describe('render', () => {
let spy;
beforeEach(() => {
spy = jest.spyOn(BrowsePage.prototype, 'generateTagInfo');
});
it('renders LoadingSpinner if state.isLoading', () => {
/* Note: For some reason setState is not updating the component in this case */
props.isLoading = true;
subject.setProps(props);
expect(subject.find(LoadingSpinner).exists()).toBeTruthy();
});
it('renders DocumentTitle w/ correct title', () => {
expect(subject.find(DocumentTitle).props().title).toEqual('Browse - Amundsen');
});
it('renders correct header', () => {
expect(subject.find('#browse-header').text()).toEqual('Browse Tags');
});
it('renders <hr> in if curatedTags.length > 0 & otherTags.length > 0 ', () => {
expect(subject.find('#browse-body').find('hr').exists()).toBeTruthy();
});
it('does not render <hr> if !(curatedTags.length > 0 & otherTags.length > 0) ', () => {
AppConfig.browse.curatedTags = ['test1', 'test2'];
subject = shallow(<BrowsePage {...props} />);
expect(subject.find('#browse-body').find('hr').exists()).toBeFalsy();
AppConfig.browse.curatedTags = ['test1']; // reset so other tests aren't affected
});
it('calls generateTagInfo with curatedTags', () => {
expect(spy).toHaveBeenCalledWith(subject.state().curatedTags);
});
it('call generateTagInfo with otherTags', () => {
expect(spy).toHaveBeenCalledWith(subject.state().otherTags);
});
});
});
describe('mapDispatchToProps', () => {
let dispatch;
let result;
beforeEach(() => {
dispatch = jest.fn(() => Promise.resolve());
result = mapDispatchToProps(dispatch);
});
it('sets getAllTags on the props', () => {
expect(result.getAllTags).toBeInstanceOf(Function);
});
});
describe('mapStateToProps', () => {
let result;
beforeEach(() => {
result = mapStateToProps(globalState);
});
it('sets allTags on the props', () => {
expect(result.allTags).toEqual(globalState.allTags.allTags);
});
it('sets isLoading on the props', () => {
expect(result.isLoading).toEqual(globalState.allTags.isLoading);
});
const setup = () => {
const wrapper = shallow<BrowsePage>(<BrowsePage/>)
return { props, wrapper };
};
let props;
let wrapper;
beforeAll(() => {
const setupResult = setup();
props = setupResult.props;
wrapper = setupResult.wrapper;
});
describe('render', () => {
it('renders DocumentTitle w/ correct title', () => {
expect(wrapper.find(DocumentTitle).props().title).toEqual('Browse - Amundsen');
});
it('renders correct header', () => {
expect(wrapper.find('#browse-header').text()).toEqual('Browse Tags');
});
it('renders <hr>', () => {
expect(wrapper.contains(<hr className="header-hr"/>));
});
it('contains TagsList', () => {
expect(wrapper.contains(<TagsList />));
});
});
});
......@@ -11,6 +11,7 @@ import PopularTables from 'components/common/PopularTables';
import { SearchAllReset } from 'ducks/search/types';
import { searchReset } from 'ducks/search/reducer';
import SearchBar from 'components/SearchPage/SearchBar';
import TagsList from 'components/common/TagsList';
export interface DispatchFromProps {
......@@ -34,6 +35,10 @@ export class HomePage extends React.Component<HomePageProps> {
<div className="row">
<div className="col-xs-12 col-md-offset-1 col-md-10">
<SearchBar />
<div className="home-element-container">
<div id="browse-tags-header" className="title-1 browse-tags-header">Browse Tags</div>
<TagsList />
</div>
<div className="home-element-container">
<MyBookmarks />
</div>
......
......@@ -5,6 +5,10 @@
margin-top: 64px;
}
.browse-tags-header {
margin-bottom: 32px;
}
@media (max-width: $screen-sm-max) {
.home-element-container {
margin-top: 32px;
......
......@@ -4,9 +4,10 @@ import { shallow } from 'enzyme';
import { mapDispatchToProps, HomePage, HomePageProps } from '../';
import SearchBar from 'components/SearchPage/SearchBar';
import MyBookmarks from 'components/common/Bookmark/MyBookmarks';
import PopularTables from 'components/common/PopularTables';
import SearchBar from 'components/SearchPage/SearchBar';
import TagsList from 'components/common/TagsList';
import { getMockRouterProps } from 'fixtures/mockRouter';
......@@ -33,9 +34,20 @@ describe('HomePage', () => {
});
describe('render', () => {
it('contains Searchbar, BookmarkList, and PopularTables', () => {
it('contains Searchbar', () => {
expect(wrapper.contains(<SearchBar />));
});
it('contains TagsList', () => {
expect(wrapper.find('#browse-tags-header').text()).toEqual('Browse Tags');
expect(wrapper.contains(<TagsList />));
});
it('contains MyBookmarks', () => {
expect(wrapper.contains(<MyBookmarks />));
});
it('contains PopularTables', () => {
expect(wrapper.contains(<PopularTables />));
});
});
......
import * as React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import './styles.scss';
import AppConfig from 'config/config';
import LoadingSpinner from 'components/common/LoadingSpinner';
import TagInfo from 'components/Tags/TagInfo';
import { Tag } from 'interfaces';
import { GlobalState } from 'ducks/rootReducer';
import { getAllTags } from 'ducks/allTags/reducer';
import { GetAllTagsRequest } from 'ducks/allTags/types';
export interface StateFromProps {
allTags: Tag[];
isLoading: boolean;
}
export interface DispatchFromProps {
getAllTags: () => GetAllTagsRequest;
}
interface TagsListState {
curatedTags: Tag[];
otherTags: Tag[];
}
export type TagsListProps = StateFromProps & DispatchFromProps;
export class TagsList extends React.Component<TagsListProps, TagsListState> {
constructor(props) {
super(props);
this.state = {
curatedTags: [],
otherTags: [],
};
}
static getDerivedStateFromProps(nextProps, prevState) {
const { allTags, isLoading } = nextProps;
if (isLoading) {
return {
...prevState,
isLoading,
};
}
const curatedTagsList = AppConfig.browse.curatedTags;
const curatedTags = allTags.filter((tag) => curatedTagsList.indexOf(tag.tag_name) !== -1);
let otherTags = [];
if (AppConfig.browse.showAllTags) {
otherTags = allTags.filter((tag) => curatedTagsList.indexOf(tag.tag_name) === -1);
}
return { curatedTags, otherTags, isLoading };
}
componentDidMount() {
this.props.getAllTags();
}
generateTagInfo(tagArray: Tag[]) {
return tagArray.map((tag, index) =>
<TagInfo data={ tag } compact={ false } key={ index }/>)
}
render() {
let innerContent;
if (this.props.isLoading) {
innerContent = <LoadingSpinner/>;
} else {
innerContent = (
<div id="browse-body" className="browse-body">
{this.generateTagInfo(this.state.curatedTags)}
{
this.state.curatedTags.length > 0 && this.state.otherTags.length > 0 &&
<hr />
}
{this.generateTagInfo(this.state.otherTags)}
</div>
);
}
return (innerContent);
}
}
export const mapStateToProps = (state: GlobalState) => {
return {
allTags: state.allTags.allTags,
isLoading: state.allTags.isLoading,
};
};
export const mapDispatchToProps = (dispatch: any) => {
return bindActionCreators({ getAllTags } , dispatch);
};
export default connect<StateFromProps, DispatchFromProps>(mapStateToProps, mapDispatchToProps)(TagsList);
import * as React from 'react';
import { shallow } from 'enzyme';
import LoadingSpinner from 'components/common/LoadingSpinner';
import { TagsList, TagsListProps, mapDispatchToProps, mapStateToProps } from '../';
import globalState from 'fixtures/globalState';
import AppConfig from 'config/config';
AppConfig.browse.curatedTags = ['test1'];
describe('TagsList', () => {
let props: TagsListProps;
let subject;
beforeEach(() => {
props = {
allTags: [
{
tag_count: 2,
tag_name: 'test1',
},
{
tag_count: 1,
tag_name: 'test2',
},
],
isLoading: false,
getAllTags: jest.fn(),
};
subject = shallow(<TagsList {...props} />);
});
describe('getDerivedStateFromProps', () => {
it('returns correct state if props.isLoading', () => {
const prevState = subject.state();
props.isLoading = true;
subject.setProps(props);
expect(subject.state()).toMatchObject({
...prevState,
isLoading: true,
});
});
it('returns correct state if !props.isLoading', () => {
props.isLoading = false;
subject.setProps(props);
expect(subject.state()).toMatchObject({
curatedTags: [{ tag_count: 2, tag_name: 'test1'}],
otherTags: [{ tag_count: 1, tag_name: 'test2'}],
isLoading: false,
});
});
it('returns correct state if !props.isLoading and !AppConfig.browse.showAllTags', () => {
AppConfig.browse.showAllTags = false;
subject = shallow(<TagsList {...props} />);
expect(subject.state()).toMatchObject({
curatedTags: [{tag_count: 2, tag_name: 'test1'}],
otherTags: [],
isLoading: false,
});
AppConfig.browse.showAllTags = true; // reset so other tests aren't affected
});
});
describe('componentDidMount', () => {
it('calls props.getAllTags', () => {
expect(props.getAllTags).toHaveBeenCalled();
});
});
describe('render', () => {
let spy;
beforeEach(() => {
spy = jest.spyOn(TagsList.prototype, 'generateTagInfo');
});
it('renders LoadingSpinner if state.isLoading', () => {
/* Note: For some reason setState is not updating the component in this case */
props.isLoading = true;
subject.setProps(props);
expect(subject.find(LoadingSpinner).exists()).toBeTruthy();
});
it('renders <hr> in if curatedTags.length > 0 & otherTags.length > 0 ', () => {
expect(subject.find('#browse-body').find('hr').exists()).toBeTruthy();
});
it('does not render <hr> if !(curatedTags.length > 0 & otherTags.length > 0) ', () => {
AppConfig.browse.curatedTags = ['test1', 'test2'];
subject = shallow(<TagsList {...props} />);
expect(subject.find('#browse-body').find('hr').exists()).toBeFalsy();
AppConfig.browse.curatedTags = ['test1']; // reset so other tests aren't affected
});
it('calls generateTagInfo with curatedTags', () => {
expect(spy).toHaveBeenCalledWith(subject.state().curatedTags);
});
it('call generateTagInfo with otherTags', () => {
expect(spy).toHaveBeenCalledWith(subject.state().otherTags);
});
});
});
describe('mapDispatchToProps', () => {
let dispatch;
let result;
beforeEach(() => {
dispatch = jest.fn(() => Promise.resolve());
result = mapDispatchToProps(dispatch);
});
it('sets getAllTags on the props', () => {
expect(result.getAllTags).toBeInstanceOf(Function);
});
});
describe('mapStateToProps', () => {
let result;
beforeEach(() => {
result = mapStateToProps(globalState);
});
it('sets allTags on the props', () => {
expect(result.allTags).toEqual(globalState.allTags.allTags);
});
it('sets isLoading on the props', () => {
expect(result.isLoading).toEqual(globalState.allTags.isLoading);
});
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment