Skip to content
Open
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
66 changes: 43 additions & 23 deletions App.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React from 'react';
import {autobind} from 'core-decorators';
import { Map } from 'immutable';

import { autobind } from 'core-decorators';
import R from 'ramda';
import classNames from 'classnames';
import Tree from './tree-component';
import './styles.less';
import {deleteNodeWithChildren} from './helpers';
import { deleteNodeWithChildren } from './helpers';
import TreeRow from './tree-row-component';
import RowRenderer from './row-renderer';
import nodes from './mock-data';
Expand All @@ -22,22 +24,22 @@ export default class App extends React.Component {

state = {
nodes
}
};
getRandomWord() {
return fetch('http://www.setgetgo.com/randomword/get.php?len=4')
.then((resp) => resp.text());
return fetch(
'http://www.setgetgo.com/randomword/get.php?len=4'
).then(resp => resp.text());
}

@autobind
handleExpand(nodeId) {
@autobind handleExpand(nodeId) {
const parentNode = this.state.nodes.byId[nodeId];
if(parentNode.lazyLoad) {
if (parentNode.lazyLoad) {
setTimeout(() => {
const randomWords = [];
this.getRandomWord()
.then((word) => randomWords.push(word))
.then(word => randomWords.push(word))
.then(this.getRandomWord)
.then((word) => randomWords.push(word))
.then(word => randomWords.push(word))
.then(() => {
const newNode1 = {
id: `${nodeId}.${randomWords[0]}`,
Expand All @@ -54,21 +56,20 @@ export default class App extends React.Component {
[nodeId]: R.assoc('childIds', [newNode1.id, newNode2.id])
}),
R.assoc(newNode1.id, newNode1),
R.assoc(newNode2.id, newNode2),
R.assoc(newNode2.id, newNode2)
)(this.state.nodes.byId);
this.setState({
nodes: {
...this.state.nodes,
byId
}
});
})
}, MOCK_SERVER_TIME)
});
}, MOCK_SERVER_TIME);
}
}

@autobind
handleClick(event, nodeId, parentId) {
@autobind handleClick(event, nodeId, parentId) {
const classNames = event.target.className;
if (R.contains('delete', classNames)) {
this.setState({
Expand All @@ -77,17 +78,36 @@ export default class App extends React.Component {
}
}

@autobind shouldSelectNode(node) {
console.log(
'shouldSelectNode ',
node.id,
'---',
this.tree.getSelectedNode()
);

if (!node || node.id === this.tree.getSelectedNode()) {
return false; // Prevent from deselecting the current node
}
return true;
}

render() {
const {nodes} = this.state;
const { nodes } = this.state;
return (
<div className="tree-wrapper">
<div className='tree-wrapper'>
<Tree
nodes={nodes}
onClick={this.handleClick}
onExpand={this.handleExpand}
onSelect={R.T}
rowRenderer={RowRenderer}
onCollapse={this.handleCollapse}/>
nodes={nodes}
onClick={this.handleClick}
onExpand={this.handleExpand}
ref={c => {
this.tree = c && c.state;
console.log('Tree ', c);
}}
shouldSelectNode={this.shouldSelectNode}
rowRenderer={RowRenderer}
onCollapse={this.handleCollapse}
/>
</div>
);
}
Expand Down
99 changes: 99 additions & 0 deletions __tests__/row.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import React from 'react';
import { shallow, mount } from 'enzyme';
import { fromJS, List } from 'immutable';
import toJSON from 'enzyme-to-json';
import Row from '../row';
import TitleComponent from '../title';
import logger from '../utils/logger';

const mockData = {
byId: {
1: {
id: '1',
name: 'One',
lazyLoad: true,
},
2: {
id: '2',
name: 'Two',
childIds: ['2.1', '2.2'],
},
2.1: {
id: '2.1',
name: 'Two.One',
},
2.2: {
id: '2.2',
name: 'Two.Two',
},
},
};

describe('<Row/>', () => {
const states = {
expander: <span>+</span>,
collapser: <span>-</span>,
loader: <span>^</span>,
};
const requiredProps = {
expandedNodeIds: List(),
loadingNodeIds: List(),
nodes: fromJS(mockData),
nodeId: '2',
parentId: '2',
rowRenderer: TitleComponent,
renderedNodeIds: List(),
selectedNodeIds: List(),
};
test('should load without crashing', () => {
const wrapper = shallow(<Row {...requiredProps} />);
expect(wrapper.length).toBe(1);
});

test('should have required default props', () => {
const wrapper = shallow(<Row {...requiredProps} />);
'expander,collapser,loader,expanded,depth'.split(',').forEach((value) => {
expect(wrapper.instance().props[value]).toBeDefined();
});
});

test('should show expand icon if node have childs or is lazy loaded', () => {});

test('should have required methods passed as props', () => {
// onClick={this.handleClick}
// onToggle={this.handleToggle}
});

test('should call `toggle` function when clicked on expand icon', () => {
const onToggleFn = jest.fn();
const wrapper = mount(<Row {...requiredProps} onToggle={onToggleFn} />);
// Row.prototype.mockToggleFn = jest.fn();
// const spy = jest.spyOn(Row.prototype, "mockToggleFn");
const ele = wrapper
.find(`#row-${requiredProps.nodeId}`)
.children('.node-header')
.children('.toggle-wrapper')
.find('a')
.simulate('click');
// expect(spy).toHaveBeenCalled();
expect(onToggleFn).toHaveBeenCalledWith(requiredProps.nodeId);
// expect(toJSON(wrapper)).toMatchSnapshot();
});

test('should call `onClick` function to `delete node` with proper args when clicked', () => {
const onClick = jest.fn();
const wrapper = mount(<Row {...requiredProps} onClick={onClick} />);
const ele = wrapper
.find(`#row-${requiredProps.nodeId}`)
.children('.node-header')
.children('.title-wrapper');
const event = ele.simulate('click');
logger.log('ele', ele.length);
// Unable to test this
// expect(onClick).toBeCalledWith(event,requiredProps.nodeId,requiredProps.parentId);
expect(onClick).toBeCalled();
});
test('should show loading indicator when node is lazily loaded', () => {});
test('should select the node when user clicks on any node', () => {});
test('should be able render the child nodes', () => {});
});
42 changes: 42 additions & 0 deletions __tests__/rowRenderer.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from 'react';
import RowRenderer from '../row-renderer';
import logger from '../utils/logger';
import toJson from 'enzyme-to-json';
import TreeRowComonent from '../tree-row-component';
import { shallow, mount } from 'enzyme';

describe('<RowRenderer/>', () => {
test('should render without crashing', () => {
const mockData = {
id: 1,
name: 'Foo',
};
const wrapper = shallow(<RowRenderer node={mockData} />);
expect(wrapper.length).toBe(1);
});

test('should allow user to rename the node', () => {
const mockData = {
id: 1,
name: 'Foo',
renameMode: true,
state: {
selected: false,
},
};
const wrapper = mount(
<RowRenderer node={Object.assign({}, mockData, { renameMode: false })} />,
);
expect(wrapper.find('.infinite-tree-rename-input').length).toBe(0);
expect(wrapper.find('.infinite-tree-title').length).toBe(1);

wrapper.setProps({ node: mockData });
expect(wrapper.find('.infinite-tree-rename-input').length).toBe(1);
expect(wrapper.find('.infinite-tree-title').length).toBe(0);
});

test('should have default props defined', () => {
const wrapper = shallow(<RowRenderer />);
expect(wrapper.instance().props.treeOptions).toEqual({});
});
});
15 changes: 15 additions & 0 deletions __tests__/title.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';
import { mount } from 'enzyme';
import Title from '../title';

describe('<Title/>', () => {
test('should render without crashing', () => {
const mockData = {
name: 'Foo',
id: '1',
};
const wrapper = mount(<Title node={mockData} />);
// wrapper.setProps({ node: mockData });
expect(wrapper.length).toBe(1);
});
});
21 changes: 21 additions & 0 deletions __tests__/treeComponent.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';

describe('<Tree/>', () => {
test('should pass', () => {
expect(1 === 1).toBe(true);
});

// test("should show collapse icon when node is expanded", () => {
// let $toggleWrapper = wrapper
// .find(`#row-${requiredProps.nodeId}`)
// .children(".toggle-wrapper");

// $toggleWrapper.find("a").simulate("click");
// // expect($toggleWrapper.find("a").html()).toEqual(states.collapser);
// });

// test("should call collapse function when clicked on collapse icon", () => {});
// test("should show loading indicator when node is lazily loaded", () => {});
// test("should select the node when user clicks on any node", () => {});
// test("should be able render the child nodes", () => {});
});
27 changes: 27 additions & 0 deletions __tests__/treeRow.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react';
import { shallow } from 'enzyme';
import toJSON from 'enzyme-to-json';
import TreeRowComponent from '../tree-row-component';
import logger from '../utils/logger';

describe('<TreeRowComponent/>', () => {
test('should load without crashing', () => {});

test('should add appropriate class whenever a node is selected', () => {
const mockData = { state: {} };
const wrapper = shallow(<TreeRowComponent node={mockData} />);
let component = wrapper.find('.infinite-tree-item');
let classNames = component.props().className.split(' ');

expect(classNames).not.toContain('infinite-tree-selected');

wrapper.setProps({
node: Object.assign({}, mockData, { state: { selected: true } }),
});

component = wrapper.find('.infinite-tree-item');
classNames = component.props().className.split(' ');

expect(classNames).toContain('infinite-tree-selected');
});
});
Loading