Closed mihkeleidast closed 2 years ago
I'm almost certain that this is the reason: https://github.com/petyosi/react-virtuoso/commit/a846a39af6ac57d55dee087c862b4aa3d069e887
But why does that pass then? https://github.com/petyosi/react-virtuoso/blob/master/test/ssr.test.tsx. Can you help me out a bit with the investigation?
Hmm, it does still work on 2.16.6 and 2.17.0, breaks on 2.17.1 - the only change in the changelog is https://github.com/petyosi/react-virtuoso/commit/fe55e3f3f5031a52bc624c6cab7afb9da22a9d8e, so I'd suspect that one more?
As for the SSR test, it does use ReactDOMServer.renderToString
directly - my tests are run through testing-library and jest, which means a jsdom environment.
Good catch. This is most likely a problem, although it beats me why.
A bit of a deviation: my take on the matter is that react-virtuoso is not easy or reasonable to be tested in jsdom environment. The lib relies on input element dimensions for its rendering, and as far as I know, this is not available. The best and most reliable way to test the component is to go through a real browser, with a tool like playwright. Of course, there are fast unit tests for the logic.
This being said, I am far from picking the battle of telling people how to test their apps. I also know that what you're doing is fairly popular and conventional. I am happy to acknowledge and leave this issue open, but I don't know if or when I will get into researching this deeper. The jsdom env is a weird world.
I looked at what data List renders with, it seems like before it rendered once and listState was:
{
items: [
{ index: 0, size: 0, offset: 0, data: [Object], originalIndex: 0 },
{ index: 1, size: 0, offset: 0, data: [Object], originalIndex: 1 },
{ index: 2, size: 0, offset: 0, data: [Object], originalIndex: 2 }
],
topItems: [],
topListHeight: 0,
offsetTop: 0,
offsetBottom: 0,
top: 0,
bottom: 0,
totalCount: 3,
firstItemIndex: 0
}
After the change, List renders twice, the first render is with the same listState, the second one is with empty items:
{
items: [],
topItems: [],
offsetTop: 0,
offsetBottom: 0,
top: 0,
bottom: 0,
topListHeight: 0,
totalCount: 3,
firstItemIndex: 0
}
So, I'm still struggling with the state system a bit, but it seems like changing the totalCount triggers an update somewhere else, I'll try to keep looking.
Thanks for taking a look. My concern is that it was accidentally working before.
A bit of a deviation: my take on the matter is that react-virtuoso is not easy or reasonable to be tested in jsdom environment. The lib relies on input element dimensions for its rendering, and as far as I know, this is not available. The best and most reliable way to test the component is to go through a real browser, with a tool like playwright. Of course, there are fast unit tests for the logic.
This being said, I am far from picking the battle of telling people how to test their apps. I also know that what you're doing is fairly popular and conventional. I am happy to acknowledge and leave this issue open, but I don't know if or when I will get into researching this deeper. The jsdom env is a weird world.
Controversial topic for sure :) In our case, our goal with the snapshot tests is twofold:
But as it pertains to this issue and the topic, to make our own wrapper component a bit more testable, we implemented a context provider that allows overriding the initialItemCount
from higher in the component tree. We currently pass the context value directly to Virtuoso, if it is defined. This was implemented logically similarly how react-responsive has a ResponsiveContext
to mock the window size in tests, in order to test different scenarios. That library is similarly "browser-only", i.e. it does not make much sense to test the other behavior much in jsdom.
What I'm thinking is, would that kind of override context for testing purposes make sense for react-virtuoso core? We could then lose our own custom implementation, and supporting this in core would probably work around this issue as well.
Some more findings:
Edit: Oops, had to delete most of the points, ran it without the change in question, not with, so of course it worked. Would still like to understand why the emitter logic runs twice, though...
I am usually throwing console log and console trace in the map/scans to see where the change originates from. I think that the changed I introduced altered the distinct until changed filter in that exact file (previously, it was working because of the object identity in EMPTY_LIST_STATE remaining the same), so now the produced list state overrides the one constructed by the initialItemCount
.
I really like the idea you outline about controlling the DOM state through some sort of a test oriented utility (context for example). Will give this some more thought.
Yeah, I did wonder if it compared the initial state object identity. Seems a bit weird, shouldn't it compare it to the current value of listState in that scenario?
It does, but in the previous state, the initial state and the first state were the same object identity.
We also have the same problem. Thank you for your help. @mihkeleidast @petyosi
@petyosi Have you had a chance to think about the test-oriented context utility? Just thinking how we should proceed with this. We are blocked on this in our library for adding React 18 support (as https://github.com/petyosi/react-virtuoso/pull/733 and possibly some other fixes are only in the latest version). We don't like accepting this issue as it is, because we do have some interactive elements used in the virtualized lists and tables that are covered by functional tests, and this not rendering in tests would mean less coverage for us.
I would be willing to help with implementing this, although not sure how exactly it would work in here (I don't think there's any similar context existing), so some guidance would be appreciated.
@mihkeleidast unfortunately, I have not had the time to think this problem through, day work is quite busy. I am happy to consider a design suggestion on the context-based approach, to be honest.
@petyosi I threw a very initial experiment in https://github.com/petyosi/react-virtuoso/pull/744, maybe you have some thoughts - let's continue under that PR perhaps?
I'm running into the same issue.
v2.17.1 breaks some of our jest tests.
The output of the tests failing is now showing that there's no children being rendered for virtuoso.
we're mocking virtuoso thusly in jest:
const { Virtuoso } = jest.requireActual('react-virtuoso');
const mockVirtuoso = (WrappedVirtuoso: ElementType) =>
class extends mockComponent<{ totalCount: number }, unknown> {
render() {
return <WrappedVirtuoso initialItemCount={this.props?.totalCount} {...this.props} />;
}
};
return { Virtuoso: mockVirtuoso(Virtuoso) };
});
Solved with the changes introduced in #744 . Warning: read 744 as it needs work on your side.
@petyosi @mihkeleidast Thank you for the fix. It works for me.
Describe the bug
After updating to 2.17.x, react-virtuoso does not render list items (or table rows) in tests anymore.
Reproduction Not sure how to do tests in Codesandbox, so created a simple repo in GH: https://github.com/mihkeleidast/react-virtuoso-test-rendering
To Reproduce Steps to reproduce the behavior:
Expected behavior
I'd expect the tests to work the same after updating react-virtuoso.
Desktop (please complete the following information):
Additional context There is no issue in the browser, as far as I can see. Only tests seem to be affected.