Reputation: 25840
I wrote a tiny library that manipulates DOM directly, using window
and document
to search and change the DOM. And now I'm trying to figure out how to test it.
So far I have tried a combination of jest + jsdom:
const jsdom = require('jsdom');
const {JSDOM} = jsdom;
const dom = new JSDOM('<!DOCTYPE html><p>Hello world</p>');
// these two lines do not seem to do anything useful:
global.window = dom.window;
global.document = dom.window.document;
test('can globally access and search the DOM', () => {
// this doesn't work
expect(global.document.querySelectorAll('p').length).toBe(1);
});
Am I doing something wrong here, or am I entirely wrong with the testing approach? And if so, what would be the right way to approach such testing?
I feel a bit lost here, between what's called e2e testing and Unit testing, because in my case this seems to be something right in between.
Ideally, I would want to end up with this thing tested against multiple browsers, and to get some sort of test coverage. But that's more like the next step. Right now I cannot get it to work at all.
I know how fast things are moving in the Web world, so if I'm wrong completely, I appreciate if you can point me at what's the right way to do it today.
UPDATE
Here's my complete code, after a few suggestions from @duxfox, since with this approach my library is now missing event DOMContentLoaded
which is supposed to trigger its DOM processing.
const jsdom = require('jsdom');
const {JSDOM} = jsdom;
const { document } = (new JSDOM('<!DOCTYPE html><p>Hello world</p>')).window;
global.document = document;
global.window = document.defaultView;
window.console = global.console;
Object.keys(document.defaultView).forEach((property) => {
if (typeof global[property] === 'undefined') {
global[property] = document.defaultView[property];
}
});
global.navigator = {
userAgent: 'node.js'
};
// Here I'm trying to follow a suggestion from Luis:
// https://stackoverflow.com/questions/36803733/jsdom-dispatchevent-addeventlistener-doesnt-seem-to-work
window.addEventListener('DOMContentLoaded', function (ev) {
console.log('DOMContentLoaded called!'); // this is not called.
/*
console.log('window click', ev.target.constructor.name,
ev.currentTarget.constructor.name);*/
});
// loading my library here:
// const root = require('../src');
test('something', () => {
// This now works, but my library is missing
// event DOMContentLoaded to start processing the DOM
expect(document.querySelectorAll('p').length).toBe(1);
});
Upvotes: 2
Views: 1140
Reputation: 10021
Below is a jsdom setup script that I use with mocha/chai/jsdom/enzyme
looks like the global.window
should be set to
dom.window.document.defaultView
rather than
dom.window
Full script, which adds other global properties:
var jsdom = require('jsdom');
const { JSDOM } = jsdom;
const { document } = (new JSDOM('')).window;
global.document = document;
global.window = document.defaultView;
window.console = global.console;
Object.keys(document.defaultView).forEach((property) => {
if (typeof global[property] === 'undefined') {
global[property] = document.defaultView[property];
}
});
global.navigator = {
userAgent: 'node.js'
};
Upvotes: 3