React native 在Jest和React Native中模拟平台检测

React native 在Jest和React Native中模拟平台检测,react-native,jestjs,React Native,Jestjs,我尝试测试的一些代码检测平台,例如: 从'react native'导入{Platform}; ... 如果(Platform.OS==='android'){ ... }否则{ ... } 有没有一种明智的方法可以用笑话和/或其他东西来模拟这一点,这样我就可以在一次测试运行中测试这两个分支 或者,将其解耦并将平台放入(例如)上下文变量中是一种明智的方法?尽管它总是觉得重新构造代码以使其更易于测试是一种欺骗 您可以从React Native模拟任何您想要的内容,如下所示: descriptio

我尝试测试的一些代码检测平台,例如:

从'react native'导入{Platform};
...
如果(Platform.OS==='android'){
...
}否则{
...
}
有没有一种明智的方法可以用笑话和/或其他东西来模拟这一点,这样我就可以在一次测试运行中测试这两个分支


或者,将其解耦并将平台放入(例如)上下文变量中是一种明智的方法?尽管它总是觉得重新构造代码以使其更易于测试是一种欺骗

您可以从
React Native
模拟任何您想要的内容,如下所示:

description('notifications actions tests',()=>{
让平台;
在每个之前(()=>{
jest.mock('react-native',()=>({
站台:{
... 
}));
Platform=require('react-native')。Platform;//如果您想在测试中引用平台
});

您必须模拟模块并将其导入测试。然后您可以使用
模拟实现
将其设置为
android
ios

从“react native”导入reactNative;
jest.mock('react-native',()=>jest.fn();
它('是安卓',()=>{
mockImplementation(()=>({Platform:{OS:'android'}}))
//测试android案例
})
它('是安卓',()=>{
mockImplementation(()=>({Platform:{OS:'io'}}))
//测试ios案例
})

我实现模拟设置平台的方法是直接在测试中设置:

it('应该只为Android运行',()=>{
Platform.OS='android';//或'ios'
//对于我的用例,此模块在iOS上出现故障
NativeModules.MyAndroidOnlyModule={
fetch:jest.fn(
(url,event)=>Promise.resolve(JSON.stringify(event.body))
),
}; 
返回myParentFunction()。然后(()=>{
expect(NativeModules.MyAndroidOnlyModule.fetch.mock.calls.length).toBe(1);
expect(fetch.mock.calls.length).toBe(0);
});
});
这会将平台设置为在测试期间仅在Android上运行,以确保我的函数仅调用特定函数。包装在平台相关编译中的函数如下所示:

导出默认函数myParentFunction(){
如果(Platform.OS==='ios'){
返回fetch();
}
返回NativeModules.MyAndroidOnlyModule.fetch();
}
我建议只创建两个不同的测试,一个将平台设置为iOS,另一个设置为Android,因为理想情况下,一个函数应该只有一个职责。但是,我相信您可以使用它来运行第一个测试,动态设置平台,并运行第二个测试“一体式”函数。

使用和

jest.resetModules()
doMock('react-native',()=>({Platform:{OS:'android'}}))

可以直接为每个测试设置操作系统

test('android',()=>{
Platform.OS='android'
const component=renderer.create().toJSON()
expect(component.toMatchSnapshot())
})
测试('ios',()=>{
Platform.OS='ios'
const component=renderer.create().toJSON()
expect(component.toMatchSnapshot())
})
这对我很有效(Jest 21.2.1,Ezyme 3.2.0):

jest.mock('Platform',()=>{
const Platform=require.requireActual(‘平台’);
Platform.OS='android';
返回平台;
});

将它放在测试的顶部,或者放在示例中。

我正在使用这个github问题的解决方案

我将jest配置从
package.json
移动到单独的文件中。 到目前为止,一切似乎都很顺利,包括: a) 根据平台导入正确的文件。例如,在ios上:.ios.tsx,然后是.native.tsx,然后是.tsx b) 运行测试IOS时,PLATFORM.IOS返回true,无需模拟任何内容

//package.json
“脚本”:{
“test”:“cross env NODE_env=test jest--config/jest.desktop.json”,
“测试ios”:“跨环境节点_env=test jest--config/jest.ios.json”,
“测试android”:“跨环境节点_env=test jest--config/jest.android.json”
}
//config/jest.web.json
{
...
}
//config/jest.ios.json
{
...
“预设”:“反应本机”,
“匆忙”:{
“defaultPlatform”:“ios”,
“平台”:[
“安卓”,
“ios”,
“本地人”
],
“提供模块解调器”:[
“本地反应”
]
},
}
//config/jest.android.json
{
...
“预设”:“反应本机”,
“匆忙”:{
“defaultPlatform”:“android”,
“平台”:[
“安卓”,
“ios”,
“本地人”
],
“提供模块解调器”:[
“本地反应”
]
},
}

如果您想在同一测试套件和一次测试运行中模拟不同的操作系统,那么其他答案将不起作用,这里有另一种方法。不要直接在代码中使用
Platform.OS
,而是在某处定义一个helper函数,并使用它来获取组件中操作系统的引用:

在“helpers.js”中:

导出函数getOS(){
returnplatform.OS;
}
在您的组件中:

import*作为“/helpers”中的助手;
render(){
如果(helpers.getOS()=='android'){//do something}
}
然后可以在测试中模拟此函数,例如

import*作为“/helpers”中的助手;
// ...
它('在Android上做点什么',()=>{
jest.spyOn(helpers,'getOS').mock实现(()=>'android');
// ...
}
它('在iOS上做其他事情',()=>{
jest.spyOn(helpers,'getOS').mock实现(()=>'ios');
// ...
}
这个想法的功劳归于。

可能是“导入”方法中的问题,请检查以下内容:

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

//import isAndroid from 'app/helpers/is_android'
使用“导入”将不起作用,需要使用“require”

从“React”导入React;
从“反应测试渲染器”导入渲染器;
从“./SmartText”导入SmartText;
描述(“标记智能文本组件”,()=>{
在每个之前(()=>{
jest.reset模块();
});
它(“在ios上使用道具进行渲染”,()=>{
mock(“平台”,()=>{
返回{OS:“ios”};
beforeEach(() => {
  jest.resetModules();
});

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

  expect(isAndroid).toBe(true);
});   
import React from "react";
import renderer from "react-test-renderer";
import SmartText from "../SmartText";

describe("markdown smart text component", () => {
  beforeEach(() => {
    jest.resetModules();
  });

  it("renders with props on ios", () => {
    jest.mock("Platform", () => {
      return { OS: "ios" };
    });
    expect(
      renderer.create(<SmartText title="code ios" code />).toJSON()
    ).toMatchSnapshot();
  });

  it("renders with props on android", () => {
    jest.mock("Platform", () => {
      return { OS: "android" };
    });
    expect(
      renderer.create(<SmartText title="code android" code />).toJSON()
    ).toMatchSnapshot();
  });
});
const mockPlatform = OS => {    
  jest.resetModules();  
  jest.doMock("Platform", () => ({ OS, select: objs => objs[OS] }));
};
it("my test on Android", () => {
  mockPlatform("android");
});

it("my test on iOS", () => {
  mockPlatform("ios");
});
jest.mock('react-native/Libraries/Utilities/Platform', () => ({
    OS: 'android', // or 'ios'
    select: () => null
}));
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
);
Platform.OS = 'android'
jest.mock('react-native/Libraries/Utilities/Platform', () => {
  const Platform = require.requireActual(
    'react-native/Libraries/Utilities/Platform'
  )
  Platform.OS = 'android'
  return Platform
})
Object.defineProperty(Platform, 'OS', { get: jest.fn(() => 'ios') })
const mockedData = 'MOCKED-DATA'
jest.mock('react-native', () => ({

    Platform: {
        select: jest.fn(() => {
            return { mockedData  } // Your Mocked Value
        }),
    }
}));
 jest.mock('Platform', () => ({
      OS: 'android', // or 'ios'
      select: () => 'mocked-value'
 }));