enzyme
enzyme copied to clipboard
Create Adapter for React Native & React 16
Problem Statement
Currently we have no support for using a react native adapter with Enzyme. This is because the current adapters are built for react native web.
Attempting to use mount with the current adapter will cause various issues from polluting the user's console with a ton of logs to inability to import necessary libraries.
While this is the case you can get some testing done by filtering the logs and using jsdom.
Most of the console error issues seem to be coming from the ReactDOM call for the React 16 adapter here
Purpose
The purpose of this ticket is to track work related to implementation and decisions regarding implementation of a react native enzyme adapter.
TODO
- Find an alternative to rendering with ReactDOM
- Decide best way to use the solution for (1) with existing adapters
- Decide whether we would like to do all necessary react native stubbing in the adapter a-la react-native-mock-render, do a RYO implementation, or not take a firm stance to the native mocking
- Add unit tests to verify functionality
- Update Necessary Docs
Related Issues
https://github.com/airbnb/enzyme/issues/1390 https://github.com/airbnb/enzyme/issues/831
We have one for React 16; but we definitely do need one for react-native.
Implementing it here in this repo would be great; anyone interested in opening a PR?
Since we’d want a different adapter as needed for different React-native versions, we might also want a utils package. We’d also want to add a new binary to the adapter helper for react-native.
Yup I'm already aware of the regular react 16 adapter. I was more saying one that works with react native apps built with react 16 as the react dependency. I've been ripping apart and experimenting with the 16 adapter as a way to boost familiarity with the adapter system.
I'm planning to start working on implementation after holiday travels.
Do you have some ideas as to what the adapter would use instead of ReactDOM? I saw that react test utils also has a render method in addition to a shallow render method. I was thinking of investigating that first.
I'm really not sure, unfortunately. I would assume/hope that the react-native team would provide something for this use case.
Looking to start investigating implementation. I started setting up my development environment and was reading through the existing test suite. I noticed that quite a bit of the tests seem to be heavily geared towards React and not React Native. This isn't really a surprise, but leads me ask how we would prefer to setup the suite for React Native.
A couple quick options I was able to come up with:
- Nest directories in
enzyme-test-suite/test
so that we haveenzyme-test-suite/test/react
andenzyme-test-suite/test/react-native
. Changenpm test:only
to something likenpm test:only:react
and react native variant. - Try to refactor the existing suite to also work with React Native.
Of these (2) sounds to be more maintainable with less duplication. I'm unsure if there are any pitfalls which would block it from being possible due to lack of familiarity with the test suite. Is one of these decisions largely preferable over the other? I'd also be interested to know if there are any other better options.
I’d prefer we move to a place where tests that are specific to each adapter (like anything React-specific) moves to that individual adapter, and the tests in enzyme-test-suite become adapter-agnostic (and thus, react and react-native agnostic)
That makes the most sense. Would you say that the test suite refactor should be a hard precondition before starting the implementation of the wrapper? Or would it make more sense to just implement the adapter with the right testing setup, allowing the other adapters to be refactored as time permits?
I'm leaning toward the refactor needing done first so that we have thorough code coverage on the native adapter from day one.
Edit: Also, would that fall under https://github.com/airbnb/enzyme/issues/1132 or should I create another issue?
I would hope it could be done first :-) and yes, that’s indeed the issue for it.
Is there a work around for this, or can someone point me in the right direction to look into this issue? Is the adapter for React Web the best place to start?
I’d start there, yes. Not sure if there’s any existing work.
I've spent a few hours looking over the adapter react 16 uses and have come to the conclusion it's unlikely something that can be done independently. I'll share that which I've learnt below for other adventurers. The following appears to be the case at time of posting.
There is a single set of tests for all adapters found there. This file runs once for each of the adapter versions in this setup file. Excluding specific version of react from running a set of tests are done in this file with an itIf
with a condition provided. If you want to test a react native adapter none of the tests cases in this file will apply to you so you will need to set up an independent test set.
When you switch between each version of react using npm run react:x
where x is a version number it removes and installs dependencies as described in this env.js file. When I created another adapter and removed react-dom as a peer dependency all the over version's tests broke.
There is no documentation on how an adapter is meant to work.
Overall it feels that react native was very much left out of the changes made when converting Enzyme to use adapters. I'm not judging; it's Airbnb's library and they can do what they want with it, but it's a shame because you can't adequately test a react native application without Enzyme imo.
I have a workaround solution I'm using that I'll post in the next few minutes.
This is the work around I'm using for the time being. It's a jest mock set that knocks out the apis that react-native use allowing you to use the standard react 16 adapter.
My implementation is similar to react native's implementation
This is meant as a functioning stop gap until a proper adapter has been built.
All the scripts can and should be modified as needed.
Fwiw tho, this wasn’t a result of any migration - enzyme has never explicitly tested itself on react native nor was it originally built to handle it. Adding more explicit react-native support is going to be an effort that necessitates changing things as needed.
In particular, the organization of the tests is such that (as you discovered) it’s not useful as a generic adapter test suite. The same is true if a preact or inferno adapter tried to use them. This is something we’ll need long term regardless.
this wasn’t a result of any migration - enzyme has never explicitly tested itself on react native
That's really interesting, after looking deeper I think I've found the duct tape module that allowed react native work.
Would you be interested in doing progressive changes rather than a big bang?
First split out the tests to allow generic adapter tests, then sort out the environment switching mechanisms that require react-dom to be installed etc?
That sounds like a great approach.
The purpose of the "react" scripts is to make sure that for each version of react, the appropriate additional packages (like react-dom) are installed. If we need a "react-native" script, great, if we come up with a better solution, great :-)
Someone working on it?
@thefelpes No one is working on it from my end. We ended up using React Test Renderer and Shallow render directly.
Hi @mcdankyl, what do you mean by "use shallow render directly"?
At least for the react 16 adapter, shallow rendering relies on ShallowTestRenderer. See https://github.com/airbnb/enzyme/blob/master/packages/enzyme-adapter-react-16/src/ReactSixteenAdapter.js#L211
We are directly using ShallowTestRenderer for shallow rendering and using TestRenderer for full renders.
It'd still be great to create a RN adapter; using those tools directly takes a lot of work to migrate across major react versions.
We're currently using enzyme with React Native by using jsdom and stubbing all of the native components: https://blog.joinroot.com/mounting-react-native-components-with-enzyme-and-jsdom/
I was able to get jsdom working as well with enzyme-adapter-react-16. I didn't need to stub anything, nor did I use react-native-mock or react-native-mock-renderer. I'll submit a documentation PR for this against: https://github.com/airbnb/enzyme/issues/1375
an explicit adapter is still needed/advised; RN isn’t the dom.
Agreed, jsdom is a stop gap
Agreed, jsdom is a stop gap
Hey! Did you happen to get this PR you're talking about started?
@mathewmorris Not yet, sorry! I might be able to get that up this weekend. Let me know if you need help with anything.
@shawnaxsom I appreciate it! As of right now I'm going to try a workaround, but if I think of anything, I sure will!
@mathewmorris We just opened sourced our boilerplate project where I have Enzyme set up with React Native. Maybe that will help?
https://github.com/ProminentEdge/mobile-boilerplate
Relevant files:
- https://github.com/ProminentEdge/mobile-boilerplate/blob/master/jest.config.js
- https://github.com/ProminentEdge/mobile-boilerplate/blob/master/setup-tests.js
- https://github.com/ProminentEdge/mobile-boilerplate/blob/master/src/screens/todo-list/todo-list.test.tsx
A draft of a documentation change for getting React Native working with jsdom is up in PR #1873 @mathewmorris, hope it helps
@shawnaxsom Hey man, I appreciate it so much! I'm going to try this out today and see what it can do! 👍🏼 You're awesome!