DEV Community

loading...
Cover image for TDD & Automated Testing in JavaScript using Jest

TDD & Automated Testing in JavaScript using Jest

dverybest profile image Charles Best ・6 min read

TDD (Test Driven Development), automated testing, unit test, integration test, are some of the popular keywords you find in recent software development job descriptions/requirements, most especially JavaScript (react, react-native, nodejs) related jobs.

In this article, I will explain how to get started on writing automated test in JavaScript using Jest.

JEST

As stated in their official landing page

Jest is a delightful JavaScript Testing Framework with a focus on simplicity.

Jest is one of the most popular JavaScript testing framework and can be used to write automated test for almost everything JavaScript. It is easy to understand and get started with.

Before we dive into writing codes, I will explain some important concepts

Automated Testing

Automated testing or test automation is a method in software testing that makes use of special software tools to control the execution of tests and then compares actual test results with predicted or expected results.

Simply put it is a way of testing our code(software) in other to compare the actual test results with predicted or expected results without manually going through the code.

This help ensure our code is bug-free at all point as tests will fail if bug is introduce to the code at any point.

Automated testing can be broken into two main types namely: unit tests and integration tests.

Unit tests simulate all possible outputs of a single function or component, given various inputs. They mock all external function calls in order to achieve a pure test of only that one function's logic.
Integration tests check to make sure that various functions or components are working together properly.

Now having understand these concepts, let dive in writing test codes.

Set-Up

You need to already have nodeJs installed/setup to follow along.

  1. Create a new folder "test_master_class"
  2. On your terminal cd into "test_master_class" and run the command npm init to scaffold package.json. Enter "jest" when asked for "test command" during scaffolding.
  3. Run npm install --save-dev jest to install jest as a dev dependency.
  4. Finally open your folder in your favorite editor.

Alt vs code showing package.json

Now to write our first test code, which will be a very simple demo, inside your working folder, create a folder named "test" and inside the folder create a file named "index.test.js" and add the following code


to run the test, on your terminal type npm testand press enter; and you would get the follow output
User@CharlesBest MINGW32 ~/Documents/MyJavaScript/test_master_class
$ npm test
> test_master_class@1.0.0 test C:\Users\User\Documents\MyJavaScript\test_master_class
> jest

PASS test/index.test.js
  test to see if test enviroment is properly set up
    √ test hello word (4 ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        5.842 s
Ran all test suites.
Enter fullscreen mode Exit fullscreen mode

From the code above in "index.test.js", describe is a global function from jest. It takes two main arguments, first a string that describes the tests to be contained in the describe block and the second argument is an an anonymous function containing the actual tests to be done. One of the main functions of the describe function is to group related test together. Similarly, test is also a global function from jest, it contains the actual test to be done. Also expect is a global function from jest, it takes the actual test result and compare it to an expected output contained in matchers like toBe.

A comprehensive list of other matchers like toBe, toEqual, toBeTruthy, etc. and their functions can be found on the documentation.

Now that we are clear with the basics of testing using jest, lets write unit and integration test for real scenarios.

Getting Real

Scenario: Let's build a simple calculator system, this system should be able to increment and decrement a counter with a given number, get the current value of the counter after each operation and the time taken to perform each operation, we should be able to reset the value of the count.

Solution: if we are to follow TDD principles, we are expect to write test first before the actual code.

In our test folder create a file named "calculator_service.test.js" and add the following code and run the test on the terminal using npm test



we get the output below

PASS test/index.test.js (6.212 s)
FAIL test/calculator_service.test.js
  ● Test suite failed to run
    Cannot find module '../service/calculator' from 'test/calculator_service.test.js'
    > 1 | const {add,subtract,getTime} = require('../service/calculator');
        |                                ^
      2 |
      3 | describe('test to see if functions are defined', () => {
      4 |

      at Resolver.resolveModule (node_modules/jest-resolve/build/index.js:306:11)
      at Object.<anonymous> (test/calculator_service.test.js:1:32)

Test Suites: 1 failed, 1 passed, 2 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        40.271 s
Ran all test suites.
npm ERR! Test failed.  See above for more details.

Enter fullscreen mode Exit fullscreen mode

an error occurs making the test in "calculator_service.test.js" not to run and this is normal as "../service/calculator" we required does not exist yet.

In the root folder, create a folder "service", inside the folder add a new file "calculator.js" and run the test again, this time we get the below output

PASS test/index.test.js
FAIL test/calculator_service.test.js
  ● test to see if functions are defined › test add function
    expect(received).not.toBeUndefined()
    Received: undefined
      4 |
      5 |     test("test add function", () => {
    > 6 |         expect(add).not.toBeUndefined()
        |                         ^
      7 |     })
      8 |
      9 |     test("test add function", () => {
      at Object.<anonymous> (test/calculator_service.test.js:6:25)
  ● test to see if functions are defined › test add function
    expect(received).not.toBeUndefined()
    Received: undefined
       8 |
       9 |     test("test add function", () => {
    > 10 |         expect(subtract).not.toBeUndefined()
         |                              ^
      11 |     })
      12 |
      13 |     test("test add function", () => {
      at Object.<anonymous> (test/calculator_service.test.js:10:30)
  ● test to see if functions are defined › test add function
    expect(received).not.toBeUndefined()
    Received: undefined
      12 |
      13 |     test("test add function", () => {
    > 14 |         expect(getTime).not.toBeUndefined()
         |                             ^
      15 |     })
      16 | });
      at Object.<anonymous> (test/calculator_service.test.js:14:29)

Test Suites: 1 failed, 1 passed, 2 total
Tests:       3 failed, 1 passed, 4 total
Snapshots:   0 total
Time:        10.71 s
Ran all test suites.
npm ERR! Test failed.  See above for more details.
Enter fullscreen mode Exit fullscreen mode

This time our test ran successfully, but the test cases failed. From the output you can see what was expected and what was received.
Next, we create the expected functions by adding the following code to "../service/calculator.js" and run the test again.



this time, all the test passes as shown in the output below

$ npm test
> test_master_class@1.0.0 test C:\Users\User\Documents\MyJavaScript\test_master_class
> jest
PASS test/index.test.js (5.568 s)
PASS test/calculator_service.test.js (9.661 s)

Test Suites: 2 passed, 2 total
Tests:       4 passed, 4 total
Snapshots:   0 total
Time:        16.167 s
Ran all test suites.
Enter fullscreen mode Exit fullscreen mode

We can add further test cases to "calculator_service.test" as much as required. Example test to check if the functions returns a correct output when given an input.

$ npm test
> test_master_class@1.0.0 test C:\Users\User\Documents\MyJavaScript\test_master_class
> jest
PASS test/index.test.js
PASS test/calculator_service.test.js

Test Suites: 2 passed, 2 total
Tests:       7 passed, 7 total
Snapshots:   0 total
Time:        9.401 s
Ran all test suites.
Enter fullscreen mode Exit fullscreen mode

So far all test done so far are unit tests. Now lets write integration tests to test the functions coupled together.

In our test folder, create a new file "calculator_controller.test.js" and add the following code



Next in the root folder, create a folder "controller", inside the folder add a new file "calculator.js" and add the following code then run the test again



if everything goes well, you should have the below output

$ npm test
> test_master_class@1.0.0 test C:\Users\User\Documents\MyJavaScript\test_master_class
> jest

PASS test/index.test.js
PASS test/calculator_service.test.js
PASS test/calculator_controller.test.js

Test Suites: 3 passed, 3 total
Tests:       12 passed, 12 total
Snapshots:   0 total
Time:        6.974 s
Ran all test suites.
Enter fullscreen mode Exit fullscreen mode

Conclusion

In "calculator_controller.test.js", you many notice that I introduced two new functions beforeAll and afterAll, they are jest functions used to perform some operations before and after your test runs respectively.

TDD is all about writing "automated test" first, before writing codes that will pass the test; this helps ensure codes are broken into testable units which in turn reduce code duplication and bugs.

To pull the whole code, goto the github link
I hope you find this article useful, if you like the content, feel free to stay in touch, follow me on twitter.

Discussion

pic
Editor guide
Collapse
sadeeq_aji profile image