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

Commit

Permalink
✅ add a test with a todomvc app
Browse files Browse the repository at this point in the history
  • Loading branch information
Fenntasy committed Jan 11, 2018
1 parent e97f84d commit 0a73820
Show file tree
Hide file tree
Showing 12 changed files with 1,339 additions and 300 deletions.
1,028 changes: 728 additions & 300 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"license": "MIT",
"dependencies": {
"fs-extra": "^4.0.1",
"live-server": "^1.2.0",
"puppeteer": "^0.13.0"
},
"devDependencies": {
Expand Down
12 changes: 12 additions & 0 deletions tests/todomvc/server/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
node_modules/director
!node_modules/director/build/director.js

node_modules/react
!node_modules/react/dist/react-with-addons.js
!node_modules/react/dist/JSXTransformer.js
node_modules/todomvc-app-css
!node_modules/todomvc-app-css/index.css

node_modules/todomvc-common
!node_modules/todomvc-common/base.css
!node_modules/todomvc-common/base.js
32 changes: 32 additions & 0 deletions tests/todomvc/server/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!doctype html>
<html lang="en" data-framework="react">
<head>
<meta charset="utf-8">
<title>React • TodoMVC</title>
<link rel="stylesheet" href="node_modules/todomvc-common/base.css">
<link rel="stylesheet" href="node_modules/todomvc-app-css/index.css">
</head>
<body>
<section class="todoapp"></section>
<footer class="info">
<p>Double-click to edit a todo</p>
<p>Created by <a href="http://github.com/petehunt/">petehunt</a></p>
<p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
</footer>

<script src="node_modules/todomvc-common/base.js"></script>
<script src="node_modules/react/dist/react-with-addons.js"></script>
<script src="node_modules/classnames/index.js"></script>
<script src="node_modules/react/dist/JSXTransformer.js"></script>
<script src="node_modules/director/build/director.js"></script>

<script src="js/utils.js"></script>
<script src="js/todoModel.js"></script>
<!-- jsx is an optional syntactic sugar that transforms methods in React's
`render` into an HTML-looking format. Since the two models above are
unrelated to React, we didn't need those transforms. -->
<script type="text/jsx" src="js/todoItem.jsx"></script>
<script type="text/jsx" src="js/footer.jsx"></script>
<script type="text/jsx" src="js/app.jsx"></script>
</body>
</html>
181 changes: 181 additions & 0 deletions tests/todomvc/server/js/app.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/*jshint quotmark:false */
/*jshint white:false */
/*jshint trailing:false */
/*jshint newcap:false */
/*global React, Router*/
var app = app || {};

(function () {
'use strict';

app.ALL_TODOS = 'all';
app.ACTIVE_TODOS = 'active';
app.COMPLETED_TODOS = 'completed';
var TodoFooter = app.TodoFooter;
var TodoItem = app.TodoItem;

var ENTER_KEY = 13;

var TodoApp = React.createClass({
getInitialState: function () {
return {
nowShowing: app.ALL_TODOS,
editing: null,
newTodo: ''
};
},

componentDidMount: function () {
var setState = this.setState;
var router = Router({
'/': setState.bind(this, {nowShowing: app.ALL_TODOS}),
'/active': setState.bind(this, {nowShowing: app.ACTIVE_TODOS}),
'/completed': setState.bind(this, {nowShowing: app.COMPLETED_TODOS})
});
router.init('/');
},

handleChange: function (event) {
this.setState({newTodo: event.target.value});
},

handleNewTodoKeyDown: function (event) {
if (event.keyCode !== ENTER_KEY) {
return;
}

event.preventDefault();

var val = this.state.newTodo.trim();

if (val) {
this.props.model.addTodo(val);
this.setState({newTodo: ''});
}
},

toggleAll: function (event) {
var checked = event.target.checked;
this.props.model.toggleAll(checked);
},

toggle: function (todoToToggle) {
this.props.model.toggle(todoToToggle);
},

destroy: function (todo) {
this.props.model.destroy(todo);
},

edit: function (todo) {
this.setState({editing: todo.id});
},

save: function (todoToSave, text) {
this.props.model.save(todoToSave, text);
this.setState({editing: null});
},

cancel: function () {
this.setState({editing: null});
},

clearCompleted: function () {
this.props.model.clearCompleted();
},

render: function () {
var footer;
var main;
var todos = this.props.model.todos;

var shownTodos = todos.filter(function (todo) {
switch (this.state.nowShowing) {
case app.ACTIVE_TODOS:
return !todo.completed;
case app.COMPLETED_TODOS:
return todo.completed;
default:
return true;
}
}, this);

var todoItems = shownTodos.map(function (todo) {
return (
<TodoItem
key={todo.id}
todo={todo}
onToggle={this.toggle.bind(this, todo)}
onDestroy={this.destroy.bind(this, todo)}
onEdit={this.edit.bind(this, todo)}
editing={this.state.editing === todo.id}
onSave={this.save.bind(this, todo)}
onCancel={this.cancel}
/>
);
}, this);

var activeTodoCount = todos.reduce(function (accum, todo) {
return todo.completed ? accum : accum + 1;
}, 0);

var completedCount = todos.length - activeTodoCount;

if (activeTodoCount || completedCount) {
footer =
<TodoFooter
count={activeTodoCount}
completedCount={completedCount}
nowShowing={this.state.nowShowing}
onClearCompleted={this.clearCompleted}
/>;
}

if (todos.length) {
main = (
<section className="main">
<input
className="toggle-all"
type="checkbox"
onChange={this.toggleAll}
checked={activeTodoCount === 0}
/>
<ul className="todo-list">
{todoItems}
</ul>
</section>
);
}

return (
<div>
<header className="header">
<h1>todos</h1>
<input
className="new-todo"
placeholder="What needs to be done?"
value={this.state.newTodo}
onKeyDown={this.handleNewTodoKeyDown}
onChange={this.handleChange}
autoFocus={true}
/>
</header>
{main}
{footer}
</div>
);
}
});

var model = new app.TodoModel('react-todos');

function render() {
React.render(
<TodoApp model={model}/>,
document.getElementsByClassName('todoapp')[0]
);
}

model.subscribe(render);
render();
})();
62 changes: 62 additions & 0 deletions tests/todomvc/server/js/footer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*jshint quotmark:false */
/*jshint white:false */
/*jshint trailing:false */
/*jshint newcap:false */
/*global React */
var app = app || {};

(function () {
'use strict';

app.TodoFooter = React.createClass({
render: function () {
var activeTodoWord = app.Utils.pluralize(this.props.count, 'item');
var clearButton = null;

if (this.props.completedCount > 0) {
clearButton = (
<button
className="clear-completed"
onClick={this.props.onClearCompleted}>
Clear completed
</button>
);
}

var nowShowing = this.props.nowShowing;
return (
<footer className="footer">
<span className="todo-count">
<strong>{this.props.count}</strong> {activeTodoWord} left
</span>
<ul className="filters">
<li>
<a
href="#/"
className={classNames({selected: nowShowing === app.ALL_TODOS})}>
All
</a>
</li>
{' '}
<li>
<a
href="#/active"
className={classNames({selected: nowShowing === app.ACTIVE_TODOS})}>
Active
</a>
</li>
{' '}
<li>
<a
href="#/completed"
className={classNames({selected: nowShowing === app.COMPLETED_TODOS})}>
Completed
</a>
</li>
</ul>
{clearButton}
</footer>
);
}
});
})();
Loading

0 comments on commit 0a73820

Please sign in to comment.