nikitaeverywhere / react-xmasonry

Simple, minimalistic and featured native masonry layout for React JS.
https://zitros.github.io/react-xmasonry
MIT License
91 stars 12 forks source link

React Testing Library #30

Open alanjohnson opened 2 weeks ago

alanjohnson commented 2 weeks ago

My project requires test coverage, but RTL never renders any of the children in XMasonry. I understand that XMasonry does 3 renders, but i never can seem to get it to finish any rendering to be able to run a test on any of the contents.

i.e. what do we need to do to get a basic test like this to pass?

import React from 'react';
import { render, screen } from '@testing-library/react';
import { XMasonry, XBlock } from 'react-xmasonry';

test('Selecting elements in Masonry', async () => {
  render(
    <XMasonry>
      <XBlock>
        <div className="card">
          <h1>Simple Card</h1>
        </div>
      </XBlock>
      <XBlock width={2}>
        <div className="card">
          <h1>Wider card</h1>
        </div>
      </XBlock>
    </XMasonry>
  );
  const testItem = await screen.findByText('Simple Card');
  expect(testItem).toBeInTheDocument();
});

Now, i've been able to get it to pass by using waitFor()... BUT, that seems like a false positive, since i can say waitFor - "THIS IS NOT THERE", and it will pass an assertion that it is there. same goes for trying to nest it inside requestAnimationFrame.

nikitaeverywhere commented 1 week ago

Hello! I don't use @testing-library/react specifically (I'm using playwright for all my e2e & functional tests), but let me drop a few suggestions here.

XMasonry's internals render 3 times as described here, rendering first time an empty block. Thus, if your test engine performs only one render before the assertion, it's expected to have it empty. It is what it is for this library - personally I lack some time to refactor internals of XMasonry, nowadays I would build the masonry layout quite differently, conforming with SSR, measuring available width with iFrame, making it a bit more modular in terms of the layout etc.

Apart from it it's still great, you just need to conform with how internals work. Purely for debugging purposes, in your case, I'd start from a simple console.log() added to a body of XMasonry (in node_modules) just to check how many times it's re-rendered. I guess @testing-library/react might not trigger effects or yes, you would need to simply "waitFor".

As for false positive test, I'm a bit unsure what you mean. In tests, typically, you test that a thing exists (hence waitFor is fine). Testing an exception (something that should not exist on a screen) should be joint with waitFor also, like for example, if you're testing that 2 cards "Cat" and "Dog" appear but no 3rd card "Turtle" is present, you'd waitFor Dog to appear, and check "Turtle" right after that, never before.