Comments (4)
Thanks! That all looks amazing. I appreciate your thoughtful response. We continue to love this lib here at Smartsheet.
from jsdom-testing-mocks.
Hello! Thank you for the issue!
You are correct, I missed this, the problem is though, that when the react observer instance is first initialised and we begin to observe
some element, it is quite often inside the first render
and at that point, there's no easy way (that I'm aware of) to set element's dimensions and if the callback shouldn't fire if the size of the element is 0 then nothing will happen anyway.
The advantage of the current situation is that I can test the state before the ro callback and then call it manually and test the state after that. I can potentially add some sort of method that will call the callback with all elements that just subscribed, but there's not much value there. The best would be to find some way to assign dimensions to elements during render. But I'm not sure that this is necessary, when we can set dimensions after render and manually call resize
.
How do you use it? Do you have any case in mind when that is necessary?
I think I will still implement that though for the case when you are able to set dimensions before observe is called
from jsdom-testing-mocks.
Good point. Without some trickery it's challenging to get all the things in the right order. Maybe these examples will spawn some ideas. In short, I don't have any great ideas. I think the current situation will work just fine but perhaps the docs could be expanded to show the caveat?
In the React case below, you'd have to either do that weird ref hack, or:
render
your component- call
mockElementBoundingClientRect
- call
rerender
to rerun whatever effect the ResizeObserver is hooked up in.
When testing a hook
We have a hook useResizeObserver
that returns a RefCallback to attach to the element being observed and when attached, hooks up the RO in an effect. Its test (jest
, @testing-library/react-hooks
) looks like this:
it("should wait on an element before attaching the resizeobserver", async () => {
const onResize = jest.fn();
const { result } = renderHook(
(onResize: ResizeObserverCallback) =>
useResizeObserver(onResize),
{
initialProps: onResize,
}
);
/*
result.current looks like this:
{
ref: RefCallback<HTMLElement>
}
*/
expect(onResize).not.toHaveBeenCalled();
// Note that in this test we can create, mock, and provide the DOM element to the ResizeObserver
// since we have full control over it.
const element = document.createElement("div");
mockElementBoundingClientRect(element, { width: 100, height: 100 });
act(() => {
result.current.ref(element);
});
// Due to this issue, we have to call this manually here still.
act(() => {
resizeObserverMock.resize(element);
});
await waitFor(() => {
expect(onResize).toHaveBeenCalledWith(...ResizeObserverEntry[]...)
});
});
When testing a React component that uses the hook from the previous example
const TestComponent = forwardRef(
(props: HTMLAttributes<HTMLDivElement>, ref: Ref<HTMLDivElement>) => {
return (
<div {...props} ref={ref}>
something.
</div>
);
}
);
it("tests resize", () => {
const fakeRef = jest.fn().mockImplementation((elem: HTMLElement | null) => {
mockElementBoundingClientRect(elem, {width: 100, height: 100});
});
render(<TestComponent ref={fakeRef} />);
// At this point, if TestComponent uses the useResizeObserver hook from the first example,
// it should be hooked up.
// Admittedly this is not optimal since it relies on the component to forward a ref.
// I think this is JUST a tiny bit better than having to re-render the whole component, but not by much.
})
from jsdom-testing-mocks.
Hey @tannerlyons !
Finally found some time to refactor ResizeObserver a bit, check out 1.6.0@beta and the docs
There isn't much change in terms of how things are done. I made some tests, trying to implement a way to assign a size to an element before/during rendering, and found out that it's problematic. Due to the nature of how the callback is triggered (multiple calls to observe
will trigger only one callback), I'm forced to trigger it outside of the main render function (inside queueMicrotask
or similar) and therefore any state update that happens in the callback will be outside the render's act
and will generate a "State update outside act" error.
But also it's not needed. I think it's best to trigger the callback manually, it gives more control over tests. I made, however, some minor changes to better mock the Resize Observer, like not including the element if its size is 0 (on both axes), auto-adding newly observed elements to the list of callback entries, and some other minor things. You can check it out in the updated docs.
Currently, I'm quite happy with how it works, I can't think of any case that is really difficult to test. If you can test the new version to see if it works for you, that would be great. If you know of any case that is problematic, let me know, maybe I missed something.
from jsdom-testing-mocks.
Related Issues (10)
- Allow adding more properties to the IntersectionDescription HOT 5
- TypeError: Cannot redefine property: ResizeObserver (v1.4.0) HOT 2
- Error with type-fest on build project HOT 2
- [Request] Add compatibility with other libraries HOT 8
- Animations aren't captured HOT 7
- `@media not all and ` is not supported HOT 1
- Do not require window at import time HOT 15
- LocalResizeObserver is not a constructor error in v1.10+ HOT 2
- Export `MockedResizeObserver` class
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from jsdom-testing-mocks.