December 11, 2023

JavaScript Testing with Jest — Demystifying the Quest for Bulletproof Code

The best time to establish protocols with your clients is when you onboard them.

Heading

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat. Aenean faucibus nibh et justo cursus id rutrum lorem imperdiet. Nunc ut sem vitae risus tristique posuere.

Testing JavaScript applications used to be a cumbersome and error-prone process. However, with the advent of Jest, that narrative has changed dramatically. Jest, known for its simplicity and speed, has revolutionized the way JavaScript developers approach testing. It’s no longer a chore. It’s an integral part of the development workflow. Jest is an open-source testing framework maintained by Facebook that provides developers with a seamless and enjoyable testing experience. It combines simplicity with powerful testing capabilities, making it an ideal choice for projects of all sizes.

In this article, we will delve into Jest’s features and understand why it’s a game-changer for JavaScript developers.

Installation and Setup

Open a Folder in VS Code (or any other editor) — create a project called SampleProjOne

Fire up the Terminal and hit the following commands:

  • npm init -y
  • npm install --save-dev jest
After project npm initialization, the side panel would have the node_modules, package.json and package-lock.json

In package.json under scripts -> test, specify “jest

Under scripts -> test, specify “jest”

Writing the first testcase

Here let’s say I have a JavaScript file for finding the nth Fibonacci Sequence number. And saved it as fibonacci.js

const getFibonacciOf = (n) => {    let a = 0, b = 1, c;

Now let’s create a folder for all test files, called Tests.

Under Tests folder, create a file with the same filename which we want to write test cases for, but with a .test.js file extension.

Thus, our filename would be fibonacci.test.js, which would be checking if our Fibonacci Series code is correct and flag any potential chinks in our code armor.

fibonacci.test.js

const fibonacci = require('../fibonacci');
test('When n=3', () => {    const res = fibonacci(3);    expect(res).toEqual(2);});

So, this is our test/jest file. Here, test() contains our sample test case. We can provide a custom name for the testcase. Here I’ve given it as ‘When n=3’ indicating that this testcase is for testing our Fibonacci code for finding the 3rd Fibonacci number in the series.

Here at line 6: expect(res).toEqual(2);

expect(res): This part of the statement, is setting up an expectation or assertion. It means we expect a certain value or behavior from the code being tested. In this case, we are expecting the value stored in the res variable, which is 2

.toEqual(2): It checks whether the value on the left-hand side (res in this case) is equal to the value on the right-hand side (2 in this case). If the values are equal, the test case will pass; else, the test case will fail.

Running our testcase

To run our test case, we would be running our test file.

The command to run test file: npm run test (testFile)

Running testfile fibonacci.test.js

Once the all the testcases in our test file has been run, it gives a summary of the different test that has been run, indicating the number of cases that has passed, failed and time it took.

It also highlights the total number of Test-Suites and the number of which passed and failed.

Let’s say we write a test case for getting the 0th Fibonacci number

const fibonacci = require('../fibonacci');

Running fibonacci.test.js after adding testcase when n=0

The test case has failed when n=0

Thus, when we have a look at our code, we see that when n=0, we return c, but c has not yet been defined because, it only does when the for loop starts. We can also see that we haven’t handled the case when n=1.

Now after realizing what edge cases (when n=0 & n=1) we missed in our code from those testcases, fibonacci.js looks like this:

const getFibonacciOf = (n) => {    let a = 0, b = 1, c;

After adding testcases for n=0 & n=1, our fibonacci.test.js looks like

const fibonacci = require('../fibonacci');

Now when we run the test cases again

All testcases passed including the ones that consider edge cases

Writing Test-Suites

In Jest, a test suite is a way to group related test cases together. It provides a structured organization for your tests, making it easier to manage and maintain your test code, especially in larger projects. Test suites help you categorize tests based on different parts of your codebase or specific functionality.

Here’s how you can create a test suite using Jest:

const fibonacci = require('../fibonacci');

You can have multiple test suites in Jest. In fact, organizing our tests into multiple test suites is a common practice, that’s extremely handy when dealing with larger codebases or complex projects. It helps keep our tests organized, makes it easier to manage and run specific sets of tests, and provides a clear structure for our test suite hierarchy.

To create multiple test suites in Jest, we can use the describe function multiple times to define different test suite blocks.

Let’s create a new file which has basic math operations like Addition, Subtraction and Multiplication.

basicMath.js

function addNumbers(a, b) {    return a + b;}

And a corresponding Test file for this would be like:

basicMath.test.js

Here we have segregated the different testcases for each of the functions into separate Test Suites.

const { addNumbers, subtractNumbers, multiplyNumbers } = require('../basicMath');

Different types of Matches

Matchers are an integral part of writing effective tests. They help us define the expected outcome of our code and ensure that it behaves as intended. Jest’s matchers make it easier to write clear and concise test cases, which ultimately leads to better code quality and maintainability. There are various types of matchers giving developers the flexibility and ease of use.

1. toEqual(expected)

test('checking toEqual()', () => {    expect({ a: 1, b: 2 }).toEqual({ a: 1, b: 2 });});

One of the most commonly used matchers, just like the name sounds, it checks if the returned value is same as the expected value. Apart from that it is also used for deep equality comparisons of objects and arrays. It recursively checks if the actual and expected values have the same properties and values. This is particularly useful when comparing complex data structures.

toEqual() matcher

2. toBe(expected)

test('adding 1 + 2 equals 3', () => {    expect(1 + 2).toBe(3);});

The toBe() matcher is used for comparing primitive values like numbers, strings, or Booleans. It checks if the actual value is strictly equal (===) to the expected value. This matcher ensures that not only the values are the same but also that they have the same data type.

toBe() matcher

3. toContain(expected)

test('Checking if an array contains a particular value', () => {    const fruits = ['BMW', 'Lamborghini', 'Alfa Romeo', 'Lexus', 'Dacia'];    expect(fruits).toContain('Alfa Romeo');});

The toContain() matcher is used to check if an array or string contains the expected value. It’s handy for verifying the presence of specific elements in collections.

toContain() matcher

4. toMatch(pattern)

test('Matching a string using a regex pattern', () => {    expect('Porsches are reliable').toMatch(/reliable/);});

The toMatch() matcher is used to match a string against a regular expression pattern. It’s useful for verifying if a string conforms to a specific format.

toMatch() matcher

5. toBeTruthy()&toBeFalsy()

test('Checking if a value is truthy', () => {    expect(1).toBeTruthy();});test('Checking if a value is falsy', () => {    expect(null).toBeFalsy();});

The toBeTruthy() and toBeFalsy() matchers are used to check if a value is truthy or falsy, respectively. They are helpful for verifying boolean values or conditions.

toBeTruthy() & toBeFalsy() matchers

6. toThrow(error)

function throwError() {    throw new Error('This is an error');}
test('Checking if a function throws an error', () => {    expect(throwError).toThrow('This is an error');});

The toThrow() matcher is used to test if a function throws an error. You can optionally specify the expected error message or error class.

toThrow() matcher

Conclusion

Thus, Jest proves to be an indispensable tool for JavaScript developers, offering a robust testing framework with a plethora of matchers that enhance the efficiency and reliability of code testing. When dealing with huge Backend applications that handle numerous APIs, Jest helps us developers by easily highlighting our Achilles’ arm, foot and face. Its simplicity, speed, and extensive features make it a powerful ally in ensuring code quality, and to write tests with ease and confidence.

CodeStax.Ai
Profile
December 7, 2023
-
6
min read
Subscribe to our newsletter
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Share this article:

More articles