Skip to content

Commit 245e39d

Browse files
committed
split component testing and behavior testing
1 parent 67ee1a0 commit 245e39d

File tree

10 files changed

+223
-47
lines changed

10 files changed

+223
-47
lines changed

examples/counter/bin/compiler.jar

6.09 MB
Binary file not shown.

examples/counter/package.json

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
{
2+
"name": "mostux-todomvc",
3+
"version": "0.0.1",
4+
"description": "",
5+
"browserify": {
6+
"transform": [
7+
[
8+
"babelify",
9+
{
10+
"extensions": [
11+
".es6",
12+
".jsx",
13+
".js"
14+
]
15+
}
16+
]
17+
]
18+
},
19+
"scripts": {
20+
"build": "NODE_ENV=production browserify src/app.jsx --extension=.jsx --extension=.es6 | java -jar bin/compiler.jar > public/app.js",
21+
"start": "ecstatic -p 8000 public",
22+
"watch": "watchify -d src/app.jsx --extension=.jsx --extension=.es6 -o public/app.js -dv",
23+
"test": "jest"
24+
},
25+
"jest": {
26+
"scriptPreprocessor": "<rootDir>/node_modules/babel-jest",
27+
"testFileExtensions": [
28+
"es6",
29+
"js",
30+
"jsx"
31+
],
32+
"moduleFileExtensions": [
33+
"js",
34+
"json",
35+
"es6",
36+
"jsx"
37+
]
38+
},
39+
"dependencies": {
40+
"classnames": "^2.2.0",
41+
"lodash": "^4.0.0",
42+
"react": "^0.14.2",
43+
"react-dom": "^0.14.2",
44+
"rest": "^1.3.1"
45+
},
46+
"devDependencies": {
47+
"babel": "^6.1.18",
48+
"babel-jest": "^6.0.0",
49+
"babel-plugin-lodash": "^2.0.1",
50+
"babel-plugin-transform-react-jsx": "^6.1.18",
51+
"babel-preset-es2015": "^6.1.18",
52+
"babelify": "^7.2.0",
53+
"browserify": "^12.0.1",
54+
"ecstatic": "^1.3.1",
55+
"jest-cli": "^0.7.0",
56+
"uglify-js": "^2.6.1",
57+
"watchify": "^3.6.1"
58+
},
59+
"author": "Jichao Ouyang",
60+
"license": "ISC",
61+
"babel": {
62+
"presets": [
63+
"es2015"
64+
],
65+
"plugins": [
66+
"transform-react-jsx",
67+
"lodash"
68+
]
69+
}
70+
}

examples/counter/src/app.jsx

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import React, { Component, PropTypes } from 'react';
2+
import {render} from 'react-dom';
3+
import most from 'most';
4+
import Most from '../../../lib/react-most'
5+
import {connect} from '../../../lib/react-most'
6+
const App = React.createClass({
7+
8+
getInitialState(){
9+
return {show: false}
10+
},
11+
componentDidMount() {
12+
this.props.actions.add();
13+
this.props.actions.add();
14+
this.props.actions.add();
15+
setTimeout(() => this.setState({
16+
show: true
17+
}, () => {
18+
this.props.actions.add();
19+
this.props.actions.add();
20+
this.props.actions.add();
21+
}), 2000);
22+
},
23+
render(){
24+
return (
25+
<div>
26+
<RCount />
27+
{this.state.show ? <RCount/> : null}
28+
<button onClick={this.props.actions.add}>+</button>
29+
</div>
30+
)
31+
}
32+
})
33+
34+
const Count = (props) => {
35+
return <div>{props.count}</div>
36+
}
37+
const RCount = connect((intent$)=>{
38+
return {
39+
countSink$: intent$
40+
.filter(x => x.type === 'add')
41+
.map(intent => state => ({count: (state.count||0) + 1})),
42+
}
43+
})(Count)
44+
45+
const RApp = connect((intent$) => {
46+
return {
47+
add: _=>({type: 'add'}),
48+
}
49+
})(App)
50+
51+
render(
52+
<Most>
53+
<RApp/>
54+
</Most>
55+
, document.getElementById('app'));
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
jcouyang@CNjcouyang.local.799

examples/type-n-search-with-undo/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
},
2525
"jest": {
2626
"scriptPreprocessor": "<rootDir>/node_modules/babel-jest",
27+
"unmockedModulePathPatterns": [
28+
"<rootDir>/node_modules/*"
29+
],
2730
"testFileExtensions": [
2831
"es6",
2932
"js",

history.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
'use strict';
2+
3+
Object.defineProperty(exports, "__esModule", {
4+
value: true
5+
});
6+
exports.default = initHistory;
7+
function initHistory(contextHistory) {
8+
var history = contextHistory.timestamp().scan(function (acc, state) {
9+
acc.push(state);
10+
return acc;
11+
}, []).tap(function (_) {
12+
return console.log(_, 'history');
13+
}).multicast();
14+
var travel = contextHistory.travel;
15+
history.cursor = -1;
16+
history.travel = travel.sample(function (offset, states) {
17+
var cursor = offset(states.length + history.cursor);
18+
if (cursor < states.length && cursor >= 0) {
19+
history.cursor = offset(history.cursor);
20+
return states[cursor].value;
21+
}
22+
}, travel, history).filter(function (x) {
23+
return !!x;
24+
});
25+
history.forward = function () {
26+
travel.send(function (x) {
27+
return x + 1;
28+
});
29+
};
30+
history.backward = function () {
31+
travel.send(function (x) {
32+
return x - 1;
33+
});
34+
};
35+
return history;
36+
}

lib/__tests__/react-most-test.jsx

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
jest.dontMock('../react-most');
2+
jest.dontMock('../history');
23
jest.dontMock('../engine/most');
4+
jest.dontMock('most')
35
import React from 'react';
46
import ReactDOM from 'react-dom';
57
import TestUtils from 'react-addons-test-utils';
@@ -14,15 +16,6 @@ describe('mostux', () => {
1416
return <div className={'todo-'+this.props.todo.id} key={this.props.todo.id} data-complete={this.props.todo.done}>{this.props.todo.text}</div>
1517
}
1618
});
17-
let Buttons = React.createClass({
18-
render(){
19-
return (
20-
<div>
21-
<button className="btn-complete" onClick={e=>this.props.actions.done(1)} >complete</button>
22-
<button className="btn-remove" onClick={e=>this.props.actions.remove(1)} >add</button>
23-
</div>)
24-
}
25-
});
2619

2720
let TodoList = React.createClass({
2821
render(){
@@ -35,12 +28,17 @@ describe('mostux', () => {
3528
}
3629
return <div>
3730
{todoElements}
38-
<Buttons actions={this.props.actions} />
3931
</div>
4032
}
4133
});
4234

4335
let RxTodoList = connect(function(intent$){
36+
let default$ = most.of(()=>({
37+
todos: [
38+
{id:1, text:5, done:false},
39+
{id:2, text:'heheda', done:false},
40+
]
41+
}))
4442
let done$ = intent$.filter(x=>x.type=='done');
4543
let delete$ = intent$.filter(x=>x.type=='remove');
4644
let doneState$ = done$.map((done)=>{
@@ -61,42 +59,51 @@ describe('mostux', () => {
6159
return state=>(
6260
{todos: state.todos.filter(todo=>todo.id!=deleted.id)}
6361
)
64-
})
65-
.startWith(()=>({
66-
todos: [
67-
{id:1, text:5, done:false},
68-
{id:2, text:'heheda', done:false},
69-
]
70-
}));
62+
});
7163
return {
7264
done: (id)=>({type:'done', id}),
73-
remove: (id)=>({type:'remove', id}),
65+
remove: function remove(id){return {type:'remove', id}},
66+
default$,
7467
deleteState$,
7568
doneState$,
7669
}
7770
})(TodoList);
78-
beforeEach(()=>{
79-
todolist = TestUtils.renderIntoDocument(
80-
<Most>
81-
<RxTodoList />
82-
</Most>
71+
72+
it('render dump Component TodoList UI correctly', () => {
73+
let todolist = TestUtils.renderIntoDocument(
74+
<TodoList todos={[
75+
{id:1, text:5, done:false},
76+
{id:2, text:'heheda', done:false},
77+
]}/>
8378
)
79+
jest.runAllTimers();
80+
let todos = TestUtils.scryRenderedComponentsWithType(todolist, Todo)
81+
expect(todos.length).toBe(2);
82+
expect(todos[0].props.todo.done).toBe(false);
8483
});
8584

86-
it('click complete buttom will complete', () => {
87-
jest.runAllTimers();
88-
expect(TestUtils.scryRenderedComponentsWithType(todolist, Todo)[0].props.todo.done).toBe(false);
89-
TestUtils.Simulate.click(TestUtils.findRenderedDOMComponentWithClass(todolist, 'btn-complete'));
90-
jest.runAllTimers();
91-
expect(TestUtils.scryRenderedComponentsWithType(todolist, Todo)[0].props.todo.done).toBe(true);
85+
it('behavior connected to dump Component works as expected', ()=> {
86+
let todolist = TestUtils.renderIntoDocument(
87+
<Most >
88+
<RxTodoList history={true}>
89+
</RxTodoList>
90+
</Most>
91+
)
9292

93+
var div = TestUtils.
94+
findRenderedComponentWithType(todolist, RxTodoList)
95+
96+
let stream = div.context['__reactive.react.historyStream__']
97+
var a = most.from([
98+
()=>div.actions.done(1),
99+
()=>div.actions.done(2),
100+
()=>div.actions.remove(2),
101+
()=>div.actions.done(1)
102+
])
103+
a.reduce((acc,x)=>x())
104+
return stream.take(5).forEach(_=>_).then(x=>expect(x).toEqual({todos: [
105+
{id: 1, text: 5, done: false}
106+
]}))
93107
});
94-
it('click remove button will remove item', ()=> {
95-
jest.runAllTimers();
96-
TestUtils.Simulate.click(TestUtils.findRenderedDOMComponentWithClass(todolist, 'btn-remove'));
97-
TestUtils.Simulate.click(TestUtils.findRenderedDOMComponentWithClass(todolist, 'btn-remove'));
98-
jest.runAllTimers();
99-
jest.runAllTicks();
100-
expect(TestUtils.scryRenderedComponentsWithType(todolist, Todo).length).toBe(1);
101-
}); });
108+
});
102109
})

lib/history.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
export default function initHistory(contextHistory){
22
let history = contextHistory
3-
.timestamp()
4-
.scan((acc,state)=>{
5-
acc.push(state)
6-
return acc;
7-
}, [])
8-
.tap(_=>console.log(_,'history'))
9-
.multicast()
3+
.timestamp()
4+
.scan((acc,state)=>{
5+
acc.push(state)
6+
return acc;
7+
}, [])
8+
.multicast()
109
let travel = contextHistory.travel
1110
history.cursor = -1
1211
history.travel = travel

lib/react-most.es6

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export function connect(main, initprops={}) {
2121
class Connect extends React.Component {
2222
constructor(props, context) {
2323
super(props, context);
24+
if(props.history) initprops.history=true
2425
this.actions = {
2526
fromEvent(e){
2627
let {type, target} = e;
@@ -39,10 +40,14 @@ export function connect(main, initprops={}) {
3940
})
4041
}
4142
for(let name in sinks){
42-
if(observable(sinks[name]))
43+
44+
if(observable(sinks[name])){
4345
actionsSinks.push(sinks[name]);
46+
}
4447
else if(sinks[name] instanceof Function){
45-
this.actions[name] = (...args)=>this.context[intentStream].send(sinks[name].apply(null, args));
48+
this.actions[name] = (...args)=>{
49+
return this.context[intentStream].send(sinks[name].apply(null, args));
50+
}
4651
}
4752
}
4853
this.context[flatObserve](actionsSinks, (action)=>{

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-most",
3-
"version": "0.3.0",
3+
"version": "0.4.0",
44
"description": "High Prefomance Monadic Reactive State Container for React",
55
"repository": {
66
"type": "git",

0 commit comments

Comments
 (0)