See the Number of Todos To Be Completed

Story: As a user, I want to see how many remaining todos I have to complete.

Should render correctly

Write the test.

// tests/todomvc/components/Footer.spec.js

'use strict';

import React from 'react'
import {expect} from 'chai'
import {shallow} from 'enzyme'

import Footer from '../../../src/todomvc/components/Footer'

function setup() {
  const component = shallow(
    <Footer/>
  );

  return {
    component: component
  }
}

describe('Footer component', () => {
  describe('Should render correctly', () => {
    it('Should be a Footer', () => {
      const {component} = setup();

      expect(component.type()).to.equal('footer')
    })
  })
});

Run the test and watch it fail.

module.js:487
    throw err;
    ^

Error: Cannot find module '../../../src/todomvc/components/Footer'

Write the code to make the test pass.

// src/todomvc/components/Footer.js

'use strict';

import React, {Component} from 'react'

export default class Footer extends Component {
  render() {
    return (
      <footer/>
    )
  }
}

Run the test and watch it pass.

  TodoMVC actions
    ✓ Should create an action to add a todo
    ✓ Should create an action to edit a todo
    ✓ Should create an action to delete a todo
    ✓ Should create an action to toggle a todo between completed and not completed
    ✓ Should create an action to toggle all todos between completed and not completed

  Footer component
    Should render correctly
      ✓ Should be a Footer

  Header component
    Should render correctly
      ✓ Should be a Header
      ✓ Should have a title
      ✓ Should have a TodoTextInput field
      ✓ Should have a toggle all complete status checkbox
    Should behave correctly
      ✓ Should call addTodo() if length of text is greater than 0
      ✓ Should call toggleCompleteAllTodos() when the all complete status checkbox is changed

  MainSection component
    Should render correctly
      ✓ Should be a MainSection component
      ✓ Should include a list of todos

  TodoApp component
    Should render correctly
      ✓ Should be a TodoApp
      ✓ Should have a header
      ✓ Should have a main section

  TodoItem component
    Should render correctly
      ✓ Should be an li
      ✓ Should have a label
      ✓ Should have a delete button
      ✓ Should have a toggle complete status checkbox
    Should behave correctly
      ✓ Should switch to edit mode when label onDoubleClick is fired
      ✓ Should call editTodo() when TodoTextInput onSave is called
      ✓ Should leave edit mode after TodoTextInput onSave
      ✓ Should call deleteTodo() when the delete button is clicked
      ✓ Should call deleteTodo() when TodoTextInput onSave is called with no text
      ✓ Should call toggleCompleteOneTodo() when the complete status checkbox is changed

  TodoTextInput component
    ✓ Should not call onSave() on blur if isNew
    Should render correctly
      ✓ Should be a TodoTextInput component
    Should behave correctly
      ✓ Should update value on change
      ✓ Should call onSave() on return key press
      ✓ Should reset state on return key press if isNew
      ✓ Should call onSave() on blur if not isNew

  TodoMVC reducer
    ✓ Should handle initial state
    ✓ Should handle ADD todo
    ✓ Should handle EDIT todo
    ✓ Should handle DELETE todo
    ✓ Should handle TOGGLE_COMPLETE_ONE todo
    ✓ Should handle TOGGLE_COMPLETE_ALL todo


  39 passing (112ms)

Commit changes.

$ git add .
$ git commit -m 'Footer component'

It should have a todo counter

Write the test.

diff --git a/tests/todomvc/components/Footer.spec.js b/tests/todomvc/components/Footer.spec.js
index f67c62d..869200a 100644
--- a/tests/todomvc/components/Footer.spec.js
+++ b/tests/todomvc/components/Footer.spec.js
@@ -6,9 +6,13 @@ import {shallow} from 'enzyme'

 import Footer from '../../../src/todomvc/components/Footer'

-function setup() {
+function setup(todos) {
+  const props = {
+    todos: todos
+  };
+
   const component = shallow(
-    <Footer/>
+    <Footer {...props} />
   );

   return {
@@ -22,6 +26,14 @@ describe('Footer component', () => {
       const {component} = setup();

       expect(component.type()).to.equal('footer')
+    });
+
+    it('Should have a todo counter', () => {
+      const {component} = setup();
+      const label = component.children('label');
+
+      expect(label.type()).to.equal('label');
+      expect(label.text()).to.equal('The number of todos not completed: ')
     })
   })
 });
(END)

Run the test and watch it fail.

  TodoMVC actions
    ✓ Should create an action to add a todo
    ✓ Should create an action to edit a todo
    ✓ Should create an action to delete a todo
    ✓ Should create an action to toggle a todo between completed and not completed
    ✓ Should create an action to toggle all todos between completed and not completed

  Footer component
    Should render correctly
      ✓ Should be a Footer
      1) Should have a todo counter

  Header component
    Should render correctly
      ✓ Should be a Header
      ✓ Should have a title
      ✓ Should have a TodoTextInput field
      ✓ Should have a toggle all complete status checkbox
    Should behave correctly
      ✓ Should call addTodo() if length of text is greater than 0
      ✓ Should call toggleCompleteAllTodos() when the all complete status checkbox is changed

  MainSection component
    Should render correctly
      ✓ Should be a MainSection component
      ✓ Should include a list of todos

  TodoApp component
    Should render correctly
      ✓ Should be a TodoApp
      ✓ Should have a header
      ✓ Should have a main section

  TodoItem component
    Should render correctly
      ✓ Should be an li
      ✓ Should have a label
      ✓ Should have a delete button
      ✓ Should have a toggle complete status checkbox
    Should behave correctly
      ✓ Should switch to edit mode when label onDoubleClick is fired
      ✓ Should call editTodo() when TodoTextInput onSave is called
      ✓ Should leave edit mode after TodoTextInput onSave
      ✓ Should call deleteTodo() when the delete button is clicked
      ✓ Should call deleteTodo() when TodoTextInput onSave is called with no text
      ✓ Should call toggleCompleteOneTodo() when the complete status checkbox is changed

  TodoTextInput component
    ✓ Should not call onSave() on blur if isNew
    Should render correctly
      ✓ Should be a TodoTextInput component
    Should behave correctly
      ✓ Should update value on change
      ✓ Should call onSave() on return key press
      ✓ Should reset state on return key press if isNew
      ✓ Should call onSave() on blur if not isNew

  TodoMVC reducer
    ✓ Should handle initial state
    ✓ Should handle ADD todo
    ✓ Should handle EDIT todo
    ✓ Should handle DELETE todo
    ✓ Should handle TOGGLE_COMPLETE_ONE todo
    ✓ Should handle TOGGLE_COMPLETE_ALL todo


  39 passing (110ms)
  1 failing

  1) Footer component Should render correctly Should have a todo counter:
     Error: Method “type” is only meant to be run on a single node. 0 found instead.
      at ShallowWrapper.single (node_modules/enzyme/build/ShallowWrapper.js:1516:17)
      at ShallowWrapper.type (node_modules/enzyme/build/ShallowWrapper.js:1110:21)
      at Context.<anonymous> (tests/todomvc/components/Footer.spec.js:31:20)

Write the code to make the test pass.

diff --git a/src/todomvc/components/Footer.js b/src/todomvc/components/Footer.js
index 8e5c5dd..43e0234 100644
--- a/src/todomvc/components/Footer.js
+++ b/src/todomvc/components/Footer.js
@@ -3,9 +3,16 @@
 import React, {Component} from 'react'

 export default class Footer extends Component {
+
+  static countNotCompleted(todos) {
+    if (typeof todos === "undefined") return ''
+  }
+
   render() {
     return (
-      <footer/>
+      <footer>
+        <label>The number of todos not completed: {Footer.countNotCompleted()}</label>
+      </footer>
     )
   }
 }
(END)

Run the test and watch it pass.

  TodoMVC actions
    ✓ Should create an action to add a todo
    ✓ Should create an action to edit a todo
    ✓ Should create an action to delete a todo
    ✓ Should create an action to toggle a todo between completed and not completed
    ✓ Should create an action to toggle all todos between completed and not completed

  Footer component
    Should render correctly
      ✓ Should be a Footer
      ✓ Should have a todo counter

  Header component
    Should render correctly
      ✓ Should be a Header
      ✓ Should have a title
      ✓ Should have a TodoTextInput field
      ✓ Should have a toggle all complete status checkbox
    Should behave correctly
      ✓ Should call addTodo() if length of text is greater than 0
      ✓ Should call toggleCompleteAllTodos() when the all complete status checkbox is changed

  MainSection component
    Should render correctly
      ✓ Should be a MainSection component
      ✓ Should include a list of todos

  TodoApp component
    Should render correctly
      ✓ Should be a TodoApp
      ✓ Should have a header
      ✓ Should have a main section

  TodoItem component
    Should render correctly
      ✓ Should be an li
      ✓ Should have a label
      ✓ Should have a delete button
      ✓ Should have a toggle complete status checkbox
    Should behave correctly
      ✓ Should switch to edit mode when label onDoubleClick is fired
      ✓ Should call editTodo() when TodoTextInput onSave is called
      ✓ Should leave edit mode after TodoTextInput onSave
      ✓ Should call deleteTodo() when the delete button is clicked
      ✓ Should call deleteTodo() when TodoTextInput onSave is called with no text
      ✓ Should call toggleCompleteOneTodo() when the complete status checkbox is changed

  TodoTextInput component
    ✓ Should not call onSave() on blur if isNew
    Should render correctly
      ✓ Should be a TodoTextInput component
    Should behave correctly
      ✓ Should update value on change
      ✓ Should call onSave() on return key press
      ✓ Should reset state on return key press if isNew
      ✓ Should call onSave() on blur if not isNew

  TodoMVC reducer
    ✓ Should handle initial state
    ✓ Should handle ADD todo
    ✓ Should handle EDIT todo
    ✓ Should handle DELETE todo
    ✓ Should handle TOGGLE_COMPLETE_ONE todo
    ✓ Should handle TOGGLE_COMPLETE_ALL todo


  40 passing (102ms)

Commit changes.

$ git add .
$ git commit -m 'have a todo counter'

Should behave correctly

It should display 'No todos left' when active count is 0

Write the test.

diff --git a/tests/todomvc/components/Footer.spec.js b/tests/todomvc/components/Footer.spec.js
index 869200a..78d81ae 100644
--- a/tests/todomvc/components/Footer.spec.js
+++ b/tests/todomvc/components/Footer.spec.js
@@ -1,6 +1,7 @@
 'use strict';

 import React from 'react'
+import {List} from 'immutable'
 import {expect} from 'chai'
 import {shallow} from 'enzyme'

@@ -34,6 +35,14 @@ describe('Footer component', () => {

       expect(label.type()).to.equal('label');
       expect(label.text()).to.equal('The number of todos not completed: ')
+    });
+
+    it('Should display \'No todos left\' when active count is 0', () => {
+      const {component} = setup(List([]));
+      const label = component.children('label');
+
+      expect(label.type()).to.equal('label');
+      expect(label.text()).to.equal('The number of todos not completed: No todos left')
     })
   })
 });
(END)

Run the test and watch it fail.

  TodoMVC actions
    ✓ Should create an action to add a todo
    ✓ Should create an action to edit a todo
    ✓ Should create an action to delete a todo
    ✓ Should create an action to toggle a todo between completed and not completed
    ✓ Should create an action to toggle all todos between completed and not completed

  Footer component
    Should render correctly
      ✓ Should be a Footer
      ✓ Should have a todo counter
      1) Should display 'No todos left' when active count is 0

  Header component
    Should render correctly
      ✓ Should be a Header
      ✓ Should have a title
      ✓ Should have a TodoTextInput field
      ✓ Should have a toggle all complete status checkbox
    Should behave correctly
      ✓ Should call addTodo() if length of text is greater than 0
      ✓ Should call toggleCompleteAllTodos() when the all complete status checkbox is changed

  MainSection component
    Should render correctly
      ✓ Should be a MainSection component
      ✓ Should include a list of todos

  TodoApp component
    Should render correctly
      ✓ Should be a TodoApp
      ✓ Should have a header
      ✓ Should have a main section

  TodoItem component
    Should render correctly
      ✓ Should be an li
      ✓ Should have a label
      ✓ Should have a delete button
      ✓ Should have a toggle complete status checkbox
    Should behave correctly
      ✓ Should switch to edit mode when label onDoubleClick is fired
      ✓ Should call editTodo() when TodoTextInput onSave is called
      ✓ Should leave edit mode after TodoTextInput onSave
      ✓ Should call deleteTodo() when the delete button is clicked
      ✓ Should call deleteTodo() when TodoTextInput onSave is called with no text
      ✓ Should call toggleCompleteOneTodo() when the complete status checkbox is changed

  TodoTextInput component
    ✓ Should not call onSave() on blur if isNew
    Should render correctly
      ✓ Should be a TodoTextInput component
    Should behave correctly
      ✓ Should update value on change
      ✓ Should call onSave() on return key press
      ✓ Should reset state on return key press if isNew
      ✓ Should call onSave() on blur if not isNew

  TodoMVC reducer
    ✓ Should handle initial state
    ✓ Should handle ADD todo
    ✓ Should handle EDIT todo
    ✓ Should handle DELETE todo
    ✓ Should handle TOGGLE_COMPLETE_ONE todo
    ✓ Should handle TOGGLE_COMPLETE_ALL todo


  40 passing (106ms)
  1 failing

  1) Footer component Should render correctly Should display 'No todos left' when active count is 0:

      AssertionError: expected 'The number of todos not completed: ' to equal 'The number of todos not completed: No todos left'
      + expected - actual

      -The number of todos not completed: 
      +The number of todos not completed: No todos left

      at Context.<anonymous> (tests/todomvc/components/Footer.spec.js:45:31)

Write the code to make the test pass.

diff --git a/src/todomvc/components/Footer.js b/src/todomvc/components/Footer.js
index 43e0234..61bf598 100644
--- a/src/todomvc/components/Footer.js
+++ b/src/todomvc/components/Footer.js
@@ -1,17 +1,24 @@
 'use strict';

 import React, {Component} from 'react'
+import PropTypes from 'prop-types'

 export default class Footer extends Component {
+  static propTypes = {
+    todos: PropTypes.object
+  };

   static countNotCompleted(todos) {
-    if (typeof todos === "undefined") return ''
+    if (typeof todos === "undefined") return '';
+    else if (todos.filter(todo => todo.get('completed') !== true).count() === 0) return 'No todos left'
   }

   render() {
+    const {todos} = this.props;
+
     return (
       <footer>
-        <label>The number of todos not completed: {Footer.countNotCompleted()}</label>
+        <label>The number of todos not completed: {Footer.countNotCompleted(todos)}</label>
       </footer>
     )
   }
(END)

Run the test and watch it pass.

  TodoMVC actions
    ✓ Should create an action to add a todo
    ✓ Should create an action to edit a todo
    ✓ Should create an action to delete a todo
    ✓ Should create an action to toggle a todo between completed and not completed
    ✓ Should create an action to toggle all todos between completed and not completed

  Footer component
    Should render correctly
      ✓ Should be a Footer
      ✓ Should have a todo counter
      ✓ Should display 'No todos left' when active count is 0

  Header component
    Should render correctly
      ✓ Should be a Header
      ✓ Should have a title
      ✓ Should have a TodoTextInput field
      ✓ Should have a toggle all complete status checkbox
    Should behave correctly
      ✓ Should call addTodo() if length of text is greater than 0
      ✓ Should call toggleCompleteAllTodos() when the all complete status checkbox is changed

  MainSection component
    Should render correctly
      ✓ Should be a MainSection component
      ✓ Should include a list of todos

  TodoApp component
    Should render correctly
      ✓ Should be a TodoApp
      ✓ Should have a header
      ✓ Should have a main section

  TodoItem component
    Should render correctly
      ✓ Should be an li
      ✓ Should have a label
      ✓ Should have a delete button
      ✓ Should have a toggle complete status checkbox
    Should behave correctly
      ✓ Should switch to edit mode when label onDoubleClick is fired
      ✓ Should call editTodo() when TodoTextInput onSave is called
      ✓ Should leave edit mode after TodoTextInput onSave
      ✓ Should call deleteTodo() when the delete button is clicked
      ✓ Should call deleteTodo() when TodoTextInput onSave is called with no text
      ✓ Should call toggleCompleteOneTodo() when the complete status checkbox is changed

  TodoTextInput component
    ✓ Should not call onSave() on blur if isNew
    Should render correctly
      ✓ Should be a TodoTextInput component
    Should behave correctly
      ✓ Should update value on change
      ✓ Should call onSave() on return key press
      ✓ Should reset state on return key press if isNew
      ✓ Should call onSave() on blur if not isNew

  TodoMVC reducer
    ✓ Should handle initial state
    ✓ Should handle ADD todo
    ✓ Should handle EDIT todo
    ✓ Should handle DELETE todo
    ✓ Should handle TOGGLE_COMPLETE_ONE todo
    ✓ Should handle TOGGLE_COMPLETE_ALL todo


  41 passing (98ms)

Commit changes.

$ git add .
$ git commit -m "display 'No todos left' when active count is 0"

It should display '1 todo left' when active count is 1

Write the test.

diff --git a/tests/todomvc/components/Footer.spec.js b/tests/todomvc/components/Footer.spec.js
index 78d81ae..e644a37 100644
--- a/tests/todomvc/components/Footer.spec.js
+++ b/tests/todomvc/components/Footer.spec.js
@@ -1,7 +1,8 @@
 'use strict';

 import React from 'react'
-import {List} from 'immutable'
+import {List, Map} from 'immutable'
+import uuid from 'uuid'
 import {expect} from 'chai'
 import {shallow} from 'enzyme'

@@ -43,6 +44,15 @@ describe('Footer component', () => {

       expect(label.type()).to.equal('label');
       expect(label.text()).to.equal('The number of todos not completed: No todos left')
+    });
+
+    it('Should display \'1 todo left\' when active count is 1', () => {
+      const todos = List([Map({id: uuid.v4(), description: 'todo 1', completed: false})]);
+      const {component} = setup(todos);
+      const label = component.children('label');
+
+      expect(label.type()).to.equal('label');
+      expect(label.text()).to.equal('The number of todos not completed: 1 todo left')
     })
   })
 });
(END)

Run the test and watch it fail.

  TodoMVC actions
    ✓ Should create an action to add a todo
    ✓ Should create an action to edit a todo
    ✓ Should create an action to delete a todo
    ✓ Should create an action to toggle a todo between completed and not completed
    ✓ Should create an action to toggle all todos between completed and not completed

  Footer component
    Should render correctly
      ✓ Should be a Footer
      ✓ Should have a todo counter
      ✓ Should display 'No todos left' when active count is 0
      1) Should display '1 todo left' when active count is 1

  Header component
    Should render correctly
      ✓ Should be a Header
      ✓ Should have a title
      ✓ Should have a TodoTextInput field
      ✓ Should have a toggle all complete status checkbox
    Should behave correctly
      ✓ Should call addTodo() if length of text is greater than 0
      ✓ Should call toggleCompleteAllTodos() when the all complete status checkbox is changed

  MainSection component
    Should render correctly
      ✓ Should be a MainSection component
      ✓ Should include a list of todos

  TodoApp component
    Should render correctly
      ✓ Should be a TodoApp
      ✓ Should have a header
      ✓ Should have a main section

  TodoItem component
    Should render correctly
      ✓ Should be an li
      ✓ Should have a label
      ✓ Should have a delete button
      ✓ Should have a toggle complete status checkbox
    Should behave correctly
      ✓ Should switch to edit mode when label onDoubleClick is fired
      ✓ Should call editTodo() when TodoTextInput onSave is called
      ✓ Should leave edit mode after TodoTextInput onSave
      ✓ Should call deleteTodo() when the delete button is clicked
      ✓ Should call deleteTodo() when TodoTextInput onSave is called with no text
      ✓ Should call toggleCompleteOneTodo() when the complete status checkbox is changed

  TodoTextInput component
    ✓ Should not call onSave() on blur if isNew
    Should render correctly
      ✓ Should be a TodoTextInput component
    Should behave correctly
      ✓ Should update value on change
      ✓ Should call onSave() on return key press
      ✓ Should reset state on return key press if isNew
      ✓ Should call onSave() on blur if not isNew

  TodoMVC reducer
    ✓ Should handle initial state
    ✓ Should handle ADD todo
    ✓ Should handle EDIT todo
    ✓ Should handle DELETE todo
    ✓ Should handle TOGGLE_COMPLETE_ONE todo
    ✓ Should handle TOGGLE_COMPLETE_ALL todo


  41 passing (107ms)
  1 failing

  1) Footer component Should render correctly Should display '1 todo left' when active count is 1:

      AssertionError: expected 'The number of todos not completed: ' to equal 'The number of todos not completed: 1 todo left'
      + expected - actual

      -The number of todos not completed: 
      +The number of todos not completed: 1 todo left

      at Context.<anonymous> (tests/todomvc/components/Footer.spec.js:55:31)

Write the code to make the test pass.

diff --git a/src/todomvc/components/Footer.js b/src/todomvc/components/Footer.js
index d19e5c2..7a4587d 100644
--- a/src/todomvc/components/Footer.js
+++ b/src/todomvc/components/Footer.js
@@ -11,6 +11,7 @@ export default class Footer extends Component {
   static countNotCompleted(todos) {
     if (typeof todos === "undefined") return ''
-    else if (todos.filter(todo => todo.get('completed') !== true).count() === 0) return 'No todos left'
+    else if (todos.filter(todo => todo.get('completed') !== true).count() === 0) return 'No todos left';
+    else if (todos.filter(todo => todo.get('completed') !== true).count() === 1) return '1 todo left'
   }

   render() {
(END)

Run the test and watch it pass.

  TodoMVC actions
    ✓ Should create an action to add a todo
    ✓ Should create an action to edit a todo
    ✓ Should create an action to delete a todo
    ✓ Should create an action to toggle a todo between completed and not completed
    ✓ Should create an action to toggle all todos between completed and not completed

  Footer component
    Should render correctly
      ✓ Should be a Footer
      ✓ Should have a todo counter
      ✓ Should display 'No todos left' when active count is 0
      ✓ Should display '1 todo left' when active count is 1

  Header component
    Should render correctly
      ✓ Should be a Header
      ✓ Should have a title
      ✓ Should have a TodoTextInput field
      ✓ Should have a toggle all complete status checkbox
    Should behave correctly
      ✓ Should call addTodo() if length of text is greater than 0
      ✓ Should call toggleCompleteAllTodos() when the all complete status checkbox is changed

  MainSection component
    Should render correctly
      ✓ Should be a MainSection component
      ✓ Should include a list of todos

  TodoApp component
    Should render correctly
      ✓ Should be a TodoApp
      ✓ Should have a header
      ✓ Should have a main section

  TodoItem component
    Should render correctly
      ✓ Should be an li
      ✓ Should have a label
      ✓ Should have a delete button
      ✓ Should have a toggle complete status checkbox
    Should behave correctly
      ✓ Should switch to edit mode when label onDoubleClick is fired
      ✓ Should call editTodo() when TodoTextInput onSave is called
      ✓ Should leave edit mode after TodoTextInput onSave
      ✓ Should call deleteTodo() when the delete button is clicked
      ✓ Should call deleteTodo() when TodoTextInput onSave is called with no text
      ✓ Should call toggleCompleteOneTodo() when the complete status checkbox is changed

  TodoTextInput component
    ✓ Should not call onSave() on blur if isNew
    Should render correctly
      ✓ Should be a TodoTextInput component
    Should behave correctly
      ✓ Should update value on change
      ✓ Should call onSave() on return key press
      ✓ Should reset state on return key press if isNew
      ✓ Should call onSave() on blur if not isNew

  TodoMVC reducer
    ✓ Should handle initial state
    ✓ Should handle ADD todo
    ✓ Should handle EDIT todo
    ✓ Should handle DELETE todo
    ✓ Should handle TOGGLE_COMPLETE_ONE todo
    ✓ Should handle TOGGLE_COMPLETE_ALL todo


  42 passing (107ms)

Commit changes.

$ git add .
$ git commit -m "display '1 todo left' when active count is 1"

It should display '5 todos left' when active count is 5

Five is used randomly here. It can be any other integer greater than one.

Write the test.

diff --git a/tests/todomvc/components/Footer.spec.js b/tests/todomvc/components/Footer.spec.js
index e644a37..5ab9f94 100644
--- a/tests/todomvc/components/Footer.spec.js
+++ b/tests/todomvc/components/Footer.spec.js
@@ -53,6 +53,21 @@ describe('Footer component', () => {

       expect(label.type()).to.equal('label');
       expect(label.text()).to.equal('The number of todos not completed: 1 todo left')
+    });
+
+    it('Should display \'5 todos left\' when active count is 5', () => {
+      const todos = List([
+        Map({id: uuid.v4(), description: 'todo 1', completed: false}),
+        Map({id: uuid.v4(), description: 'todo 2', completed: false}),
+        Map({id: uuid.v4(), description: 'todo 3', completed: false}),
+        Map({id: uuid.v4(), description: 'todo 4', completed: false}),
+        Map({id: uuid.v4(), description: 'todo 5', completed: false})
+      ]);
+      const {component} = setup(todos);
+      const label = component.children('label');
+
+      expect(label.type()).to.equal('label');
+      expect(label.text()).to.equal('The number of todos not completed: 5 todos left')
     })
   })
 });
(END)

Run the test and watch it fail.

  TodoMVC actions
    ✓ Should create an action to add a todo
    ✓ Should create an action to edit a todo
    ✓ Should create an action to delete a todo
    ✓ Should create an action to toggle a todo between completed and not completed
    ✓ Should create an action to toggle all todos between completed and not completed

  Footer component
    Should render correctly
      ✓ Should be a Footer
      ✓ Should have a todo counter
      ✓ Should display 'No todos left' when active count is 0
      ✓ Should display '1 todo left' when active count is 1
      1) Should display '5 todos left' when active count is 5

  Header component
    Should render correctly
      ✓ Should be a Header
      ✓ Should have a title
      ✓ Should have a TodoTextInput field
      ✓ Should have a toggle all complete status checkbox
    Should behave correctly
      ✓ Should call addTodo() if length of text is greater than 0
      ✓ Should call toggleCompleteAllTodos() when the all complete status checkbox is changed

  MainSection component
    Should render correctly
      ✓ Should be a MainSection component
      ✓ Should include a list of todos

  TodoApp component
    Should render correctly
      ✓ Should be a TodoApp
      ✓ Should have a header
      ✓ Should have a main section

  TodoItem component
    Should render correctly
      ✓ Should be an li
      ✓ Should have a label
      ✓ Should have a delete button
      ✓ Should have a toggle complete status checkbox
    Should behave correctly
      ✓ Should switch to edit mode when label onDoubleClick is fired
      ✓ Should call editTodo() when TodoTextInput onSave is called
      ✓ Should leave edit mode after TodoTextInput onSave
      ✓ Should call deleteTodo() when the delete button is clicked
      ✓ Should call deleteTodo() when TodoTextInput onSave is called with no text
      ✓ Should call toggleCompleteOneTodo() when the complete status checkbox is changed

  TodoTextInput component
    ✓ Should not call onSave() on blur if isNew
    Should render correctly
      ✓ Should be a TodoTextInput component
    Should behave correctly
      ✓ Should update value on change
      ✓ Should call onSave() on return key press
      ✓ Should reset state on return key press if isNew
      ✓ Should call onSave() on blur if not isNew

  TodoMVC reducer
    ✓ Should handle initial state
    ✓ Should handle ADD todo
    ✓ Should handle EDIT todo
    ✓ Should handle DELETE todo
    ✓ Should handle TOGGLE_COMPLETE_ONE todo
    ✓ Should handle TOGGLE_COMPLETE_ALL todo


  42 passing (116ms)
  1 failing

  1) Footer component Should render correctly Should display '5 todos left' when active count is 5:

      AssertionError: expected 'The number of todos not completed: ' to equal 'The number of todos not completed: 5 todos left'
      + expected - actual

      -The number of todos not completed: 
      +The number of todos not completed: 5 todos left

      at Context.<anonymous> (tests/todomvc/components/Footer.spec.js:70:31)

Write the code to make the test pass.

diff --git a/src/todomvc/components/Footer.js b/src/todomvc/components/Footer.js
index 45431f4..2b54275 100644
--- a/src/todomvc/components/Footer.js
+++ b/src/todomvc/components/Footer.js
@@ -11,7 +11,8 @@ export default class Footer extends Component {
   static countNotCompleted(todos) {
     if (typeof todos === "undefined") return '';
     else if (todos.filter(todo => todo.get('completed') !== true).count() === 0) return 'No todos left';
-    else if (todos.filter(todo => todo.get('completed') !== true).count() === 1) return '1 todo left'
+    else if (todos.filter(todo => todo.get('completed') !== true).count() === 1) return '1 todo left';
+    else return `${todos.filter(todo => todo.get('completed') !== true).count()} todos left`
   }

   render() {
(END)

Run the test and watch it pass.

  TodoMVC actions
    ✓ Should create an action to add a todo
    ✓ Should create an action to edit a todo
    ✓ Should create an action to delete a todo
    ✓ Should create an action to toggle a todo between completed and not completed
    ✓ Should create an action to toggle all todos between completed and not completed

  Footer component
    Should render correctly
      ✓ Should be a Footer
      ✓ Should have a todo counter
      ✓ Should display 'No todos left' when active count is 0
      ✓ Should display '1 todo left' when active count is 1
      ✓ Should display '5 todos left' when active count is 5

  Header component
    Should render correctly
      ✓ Should be a Header
      ✓ Should have a title
      ✓ Should have a TodoTextInput field
      ✓ Should have a toggle all complete status checkbox
    Should behave correctly
      ✓ Should call addTodo() if length of text is greater than 0
      ✓ Should call toggleCompleteAllTodos() when the all complete status checkbox is changed

  MainSection component
    Should render correctly
      ✓ Should be a MainSection component
      ✓ Should include a list of todos

  TodoApp component
    Should render correctly
      ✓ Should be a TodoApp
      ✓ Should have a header
      ✓ Should have a main section

  TodoItem component
    Should render correctly
      ✓ Should be an li
      ✓ Should have a label
      ✓ Should have a delete button
      ✓ Should have a toggle complete status checkbox
    Should behave correctly
      ✓ Should switch to edit mode when label onDoubleClick is fired
      ✓ Should call editTodo() when TodoTextInput onSave is called
      ✓ Should leave edit mode after TodoTextInput onSave
      ✓ Should call deleteTodo() when the delete button is clicked
      ✓ Should call deleteTodo() when TodoTextInput onSave is called with no text
      ✓ Should call toggleCompleteOneTodo() when the complete status checkbox is changed

  TodoTextInput component
    ✓ Should not call onSave() on blur if isNew
    Should render correctly
      ✓ Should be a TodoTextInput component
    Should behave correctly
      ✓ Should update value on change
      ✓ Should call onSave() on return key press
      ✓ Should reset state on return key press if isNew
      ✓ Should call onSave() on blur if not isNew

  TodoMVC reducer
    ✓ Should handle initial state
    ✓ Should handle ADD todo
    ✓ Should handle EDIT todo
    ✓ Should handle DELETE todo
    ✓ Should handle TOGGLE_COMPLETE_ONE todo
    ✓ Should handle TOGGLE_COMPLETE_ALL todo


  43 passing (111ms)

Commit changes.

$ git add .
$ git commit -m "display '5 todos left' when active count is 5"

MainSection component

Should render correctly

Write the test.

diff --git a/tests/todomvc/components/MainSection.spec.js b/tests/todomvc/components/MainSection.spec.js
index d69e408..9ffc1de 100644
--- a/tests/todomvc/components/MainSection.spec.js
+++ b/tests/todomvc/components/MainSection.spec.js
@@ -52,6 +52,13 @@ describe('MainSection component', () => {
         expect(item.type()).to.equal(TodoItem);
         expect(item.props().todo).to.equal(props.todos.get(i))
       })
+    });
+
+    it('Should include a Footer component', () => {
+      const {component} = setup();
+      const footer = component.children('Footer');
+
+      expect(footer).to.have.length(1);
     })
   })
 });
(END)

Run the test and watch it fail.

  TodoMVC actions
    ✓ Should create an action to add a todo
    ✓ Should create an action to edit a todo
    ✓ Should create an action to delete a todo
    ✓ Should create an action to toggle a todo between completed and not completed
    ✓ Should create an action to toggle all todos between completed and not completed

  Footer component
    Should render correctly
      ✓ Should be a Footer
      ✓ Should have a todo counter
      ✓ Should display 'No todos left' when active count is 0
      ✓ Should display '1 todo left' when active count is 1
      ✓ Should display '5 todos left' when active count is 5

  Header component
    Should render correctly
      ✓ Should be a Header
      ✓ Should have a title
      ✓ Should have a TodoTextInput field
      ✓ Should have a toggle all complete status checkbox
    Should behave correctly
      ✓ Should call addTodo() if length of text is greater than 0
      ✓ Should call toggleCompleteAllTodos() when the all complete status checkbox is changed

  MainSection component
    Should render correctly
      ✓ Should be a MainSection component
      ✓ Should include a list of todos
      1) Should include a Footer component

  TodoApp component
    Should render correctly
      ✓ Should be a TodoApp
      ✓ Should have a header
      ✓ Should have a main section

  TodoItem component
    Should render correctly
      ✓ Should be an li
      ✓ Should have a label
      ✓ Should have a delete button
      ✓ Should have a toggle complete status checkbox
    Should behave correctly
      ✓ Should switch to edit mode when label onDoubleClick is fired
      ✓ Should call editTodo() when TodoTextInput onSave is called
      ✓ Should leave edit mode after TodoTextInput onSave
      ✓ Should call deleteTodo() when the delete button is clicked
      ✓ Should call deleteTodo() when TodoTextInput onSave is called with no text
      ✓ Should call toggleCompleteOneTodo() when the complete status checkbox is changed

  TodoTextInput component
    ✓ Should not call onSave() on blur if isNew
    Should render correctly
      ✓ Should be a TodoTextInput component
    Should behave correctly
      ✓ Should update value on change
      ✓ Should call onSave() on return key press
      ✓ Should reset state on return key press if isNew
      ✓ Should call onSave() on blur if not isNew

  TodoMVC reducer
    ✓ Should handle initial state
    ✓ Should handle ADD todo
    ✓ Should handle EDIT todo
    ✓ Should handle DELETE todo
    ✓ Should handle TOGGLE_COMPLETE_ONE todo
    ✓ Should handle TOGGLE_COMPLETE_ALL todo


  43 passing (126ms)
  1 failing

  1) MainSection component Should render correctly Should include a Footer component:

      AssertionError: expected { Object (root, unrendered, ...) } to have a length of 1 but got 0
      + expected - actual

      -0
      +1

      at Context.<anonymous> (tests/todomvc/components/MainSection.spec.js:61:30)

Write the code to make the test pass.

diff --git a/src/todomvc/components/MainSection.js b/src/todomvc/components/MainSection.js
index b4248af..5a40455 100644
--- a/src/todomvc/components/MainSection.js
+++ b/src/todomvc/components/MainSection.js
@@ -4,6 +4,7 @@ import React, {Component} from 'react'
 import PropTypes from 'prop-types'

 import TodoItem from './TodoItem'
+import Footer from "./Footer";

 export default class MainSection extends Component {
   static propTypes = {
@@ -19,6 +20,7 @@ export default class MainSection extends Component {
         <ul>
           {todos.map(todo => <TodoItem key={todo.get('id')} todo={todo} {...actions} />)}
         </ul>
+        <Footer todos={todos}/>
       </section>
     )
   }
(END)

Run the test and watch it pass.

  TodoMVC actions
    ✓ Should create an action to add a todo
    ✓ Should create an action to edit a todo
    ✓ Should create an action to delete a todo
    ✓ Should create an action to toggle a todo between completed and not completed
    ✓ Should create an action to toggle all todos between completed and not completed

  Footer component
    Should render correctly
      ✓ Should be a Footer
      ✓ Should have a todo counter
      ✓ Should display 'No todos left' when active count is 0
      ✓ Should display '1 todo left' when active count is 1
      ✓ Should display '5 todos left' when active count is 5

  Header component
    Should render correctly
      ✓ Should be a Header
      ✓ Should have a title
      ✓ Should have a TodoTextInput field
      ✓ Should have a toggle all complete status checkbox
    Should behave correctly
      ✓ Should call addTodo() if length of text is greater than 0
      ✓ Should call toggleCompleteAllTodos() when the all complete status checkbox is changed

  MainSection component
    Should render correctly
      ✓ Should be a MainSection component
      ✓ Should include a list of todos
      ✓ Should include a Footer component

  TodoApp component
    Should render correctly
      ✓ Should be a TodoApp
      ✓ Should have a header
      ✓ Should have a main section

  TodoItem component
    Should render correctly
      ✓ Should be an li
      ✓ Should have a label
      ✓ Should have a delete button
      ✓ Should have a toggle complete status checkbox
    Should behave correctly
      ✓ Should switch to edit mode when label onDoubleClick is fired
      ✓ Should call editTodo() when TodoTextInput onSave is called
      ✓ Should leave edit mode after TodoTextInput onSave
      ✓ Should call deleteTodo() when the delete button is clicked
      ✓ Should call deleteTodo() when TodoTextInput onSave is called with no text
      ✓ Should call toggleCompleteOneTodo() when the complete status checkbox is changed

  TodoTextInput component
    ✓ Should not call onSave() on blur if isNew
    Should render correctly
      ✓ Should be a TodoTextInput component
    Should behave correctly
      ✓ Should update value on change
      ✓ Should call onSave() on return key press
      ✓ Should reset state on return key press if isNew
      ✓ Should call onSave() on blur if not isNew

  TodoMVC reducer
    ✓ Should handle initial state
    ✓ Should handle ADD todo
    ✓ Should handle EDIT todo
    ✓ Should handle DELETE todo
    ✓ Should handle TOGGLE_COMPLETE_ONE todo
    ✓ Should handle TOGGLE_COMPLETE_ALL todo


  44 passing (109ms)

Commit changes.

$ git add .
$ git commit -m "have a Footer component"

Run It!

Now let's see what this looks like.

Open http://localhost:4000 in your web browser.

You should immediately see the 'The number of todos not completed: No todos left' message.

Add a todo and see the message change to 'The number of todos not completed: 1 todo left'.

Add some more todos and set their completed status. See the message change accordingly.

Last updated

Was this helpful?