Repository navigation
Open
Description
Describe the bug
In browser table rows are rendered as expected. In unit tests useVirtualizer returns an empty array from rowVirtualizer.getVirtualItems(). The bug is introduce with changes introduced by v3.0.0-beta.63. It also exists in the latest release v3.0.1
I think it was introduced by #598 here
Your minimal, reproducible example
below
Steps to reproduce
This unit test will pass for v3.0.0-beta.62 and fail for any version there after.
import { useVirtualizer } from "@tanstack/react-virtual";
import { render, screen } from "@testing-library/react";
import { styled } from "@mui/material";
import { useCallback, useRef } from "react";
const items = [
{ id: 1, name: "foo" },
{ id: 2, name: "bar" },
];
const Parent = styled("div")({ height: "100%", width: "100%", overflow: "auto" });
const Inner = styled("div")({ width: "100%", position: "relative" });
const Row = styled("div")({ position: "absolute", top: 0, left: 0, width: "100%" });
function VirtualTableComponent() {
const parentRef = useRef<HTMLDivElement>(null);
const rowVirtualizer = useVirtualizer({
count: items.length,
getScrollElement: () => parentRef.current,
estimateSize: useCallback(() => 56, []),
});
return (
<Parent ref={parentRef}>
<Inner sx={{ height: `${rowVirtualizer.getTotalSize()}px` }}> {/* set at 112px as expected */}
{rowVirtualizer.getVirtualItems().map((virtualRow) => ( // always an empty array
<Row
key={virtualRow.index}
data-index={virtualRow.index}
ref={rowVirtualizer.measureElement}
style={{ transform: `translateY(${virtualRow.start}px)` }}
>
<div>{items[virtualRow.index].name}</div>
</Row>
))}
</Inner>
</Parent>
);
}
describe("@tanstack/react-virtual", () => {
it("renders rows", () => {
render(<VirtualTableComponent />);
expect(screen.getByText(items[0].name)).toBeInTheDocument();
expect(screen.getByText(items[1].name)).toBeInTheDocument();
});
});Expected behavior
As a user I expect the provided unit test to pass but it fails.
How often does this bug happen?
Every time
Screenshots or Videos
No response
Platform
macOS
tanstack-virtual version
v3.0.1
TypeScript version
v4.9.5
Additional context
I've console.log'd out the value of rowVirtualizer.getTotalSize() and it is given 112 as expected
Terms & Code of Conduct
- I agree to follow this project's Code of Conduct
- I understand that if my bug cannot be reliable reproduced in a debuggable environment, it will probably not be fixed and this issue may even be closed.
Reacted by Fabien Rogeret, Branislav Makan, Tobias Skarhed, Matt Champagne, Charles Richardson, Yusuf Canbaz, Kirk Holloway, Andri Óskarsson, Jonathan Wieben, Vicente Almeida and 4 more
Metadata
Metadata
Assignees
Labels
No labels
Activity
piecyk commentedon Jan 3, 2024
@densk1 that is correct behaviour, it's because in unit test elements don't have height or width. One option is to mock the getBoundingClientRect for the scroller element to return some height.
densk1 commentedon Jan 3, 2024
Ah ok, thanks! So it won't matter if set height on parent CSS because getBoundingClientRect won't return it anyway?
Is there a challenge with mocking getBoundingClientRect that it needs to be mocked for both the parent, inner and rows themselves?
ak274 commentedon Jan 5, 2024
I'm facing the same issue
rowVirtualizer.getVirtualItems()is always empty. Is there any example how to write unit tests for this?luchiago commentedon Jan 5, 2024
Same issue here using
3.0.1. The proposed solutionOne option is to mock the getBoundingClientRect for the scroller element to return some height.worked on my test suite.zroux93 commentedon Jan 5, 2024
@luchiago When I tried this, it changed the sizes of all HTML elements (both the container and the option elements), so my test list only rendered 2 options (presumably a visible one and the option below it) even though I passed more options to it. Is this how your tests are written or do you have a workaround for this?
luchiago commentedon Jan 5, 2024
@zroux93 In my case, the whole test file was failing for the same reason, the same as you. The tests passed when I put a
beforeEachwith this workaround. But before it started failing, I only expected an array with two virtual rows. That may be why it worked for me.saomartinho commentedon Jan 16, 2024
@luchiago, can you put a example? Because a follow your suggestion, and put
beforeEach, but still return 0 virtual rows.Oki, found it my issue is in the logic file, where I use the
renderHookfunction from testing-library. Do you know what to do here?luchiago commentedon Jan 17, 2024
@saomartinho can you share the code problem here?
istvandesign commentedon Jan 20, 2024
I think the issue here is that we should have unit tests in the examples.
Documentation should contain at least how to mock getBoundingClientRect in jest with JS and TypeScript to test with TanStack/virtual.
I've wasted a day trying to figure out why my mock data was not working in a unit test, if you are refactoring someone else's code and you update react-virtual you will encounter this issue.
Do we have some other way to do this, like mocking some function inside the library ?
I've checked
and
both solutions allow the tests to render the items in a virtualised table.
luchiago commentedon Jan 20, 2024
@istvandesign it's a similar approach to what I did, but you did it with more options. I agree it's missing a documentation on how to mock, but I believe it should be an issue to investigate.
istvandesign commentedon Jan 20, 2024
That's because I am using TypeScript.
piecyk commentedon Jan 20, 2024
Yes i agree, we should include it. Nevertheless mocking Element.prototype is enough, for more complex scenarios we can even return different values, for example like here if we add
aria-labelon scroller div of virtualizerOther option would be to create context provider that would pass your own observeElementRect for test, something like
ipsips commentedon Feb 19, 2024
i am facing the same problem but not in simulated test environment:
it seems to me that if getScrollElement returns null, then getVirtualItems returns an empty array.
and it seems that getScrollElement is called during initial render and if you've chosen to return a ref object's current value (which is expected to point to DOM element) then you are not doing React correctly because:
coming up with a workaround to this should be trivial, however using a ref object to refer to a DOM node does seem like to most natural approach in getScrollElement.
denchen commentedon May 5, 2025
Sorry to dredge up an old topic, but I had been using the mocking of
getBoundingClientRect()from #641 (comment) successfully, but this no longer works with @TanStack/virtual@3.13.7 (published on May 5th). I believe it's due to this change -- #986 -- with no longer usinggetBoundingClientRect().Width this change, I'm unsure with how to properly mock the calculated width / height.
EDIT: The following is a new workaround that passes my tests:
shniubobo commentedon May 12, 2025
Thank you very much for the new workaround! In my case, it has worked even without
beforeEach.🔧(ui) Fix tests broken by `@tanstack/vue-virtual`
piecyk commentedon May 12, 2025
Yes, that's correct! We’ve transitioned to using offsetHeight and offsetWidth for measuring the scroller's size. To mock these values properly, you’ll need to adjust your mocks accordingly. This definitely should be mentioned in the documentation to avoid confusion. I'll make sure to bring it up.
nataliethistime commentedon Oct 7, 2025
For anyone interested, another way of solving this is to pass in a custom element rect observer that returns the value you need. We had to take this approach as we were mocking
ResizeObserverto do nothing due to other parts of our application.The usage of this function is documented here and you can also refer to the original implementation if it helps.
hashcode-adrien commentedon Oct 28, 2025
I wrote a custom VirtualListBox for joyui
Autocompletewhich uses@tanstack/react-virtualinstead ofreact-window.I share the code to make it work as expected with vitest :
ToshiakiOmori commentedon Oct 28, 2026
A heads-up for anyone mocking element sizes in unit tests (happy-dom / jsdom), following the
offsetHeight/offsetWidthadvice earlier in this thread:Since
@tanstack/virtual-core3.19.6 (#1326, "Measure the scroll viewport using client dimensions"), the scroll element's size is read fromclientHeight/clientWidth, while items are still measured withoffsetHeight/offsetWidth. If you only mock theoffset*getters, the viewport size is 0 andgetVirtualItems()returns nothing again.In our case this showed up as Headless UI's virtual
Comboboxrendering no options in tests after a patch update (@tanstack/react-virtual3.14.13 → 3.14.23), while it kept working in a real browser.Mocking both pairs fixed it for us. Note that in happy-dom these getters live on
HTMLElement.prototype, notElement.prototype. We return sizes only for the listbox and its options so that other code readingclient*(e.g. overflow checks) keeps seeing 0:Question for the maintainers: is mocking the getters like this the recommended approach going forward, or would you suggest passing a custom
observeElementRect/initialRectin tests instead? A short note in the testing docs about which properties are read for the scroll element vs. the items would help, since this has changed twice (getBoundingClientRect→offset*in 3.13.7,offset*→client*in 3.19.6).