Helper Functions for Assertions (Jest & Node.js)
Tags: javascript, testing, tutorial, webdev
Published: 2021-01-21 09:01:28

Whether you are new to software development or have been at it for a while, software testing is something you are likely to encounter. It is an integral part of any development process.

## Unit Tests 🧪
There is an expectancy for developers to write unit tests for their application's code. Unit tests are the right way of testing the smallest unit of code within a system. Ideally, these are isolated pieces of code that exist in separate files on an application. 

Unit tests consist of testing individual methods and functions of your software's classes, components, or modules. Unit tests are, in general, relatively cheap to automate and can be run very quickly by a continuous integration server.

### The backstory 🔙
So recently, I've been improving some of the projects on my GitHub. One of the main points has been to increase the code coverage by writing unit tests for my projects. 

I've become quite accustomed to using the Jest testing framework. Not a knock to any other testing frameworks, but Jest has become a recent favorite go-to of sorts. Thus I decided to implement testing using Jest on a Node.js project of mine. 

**Disclaimer ‼️** _Mocha/Chai could've also been a viable option, but I wanted to play around the backend with Jest this time around_. 🙈

### My Problem 🤔
Something that kept repeatedly happening is similar assertions that came up for multiple modules. 

### **Module** 1️⃣

_isNotNumber.helper.js_
```javascript
module.exports = (incomingId) => isNaN(incomingId);
```
_isNotNumber.helper.test.js_
```javascript
const isNotNumber = require("../isNotNumber.helper");

describe("isNotNumber helper function unit tests", () => {
  it("should validate incoming module truthiness", () => {
    expect(isNotNumber).not.toBeNull();
    expect(isNotNumber).toBeTruthy();
  });

  it("should validate string type as true", () => {
    const results = isNotNumber("dummy")

    expect(results).not.toBe(false);
    expect(results).toBe(true);
  });

  it("should validate number type as false", () => {
    const results = isNotNumber(1)

    expect(results).not.toBe(true);
    expect(results).toBe(false);
  });
});
```

### **Module** 2️⃣

_isObjectPropertyEmpty.helper.js_
```javascript
module.exports = (incomingObject) =>
  Object.values(incomingObject).some((key) => key === null || key === "");
```
_isObjectPropertyEmpty.helper.test.js_
```javascript
const isObjectPropertyEmpty = require("../isObjectPropertyEmpty.helper");

describe("isObjectPropertyEmpty helper function unit tests", () => {
  it("should validate incoming module truthiness", () => {
    expect(isObjectPropertyEmpty).not.toBeNull();
    expect(isObjectPropertyEmpty).toBeTruthy();
  });

  it("should validate object with empty field as true", () => {
    const results = isObjectPropertyEmpty({ id: "" })

    expect(results).not.toBe(false);
    expect(results).toBe(true);
  });

  it("should validate object with non-empty field as false", () => {
    const results = isObjectPropertyEmpty({ id: 1 }

    expect(results).not.toBe(true);
    expect(results).toBe(false);
  });
});
```
I realized quickly that this could be an issue that may repeat over time with many of the other modules. It probably is acceptable to re-write the same assertions in multiple tests, but it felt very impractical and not-very D.R.Y.

### The Solution 💡
The thing that ended up being helpful was <u>refactoring</u> and creating "Helper Functions" that took care of covering the repeating assertions. 

The process was as simple as:

1. **Create a function(s) with the assertion logic in a separate file** (_use logical naming constructs_). ✅
2. **Call on the required helper when writing unit tests.** ✅

<u>**Helper functions with assertion logic**</u>
_validators.js_
```javascript
module.exports = {
  validateTruthiness: (received) => {
    expect(received).not.toBeNull();
    expect(received).toBeTruthy();
  },
  validateBooleanValues: (received, boolean) => {
    expect(received).not.toBe(!boolean);
    expect(received).toBe(boolean);
  },
  ....
}
```

<u>**Using helpers in the unit tests**</u>
_isNotNumber.helper.test.js_
```javascript
const isNotNumber = require("../isNotNumber.helper");

const {
  validateTruthiness,
  validateBooleanValues,
} = require("../../../utils/validators");

describe("isNotNumber helper function unit tests", () => {
  it("should validate incoming module truthiness", () => {
    validateTruthiness(isNotNumber);
  });
  it("should validate string type as true", () => {
    validateBooleanValues(isNotNumber("dummy"), true);
  });

  it("should validate number type as false", () => {
    validateBooleanValues(isNotNumber(1), false);
  });
});
```

_isObjectPropertyEmpty.helper.test.js_
```javascript
const isObjectPropertyEmpty = require("../isObjectPropertyEmpty.helper");

const {
  validateTruthiness,
  validateBooleanValues,
} = require("../../../utils/validators");

describe("isObjectPropertyEmpty helper function unit tests", () => {
  it("should validate incoming module truthiness", () => {
    validateTruthiness(isObjectPropertyEmpty);
  });

  it("should validate object with empty field as true", () => {
    validateBooleanValues(isObjectPropertyEmpty({ id: "" }), true);
  });

  it("should validate object with non-empty field as false", () => {
    validateBooleanValues(isObjectPropertyEmpty({ id: 1 }), false);
  });
});
```

### Conclusion 🏁
That's pretty much it! Refactoring and introducing helper functions that took care of the assertion logic took away the need to repeat code. 

As I soon found out, more tests also had identical assertions, so the need to have a test validation file became warranted. In the end, a single file housed all the validators used throughout the project. 

I'm pretty sure other approaches to this situation I found myself in. 

Let me know what you think about this? 
And feel free to share any improvement tips for this. ✌️

---
Find the above code snippets 👉 [here](https://github.com/reMRKableDev/reading-list/tree/master/helpers/requestValidators) 👈
Full repo 👉 [here](https://github.com/reMRKableDev/reading-list) 👈