OSD600 - Adding Testing Tool
Tags: opensource, testing
Published: 2021-11-13 03:32:26

#1. Lab8 requirement
Testing is an important part of developer's community, it helps programmers to test their code, detect unexpected bugs, etc. 
In this lab, I will set up a testing framework called [Jest](https://jestjs.io/) to test my-ssg.

Jest is a JavaScript testing framework, it helps JS developers to ensure the correctness of their source code. Jest pays attention to simplicity and that is the reason I make use of it in my project.

#2. Modification process

* Install Jest:
```
npm install --save-dev jest
```
* Add script for testing so you can run `npm test` to run all tests in the command line:
```
{
  "scripts": {
    "test": "jest --verbose"
  }
}
```
* Write tests:

My-ssg is divided into 6 modules but in this lab I just created testing for 3 modules namely `generateHTML`, `readTextFile` and `readJson`, the rest will be updated later on.

I created `generateHTML.test.js`, `readTextFile.test.js`, `readJson` files which contains all test cases for 3 modules I chose.

In `generateHTML.test.js`, I came up with some ideas to test the `generateHTML(title, body, language, stylesheet, htmlContainer)`:
 * Function should create a `title.html` file inside the specified folder or `./dist` by default.
 * Function will throw an error if the `title` is an empty string or is not passed to the function
 * Function will use default value if `language`, `stylesheet` and `htmlContainer` are not passed to the function 
 * Function accepts empty value for `language` and `stylesheet`

Before turning these ideas into code, I need to **require** the function from `generateHTML` module:
```
const { generateHTML } = require("./generateHTML");
```
I will create test cases inside a `describe` block, I declare some `const` variables which can be reuse in some test cases (best practice is declare them locally in each test case):

```
describe("test generateHTML(title, body, language, stylesheet, htmlContainer)", () => {
  const title = "index";
  const body = "Hello World!";
  const lang = "en-CA";
  const stylesheet = "https://cdn.jsdelivr.net/npm/water.css@2/out/water.css";
  const htmlContainer = "./dist";
  const expectedPath = "./dist/index.html";

  // test cases...
}

```
And here is how the test case look like:
```
test("function should create new HTML file named ${title}.html inside the ${htmlContainer} folder", () => {
    expect(
      generateHTML(title, body, lang, stylesheet, htmlContainer)
    ).toStrictEqual(expectedPath);
  });


test("function should throw an error when title is an empty string", () => {
    try {
      generateHTML("");
    } catch (err) {
      expect(err).toEqual(
        new Error(chalk.bold.red("***title cannot be empty!***"))
      );
    }
  });
```

The logic to test `readTextFile()` and `readJson()` are very similar, I check how the function behaves when the `arg` is empty or it is not passed to the function.

To pass all created test cases, I need to make some small modifications to the original source code.

View my commit: [6313fab](https://github.com/hlavu/my-ssg/commit/6313fab04be683ee135b2f5caa4f94da75280c92)

#3. Overall
Writing test is a painful process, you may never know *how many more tests* you need to write for a snippet code to make sure that you get all problems it may produce. However, writing good tests helps improve the quality of the source code so this skill is necessary for any programmer to achieve.  

All in all, thank you for reading the post.

Happy coding!