I have this custom hook:
import {useEffect, useState} from 'react';
...
const isScrollerAtBottom = (elt: HTMLElement) => {
return (
Math.floor(Number(elt?.scrollHeight) - Number(elt?.scrollTop)) >
Number(elt?.clientHeight)
);
};
export function useScroll(container: HTMLElement): useScrollProps {
console.dir(container, {depth: 12});
const [displayScroller, setDisplayScroller] = useState(true);
const [scrollerTop, setScrollerTop] = useState(0);
const [scrollerLeft, setScrollerLeft] = useState(0);
useEffect(() => {
const containerDimensions = container
? container.getBoundingClientRect()
: null;
console.dir(containerDimensions, {depth: 12});
const left =
(containerDimensions?.x || 0) +
(containerDimensions?.width || 0) -
40;
const top = containerDimensions?.height || 0;
setScrollerTop(top);
setScrollerLeft(left);
setDisplayScroller(isScrollerAtBottom(container));
});
...
const handleScroll = (event: React.UIEvent<HTMLElement>) => {
const elt = event.target as HTMLElement;
setDisplayScroller(isScrollerAtBottom(elt));
};
return {
displayScroller,
scrollerTop,
scrollerLeft,
handleScroll,
};
}
And I'd like to test it. My problem is how to mock the HTMLElement as container.
I tried this:
import { JSXElement } from "@babel/types";
import React from 'react';
import { render, renderHook, screen } from "@testing-library/react";
import { useScroll, useScrollProps } from "../../hooks/useScroll";
describe("useScroll", () => {
const container: HTMLElement = document.createElement("div");
container.style.width = "300px";
container.style.height = "800px";
container.style.display = "block";
const content: HTMLElement = document.createElement("p");
content.innerHTML = `... ... ...`;
container.appendChild(content);
test("should return scroller position and display flag", () => {
const { result } = renderHook(() => useScroll(container));
console.log(result.current);
});
});
But the container dimension is not get in the customHook:
console.dir
{
x: 0,
y: 0,
bottom: 0,
height: 0,
left: 0,
right: 0,
top: 0,
width: 0
}
If I can get the right dimension of the container mock then I think I can continue to proceed to do some assertions, but I don't know how to get there.
Any idea will be appreciated. Thanks!
POST-EDIT:
What I have seen so far about similar needs is people use to mock such function (getBoundingClientRect
), but if I can't use a mocked HTML element and have the expected calculations for the mocked HTMLElement using the hook I don't think the test will make sense. What I want to test is it returns true/false if the scroll is at the bottom of the container.
Any ideas, comments and/or opinions about this are welcome.
TRY: Render component
import { fireEvent, render, renderHook } from "@testing-library/react";
import { useScroll } from "../../hooks/useScroll";
describe("useScroll", () => {
test("should return scroller position and display flag", () => {
const { container } = render(
<div style={{ width: "200px", height: "700px" }}></div>
);
const { result } = renderHook(() => useScroll(container));
container.addEventListener("scroll", result.current.handleScroll);
fireEvent.scroll(container, { target: { scrollTop: 0 } });
expect(result.current.displayScroller).toBeFalsy();
fireEvent.scroll(container, { target: { scrollTop: 700 } });
expect(result.current.displayScroller).toBeTruthy();
});
});
But the last assertion expect(result.current.displayScroller).toBeTruthy();
is still false although the event returned in the hook I am testing is trigered.