7

I'm using mocha to test my JavaScript code. The code involves html and css and implements a chat app. As far as I saw, Mocha can test JavaScript functions by matching the expected value to the function's return value.

But what if I want to test functions that don't return a value? Functions that mainly deal with DOM elements. (Like appending an image for example ).

How exactly can I mock DOM elements in mocha and then test if the function succeeds in generating the appropriate DOM elements?

I had looked around and found it was possible with selenium webdriver and jsdom. Is it possible to do this test with mocha alone and no other additional interfaces?

Shaked
  • 185
  • 1
  • 9
  • 3
    JSDom is the right tool. Why would you prefer to avoid it? – joews Jul 04 '17 at 13:03
  • Some example tests using JSDom (using Jest, which has a similar API): https://github.com/ripjar/material-datetime-picker/blob/master/lib/js/__tests__/index-test.js#L37 – joews Jul 04 '17 at 13:04
  • I was told to use mocha alone...But thanks anyway – Shaked Jul 04 '17 at 13:05
  • Can you use an assertion library (e.g. chai) as well? mocha doesn't give you a way to make assertions about your code. – joews Jul 04 '17 at 13:19
  • I don't think I can.. Just mocha. Are you saying it's impossible? – Shaked Jul 04 '17 at 13:23
  • Mocha is only a test _runner_; it needs another library to describe _how_ your code should work. If you run your tests in Node you can use `assert` for that... but you'd need JSDOM there. Bundlers like browserify may give you a port of `assert` for running tests in the browser. However, most people use a richer assertion library like chai. Are there any other tests in your project? How do they describe the code's behaviour? – joews Jul 04 '17 at 13:28

3 Answers3

5

JSDOM is convenient because it allows you to test against a "real" DOM implementation without the overhead of running in a web browser.

If you can run your unit tests inside a browser you can assert against the DOM in the same way:

describe("the super special button", () => {

  it("adds an image", (done) => {
    const button = document.querySelector(".js-super-special");
    button.click();

    // give the browser a chance to update the DOM
    setTimeout(() => {
      const image = document.querySelector(".js-image")

      // using assertion library, like chai
      expect(image).to.not.beNull();

      // or using a port of Node's `assert` from a bundler like browserify:
      assert(image != null);

      done();
    })
  })
});
joews
  • 29,767
  • 10
  • 79
  • 91
  • I had already tried using document.querySelector before. When I ran npm test it said "document is not defined". How can you reslove this error? It works on my code but doesn't work when I run this as mocha testing code. – Shaked Jul 04 '17 at 13:31
  • 1
    It sounds like you're running your tests in Node. In that case, you really do need JSDOM (because Node doesn't know what `document` is by itself). In a browser, this test will work against the "real" DOM. – joews Jul 04 '17 at 13:32
  • I decided to run the tests inside the browser. That way I don't use any external interfaces such as JSDom or selenium webdriver. Thanks a lot!!! – Shaked Jul 04 '17 at 16:58
0

You have to use fake DOM APIs in nodejs context, and make them global on before hooks of mocha.

beforeEach(() => {
  const dom = new JSDOM(
    `<html>
       <body>
       </body>
     </html>`,
     { url: 'http://localhost' },
  );

  global.window = dom.window;
  global.document = dom.window.document;
});

Read more here: https://seesparkbox.com/foundry/improve_unit_testing_with_mocha_chai_jsdom

Navid Shad
  • 738
  • 7
  • 15
0

you can use jsdom-global package alternative that also works outside of Mocha. mocha-jsdom still works, but jsdom-global is better supported.

npm install --save-dev --save-exact jsdom jsdom-global

modify npm test script to be:

"test": "mocha -r jsdom-global/register"

test example: app.test.js

import {JSDOM} from 'jsdom'; // can also use common js

describe('DOM', () => {
  it('should log selector list', () => {
    const dom = new JSDOM(
      `<html>
         <body>
           <div class="card">1</div>
           <div class="card">2</div>
           <div class="card">3</div>
         </body>
       </html>`,
     {url: 'http://localhost'},
    );
  });

  global.document = dom.window.document;
  console.log(document.querySelectorAll('.card'));
});


Muhammed Moussa
  • 4,589
  • 33
  • 27