Open IanVS opened 8 years ago
I use an environment variable to set the platform, like APP_PLATFORM=android npm test
. And in the code I do var platform = process.env.APP_PLATFORM || 'ios'
and then use this variable during mocking a require or doing other platform-specific stuff.
Another option is to have separate tests for each platform, but this leads to code doubling. Not sure which of these approaches is better.
React Native uses packager that dynamically builds js-bundles depending on provided parameters, like platform
, dev
, hot
, that's why it's so flexible and power.
Besides just using a load of conditionals to check, what you could do is change the way node requires js files, and check if there's a .android.js
or .ios.js
version and return that instead, which you could switch on an env var. Best library i've found to do it is node-hook, but I have no idea if it actually works, or plays nice with react-native-mock
I just want to share something in case someone come through the problem of testing platform specific code.
Not related to the import themselves but I found a solution for platform specific code using the RN Platform
module.
I use mocha
and as entry point for my tests I require this file /bin/test.js
:
var ReactNativeMock = require('react-native-mock');
ReactNativeMock.Platform.OS = process.env.PLATFORM || 'ios';
require('react-native-mock/mock');
This way I don't have to change my code, I keep using the RN module and I can simulate the Platform with an env var. Unfortunately this doesn't work for imports as they are handled by the RN packager.
@julien-rodrigues whilstt that is a nice solution, we already support something like this. You can use 'Platform.__setOS' to set the OS programatically during tests. This should make things much easier for you, and it's still possible to use process.env.
I forgot to say that in my case I need to set stuffs outside of the render cycle. So I need to have the OS correctly set before anything else.
I am testing a component which style has a color property which is changing depending on the Platform.OS value.
export const selectionColor = Platform.OS === 'ios' ? Colors.lighterGrey : Colors.lighterGrey20;
I can't put it inside a RN Stylesheet as selectionColor
is going to be used to fill the selectionColor
prop of the RN TextInput component.
I could put the ternary inside the selectionColor
prop of the TextInput and this would allow me to change the OS programatically in my tests as the check is done inside the render
cycle.
But I don't see the case where the Platform would change its OS when running the app.
And for the sake of consistancy, all my component styles are in a separate file.
But wrapping it into a function would be a working solution tho. lol
And as for the __setOS
method, seeing the __
made me think that I shouldn't be using that. But knowing that I can I'm going to change my test's entry point. Thanks for the hint!
Another way to do it is to do it is by component basis. The issue with this is that you need to include the a boolean for Platform as a prop. While it adds a bit extra code . Its allows me to mock things in a contained manner.
Here is a webView component below as an example. I use it to conditionally create a vertical offset due to a navigation bar component. Would love to hear your feedback!
const SHWebView = ({ verticalOffset, uri, android }) => {
const androidOffset = 53;
const iosOffset = 64;
const marginTop =
isNaN(verticalOffset) ? (android ? androidOffset: iosOffset) : verticalOffset;
return (
<View style={[styles.container, { marginTop }]}>
<WebView source={{ uri }}/>
</View>
)
};
SHWebView.defaultProps = {
android: Platform === 'android'
}
@RealOrangeOne I am trying to set the platform to Android, using:Platform.__setOS('android');
Unfortunately it is not working, the component does not render. Is there another way to do it?
If I do Platform.__setOS('ios');
it does what is expected that is keep the iOS
platform.
@SandroMachado I'm going to need a lot more information than that. You have to re render you component completely after changing the OS. We also currently dont support using platforms in require statements, if that's what you meant
Just pass it in as a default boolean prop!
Component.defaultProps { android: Platform.OS === 'android' }
Does that work for you?
On 29 Nov 2016, at 21:42, Jake Howard notifications@github.com<mailto:notifications@github.com> wrote:
@SandroMachadohttps://github.com/SandroMachado I'm going to need a lot more information than that. You have to re render you component completely after changing the OS. We also currently dont support using platforms in require statements, if that's what you meant
- You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/RealOrangeOne/react-native-mock/issues/17#issuecomment-263692513, or mute the threadhttps://github.com/notifications/unsubscribe-auth/AGWFMh2VPbd5ZDHmlON8Q_PY09j-1Ximks5rDI4sgaJpZM4Hnv1G.
I think I found the issue, the problem is that the DatePickerAndroid
is
not mocked.
On 29 Nov 2016 20:50, "Daniel Hollcraft" notifications@github.com wrote:
Just pass it in as a default boolean prop!
Component.defaultProps { android: Platform.OS === 'android' }
Does that work for you?
On 29 Nov 2016, at 21:42, Jake Howard <notifications@github.com<mailto: notifications@github.com>> wrote:
@SandroMachadohttps://github.com/SandroMachado I'm going to need a lot more information than that. You have to re render you component completely after changing the OS. We also currently dont support using platforms in require statements, if that's what you meant
- You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://github.com/ RealOrangeOne/react-native-mock/issues/17#issuecomment-263692513, or mute the threadhttps://github.com/notifications/unsubscribe- auth/AGWFMh2VPbd5ZDHmlON8Q_PY09j-1Ximks5rDI4sgaJpZM4Hnv1G.
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/RealOrangeOne/react-native-mock/issues/17#issuecomment-263694708, or mute the thread https://github.com/notifications/unsubscribe-auth/AAmju3Yhh0prHjt9eZhCbCIMMWVC_PLhks5rDJAugaJpZM4Hnv1G .
Curious if anyone reached a good solution for the import issue? Currently, I'm creating a .js
file at test runtime and then deleting it after in my script. Talk about a hack 😝
React Native does some magic around requires to allow
require(img.png)
as pointed out in https://github.com/lelandrichardson/react-native-mock/issues/11, but it also allows platform-specific components to be named with an extension.ios.js
or.android.js
, and then be imported with a simpleimport {MyComponent} from 'my-component.js';
(http://facebook.github.io/react-native/docs/platform-specific-code.html#platform-specific-extensions). This avoids the need to sprinklePlatform.OS
ternaries throughout the code, but of course Node has no idea how to resolve the import/require and blows up.Do you have any suggestions or ideas of the best way to handle this?