Unit Testing UI-related functions

Viewed 83

I'm trying to get unit-testing concept and get lost with testing UI-related functions, like this:

const hideElem = elem => {
  elem.classList.add('js-hidden')
}

or this:

const getInputValue = (inputElem) => {
  let inputEl = document.querySelector(inputElem)

  return inputEl.value
}

or this:

const cleanInput = input => {
  const inputEl = document.querySelector(input)
  inputEl.value = ''
}

Do I need to cover such functions with unit tests in Jest? If yes - could you please explain how to combine here Jest and DOM-related things?

1 Answers

Unit testing should focus on code logic rather than the DOM related thing of the browser. It's NOT e2e testing. For unit testing, we can create and use mocked objects to check the code logic is correct or not.

Unit testing should not depend on any external environment, such as browsers, third-party services. In other words, we need to mock dom-related things to make the unit test code have good isolation.

For node.js environment, we can use jsdom to emulate dom-related thing and web API.

In general, the goal of the project is to emulate enough of a subset of a web browser to be useful for testing and scraping real-world web applications.

E.g.

index.js:

const hideElem = (elem) => {
  elem.classList.add('js-hidden');
};

const getInputValue = (inputElem) => {
  let inputEl = document.querySelector(inputElem);

  return inputEl.value;
};

const cleanInput = (input) => {
  const inputEl = document.querySelector(input);
  inputEl.value = '';
};

export { hideElem, getInputValue, cleanInput };

index.test.js:

import { hideElem, getInputValue, cleanInput } from './';

describe('62455692', () => {
  describe('hideElem', () => {
    it('should hide elem', () => {
      const mElem = { classList: { add: jest.fn() } };
      hideElem(mElem);
      expect(mElem.classList.add).toBeCalledWith('js-hidden');
    });
  });

  describe('getInputValue', () => {
    it('should get input value', () => {
      const mInputElem = { value: 'mocked value' };
      jest.spyOn(document, 'querySelector').mockReturnValueOnce(mInputElem);
      const actual = getInputValue('#foo');
      expect(actual).toBe('mocked value');
      expect(document.querySelector).toBeCalledWith('#foo');
      document.querySelector.mockRestore();
    });
  });

  describe('cleanInput', () => {
    it('should clean input', () => {
      const mInputElem = { value: 'mocked value' };
      jest.spyOn(document, 'querySelector').mockReturnValueOnce(mInputElem);
      cleanInput('#foo');
      expect(mInputElem.value).toBe('');
      expect(document.querySelector).toBeCalledWith('#foo');
      document.querySelector.mockRestore();
    });
  });
});

unit test result:

 PASS  stackoverflow/62455692/index.test.js (10.489s)
  62455692
    hideElem
      ✓ should hide elem (5ms)
    getInputValue
      ✓ should get input value (2ms)
    cleanInput
      ✓ should clean input (1ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |     100 |      100 |     100 |     100 |                   
 index.js |     100 |      100 |     100 |     100 |                   
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       3 passed, 3 total
Snapshots:   0 total
Time:        11.874s, estimated 13s
Related