DEV Community

Clark
Clark

Posted on • Edited on

Use Jest write unit testing for DOM manipulation

Hello I am Clark! Today we're gonna write test case of unit testing for DOM manipulation.

If we have a piece code of HTML and JavaScript in one index.html file, this is a todo list:



<html>
  <body>
    <input id="newTodo" />
    <button onclick="addTodo()">Add todo</button>
    <ol id="todoList"></ol>
    <script>
      const addTodo = () => {
        const newTodoInput = document.getElementById('newTodo');
        let currentTodoList = document.getElementById('todoList').innerHTML;
        currentTodoList += `<li>${newTodoInput.value}</li>`;
        document.getElementById('todoList').innerHTML = currentTodoList;
        newTodoInput.value = '';
      }
    </script>
  </body>
</html>


Enter fullscreen mode Exit fullscreen mode

Umm...this todo list give people quite don't know how to write test case, because this code confuse DOM with logic of JavaScript, so first of all, we should would logic of control todo list disassemble from index.html:



<html>
  <body>
    <input id="newTodo" />
    <button id="addTodo">Add todo</button>
    <ol id="todoList"></ol>

    <script type="text/javascript" src="./todolist.js"></script>
  </body>
</html>


Enter fullscreen mode Exit fullscreen mode

About logic of todo list move to todoList.js file:



const addTodo = () => {
  const newTodoInput = document.getElementById('newTodo');
  let currentTodoList = document.getElementById('todoList').innerHTML;
  currentTodoList += `<li>${newTodoInput.value}</li>`;
  document.getElementById('todoList').innerHTML = currentTodoList;
  newTodoInput.value = '';
}

document.getElementById('addTodo').addEventListener('click', addTodo);


Enter fullscreen mode Exit fullscreen mode

Right now, view is view, logic is logic, so we can very easy to write test case for JavaScript, but...we no have DOM, how to trigger addTodo? yes! so we must ready DOM for test case of addTodo!

As mention document of Jest:

Jest ships with jsdom which simulates a DOM environment as if you were in the browser. This means that every DOM API that we call can be observed in the same way it would be observed in a browser!

So we can very easy to simulates a DOM environment when use Jest, get start install Jest and write test case!

Install Jest in project(If you have no npm or NodeJS environment, must download Node when before start):



npm install jest


Enter fullscreen mode Exit fullscreen mode

Next, we add file todoList.test.js and write a test case:



test('Check addTodo able add todo to todoList', () => {

});


Enter fullscreen mode Exit fullscreen mode

Like above name of test case, I want test function addTodo can be real add todo to todoList.

I’ve divided write test case into three parts:

  1. We have to find out which elements is addTodo need? let's look at todoList.js,first we need a button of id is addTodo, we will would add click event of addTodo for it, also need a input of id is newTodo, last we need a ol of id is todoList to display todo list.

    Yes! just three elements is addTodo need! we don't care other elements in the HTML file, we just only prepare those for test case:



test('Check addTodo able add todo to todoList', () => {
  document.body.innerHTML = `
    <input id="newTodoInput" />
    <button id="addTodoBtn">Add todo</button>
    <ol id="todoList"></ol>
  `;
});


Enter fullscreen mode Exit fullscreen mode
  1. Use require import todoList.js file add logic to elements of readied, it have logic of addTodo, it is we target of test in test case too:


test('Check addTodo able add todo to todoList', () => {
  document.body.innerHTML = `
    <input id="newTodoInput" />
    <button id="addTodoBtn">Add todo</button>
    <ol id="todoList"></ol>
  `;
  require('../todolist.js');
});


Enter fullscreen mode Exit fullscreen mode
  1. Use selector get element, write new todo name input and trigger addTodo by button, then check if innerHTML of ol correct add new todo!


test('Check addTodo able add todo to todoList', () => {
  document.body.innerHTML = `
    <input id="newTodoInput" />
    <button id="addTodoBtn">Add todo</button>
    <ol id="todoList"></ol>
  `;
  require('../todolist.js');

  const newTodoInput = document.getElementById('newTodoInput');
  const addTodoBtn = document.getElementById('addTodoBtn');
  const todolist = document.getElementById('todoList');

  newTodoInput.value = 'New todolist!';
  addTodoBtn.click();

  expect(todolist.innerHTML).toBe('<li>New todolist!</li>');
});


Enter fullscreen mode Exit fullscreen mode

Now we're finish first test case for todoList.js! let's execute test check if logic correct:

Alt Text

Thanks guys for reading this post, if you have any question or find out ant wrong in the post, please submit discussion for me! 😃

On the other hand, this post simultaneous publish to my blog: Jest | Use Jest write unit testing for DOM manipulation

Top comments (10)

Collapse
 
christianotieno profile image
Christian Otieno

We have a typo on npm install jest

Collapse
 
datajango profile image
Anthony Leotta • Edited

is there any way to unit test the following? addTodo is not found.

document.body.innerHTML =
<input id="newTodoInput" />
<button id="addTodoBtn" onclick="addTodo()">Add todo</button>
<ol id="todoList"></ol>
;

I wrote this:

test('Check addTodo able add todo to todoList', () => {
document.body.innerHTML =
<input id="newTodoInput" />
<button id="addTodoBtn">Add todo</button>
<ol id="todoList"></ol>
;

const newTodoInput = document.getElementById('newTodoInput');
const addTodoBtn = document.getElementById('addTodoBtn');
addTodoBtn.addEventListener('click', addTodo);
const todolist = document.getElementById('todoList');
newTodoInput.value = 'New todolist!';
addTodoBtn.click();
expect(todolist.innerHTML).toBe('<li>New todolist!</li>');
});

which does work.

Collapse
 
christianotieno profile image
Christian Otieno

Good read actually.

Collapse
 
ms314006 profile image
Clark

Thank you for you read this article!

Collapse
 
macarcillar profile image
markangel • Edited

Check the "newTodo" and "addToDo" ID. It's not the same with the test file.

Btw, thank you for this.

Collapse
 
martreyz profile image
Marta Rey

You just saved my life <3

Collapse
 
ajinkyax profile image
Ajinkya Borade

I tried added style to this innerHtml doesnt work.

Collapse
 
joset98 profile image
joset98

Thank you for this post, you save my life pal, blessings

Collapse
 
jssapphire profile image
js-sapphire

When we access document object inside a test, what exactly is that? When we do an appendElement or whichever DOM API, what happens? Is it a virtual DOM?

Some comments may only be visible to logged-in visitors. Sign in to view all comments.