Reputation: 929
I want to write a test for a utils method. In that method I get a html element by id and then change the color of the element. The problem is that element is only available after a button click. How can I mock the element?
UtilListItem.js
import variables from '../stylesheets/Variables.scss';
export function activeListItem(props){
let listItem = document.getElementById(props.id);
listItem.style.backgroundColor = variables.whiteGray;
return listItem;
}
UtilListeItem.test.js
it('check if the correct color is set for the acitve list item', () => {
let props = {id:'123'}
const listItem = activeListItem(props);
expect(listItem.style.backgroundColor).toBe('#ededed');
});
error
TypeError: Cannot read property 'style' of null
Upvotes: 15
Views: 78526
Reputation: 32158
I'd suggest you to you jest.spyOn. It's a really handy way to spy on a function and/or attach some mock behaviour.
You can use it like this:
import { activeListItem } from './utils';
let spy;
beforeAll(() => {
spy = jest.spyOn(document, 'getElementById');
});
describe('activeListItem', () => {
describe('with found element', () => {
let mockElement;
beforeAll(() => {
// Here you create the element that the document.createElement will return
// It might be even without an id
mockElement = document.createElement(....);
spy.mockReturnValue(mockElement);
});
// And then you could expect it to have the background
it('should have the background applied', () => {
expect(mockElement.style.backgroundColor).toBe('#ededed');
});
});
describe('without found element', () => {
// And here you can create a scenario
// When document.createElement returns null
beforeAll(() => {
spy.mockReturnValue(null);
});
// And expect you function not to throw an error
it('should not throw an error', () => {
expect(() => activeListItem({id:'123'})).not.toThrow();
});
});
});
It's also a good idea to mock the .scss
file, since it's a dependency of your utility file, so that when it's change it won't affect your unit test.
Upvotes: 25
Reputation: 6436
A combination of the top two answers worked well for me:
...
beforeAll(() => {
const modalDiv = document.createElement("div");
modalDiv.setAttribute("id", "react-modal-container");
document.body.appendChild(modalDiv);
});
...
Upvotes: 0
Reputation: 338
This line have problem:
let listItem = document.getElementById(props.id);
Create element in the first place for mocking in jest. Be sure to wait for document and inject it.
What you doing is getting element when isn't ready to test / non exist in this context.
--- EDITED TO ADD EXAMPLE ---
What need to be added: https://jestjs.io/docs/en/configuration#setupfiles-array
Others response to similar problem with example solution: https://stackoverflow.com/a/41186342/5768332
Upvotes: 1
Reputation: 220
There are two options I can think of, you can opt either of them:
Put a check on listItem of function activeListItem
export function activeListItem(props) {
let listItem = document.getElementById(props.id);
if (listItem === null) {
return;
}
listItem.style.backgroundColor = variables.whiteGray;
return listItem;
}
Add dummy element in your test case
it('check if the correct color is set for the acitve list item', () => {
/** Create and add dummy div **/
let testId = "dummy-testId";
let newDiv = document.createElement("div");
newDiv.setAttribute("id", testId);
document.body.appendChild(newDiv);
let props = {id: testId}
const listItem = activeListItem(props);
expect(listItem.style.backgroundColor).toBe('#ededed');
});
Upvotes: 8