Mock an internally used function from a sub package with Jest - reactjs

I have a Lerna monorepo, a #project/shared-component sub package and a #project/consumer sub package. The #project/shared-component package exposes a SharedComponent react component, which internally uses a useData hook which is also exposed. In the #project/consumer, I have a ConsumerComponent which renders the SharedComponent component. In #project/consumer, I also have a test which tests the ConsumerComponent. There I want to mock the innards of the useData hook with Jest. This is the code I use to mock:
jest.mock("#project/shared-component", () => ({
...jest.requireActual("#project/shared-component"),
useData: jest.fn(),
}));
This would be possible if everything would be in one package, but since I am trying to mock a function that is internally used in the mocked package, the SharedComponent uses the actual function rather than the mocked one. Does anyone have an idea on how to mock the useData hook internally used by SharedComponent? Thanks!

I have a similar issue. The comment by #Steven Scott does indeed seem like a proper solution, but in my case, extracting and then injecting the dependencies takes away the need to extract the shared components in the first place because my consumer components would then need to know about the dependencies, and to be honest, I don't like the idea of changing my code purely for the tests, since I don't use my hooks in that way.
#Lukas, If you find/found a way in the meantime, please post it back here. My current solution is to just test the SharedComponent thoroughly in it's package, and then just test that my ConsumerComponent calls the SharedComponent correctly. Then I depend on the idea that I can use (and trust) every component I use because they are properly tested internally.
But again, if you find a better solution, I would love to hear about it.

Related

Redux Tookit, How to dispatch action in a non component function?

I have a global toast, which I am opening using redux slice. I need to open the toast for error message when call from api fails in api-slice of rtk-query.
I have seen the answer, using store.dispatch method, but this causes dependency cycle. Is there a way to do this?
Yeah, you should always avoid directly importing the store into other application files.
Ideally, none of the rest of your code would ever need to refer to store directly.
Depending on where in the RTKQ setup you need to trigger this toast, you may have access to dispatch as part of the lifecycle function arguments.
In the worst case, you can use our fallback recommendation to inject the store into the necessary files from the app setup logic.

Using testing-library findBy* on a component that uses setState causes a "not wrapped in act" warning

I've got a React component which retrieves data using a Promise and then calls setState when the promise resolves. It then uses the updated state to change what's rendered.
When testing this, I use the testing library's findBy* methods to wait for the rendered component to have been updated with the content from the Promise:
await findByText("Failure details", { exact: false });
My tests pass - they correctly wait until the component has re-rendered. However, I get a warning like this when running them (I'm using Jest, but I don't think that's relevant):
Warning: An update to MyComponent inside a test was not wrapped in act(...).
Everything I've found online that's related to this is either about components using useEffect or about tests which include explicit calls to act in them (mine don't), which I don't think should be necessary here - my test itself isn't changing the component, apart from the fact that it calls render.
In short, my situation seems simpler than those that others are writing about - I'm just using setState and the findBy* queries, nothing more complex.
Is there an equally simple solution to this problem?
Thankfully, the solution was simple - upgrading React and React-DOM to >= 16.9.0. I didn't have to change my tests or my component.
16.9.0 includes an asynchronous version of act. As I say, I didn't have to explicitly use it, but it was obviously being used behind the scenes because it solved my problem.

Test method in component without Enzyme - React Native

I'm pretty new to React Native and Javascript, I'm currently trying to test methods inside my components, I've seen this being done with Enzyme like
const wrapper = shallow(<Component/>);
wrapper.instance().methodIwannaCall();
Coming from the iOS Dev world, I'm having a hard to understanding why it seems to be so complicated to get an instance of a class and call a method on it.
Unfortunately I'm using React 16.0.0-alpha.12 which means I can't for now use Enzyme, which seems to be the library everyone is using to accomplish what I need.
Also notice I'm not using Redux, I suspect this would be less of a pain if I'd use Redux, since that way all my business logic would be within actions and hence would be easier to test.
Any comments/help are greatly appreciated.
Cheers
You can use pure ReactTestUtils to get instance of your component, for example using renderIntoDocument method:
import ReactTestUtils from 'react-dom/test-utils';
const wrapper = ReactTestUtils.renderIntoDocument(<Component/>);
wrapper.methodIwannaCall();

IoC in React without typescript

I'm pretty new to React, and I would essentially have a service (one single instance) that I could somehow inject and use in multiple React components.
So far, the options I've come across by googling were:
Using React's context, but it's not recommended, because it is an undocumented API.
Passing the object along in the props, from component to component, but it feels a bit inelegant and tedious
Using an IoC container, such as inversifyJS, who looks great, only it relies on typescript, and I don't wish to write my React app in typescript.
Now, Inversify can apparently be used in vanilla JS, with inversify-vanillajs-helpers, but when I tried using it in React to resolve a component (my App component), it kept throwing an exception stating
"Missing required #injectable annotation in: ReactComponent"
So, I'm trying to figure out a way to get an instance of my service (the same instance shared across the few components that use it), either by making inversify work with React but without typescript, or a new approach I haven't explored yet.
Any ideas ?
There are a few things that you can do if you don't like TypeScript:
First, you are going to need the inversify.decorate method.
Second, this method is probably going to be too verbose for you. We created a helper called inversify-vanillajs-helpers for that reason.
And third, React doesn't play nicely with constructor injection so we created a helper to facilitate lazy property injection called inversify-inject-decorators.
Those three tools should lead yo to the desired result :)

Enzyme testing: mount vs render

Besides render uses "traversal library Cheerio"..
I've just replaced all my mount's with render's and it works the same.
They look similar to me.
What should I choose? Is API of those two is somehow not identical?
What are particular recommendations when to use render over mount?
Render doesn't need a global DOM to be available. So it allows the tests to be run outside of an environment like a browser. In your case, if your test cases were working before it would seem you are running the tests in a browser (since mount worked) and you wouldn't need to use render. If however, your tests were failing because there was no global DOM available, then render might be a good solution
http://airbnb.io/enzyme/docs/api/render.html
Mount is FullDom rendering. Take a look at the official documentation for examples. From my understanding if you want to test lifecycle events such as componentDidMount you should use mount.
Docs: http://airbnb.io/enzyme/docs/api/mount.html

Resources