Things I learned after writing tests for JS and HTML page
Tags: jest, testing, javascript, html
Published: 2019-01-12 01:14:00

---
title: Things I learned after writing tests for JS and HTML page
published: true
description: I try to find how to test with Jest but I found most tutorials are using Jest with React. Is it really possible to test HTML page with Jest? Yes!
tags: jest, testing, javascript, html
cover_image: https://thepracticaldev.s3.amazonaws.com/i/fv71y5nxqq5zta3340sf.png
---

In these weeks, I always want to learn about writing tests using Jest, Mocha or other stuffs. Unfortunately, I don't have any React apps that want to test these days but I have chances to figure out how to test HTML page with pure JavaScript.

I found most tutorials are using Jest with React or other JavaScript frameworks. Is it really possible to test HTML page with Jest? Yes!

# How to start
[View the demo here](https://snowleo208.github.io/test-js-example/) for my sample HTML page. Just a simple page to fetch JSON, show a list based on it and a button to show/hide translations.

In your root folder, create a `package.json` like this, and run `npm install` in console.

```json
{
    "scripts": {
        "test": "jest --watch",
        "coverage": "jest --coverage"
    },
    "devDependencies": {
        "jest": "^23.6.0"
    }
}

```

When you finished, you can start testing your app! Create a file `<YOUR-FILENAME>.spec.js` and start testing like:

```javascript
const fs = require('fs');
const path = require('path');
const html = fs.readFileSync(path.resolve(__dirname, '../index.html'), 'utf8');

jest
    .dontMock('fs');

describe('button', function () {
    beforeEach(() => {
        document.documentElement.innerHTML = html.toString();
    });

    afterEach(() => {
        // restore the original func after test
        jest.resetModules();
    });

    it('button exists', function () {
        expect(document.getElementById('disable')).toBeTruthy();
    });
});

```

Save it and run `npm test`!

[View my GitHub here for codes](https://github.com/snowleo208/test-js-example)


# What I learned

### 1. Difference between testing HTML and React page
In React, you can use Enzyme to `shallow` the component and get state for testing. But in HTML and JavaScript page, the only thing you can test is the classes, content and function output. When you are used to test by states, it might be not so convenient to test HTML page.

As pure JS did not export anything for Jest to test, you also need to add this at the end: 

```javascript
if (typeof exports !== 'undefined') {
    module.exports = {
        getItem,
        setItems,
        triggerItem
    };
}
```

Then Jest can import/export functions for testing.

For HTML, you cannot directly import it like React component. You need to add this snippet before tests, to import the whole HTML:

```javascript
const fs = require('fs');
const path = require('path');
const html = fs.readFileSync(path.resolve(__dirname, '../index.html'), 'utf8');

jest
    .dontMock('fs');

```

or write inline HTML inside tests. For example: 

```javascript
const html = document.createElement('div');
html.innerHTML = `<div class="lang-grid" id="language">This is a sample</div>`;
document.body.appendChild(div);
```


### 2. Special way to test asynchronous code
It is still easy to test basic thing, like checking the menu button will appear in mobile view using Jest. Like:

```javascript
    it('menu button exists', function () {
        expect(document.getElementById('menu-btn')).toBeTruthy();
    });

```

But for asynchronous code, like Promise, you need to use different approach.

The most important thing is to add `done()` in each test.

```javascript

    it('get same items from json', function (done) {
        fetch.mockResponse(JSON.stringify(json))
        const {getItem} = require('../scripts/main.js');

        getItem().then(res => {
            expect(res).toEqual([{
                "phase": "Entschuldigung!",
                "trans": "Excuse me. [as in may I have your attention]."
            },
            {
                "phase": "Sprechen Sie Englisch?",
                "trans": "Do you speak English?"
            }])

            expect(res.length).toEqual(2);
            done();
        })
        .catch(err => console.log(err))
    });

```

Just like what [Jest documentation](https://jestjs.io/docs/en/asynchronous) said, it is important to add `done()` in the test. Otherwise, it may have wrong results. 

After you added `done()`, it will wait till your async call to be resolved and get the expected result.

---

### 3. Check coverage using Jest

Jest has built-in coverage function, you can call it using `jest --coverage`. Then you can see your reports in `coverage/lcov-report/index.html`. The chart is very useful and inform you which code have not tested.

![Coverage tool](https://thepracticaldev.s3.amazonaws.com/i/xwt4bi0qkp4my37t0mxz.jpg)
*(Why it is not 100% in branches? Because I skipped the test of exporting module statement at the end. )*

I have not use coverage tool before, that's why I am motivated when I saw my code changed from red to green!

---


# Is testing fun?

Well, it may not be fun, but surely is satisfactory when I saw my code changed from RED to GREEN. 

Do you have any suggestions to my flow? Or any ideas on testing? Feel free to drop me a line here :)