Skip to content

Commit

Permalink
add code to make render_item test pass see: #52
Browse files Browse the repository at this point in the history
  • Loading branch information
nelsonic committed Aug 7, 2018
1 parent e7d6784 commit 3cbb25b
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 47 deletions.
2 changes: 1 addition & 1 deletion elmish.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ and **`then`** the _least_ amount of code necessary to pass the test

> _**Test** & **Document-Driven Development** is **easy** and it's **easily**
one of the **best habits** to form in your software development "career".
This walkthrough shows **how** you can do it **the right way**
This walkthrough shows **how** you can do it **the right way**;
from the **start** of a project._

<br />
Expand Down
41 changes: 1 addition & 40 deletions examples/todo-list/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,46 +13,7 @@

</head>
<body>
<section class="todoapp">
<header class="header">
<h1>todos</h1>
<input class="new-todo" placeholder="What needs to be done?" autofocus>
</header>
<section class="main">
<input id="toggle-all" class="toggle-all" type="checkbox">
<label for="toggle-all">Mark all as complete</label>
<ul class="todo-list"></ul>
</section>
<footer class="footer">
<span class="todo-count"></span>
<ul class="filters">
<li>
<a href="#/" class="selected">All</a>
</li>
<li>
<a href="#/active">Active</a>
</li>
<li>
<a href="#/completed">Completed</a>
</li>
</ul>
<button class="clear-completed">Clear completed</button>
</footer>
</section>
<footer class="info">
<p>Double-click to edit a todo</p>
<p>Created by <a href="https://github.com/dwyl">@dwyl community</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="js/helpers.js"></script>
<script src="js/store.js"></script>
<script src="js/model.js"></script>
<script src="js/template.js"></script>
<script src="js/view.js"></script>
<script src="js/controller.js"></script>
<script src="js/app.js"></script> -->


<!--
<script src="todo-app.js" data-cover></script> load counter
Expand Down
40 changes: 34 additions & 6 deletions examples/todo-list/todo-app.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
(function() { // scope functions to prevent naming conflicts
/* if require is available, it means we are in Node.js Land i.e. testing! */
/* istanbul ignore next */
if (typeof require !== 'undefined' ) { // require elm(ish) creating local copy
const { a, button, div, empty, footer, input, h1, header, label, li, mount,
route, section, span, strong, text, ul } = require('./elmish.js');
} // in the browser elm(ish) functions are automatically be available

const { a, button, div, empty, footer, input, h1, header, label, li, mount,
route, section, span, strong, text, ul } =
(typeof require !== 'undefined') ? require('./elmish.js') : {};

var initial_model = {
todos: [],
Expand Down Expand Up @@ -42,6 +40,36 @@ function update(action, model, data) {
return new_model;
}

/**
* `render_item` creates an DOM "tree" with a single Todo List Item
* using the "elmish" DOM functions (`li`, `div`, `input`, `label` and `button`)
* returns an `<li>` HTML element with a nested `<div>` which in turn has the:
* + `<input type=checkbox>` which lets users to "Toggle" the status of the item
* + `<label>` which displays the Todo item text (`title`) in a `<text>` node
* + `<button class="destroy">` lets people "delete" a todo item.
* see: https://github.com/dwyl/learn-elm-architecture-in-javascript/issues/52
* @param {Object} item the todo item object
* @return {Object} <li> DOM Tree which is nested in the <ul>.
* @example
* // returns <li> DOM element with <div>, <input>. <label> & <button> nested
* var DOM = render_item({id: 1, title: "Build Todo List App", done: false});
*/
function render_item(item) {
return (
li([
"data-id=" + item.id,
"id=" + item.id,
item.done ? "class=completed" : ""
], [
div(["class=view"], [
input(["class=toggle", "type=checkbox",
(item.done ? "checked=true" : "")], []),
label([], [text(item.title)]),
button(["class=destroy"])
]) // </div>
]) // </li>
)
}


// function view(signal, model, root) {
Expand All @@ -62,7 +90,7 @@ if (typeof module !== 'undefined' && module.exports) {
module.exports = {
model: initial_model,
update: update,
// view: view
render_item: render_item, // export so that we can unit test
}
}

Expand Down
45 changes: 45 additions & 0 deletions test/todo-app.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const html = fs.readFileSync(path.resolve(__dirname,
require('jsdom-global')(html); // https://github.com/rstacruz/jsdom-global
const app = require('../examples/todo-list/todo-app.js'); // functions to test
const id = 'test-app'; // all tests use 'test-app' as root element
const elmish = require('../examples/todo-list/elmish.js'); // import "empty" etc

test('todo `model` (Object) has desired keys', function (t) {
const keys = Object.keys(app.model);
Expand Down Expand Up @@ -57,3 +58,47 @@ test('`TOGGLE` (undo) a todo item from done=true to done=false', function (t) {
t.deepEqual(model_todo_undone.todos[0],undone, "Todo item Toggled > undone!");
t.end();
});

test('render_item HTML for a single Todo Item', function (t) {
const model = {
todos: [
{ id: 1, title: "Learn Elm Architecture", done: true },
],
hash: '#/' // the "route" to display
};
// render the ONE todo list item:
document.getElementById(id).appendChild(app.render_item(model.todos[0]))

const done = document.querySelectorAll('.completed')[0].textContent;
t.equal(done, 'Learn Elm Architecture', 'Done: Learn "TEA"');

const checked = document.querySelectorAll('input')[0].checked;
t.equal(checked, true, 'Done: ' + model.todos[0].title + " is done=true");

elmish.empty(document.getElementById(id)); // clear DOM ready for next test
t.end();
});

test('render "main" view using (elmish) HTML DOM functions', function (t) {
const model = {
todos: [
{ id: 1, title: "Learn Elm Architecture", done: true },
{ id: 2, title: "Build Todo List App", done: false },
{ id: 3, title: "Win the Internet!", done: false }
],
hash: '#/' // the "route" to display
};
// render the "main" view and append it to the DOM inside the `test-app` node:
console.log(app.render_item(model.todos[0]));
// elmish.append_childnodes(app.render_main(model), document.getElementById(id));
// const done = document.querySelectorAll('.completed')[0].textContent;
// t.equal(done, 'Learn Elm Architecture', 'Done: Learn "TEA"');
// const todo = document.querySelectorAll('.view')[1].textContent;
// t.equal(todo, 'Build Todo List App', 'Todo: Build Todo List App');
// const todos = document.querySelectorAll('.toggle');
// [true, false, false].forEach(function(state, index){
// t.equal(todos.checked, state, "Todo #" + index + " is done=" + state)
// })
// elmish.empty(document.getElementById(id)); // clear DOM ready for next test
t.end();
});
96 changes: 96 additions & 0 deletions todo-list.md
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,100 @@ which is _checked_ (`done=true`)
+ [ ] The ***remaining*** **`<li>'s`** have **`<input type="checkbox">`**
that are _unchecked_ (`done=false`)

Let's "tackle" the _first_ assertion _first_:

#### Render a _Single_ Todo List Item Using `render_list` Test

It's _always_ a good idea to "break apart" a test into smaller tests
because it means we will write smaller
(_and thus **more maintainable**_) "_composable_" functions.
With that in mind, let's add the following _test_ to `test/todo-app.test.js`:

```js
test.only('render_item HTML for a single Todo Item', function (t) {
const model = {
todos: [
{ id: 1, title: "Learn Elm Architecture", done: true },
],
hash: '#/' // the "route" to display
};
// render the ONE todo list item:
document.getElementById(id).appendChild(app.render_item(model.todos[0]))

const done = document.querySelectorAll('.completed')[0].textContent;
t.equal(done, 'Learn Elm Architecture', 'Done: Learn "TEA"');

const checked = document.querySelectorAll('input')[0].checked;
t.equal(checked, true, 'Done: ' + model.todos[0].title + " is done=true");

elmish.empty(document.getElementById(id)); // clear DOM ready for next test
t.end();
});
```

After saving the `test/todo-app.test.js` file, if you attempt to run it:
```sh
node test/todo-app.test.js
```
you will see something like this:

![render_item-test-failing](https://user-images.githubusercontent.com/194400/43743931-b397cd7a-99cf-11e8-81a6-3218207ca05b.png)

#### `render_list` Implementation

Given the test above, I added the following code to my `todo-app.js` file:

```js
/**
* `render_item` creates an DOM "tree" with a single Todo List Item
* using the "elmish" DOM functions (`li`, `div`, `input`, `label` and `button`)
* returns an `<li>` HTML element with a nested `<div>` which in turn has the:
* + `<input type=checkbox>` which lets users to "Toggle" the status of the item
* + `<label>` which displays the Todo item text (`title`) in a `<text>` node
* + `<button class="destroy">` lets people "delete" a todo item.
* see: https://github.com/dwyl/learn-elm-architecture-in-javascript/issues/52
* @param {Object} item the todo item object
* @return {Object} <li> DOM Tree which is nested in the <ul>.
* @example
* // returns <li> DOM element with <div>, <input>. <label> & <button> nested
* var DOM = render_item({id: 1, title: "Build Todo List App", done: false});
*/
function render_item(item) {
return (
li([
"data-id=" + item.id,
"id=" + item.id,
item.done ? "class=completed" : ""
], [
div(["class=view"], [
input(["class=toggle", "type=checkbox",
(item.done ? "checked=true" : "")], []),
label([], [text(item.title)]),
button(["class=destroy"])
]) // </div>
]) // </li>
)
}
```
Add the `render_item` to the `module.exports` at the end of the file:
```js
if (typeof module !== 'undefined' && module.exports) {
module.exports = {
model: initial_model,
update: update,
render_item: render_item, // export so that we can unit test
}
}
```

This will make the test pass:
![image](https://user-images.githubusercontent.com/194400/43762133-f6c21de0-9a1e-11e8-871d-e6f5b86d1d55.png)







We can _easily_ write a _test_ that includes these 3 assertions.
Append following test code to your `test/todo-app.test.js` file:
Expand Down Expand Up @@ -824,6 +918,8 @@ you will see something like this:





<!--
## What _Next_?
Expand Down

0 comments on commit 3cbb25b

Please sign in to comment.