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

[EuiToolTip] Convert tests to RTL and export tooltip RTL helpers #6106

Merged
merged 6 commits into from
Aug 9, 2022

Conversation

cee-chen
Copy link
Member

@cee-chen cee-chen commented Aug 3, 2022

Summary

This PR:

Checklist

@cee-chen
Copy link
Member Author

cee-chen commented Aug 3, 2022

Quick note: CI on this PR will fail until #6105 is merged (on the Enzyme regression test)

@@ -40,6 +40,7 @@ export class EuiToolTipPopover extends Component<Props> {
componentDidMount() {
document.body.classList.add('euiBody-hasPortalContent');
window.addEventListener('resize', this.updateDimensions);
this.updateDimensions();
Copy link
Member Author

@cee-chen cee-chen Aug 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not 100% sure this is the best way to solve #6065 but it definitely is the quickest!

The issue here is that EuiToolTipPopover.updateDimensions/EuiToolTip.positionToolTip simply isn't getting called in tests.

I believe position styles are initially set/work in browser environments because of the EuiResizeObserver here:

<EuiResizeObserver onResize={this.positionToolTip}>
{(resizeRef) => <div ref={resizeRef}>{content}</div>}
</EuiResizeObserver>

But because this is jsdom, and jsdom doesn't support MutationObservers on the version we're on (v11), and presumably also does not support ResizeObservers, positionToolTip never gets called and the visibility styles never get set.

Calling updateDimensions on mount should fix the issue and have minimal perf impact, but I could be wrong on that - 2nd opinions appreciated (cc @thompsongl).

If we absolutely had to we could attempt to either 1. polyfill window.ResizeObserver or 2. mock EuiResizeObserver, but one downside to those approaches is that consuming applications will have to import those mocks as opposed to simply getting a fix (this approach).

Copy link
Contributor

@thompsongl thompsongl Aug 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could use the IS_JEST_ENVIRONMENT util and only run this during tests. Just confirmed locally that it'd work.

if (IS_JEST_ENVIRONMENT) this.updateDimensions();

Copy link
Member Author

@cee-chen cee-chen Aug 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's definitely an approach we can use - but I guess like, in a vacuum, doesn't it feel like positionTooltip should be called on tooltip mount in any case? If you told me that it gets passed to a window resize listener and a resize observer, I wouldn't assume positionTooltip gets called except on resize.

(Separately I also wonder if we should examine our EuiResizeObserver to make sure it isn't incorrectly calling the onResize callback on mount when it shouldn't be)

Copy link
Contributor

@thompsongl thompsongl Aug 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't it feel like positionTooltip should be called on tooltip mount in any case? If you told me that it gets passed to a window resize listened and a resize observer, I wouldn't assume positionTooltip gets called except on resize. I do wonder if we should examine our EuiResizeObserver to make sure it isn't incorrectly calling the onResize callback on mount when it shouldn't be.

So ResizeObserver does call the callback immediately upon instantiation, per spec: WICG/resize-observer#38 (comment)
https://codepen.io/thompsongl/pen/MWVVZjZ?editors=1111
At one point before browser support was there, EUI had it's own polyfill to mimic the callback-on-init behavior:

requestAnimationFrame(this.onResize); // Mimic ResizeObserver behavior of triggering a resize event on init

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not that it's intuitive at all, but calling the callback on mount explicitly would mean that the callback is called twice on mount in normal browsers situations.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ha 🙃 That spec is super unintuitive. Thanks for the source!

To be honest, I'm not a huge fan of our various usages of IS_JEST_ENVIRONMENT and I'd rather move away from them than add another instance. I think jest.mock()s are a safer way of handling test-only logic without adding unreachable branches to source/production code.

If we don't want the extra call on mount, I'd personally rather add a testenv mock to EuiResizeObserver that simply calls on the onResize callback on mount. Thoughts?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a testenv mock to EuiResizeObserver that simply calls on the onResize callback on mount

Probably worth looking into. I wonder how/if that would impact consumers who are use the polyfill. Kibana doesn't use it as far as I know.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consumers who use the polyfill wouldn't be importing/automatically using our testenv mock, so it shouldn't affect them 🤷

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah right!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alrighty, added a testenv mock: acb564c

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_6106/

+ prefer runAllTimers over static timeout
+ restore real timers after
- keep single Enzyme test for legacy/portal regression catches
@cee-chen cee-chen marked this pull request as ready for review August 4, 2022 15:24
@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_6106/

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_6106/

Comment on lines 32 to 33
// Re-export other exports
export { hasResizeObserver, useResizeObserver } from './resize_observer';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't work because resize_observer.testenv.tsx completely replaces resize_observer.tsx in the testenv build.

For hasResizeObserver you could probably copy-paste. For useResizeObserver I'm not exactly sure. Maybe it's similar to EuiResizeObserver and it just does an on mount useEffect?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ahhh gotcha gotcha, sorry, I totally brainfarted on how our test-env export works. looking into this now

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok this time for real 5f15f23

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_6106/

@kibanamachine
Copy link

Preview documentation changes for this PR: https://eui.elastic.co/pr_6106/

Copy link
Contributor

@thompsongl thompsongl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code here looks good but when I run tests in Kibana I get a bunch of errors like this:

Error: Uncaught [TypeError: Cannot read properties of undefined (reading '_context')]

I think it's unrelated and my local env is just borked but want to confirm that, say, src/plugins/discover Jest tests all pass for you.

@cee-chen
Copy link
Member Author

cee-chen commented Aug 8, 2022

No failures with the following commands:

yarn kbn reset // since my local Kibana has upgrade work
yarn kbn bootstrap --no-validate
yarn test:jest src/plugins/discover

@cee-chen cee-chen merged commit b060306 into elastic:main Aug 9, 2022
@cee-chen cee-chen deleted the tooltip-testing branch August 9, 2022 15:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Testing popover visibility and contents with react testing library.
3 participants