Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do i use jest to test javascript code with DOM elements

Tags:

jestjs

Am new to javascript and i have been trying to write tests for his code but i have not been able to,we are supposed to use jest. I have researched for long without getting a solution.

document.getElementById("signup").addEventListener("submit", function(e) {
  e.preventDefault();
  data = {
    username: document.getElementById("username").value,
    email: document.getElementById("email").value,
    password: document.getElementById("password").value,
    confirm_password: document.getElementById("confirmPassword").value,
  };
});


signUp = (data) => {

    fetch("https://diaryapi-v2.herokuapp.com/mydiary/v1/auth/register", {
        method: "POST",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify(data)
      })
      .then(res => res.json())

      .then(data => {
        if (data.message === "Your account was created") {
          let msg = data.message;
          document.getElementById("white").innerHTML = msg;
          window.location.href = "/signin";
        } else {
          let msg = Object.values(data);
          console.log(msg)
          document.getElementById("white").innerHTML = msg;
        }

      })
      .catch(error => console.error("Error:", error));

}
like image 805
Chariss Avatar asked Aug 18 '18 14:08

Chariss


1 Answers

Your code does not have any exports so you will need to use require() at the point in your test you want it to run.

It makes network requests and sets the window location so you will want to use Mocks Functions to verify it is working as expected without actually making network requests and setting the window location.

It performs some work asynchronously through the use of callbacks given to then() so you will need to account for that in your test.

Jest uses jsdom to provide a browser-like environment within the unit tests and you can use that to set everything up before running your code with require().

I made a few small modifications to your code noted in the comments below:


code.js

document.getElementById("signup").addEventListener("submit", function (e) {
  e.preventDefault();
  // add 'const'
  const data = {
    username: document.getElementById("username").value,
    email: document.getElementById("email").value,
    password: document.getElementById("password").value,
    confirm_password: document.getElementById("confirmPassword").value,
  };
  signUp(data); // call signUp with the data
});

// add 'const'
const signUp = (data) => {

  fetch("https://diaryapi-v2.herokuapp.com/mydiary/v1/auth/register", {
    method: "POST",
    headers: {
      "Content-Type": "application/json"
    },
    body: JSON.stringify(data)
  })
    .then(res => res.json())

    .then(data => {
      if (data.message === "Your account was created") {
        let msg = data.message;
        document.getElementById("white").innerHTML = msg;
        window.location.assign("/signin"); // change this to assign() so it can be mocked
      } else {
        let msg = Object.values(data);
        console.log(msg)
        document.getElementById("white").innerHTML = msg;
      }

    })
    .catch(error => console.error("Error:", error));

}

Here is a working test for the above code that you can use as a reference:

code.test.js

describe('code', () => {

  let fetchMock;
  let assignMock;

  beforeEach(() => {
    // Jest uses jsdom as the default test environment which emulates
    // a browser and provides a document object for the unit tests.
    // Initialize the document body with the HTML needed for the tests
    document.body.innerHTML += `
      <form id="signup">
        <input type="text" id="username" value="the username">
        <input type="text" id="email" value="the email">
        <input type="text" id="password" value="the password">
        <input type="text" id="confirmPassword" value="the confirmPassword">
        <input type="submit" id="submitbutton">
      </form>
      <div id="white"></div>
    `;
    // Create a mock for fetch and provide a mock implementation
    // so the unit tests aren't actually making network requests
    fetchMock = jest.spyOn(global, 'fetch');
    fetchMock.mockImplementation(() => Promise.resolve({
      json: () => Promise.resolve({ message: 'Your account was created' })
    }));
    // Create a mock for window.location.assign()
    // so the unit tests aren't actually changing the window location
    assignMock = jest.spyOn(window.location, 'assign');
    assignMock.mockImplementation(() => {});
    // With everything set up, require the code
    require('./code');
  });

  afterEach(() => {
    // After each test call mockRestore() to restore the original functions
    fetchMock.mockRestore();
    assignMock.mockRestore();
    // resetModules() resets the module registry in Jest and ensures
    // a fresh copy of './code' executes on require()
    jest.resetModules();
  });

  it('should fetch data, change contents of #white, and change the page location on submit', async () => {
    // Submit the form
    document.getElementById('submitbutton').click();

    // Check that fetch was called with the expected arguments
    expect(fetchMock).toHaveBeenCalledTimes(1);
    const fetchArgs = fetchMock.mock.calls[0];
    expect(fetchArgs[0]).toBe('https://diaryapi-v2.herokuapp.com/mydiary/v1/auth/register');
    expect(fetchArgs[1]).toEqual({
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify({
        username: 'the username',
        email: 'the email',
        password: 'the password',
        confirm_password: 'the confirmPassword',
      })
    });

    // pause synchronous execution of the test for two event loop cycles
    // so the callbacks queued by the then()'s within signUp have a chance to run    
    await Promise.resolve().then();

    // Check that window.location.assign() was called with the expected arguments
    expect(assignMock).toHaveBeenCalledTimes(1);
    expect(assignMock.mock.calls[0][0]).toBe('/signin');

    // Check that #white was updated
    expect(document.getElementById('white').innerHTML).toBe('Your account was created');
  });

});
like image 69
Brian Adams Avatar answered Oct 16 '22 09:10

Brian Adams