Skip to content

Commit

Permalink
add *failing* test for DELETE an item #59
Browse files Browse the repository at this point in the history
  • Loading branch information
nelsonic committed Sep 2, 2018
1 parent a47b24c commit 77546af
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 28 deletions.
30 changes: 15 additions & 15 deletions examples/counter-basic/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -95,22 +95,22 @@
<script src="../counter-basic-test/test.js"></script> <!-- load test.js last -->

<div onclick="doubleclick(this, function(){alert('single')}, function(){alert('double')})">click me</div>
<script>
function doubleclick(el, onsingle, ondouble) {
if (el.getAttribute("data-dblclick") == null) {
el.setAttribute("data-dblclick", 1);
setTimeout(function () {
if (el.getAttribute("data-dblclick") == 1) {
onsingle();
}
el.removeAttribute("data-dblclick");
}, 300);
} else {
el.removeAttribute("data-dblclick");
ondouble();
}
<script>
function doubleclick(el, onsingle, ondouble) {
if (el.getAttribute("data-dblclick") == null) {
el.setAttribute("data-dblclick", 1);
setTimeout(function () {
if (el.getAttribute("data-dblclick") == 1) {
onsingle();
}
</script>
el.removeAttribute("data-dblclick");
}, 300);
} else {
el.removeAttribute("data-dblclick");
ondouble();
}
}
</script>

</body>
</html>
2 changes: 1 addition & 1 deletion examples/todo-list/elmish.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ function mount (model, update, view, root_element_id, subscriptions) {
root.appendChild(view(mod, sig)) // render view based on model & signal
}

function signal(action, data) { // signal function takes action
function signal(action, data, model) { // signal function takes action
return function callback() { // and returns callback
model = JSON.parse(localStorage.getItem(store_name)) //|| model;
var updatedModel = update(action, model, data); // update model for the action
Expand Down
21 changes: 16 additions & 5 deletions examples/todo-list/todo-app.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ var initial_model = {
/**
* `update` transforms the `model` based on the `action`.
* @param {String} action - the desired action to perform on the model.
* @param {Object} model - the App's (current) model (or "state").
* @param {String} data - the data we want to "apply" to the item.
* @param {Object} model - the App's (current) model (or "state").
* @return {Object} updated_model - the transformed model.
*/
function update(action, model, data) {
console.log(arguments)
console.log(' - - - - - - - - - - - ');
var new_model = JSON.parse(JSON.stringify(model)) // "clone" the model
switch(action) { // and an action (String) runs a switch
case 'ADD':
Expand Down Expand Up @@ -51,6 +53,9 @@ function update(action, model, data) {
item.done = new_model.all_done;
});
break;
// case 'DELETE':
// console.log('DELETE', data)
// break;
default: // if action unrecognised or undefined,
return model; // return model unmodified
} // see: https://softwareengineering.stackexchange.com/a/201786/211301
Expand All @@ -66,12 +71,14 @@ function update(action, model, data) {
* + `<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
* @param {Object} model - the App's (current) model (or "state").
* @param {Function} singal - the Elm Architicture "dispacher" which will run
* @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, signal) {
function render_item (item, model, signal) {
return (
li([
"data-id=" + item.id,
Expand All @@ -87,7 +94,7 @@ function render_item (item, signal) {
],
[]), // <input> does not have any nested elements
label([], [text(item.title)]),
button(["class=destroy"])
button(["class=destroy", ]) // signal('DELETE', 'blah!', model)])
]) // </div>
]) // </li>
)
Expand All @@ -97,6 +104,7 @@ function render_item (item, signal) {
* `render_main` renders the `<section class="main">` of the Todo List App
* which contains all the "main" controls and the `<ul>` with the todo items.
* @param {Object} model - the App's (current) model (or "state").
* @param {Function} singal - the Elm Architicture "dispacher" which will run
* @return {Object} <section> DOM Tree which containing the todo list <ul>, etc.
*/
function render_main (model, signal) {
Expand All @@ -114,8 +122,9 @@ function render_main (model, signal) {
label(["for=toggle-all"], [ text("Mark all as complete") ]),
ul(["class=todo-list"],
(model.todos && model.todos.length > 0) ?
model.todos.map(function (item) { return render_item(item, signal) })
: null
model.todos.map(function (item) {
return render_item(item, model, signal)
}) : null
) // </ul>
]) // </section>
)
Expand All @@ -126,6 +135,7 @@ function render_main (model, signal) {
* which contains count of items to (still) to be done and a `<ul>` "menu"
* with links to filter which todo items appear in the list view.
* @param {Object} model - the App's (current) model (or "state").
* @param {Function} singal - the Elm Architicture "dispacher" which will run
* @return {Object} <section> DOM Tree which containing the <footer> element.
* @example
* // returns <footer> DOM element with other DOM elements nested:
Expand Down Expand Up @@ -183,6 +193,7 @@ function render_footer (model, signal) {
* which contains count of items to (still) to be done and a `<ul>` "menu"
* with links to filter which todo items appear in the list view.
* @param {Object} model - the App's (current) model (or "state").
* @param {Function} singal - the Elm Architicture "dispacher" which will run
* @return {Object} <section> DOM Tree which containing all other DOM elements.
* @example
* // returns <section class="todo-app"> DOM element with other DOM els nested:
Expand Down
20 changes: 14 additions & 6 deletions test/todo-app.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ test('render_item HTML for a single Todo Item', function (t) {
hash: '#/' // the "route" to display
};
// render the ONE todo list item:
document.getElementById(id).appendChild(app.render_item(model.todos[0]))
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"');
Expand Down Expand Up @@ -307,7 +309,7 @@ test('3. Mark all as completed ("TOGGLE_ALL")', function (t) {
t.end();
});

test('4. Item, should allow me to mark items as complete', function (t) {
test('4. DELETE an item', function (t) {
elmish.empty(document.getElementById(id));
localStorage.removeItem('elmish_' + id);
const model = {
Expand Down Expand Up @@ -337,7 +339,7 @@ test('4. Item, should allow me to mark items as complete', function (t) {
t.end();
});

test.skip('4.1 Item, should allow me to edit an item ("EDIT")' , function (t) {
test.only('4.1 DELETE item by clicking <button class="destroy">', function (t) {
elmish.empty(document.getElementById(id));
localStorage.removeItem('elmish_' + id);
const model = {
Expand All @@ -348,10 +350,16 @@ test.skip('4.1 Item, should allow me to edit an item ("EDIT")' , function (t) {
};
// render the view and append it to the DOM inside the `test-app` node:
elmish.mount(model, app.update, app.view, id, app.subscriptions);
// const todo_count = ;
t.equal(document.querySelectorAll('.destroy').length, 1, "one destroy button")

const item = document.getElementById('0')
t.equal(item.textContent, model.todos[0].title, 'Item contained in model.');
// confirm that the todo item is NOT done (done=false):


// DELETE the item by clicking on the <button class="destroy">:
const button = item.querySelectorAll('button.destroy')[0];
button.click()
// confirm that there is no loger a <button class="destroy">
t.equal(document.querySelectorAll('button.destroy').length, 0,
'there is no loger a <button class="destroy"> as the only item was DELETEd')
t.end();
});
89 changes: 88 additions & 1 deletion todo-list.md
Original file line number Diff line number Diff line change
Expand Up @@ -1781,13 +1781,100 @@ function render_item (item, signal) {
```



#### 4.1 `DELETE` an Item

```
should show the remove button on hover
```

##### Acceptance Criteria

+ [ ] should show the `<button class="destroy">`
on hover (over the item) ... thankfully the TodoMVC CSS
handles this for us, we just need our `view`
to render the `<button>`
+ [ ] Clicking/tapping the `<button class="destroy">`
sends the `signal('DELETE', todo.id, model)`
+ [ ] The `DELETE` update case receives the `todo.id`
and removes it from the `model.todos` Array.

In order to `DELETE` an item from the `model.todos` Array,
we need to "_supply_" the `model` when invoking the `signal`
function. This means we need to _extend_ the `signal` function's
parameters to include the `model` as an _optional_ argument.

In the `elmish.js` file, locate the `mount` function
and add a `model` parameter to the `signal` function definition.
Thus it should change from:
```js
function signal(action, data) { // signal function takes action
return function callback() { // and returns callback
model = JSON.parse(localStorage.getItem(store_name)) //|| model;
var updatedModel = update(action, model, data); // update model for the action
render(updatedModel, signal, ROOT);
};
};
```

To:
```js
function signal(action, data, model) { // signal function takes action
return function callback() { // and returns callback
model = JSON.parse(localStorage.getItem(store_name)) //|| model;
var updatedModel = update(action, model, data); // update model for the action
render(updatedModel, signal, ROOT);
};
};
```

Thankfully, we have a "bank" (or "suite") of tests that cover
all of our existing functionality,
so when we make a change like this
we can _confirm_ that all _existing_ functionality
still works as expected.

Run the tests: `npm test` and ensure they all still pass
after making the change to the `signal` function. (_they should!_)

![tests-still-passing](https://user-images.githubusercontent.com/194400/44953303-a109ce00-ae93-11e8-8f0c-c271832df3a5.png)


##### `DELETE` Item _Test_

Append following test code to your `test/todo-app.test.js` file:

```js
test.only('4.1 DELETE item by clicking <button class="destroy">', function (t) {
elmish.empty(document.getElementById(id));
localStorage.removeItem('elmish_' + id);
const model = {
todos: [
{ id: 0, title: "Make something people want.", done: false }
],
hash: '#/' // the "route" to display
};
// render the view and append it to the DOM inside the `test-app` node:
elmish.mount(model, app.update, app.view, id, app.subscriptions);
// const todo_count = ;
t.equal(document.querySelectorAll('.destroy').length, 1, "one destroy button")

const item = document.getElementById('0')
t.equal(item.textContent, model.todos[0].title, 'Item contained in model.');
// DELETE the item by clicking on the <button class="destroy">:
const button = item.querySelectorAll('button.destroy')[0];
button.click()
// confirm that there is no loger a <button class="destroy">
t.equal(document.querySelectorAll('button.destroy').length, 0,
'there is no loger a <button class="destroy"> as the only item was DELETEd')
t.end();
});
```

If you run the tests `node test/todo-app.test.js`
you should now see:
![delete-test-one-assertion-failing](https://user-images.githubusercontent.com/194400/44953479-21313300-ae96-11e8-971a-51757702bacc.png)



<!--
Expand Down

0 comments on commit 77546af

Please sign in to comment.