Reputation: 5761
I have a function like so inside a react component:
handleOnScroll = () => {
const {navigationSections, setNavigationSectionActive} = this.props;
const reversedSections = this.getReversedNavigationSections();
const OFFSET_TOP = 32;
const st = window.pageYOffset || document.documentElement.scrollTop;
if (st > lastScrollTop) {
for (let i = 0; i < navigationSections.length; i += 1) {
if(document.getElementById(navigationSections[i].id).getBoundingClientRect().top <= OFFSET_TOP) {
setNavigationSectionActive(navigationSections[i].id);
}
}
} else if (st < lastScrollTop) {
for (let y = 0; y < reversedSections.length; y += 1) {
if(document.getElementById(navigationSections[y].id).getBoundingClientRect().top <= OFFSET_TOP) {
setNavigationSectionActive(navigationSections[y].id);
}
}
}
lastScrollTop = st <= 0 ? 0 : st;
}
and some of the tests like so:
it('should handle handleOnScroll', () => {
instance.handleOnScroll();
expect(instance.getReversedNavigationSections()).toEqual(props.navigationSections.reverse());
});
props.navigationSections.forEach(navSection => {
it('should call setNavigationSectionActive', () => {
instance.handleOnScroll();
expect(props.setNavigationSectionActive).toHaveBeenCalledWith(navSection.id);
});
});
the first test passes but the second one ('should call setNavigationSectionActive') fails as you can see:
I think the reason is because the document is not mocked therefore the if fails. However, in the actual implementation when this gets executed:
document.getElementById(navigationSections[i].id).getBoundingClientRect().top
the DIVs that have these IDs are in another section (not in the wrapper component used for the test in question).
should I mock the document to mimic the actual structure for the if statement to pass or am I completely wrong?
MY ATTEMPT SO FAR
it('should handle custom handleOnScroll', () => {
document.body.innerHTML = '<div><div id="id">my div</div><div id="id-1">my div</div></div>';
const div = document.getElementById('id');
div.getBoundingClientRect = () => ({ top: 100 }); // <= mock getBoundingClientRect
instance.handleOnScroll();
props.navigationSections.forEach(() => {
if (global.document.getElementById('id').getBoundingClientRect().top <= global.OFFSET_TOP) {
expect(props.setNavigationSectionActive).toHaveBeenCalledWith('id');
}
});
});
Upvotes: 2
Views: 2835
Reputation: 45780
The default test environment for Jest
is jsdom
which provides a browser-like environment.
If your test requires specific content in document
then you can set the document body by using something like document.body.innerHTML
.
jsdom
implements a lot of browser functionality, but not everything. In this case getBoundingClientRect
is stubbed to always return 0
so if you want it to return something else you'll have to mock it.
Here is a simple working example to get you started:
const OFFSET_TOP = 5;
const func = () =>
document.getElementById('theid').getBoundingClientRect().top <= OFFSET_TOP ?
'less' :
'more';
test('func', () => {
document.body.innerHTML = '<div id="theid">my div</div>';
expect(func()).toBe('less'); // Success!
const div = document.getElementById('theid');
div.getBoundingClientRect = () => ({ top: 10 }); // <= mock getBoundingClientRect
expect(func()).toBe('more'); // Success!
});
Upvotes: 3