user-event: Regression: Click event suddenly stopped working (Reactstrap / Popper.js 1.x)
@testing-library/user-eventversion: 13.1.1
- Testing Framework and version: Jest 26.6.3.
- DOM Environment: JSDOM 16.4.0, node 12.19.0
Relevant code or config
This code opens a modal that contains some buttons and clicks on them. The modal is provided by Reactstrap (8.9.0).
it('can discard and apply a filter selection', () => {
render(
<TestRootContainer initialState={mockStore}>
<BookingsFilter />
</TestRootContainer>,
);
// open filter popover
user.click(
screen.getByRole('button', {
name: 'cmb-web.filter.filter-by',
}),
);
// expect filter apply button
screen.getByRole('button', { name: 'cmb-web.filter.apply' });
// expect no filters set
screen.getByText('cmb-ui-core.active-filter-items.no-active-filters');
// expect no reset button
expect(screen.queryByRole('button', { name: 'cmb-web.filter.reset' })).toBe(null);
// select a byType filter
user.click(screen.getByRole('button', { name: 'cmb-ui-core.account-detail-filter.credit' }));
//^^^^^^^^^^^^^
//Here the code execution just stops. The onclick handler on the button is never called.
// The test failed here because the button does not appear.
user.click(screen.getByRole('button', { name: 'cmb-web.filter.reset' }));
// Expect popover to have closed
expect(screen.queryByRole('button', { name: 'cmb-web.filter.apply' })).toBe(null);
What you did: This test failed after an upgrade of user-events from 12.6.3 to 13.1.1. It worked again when I downgraded back to 12.6.3.
What happened:
The test failed at the marked spot. Adding async / await did not help. Also using the bound getByRole did not help.
When run with the debugger the context never switched back to the React component after the click on the button. The flow went straight to the next line in the test.
The test then failed in the next line since the button click handler had not been called the UI never updated.
Reproduction repository:
I’ll try to find time to create a minimal repo that can reproduce the issue. But I hope that maybe you have an idea what could be the reason for this regression.
Problem description: The modal component does register some event listeners on document that close it when the user clicked outside of it. Could this be the reason?
If it helps, I can go through every release in between and try to see where the regression happened.
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 4
- Comments: 33 (19 by maintainers)
If somebody still has this problem
skipPointerEventsCheckoption was introduced and can be used in the following way:Cool! I’ll try get something up next week 😃
Workaround for version 14.0.0+:
@ph-fritsche I’ve also experienced this issue, and even though I fully understand the rationale behind this decision (and think it makes sense to consider no-pointer-events as being non-clickable), I think we could perhaps improve this behaviour.
Similar to how
testing-libraryhas thegetByquery which will error if the element is not found, and the convenientfindBy( /waitFor) helpers to retry until the element is found, could it make sense to add a behaviour which would throw an error if we try to click a non-clickable element? (i.e. disabled, or no pointer events). (or at a minimum, aconsole.warningwhen this occurs)This would really ease the DX for people dealing with external libraries where you can’t easily control this behaviour, animated components, and as well make it way more clear why tests are failing. Right now, it’ll just ‘no-op’ if the element is not clickable, giving the responsibility of raising an error to the next assertion, and thus easily making the cause of the test failure quite obscure.
This would also make it way easier to work around when you have animating components or inflexible libraries: you’d then simply have to wrap your click in
Please let me know what you think and if this deserves its own ticket. I’d also be happy to try contribute this to the project if this is something you’d be interested in.
pointer-events is
auto.@vicrep Don’t get me wrong. If you feel strongly about this, a feature request in a separate issue is welcome. It’s just that at the moment I fear it brings a couple of new problems while not really solving one. If you come up with a consistent policy for such a flag that we could implement across our APIs and it receives positive feedback, I would consider an implementation.
@ph-fritsche I was thinking, could we consider adding a
forceoption to user events, which bypasses interactivity checks? That way people can still use library for user events instead of falling back to the inferiorfireEvent.*, or inconsistently using one or the other. (Again, happy to contribute)Something like
It’s nice to have errors if elements can’t be clicked. But I can’t solve the initial issue.
I tried a number of different ways to do this:
As of now I sadly can’t upgrade the project away from popper v1, which is used by blueprint.
In the final application the pointer events are set to
autoas expected.I’m pretty much stuck here, the only way I know which “solves” this is by using
fireEvent.clickinstead@markivancho how did you solve this?
I am facing the same issue with v13.1.x. I am using react-popper v1.3.6
It returns
autoin the browser’s developer console but returnsnonewhen I log it in the test file.As mentioned by @markivancho , react-popper adds
pointer-events: noneas initial style to the popper element. Then the element re-renders and updates the value toauto. This creates a race-condition as when the click event is triggered, the value of pointer-events is stillnoneAdding a waiting time of “0 ms” resolves this issue.
await new Promise(res => setTimeout(() => res(), 0))But, it’s not feasible to add this workaround for multiple failing tests.