Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to fire user-events with @testing-library/react library inside of resizable panel #367

Closed
florianmartens opened this issue Jun 24, 2024 · 9 comments
Labels
help wanted Extra attention is needed

Comments

@florianmartens
Copy link

florianmartens commented Jun 24, 2024

Hey, thanks for putting all this work into this library. It is really great!

What issue have I encountered

When using @testing-library/react inside of a component that lives inside of <ResizablePanelGroup />, I'm unable to dispatch events with the @testing-library/user-event library. This does not seem to be an issue with testing library nor any other dependency.

I suspect that somewhere dom nodes are remounted in an unforeseen way. By the time we want to dispatch an event the reference to the dom node is invalid. Strangely, events dispatched with fireEvent work.

How to reproduce?

I've created a repo for reproduction. The important part is the test file resizable-layout.test.tsx.

test("click has no output with userEvent", async () => {
  render(<ResizableDemo />);
  const btn = screen.getByTestId("test");
  const user = userEvent.setup();
  await user.click(btn); // Will not call the onClick handler
});

test("click has output with fireEvent", async () => {
  render(<ResizableDemo />);
  const btn = screen.getByTestId("test");
  fireEvent.click(btn); // Will call the onClick handler
});

Steps for reproduction

  • Clone the repo
  • pnpm i
  • pnpm run test

What is the impact?

React testing library is a popular way of testing react applications and user-event is the recommended way working with events. Currently any component inside of a resizable area cannot dispatch user events.

@bvaughn bvaughn added the help wanted Extra attention is needed label Jul 2, 2024
@bvaughn
Copy link
Owner

bvaughn commented Jul 2, 2024

Open to reviewing a PR if you'd like to suggest a fix!

@jazzy-em
Copy link

I faced similar issue. After initial investigation looks like the root cause is user-event library bug
testing-library/user-event#1206

@bvaughn
Copy link
Owner

bvaughn commented Jul 22, 2024

I'm not sure to what to do with this one. My guess would be that this has something to do with the user-event helper. I don't think this library is using pointer events in any sort of unusual way. Also I don't really know that library (or what the difference between those two helper methods would be) so I'm not sure how realistic it is for me to "support" it here.

My first thought was that it's possible this library is calling event.preventDefault() and that's blocking the simulated "click" event, which may be happening because the example app share doesn't have meaningful styles, causing a lot of the components to overlap in such a way as to potentially cause multiple components to handle the same event?
Screenshot 2024-07-21 at 9 58 47 PM

But when I ran the test locally I saw this in the console:

 FAIL  src/components/resizable-layout.test.tsx > click has output with fireEvent
TestingLibraryElementError: Found multiple elements by: [data-testid="test"]

Here are the matching elements:

Ignored nodes: comments, script, style
<button
  data-testid="test"
>
  Test btn
</button>

Ignored nodes: comments, script, style
<button
  data-testid="test"
>
  Test btn
</button>

Looking at the HTML in the console at this point shows:

<body>
  <div>
    <div
      class="flex h-full w-full data-[panel-group-direction=vertical]:flex-col max-w-md rounded-lg border"
      data-panel-group=""
      data-panel-group-direction="horizontal"
      data-panel-group-id=":r0:"
      style="display: flex; flex-direction: row; height: 100%; overflow: hidden; width: 100%;"
    >
      <div
        class="Panel"
        data-panel=""
        data-panel-group-id=":r0:"
        data-panel-id=":r1:"
        data-panel-size="50.0"
        style="flex-basis: 0px; flex-grow: 50; flex-shrink: 1; overflow: hidden;"
      >
        <div
          class="flex h-[200px] items-center justify-center p-6"
        >
          <span
            class="font-semibold"
          >
            One
          </span>
        </div>
      </div>
      <div
        class="relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90"
        data-panel-group-direction="horizontal"
        data-panel-group-id=":r0:"
        data-panel-resize-handle-enabled="true"
        data-panel-resize-handle-id=":r2:"
        data-resize-handle=""
        data-resize-handle-state="hover"
        role="separator"
        style="user-select: none;"
        tabindex="0"
      />
      <div
        class="Panel"
        data-panel=""
        data-panel-group-id=":r0:"
        data-panel-id=":r3:"
        data-panel-size="50.0"
        style="flex-basis: 0px; flex-grow: 50; flex-shrink: 1; overflow: hidden;"
      >
        <div
          class="flex h-full w-full data-[panel-group-direction=vertical]:flex-col"
          data-panel-group=""
          data-panel-group-direction="vertical"
          data-panel-group-id=":r4:"
          style="display: flex; flex-direction: column; height: 100%; overflow: hidden; width: 100%;"
        >
          <div
            class="Panel"
            data-panel=""
            data-panel-group-id=":r4:"
            data-panel-id=":r5:"
            data-panel-size="25.0"
            style="flex-basis: 0px; flex-grow: 25; flex-shrink: 1; overflow: hidden;"
          >
            <div
              class="flex h-full items-center justify-center p-6"
            >
              <button
                data-testid="test"
              >
                Test btn
              </button>
            </div>
          </div>
          <div
            class="relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90"
            data-panel-group-direction="vertical"
            data-panel-group-id=":r4:"
            data-panel-resize-handle-enabled="true"
            data-panel-resize-handle-id=":r6:"
            data-resize-handle=""
            data-resize-handle-state="hover"
            role="separator"
            style="user-select: none;"
            tabindex="0"
          />
          <div
            class="Panel"
            data-panel=""
            data-panel-group-id=":r4:"
            data-panel-id=":r7:"
            data-panel-size="75.0"
            style="flex-basis: 0px; flex-grow: 75; flex-shrink: 1; overflow: hidden;"
          >
            <div
              class="flex h-full items-center justify-center p-6"
            >
              <span
                class="font-semibold"
              >
                Three
              </span>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
  <div>
    <div
      class="flex h-full w-full data-[panel-group-direction=vertical]:flex-col max-w-md rounded-lg border"
      data-panel-group=""
      data-panel-group-direction="horizontal"
      data-panel-group-id=":r8:"
      style="display: flex; flex-direction: row; height: 100%; overflow: hidden; width: 100%;"
    >
      <div
        class="Panel"
        data-panel=""
        data-panel-group-id=":r8:"
        data-panel-id=":r9:"
        data-panel-size="50.0"
        style="flex-basis: 0px; flex-grow: 50; flex-shrink: 1; overflow: hidden;"
      >
        <div
          class="flex h-[200px] items-center justify-center p-6"
        >
          <span
            class="font-semibold"
          >
            One
          </span>
        </div>
      </div>
      <div
        class="relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90"
        data-panel-group-direction="horizontal"
        data-panel-group-id=":r8:"
        data-panel-resize-handle-enabled="true"
        data-panel-resize-handle-id=":ra:"
        data-resize-handle=""
        data-resize-handle-state="inactive"
        role="separator"
        style="user-select: none;"
        tabindex="0"
      />
      <div
        class="Panel"
        data-panel=""
        data-panel-group-id=":r8:"
        data-panel-id=":rb:"
        data-panel-size="50.0"
        style="flex-basis: 0px; flex-grow: 50; flex-shrink: 1; overflow: hidden;"
      >
        <div
          class="flex h-full w-full data-[panel-group-direction=vertical]:flex-col"
          data-panel-group=""
          data-panel-group-direction="vertical"
          data-panel-group-id=":rc:"
          style="display: flex; flex-direction: column; height: 100%; overflow: hidden; width: 100%;"
        >
          <div
            class="Panel"
            data-panel=""
            data-panel-group-id=":rc:"
            data-panel-id=":rd:"
            data-panel-size="25.0"
            style="flex-basis: 0px; flex-grow: 25; flex-shrink: 1; overflow: hidden;"
          >
            <div
              class="flex h-full items-center justify-center p-6"
            >
              <button
                data-testid="test"
              >
                Test btn
              </button>
            </div>
          </div>
          <div
            class="relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90"
            data-panel-group-direction="vertical"
            data-panel-group-id=":rc:"
            data-panel-resize-handle-enabled="true"
            data-panel-resize-handle-id=":re:"
            data-resize-handle=""
            data-resize-handle-state="inactive"
            role="separator"
            style="user-select: none;"
            tabindex="0"
          />
          <div
            class="Panel"
            data-panel=""
            data-panel-group-id=":rc:"
            data-panel-id=":rf:"
            data-panel-size="75.0"
            style="flex-basis: 0px; flex-grow: 75; flex-shrink: 1; overflow: hidden;"
          >
            <div
              class="flex h-full items-center justify-center p-6"
            >
              <span
                class="font-semibold"
              >
                Three
              </span>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</body>

Does this mean you just aren't cleaning up the DOM between tests?

I tried commenting out the first test and the second one passes. I comment out the second one and the first one passes.

Then I added an explicit call to result.unmount() for the render-result and both tests pass.

So the problem here seems to be the test, not this library.

@bvaughn bvaughn closed this as completed Jul 22, 2024
@guntherlaurijssens
Copy link

I ran into this issue as well. After some investigating I found that a certain event.preventDefault() is most likely the culprit.
https://github.com/bvaughn/react-resizable-panels/blob/main/packages/react-resizable-panels/src/PanelResizeHandleRegistry.ts#L102

After commenting the culprit the tests that use userEvent.click() work as intended.

Not sure how to go about fixing this, as I'm not sure what side-effects removing this line would have.

Any feedback is welcome.

@bvaughn
Copy link
Owner

bvaughn commented Aug 28, 2024

I don’t know what scenario you saw this issue with but in the situation I looked at above, the tests seemed to be the problem.

I don’t remember why I added that call to preventDefault. (It’s been a while.) I assume I had a good reason.

@guntherlaurijssens
Copy link

guntherlaurijssens commented Aug 28, 2024

I'll try to get a reproduction when I have time later on but when running my tests I don't see a failure with
FAIL ... Found multiple elements by: [data-testid="test"].

I have multiple cases where the user-event.click works fine until I add <PanelResizeHandle ... /> to my component tree.
After adding the handle all tests that attempt to click an element just don't receive the click.

@bvaughn
Copy link
Owner

bvaughn commented Aug 28, 2024

Did you read my comment above? #367 (comment)

I start off by mentioning an idea related to styles for why that might be happening

@guntherlaurijssens
Copy link

Fair enough, sorry about that 😞 i swear I read it 🙈 but my brain must have forgotten about it. I'll try and work out if that could be the case!

Thanks for the feedback/reply!

@bvaughn
Copy link
Owner

bvaughn commented Aug 28, 2024

No problem. I do that sometimes too.

Let me know what you find

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

4 participants