Some of the code I am trying to test detects the platform, using, e.g.:
import { Platform } from 'react-native';
...
if (Platform.OS === 'android') {
...
} else {
...
}
Is there a sensible way to mock this with Jest and/or something else, so I can test both branches in one test run?
Or is the smart way to decouple it and put the platform into, e.g., a context variable? Although it always feels restructuring code to make it easier to test is something of a cheat.
This worked for me (Jest 21.2.1, Enzyme 3.2.0):
jest.mock('Platform', () => { const Platform = require.requireActual('Platform'); Platform.OS = 'android'; return Platform; });
Put it either at the top of your test, or in a beforeAll
for example.
For everyone looking for this, what it helped me was the following:
jest.mock('react-native/Libraries/Utilities/Platform', () => ({ OS: 'android', // or 'ios' select: () => null }));
I implemented a small mock that allows you to change Platform
during tests in the same test file.
Add this to your jest setup file
jest.mock('react-native/Libraries/Utilities/Platform', () => {
let platform = {
OS: 'ios',
}
const select = jest.fn().mockImplementation((obj) => {
const value = obj[platform.OS]
return !value ? obj.default : value
})
platform.select = select
return platform
});
Then you can easily change Platform
in your test. If you are using Platform.select
it will also work as expected!
import { Platform } from 'react-native'
describe('When Android', () => {
it('should ...', () => {
Platform.OS = 'android'
...
})
})
describe('When iOS', () => {
it('should ...', () => {
Platform.OS = 'ios'
...
})
})
The way that I achieved mocking setting the platform was just set it directly in the tests:
it('should only run for Android', () => {
Platform.OS = 'android'; // or 'ios'
// For my use case this module was failing on iOS
NativeModules.MyAndroidOnlyModule = {
fetch: jest.fn(
(url, event) => Promise.resolve(JSON.stringify(event.body))
),
};
return myParentFunction().then(() => {
expect(NativeModules.MyAndroidOnlyModule.fetch.mock.calls.length).toBe(1);
expect(fetch.mock.calls.length).toBe(0);
});
});
This would setup the platform to only run on Android during tests to make sure that my function was calling only specific functions. My function that was wrapped in platform dependent compilation looked like:
export default function myParentFunction() {
if (Platform.OS === 'ios') {
return fetch();
}
return NativeModules.MyAndroidOnlyModule.fetch();
}
I would suggest just creating two different tests one with the platform set to iOS and the other to Android since ideally a function should only have one responsibility. However, I'm sure you can use this to run the first test, dynamically set the platform and run test number two all in one function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With