-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Any possibility of using this for react native project? #22
Comments
Hi @amay! I'd love react native support, but I have no idea how hard that would be... I know very little about react native. I'm pretty sure the only way to make this work is if you could render react-native components to the DOM. I'm not sure whether there's anything out there which makes this possible though... I'd love to look at a PR for it so long as it doesn't make this library more complex to use or over-complicate the implementation. Anyone can feel free to investigate this 😄 |
Hey @kentcdodds, I had some luck getting this working with some (admittedly nasty) hacking. I will post here in case it is helpful to anyone else: // in setupTests.js which is configured as jest's setup file.
// Adapted from https://blog.joinroot.com/mounting-react-native-components-with-enzyme-and-jsdom/ and
// https://stackoverflow.com/questions/42039383/how-to-use-enzyme-for-react-native-with-jest
import { JSDOM } from 'jsdom'
// used to fully render native components as react components
import 'react-native-mock-render/mock'
// copy props needed to render HTML from JSDOM window to node's global object
function copyProps(src, target) {
Object.getOwnPropertyNames(src)
.filter(prop => typeof target[prop] === 'undefined')
.forEach(prop => {
// eslint-disable-next-line no-param-reassign
target[prop] = src[prop]
})
}
const { window } = new JSDOM()
global.window = window
global.document = window.document
global.navigator = {
userAgent: 'node.js',
}
copyProps(window, global)
// react doesn't like some of the props that are set on native components (that eventually are set on DOM nodes, so suppress those warnings
const suppressedErrors = /(React does not recognize the.*prop on a DOM element|Unknown event handler property|is using uppercase HTML|Received `true` for a non-boolean attribute `accessible`|The tag.*is unrecognized in this browser)/
// eslint-disable-next-line no-console
const realConsoleError = console.error
// eslint-disable-next-line no-console
console.error = message => {
if (message.match(suppressedErrors)) {
return
}
realConsoleError(message)
} With this, I can get a test like the following to pass in jest: import React from 'react'
import { StyleSheet, Text, TouchableHighlight } from 'react-native'
import PropTypes from 'prop-types'
import { render, Simulate } from 'react-testing-library'
const Button = ({ onPress, text }) => (
<TouchableHighlight onPress={onPress}>
<Text>{text}</Text>
</TouchableHighlight>
)
test('renders text', () => {
const { getByText } = render(<Button text="Test Button" />)
expect(getByText('Test Button').textContent).toBe('Test Button')
}) However, I can't get calls to Simulat to work because test('invokes onPress prop on press', () => {
const onPress = jest.fn()
const { container } = render(<Button onPress={onPress} />)
Simulate.press(container) // throws error
// Simulate.click(container) doesn't work because it doesn't trigger press event
expect(onPress).toHaveBeenCalled()
}) So far I haven't been able to think of any way to extend |
Awesome! I'm pretty sure that you shouldn't have to do the JSDOM stuff because jest will handle that all by default anyway (perhaps in your tests you're specifying a different The Also the As for the simulate stuff, I'm not sure what the code would entail, but you should be able to simply: Now that I think about it though, there's not a whole lot that I want to include in the library itself... Perhaps we could just have some examples of the setup you'd need to do to support React Native 🤔 |
At the very least, I'd like to have people doing things in the wild before we decide on including anything into the core so we have time to decide what works best. |
Thanks for the tip on After doing the research into what was needed to get this working, I definitely agree that it doesn't make sense to try to incorporate these changes as this package is really about DOM testing. I did end up getting Here is the final import 'react-native-mock-render/mock'
import { Simulate } from 'react-dom/test-utils'
function suppressDomErrors() {
const suppressedErrors = /(React does not recognize the.*prop on a DOM element|Unknown event handler property|is using uppercase HTML|Received `true` for a non-boolean attribute `accessible`|The tag.*is unrecognized in this browser)/
// eslint-disable-next-line no-console
const realConsoleError = console.error
// eslint-disable-next-line no-console
console.error = message => {
if (message.match(suppressedErrors)) {
return
}
realConsoleError(message)
}
}
function setupSimulatePress() {
Simulate.press = Simulate.click
jest.mock('TouchableHighlight', () => {
// eslint-disable-next-line global-require
const React = require('react')
const RealComponent = require.requireActual('TouchableHighlight')
const TouchableHighlight = props =>
React.createElement(
'TouchableHighlight',
{
...props,
onClick: props.onPress,
},
props.children
)
TouchableHighlight.propTypes = RealComponent.propTypes
return TouchableHighlight
})
}
suppressDomErrors()
setupSimulatePress() |
I think that code would make a handy package by itself. I definitely would love to reduce friction for folks testing with React Native, I'm just not 100% certain I want to commit to building-in a RN implementation at the moment. Would you be interested in making your code a package then make a PR to this repo to show how to integrate it? |
I just noticed that code says: |
Hey @kentcdodds I agree with your proposal that this functionality not be included in this simple core library. I'm dogfooding my approach on a project right now, and if it goes well, I'm definitely interested in adding a simple package to simplify the test setup for react native projects. I'll post back here when I've made progress, but I'll close this out for now. |
Super. Thanks @amay! I can't wait to see the package if it turns up on npm :) I'd love to link to it in the README here :) |
Hey @amay! Folks are curious to hear how your experiment went! Is this something that'll work for react native? |
@kentcdodds @amay any news on this topic? Thanks! |
Hey @kentcdodds @hnordt I didn't get to do as an exhaustive of a deep dive as I would have liked for this, but early indications suggest there would need to be some more work put in to get this to work well. The specific issues come down to bridging native behavior to the dom. E.g. you wan't react native's The I recently saw the announcement for this project: https://github.com/vincentriemer/react-native-dom, and I'm curious if using that could result in a much better and comprehensive test setup. That project ostensibly does the bridging between react native components to true DOM components, so in theory it could work very well. I haven't had time to test it out unfortunately. |
@amay thanks for the quick answer. I think we might need to clone I think emulating React Native into a fake dom is not a good idea cause you are not testing the app in the real environment it's gonna run, so you won't be confident about your tests anyway. |
Any update on this? |
I've not been made aware of any progress on making react-testing-library work nicely with react native. I'd love it someone could build something though! |
I'm using it by rendering component with react-native-web. It works pretty well but you have to structure your components so you can render what you want to test outside of very RN-specific libs like react-navigation, etc. While there are a few components I can't test, generally I'm able to test most of the ones that have complex business logic. The rendering doesn't look 100% perfect with what's on mobile, but it works for just testing behavior and stuff. It actually works well enough that this is all you really need: fireEvent['press'] = (node, init) => {
fireEvent.mouseDown(node, init);
fireEvent.mouseUp(node, init);
}; I use Then you just module.exports = {
moduleFileExtensions: [
'web.js',
'ios.js',
'mjs',
'js',
'json'
],
moduleDirectories: ['<rootDir>/node_modules', 'node_modules'],
testEnvironment: 'jsdom',
setupTestFrameworkScriptFile: '<rootDir>/src/setupTests.js',
testMatch: ['<rootDir>/src/components/mobile/**/*.test.js'],
moduleNameMapper: {
'^react-native$': 'react-native-web',
// Ignore react-art. react-native-web tries to pull it in but we
// never use or need it, and it throws errors in jsdom
'^react-art$': 'node-noop'
},
globals: {
IS_REACT_NATIVE: true
}
}; There might be a few other things I forget, but it mostly just works. The only downsides is you run into problems pretty quickly with stuff that doesn't work under react-native-web, but if you're just looking to test the logic of isolated components, it works well enough. Anything that uses more complex stuff like a native dependency, react-navigation, etc will have to live outside of those components. |
Awesome! Thanks James! Have you tried mocking those react native components to be able to test more? Would anyone like to try this out and verify it works for you as well? Then we can add this to the docs 👌 |
You can't really mock react-navigation. It's a huge lib and your component will depend on it passing specific things to you. You might be able to mock native modules, depends on what they do, I haven't run in to the need for it yet. I think I saw some commits in react-navigation talking about web support, but I haven't looked closely yet. Last I tried it didn't work, and didn't care too much about it. I need to test my critical components and I already pull them out of route-specific ones so it doesn't bother me. |
Sounds good 👍 thanks again! |
@kentcdodds this works for me. I've put up a repo showing the bare minimum setup with a single test. |
That's fantastic @thchia! Could you please make a pull request to the README with a little documentation about this along with a link to your repo? Thank you team! |
<!-- What changes are being made? (What feature/bug is being fixed here?) --> **What**: Add some documentation regarding usage with React Native. <!-- Why are these changes necessary? --> **Why**: First step to tackling a long(ish) standing [issue](#22) regarding this. <!-- How were these changes implemented? --> **How**: Added an FAQ point discussing how one might go about using this library with React Native. Main credit to @jlongster [here](#22 (comment)). I just corroborated the findings 🙂 <!-- Have you done all of these things? --> **Checklist**: <!-- add "N/A" to the end of each line that's irrelevant to your changes --> <!-- to check an item, place an "x" in the box like so: "- [x] Documentation" --> - [x] Documentation - [ ] Tests - [x] Ready to be merged <!-- In your opinion, is this ready to be merged as soon as it's reviewed? --> - [x] Added myself to contributors table <!-- this is optional, see the contributing guidelines for instructions --> <!-- feel free to add additional comments -->
Though this is closed, linking a library which looks very promising for people who land here (haven't used the linked library in prod yet). https://github.com/callstack/react-native-testing-library |
<!-- What changes are being made? (What feature/bug is being fixed here?) --> **What**: Add some documentation regarding usage with React Native. <!-- Why are these changes necessary? --> **Why**: First step to tackling a long(ish) standing [issue](testing-library/react-testing-library#22) regarding this. <!-- How were these changes implemented? --> **How**: Added an FAQ point discussing how one might go about using this library with React Native. Main credit to @jlongster [here](testing-library/react-testing-library#22 (comment)). I just corroborated the findings 🙂 <!-- Have you done all of these things? --> **Checklist**: <!-- add "N/A" to the end of each line that's irrelevant to your changes --> <!-- to check an item, place an "x" in the box like so: "- [x] Documentation" --> - [x] Documentation - [ ] Tests - [x] Ready to be merged <!-- In your opinion, is this ready to be merged as soon as it's reviewed? --> - [x] Added myself to contributors table <!-- this is optional, see the contributing guidelines for instructions --> <!-- feel free to add additional comments -->
I really appreciate the guiding principles behind this library, have felt some of the pain associated with the drawbacks you all have identified with enzyme, and I'm curious how much work would be involved to get this library to work for a react native project? Given the reliance on DOM testing, I'm guessing it might not be possible or a good idea. Any guidance is greatly appreciated.
The text was updated successfully, but these errors were encountered: