Mocking platform detection in Jest and React Nativ

2020-02-26 04:17发布

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.

13条回答
放荡不羁爱自由
2楼-- · 2020-02-26 04:21

Maybe the problem in the "import" method, check this:

const isAndroid = require('app/helpers/is_android');

//import isAndroid from 'app/helpers/is_android'

with "import" this will not work, need to use "require".

beforeEach(() => {
  jest.resetModules();
});

it("should be true when Android", () => {
  jest.mock('Platform', () => {
    return { OS: 'android' };
  });

  expect(isAndroid).toBe(true);
});   
查看更多
冷血范
3楼-- · 2020-02-26 04:23

React Native 0.61 update

Though the accepted solution works for versions of React Native 0.60 and below, React Native 0.61 has dropped Haste support and this gives an error.

I was able to mock platform detection following the implementation described in this blog post.

Practically, according to the React team, we now have to mock the react-native interface. So, you can create a react-native.js file inside the tests/__mocks__ folder and add this code to mock Platform:

import * as ReactNative from "react-native";

export const Platform = {
  ...ReactNative.Platform,
  OS: "ios",
  Version: 123,
  isTesting: true,
  select: objs => objs["ios"]
};

export default Object.setPrototypeOf(
  {
    Platform
  },
  ReactNative
);

With this implementation, we can now simply overwrite the OS before running the test like:

Platform.OS = 'android'
查看更多
来,给爷笑一个
4楼-- · 2020-02-26 04:26

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.

查看更多
爷、活的狠高调
5楼-- · 2020-02-26 04:28

this is the mock you need:

const mockPlatform = OS => {    
  jest.resetModules();  
  jest.doMock("Platform", () => ({ OS, select: objs => objs[OS] }));
};

with it you can do the following:

it("my test on Android", () => {
  mockPlatform("android");
});

it("my test on iOS", () => {
  mockPlatform("ios");
});

That way you can have tests for both platforms

查看更多
Evening l夕情丶
6楼-- · 2020-02-26 04:28

OS can be set directly for each test

 test('android', () => {
     Platform.OS = 'android'
     const component = renderer.create(<Component />).toJSON()
     expect(component).toMatchSnapshot()
 })
 test('ios', () => {
     Platform.OS = 'ios'
     const component = renderer.create(<Component />).toJSON()
     expect(component).toMatchSnapshot()
 })
查看更多
倾城 Initia
7楼-- · 2020-02-26 04:29

You have to mock the module and import it into your test. Then you can use mockImplementation to set the it to either android or ios

import reactNative from 'react-native';
jest.mock('react-native', () = > jest.fn();

it('is android', () => {
  reactNative.mockImplementation(()=>({Platform:{OS: 'android'}}))
  //test the android case
})

it('is android', ()=>{
  reactNative.mockImplementation(()=>({Platform: { OS: 'io' }}))
  //test the ios case
})
查看更多
登录 后发表回答