I have a function that manipulates the DOM and there are 2 cases that I want to test. One of those cases involve mocking some document functions to check if they were called and other other involves checking the DOM to see if it was actually changed.
Probably relevant data:
Jest: ^27.0.6
jsdom: ^16.6.0
Here's my function:
// file.js
export const loadStyles = () => {
const fontLink = document.createElement('link');
fontLink.setAttribute('href', 'some_href_1');
fontLink.setAttribute('rel', 'stylesheet');
const iconLink = document.createElement('link');
iconLink.setAttribute('href', 'some_href_2');
iconLink.setAttribute('rel', 'stylesheet');
const head = document.head;
head.appendChild(fontLink);
head.appendChild(iconLink);
};
The problem is that the mocks from test 1
are still persistent in test 2
, even if the document
is overwritten by a new instance of JSDOM. However, if I put test 2
before test 1
, then the tests pass. Here's my test file:
import * as functions from './file.js';
import { JSDOM } from 'jsdom';
describe('Test Functions', () => {
describe('loadStyles', () => {
beforeEach(() => {
jest.clearAllMocks();
document = new JSDOM().window.document;
});
// test 1
it('should create the style link attributes', () => {
document.createElement = jest.fn().mockReturnValue({
setAttribute: jest.fn()
} as unknown as HTMLElement);
document.head.appendChild = jest.fn();
functions.loadStyles();
expect(document.createElement).toHaveBeenCalledTimes(2);
expect(document.createElement).toHaveBeenCalledWith('link');
expect(document.createElement).toHaveBeenLastCalledWith('link');
expect(document.head.appendChild).toHaveBeenCalledTimes(2);
});
// test 2
it('should add the style links to the DOM', () => {
functions.loadStyles();
const linkElements = document.querySelectorAll<HTMLLinkElement>('link');
expect(linkElements.length).toBe(2);
const firstLink = linkElements.item(0);
const secondLink = linkElements.item(1);
expect(firstLink.href).toEqual('some_href_1');
expect(firstLink.rel).toEqual('stylesheet');
expect(secondLink.href).toEqual('some_href_2');
expect(secondLink.rel).toEqual('stylesheet');
});
});
});
Ideally, I'd like to have a fresh instance of document
in each it
block. I thought that overwriting the document
with new JSDOM().window.document
would have worked but I guess it didn't. Thanks for the help in advance!