How to mock DOM element in Javascript/JQuery using Jest

Jest is a JavaScript testing framework developed and maintained by Facebook, Inc. It was designed and built by Christoph Nakazawa with a focus on simplicity and support for large web applications. Jest is widely used and compatible with various technologies such as Babel, TypeScript, Node.js, React, Angular, Vue.js, and Svelte.

In this blog post, I will demonstrate how to utilize Jest’s mocking feature to test DOM elements without the need to load the actual DOM. But before diving into the mocking aspect, let’s understand why mocking is important in the context of unit testing.

The Importance of Mocking

Mocking is a crucial process employed in unit testing, especially when the unit being tested has external dependencies. The purpose of mocking is to isolate and focus on the specific code being tested, rather than worrying about the behavior or state of those external dependencies.

Consider the following JavaScript code snippet:

const $ = require("jquery");
function showHide() {
    let element = $('#test');
    const top = element[0].getBoundingClientRect().top;
    if (top >= 100) {
        element[0].addClass("success");
    } else {
        element[0].removeClass("failed");
    }
}

module.exports = { showHide };

In the above function, we are utilizing the jQuery selector and invoking the addClass and removeClass methods from jQuery. When testing this function, one approach would be to load the actual HTML to ensure the correct behavior. However, an alternative approach is to leverage Jest’s mocking feature, which allows us to avoid loading the DOM and external dependencies.

In this blog post, I will demonstrate how to test the above function without loading the actual DOM.

const $ = require("jquery");

const { showHide, showTooltip } = require("../playground");

describe('Jquery DOM ', () => {

    it('should call document.getElementById', () => {

        const getBoundingClientRectSpy = jest.fn(() => ({ top: 100 }));
        var myObj = [{
            name: 'test',
            getBoundingClientRect: getBoundingClientRectSpy,
            addClass: jest.fn(),
        }];
        jest.spyOn($.fn, 'init').mockReturnValue(myObj);
        showHide();
        expect(getBoundingClientRectSpy).toBeCalled();


    })
    it('should call document.getElementById2', () => {

        const getBoundingClientRectSpy = jest.fn(() => ({ top: 10 }));
        const removeClass = jest.fn();
        var myObj = [{
            name: 'test',
            getBoundingClientRect: getBoundingClientRectSpy,
            addClass: jest.fn(),
            removeClass
        }];
        jest.spyOn($.fn, 'init').mockReturnValue(myObj);
        showHide();
        expect(getBoundingClientRectSpy).toBeCalled();
        expect(removeClass).toBeCalledTimes(1);


    })
    it('Should be mocked through fn.find()',function(){
        var mockElement = {
            parentNode:true,
            expression:"#myId .myClass"
        };
        var fn_find = $.fn.find;
        var spy = jest.spyOn($.fn, "find").mockImplementation((expression)=>{
            if(expression===mockElement.expression){
                return mockElement;
            }
            return fn_find(expression);
        });
        var foundElement = $(mockElement.expression);
        expect(foundElement).toBe(mockElement);
        $.fn.find = fn_find;
    });
    it('Should be mocked through document.getElementById',function(){
        var mockElement = {
            id:"someId", 
            parentNode:true
        };
        var document_getElementById = document.getElementById;
        var spy = jest.spyOn(document, "getElementById").mockImplementation((id)=>{
            if(id===mockElement.id){
                return mockElement;
            }
            return document_getElementById(id);
        });
        var foundElement = $("#"+mockElement.id);
        expect(foundElement[0]).toBe(mockElement);
        document.getElementById = document_getElementById;
    });

})


In the above example, we employ Jest’s mocking capabilities to test the showHide function without actually loading the DOM. We create a spy function, getBoundingClientRectSpy, which returns a predefined object with a top value. This spy function is then assigned to the getBoundingClientRect property of a mock object.

By using jest.spyOn, we mock the init method of the jQuery object ($.fn.init) to return our mock object. This way, we can control the behavior of the jQuery selector and ensure that the expected functions are called.

By utilizing Jest’s mocking feature, we can effectively isolate the code under test and focus solely on its behavior, without worrying about external dependencies like the DOM.

Conclusion

In this blog post, we explored how to use Jest’s mocking feature to test DOM elements without loading the actual DOM. By effectively mocking external dependencies, we can isolate the code being tested and focus on its specific behavior. This approach simplifies unit testing and allows for more reliable and focused test cases.

إرسال تعليق

Please do not post any spam link in the comment box😊

أحدث أقدم

Blog ads

CodeGuru