Unit Test Your JavaScript Code Without a Framework

Amit Gupta
JavaScript in Plain English
6 min readMay 1, 2020

--

Lately, I am learning to write more and more of my JavaScript code without the help of any library or framework. I like to have a good unit test coverage for any code I write because that gives me confidence whenever I want to refactor my code or change it for any other reason. In this blog post, I have demonstrated how I went about writing unit tests without any framework.

We will start by creating two files:

  • test.js contains the test functions assert and it that we need for testing. It also contains all the unit tests.
  • test.html is the test runner.

Test Functions

Let’s first create a test.js file and write the it function as shown below

The it function takes two parameters. First parameter desc is the description of the test case and second parameter fn is the test function. fn is encapsulated in a try/catch block. If fn executes successfully then we show the success message in the console and if the test fails then we show the fail message in the console.

Next, we implement the assert function in test.js.

assert function takes one parameter isTrue which is a condition such as
x === y. assert checks the condition and throws an error if the condition is false.

That’s it. That’s our entire testing framework.

Test Runner

test.html is our test runner that includes the test.js file.

Simple Test Cases to Test the Framework

Let us make sure our test framework is working as intended by writing a couple of simple tests.

Failing Test

Write the following test case after the assert function in test.js

it('should fail', function() {
assert(1 !== 1);
});

Open the test runner file test.html in a browser (preferably Chrome). Open the browser console. You should see a failure message in the console like below

Sample Test Fail Message

Since 1 !== 1 is an invalid condition, the test fails. You get an idea of where the failure occurred by looking at the error stack. In this case, I would check line 26 in my test.js to start debugging the issue.

Passing Test

Now let us write a small passing test in test.js.

it('should pass', function() {
assert(1 === 1);
});

Refresh test.html in the browser and inspect the console. You should see a success message in the console like below

Great! Our test framework seems to be working fine. Now, let us use our test framework for some real world scenarios.

Create Application Code File

Typically, you will be writing your application code in a separate JavaScript file such as app.js. Let us create app.js file

                           /* app.js */(function(){
'use strict';
//Create a global variable and expose it to the world
var $myapp = {};
self.$myapp = $myapp;
})();

We created a global variable $myapp and exposed it to the world so that we can call this global variable from test.js file. Always use a unique name for your global variable so that it does not clash with other global variables.

Now let us include app.js file in test.html like below

                           /* test.html */
...
<body>
...
<script src="app.js"></script>
<script src="test.js"></script>
</body>

Make sure that app.js is included before test.js

Test a Method in Application Code

Let us write a date validation method in our app.js file

isValidDate determines if a given date string is valid and return a true or false.

Now, let us write a test case for this method in our test.js

//test.js...
it('should validate a date string', function () {
// Valid Date
assert($myapp.isValidDate('02/02/2020'));
// Invalid Date
assert(!$myapp.isValidDate('01/32/2020'));
});
...

In the above test case, first assert checks for a valid date string and the second assert checks for an invalid date string. Open or refresh test.html test runner file and check the console. You should see a message like below

Test DOM

Let’s say we are writing a simple todo list application. We have a form with an input field to enter a todo item and a submit button. We listen to the submit event in our app.js file and the event handler updates the todo list in the DOM.

Here is the html code

Following is the JavaScript code in app.js that updates the todo list.

We want to test the JavaScript code and make sure it adds a todo item to the #todo-list unordered list element in the DOM as expected.

Test Case for DOM

Following is the test case to check the event handler code to make sure it updates the DOM when a new todo item is entered

In our test.html we had created a placeholder element <div id="selector"></div> to insert test code in our test runner’s DOM.

In the test case, var selector = document.querySelector('#selector') gets a reference to our placeholder element. Then we append the selector with the form that has an id aform. We have to make sure that all the element names and ids are same as expected by the event handler in app.js.

Following line sets the value of the input field

form.elements['todo-input'].value = 'task 1'

Then we create and initialize a ‘submit’ HTML event, and have our form dispatch the event

form.dispatchEvent(ev)

This will trigger the event handler in app.js file that is listening to the ‘submit’ event. The event handler will add ‘task 1’ to the todo-input HTML list.

Following line of code asserts to check if a task was added to the HTML list as expected.

assert(selector.innerHTML.toLowerCase().includes('<li>task 1</li>'));

Run the test runner in a browser and check the browser console. You should see the following success message if everything went as expected.

The final line in the test case selector.innerHTML = '' clears up the placeholder element.

Testing when Asynchronous Function is Involved

Let’s say we are making a REST API call to get a user’s first name and last name, which then gets rendered to the DOM. We want to test if the DOM gets successfully rendered without actually making the API call.

Following is the code that we would like to test

$myapp.get method encapsulates an XMLHttpRequest GET request. It takes a string url parameter and calls the callback function with response.

$myapp.getUser is the method we want to test. It calls $myapp.get method and then the callback function renders the DOM with the user’s first name and last name.

Stub the Asynchronous Code

As shown above, we stub the asynchronous $myapp.get method and return a fake user object.

We call $myapp.getUser(1) method. This should successfully execute the stubbed $myapp.get method and render the user’s first and last name as defined in the stub.

The following code asserts to see if our test DOM was updated with proper first and last name.

assert(selector.innerHTML.includes('Amit Gupta'))

Finally we clear out the placeholder DOM object by resetting its innerHTML.

Summary

This blog post showed how you can unit test your front end JavaScript code without using any framework. The blog showed

  • How to create it and assert test functions
  • How to unit test application functions
  • How to unit test the DOM
  • How to unit test when asynchronous calls are involved

This is a simple and practical way to unit test front end JavaScript code in the browser.

Source Code

The source with sample tests is hosted on GitHub.

A note from JavaScript In Plain English

We are always interested in helping to promote quality content. If you have an article that you would like to submit to any of our publications, send us an email at submissions@plainenglish.io with your Medium username and we will get you added as a writer.

--

--