我尝试测试的一些代码使用例如:
来检测平台import { Platform } from 'react-native';
...
if (Platform.OS === 'android') {
...
} else {
...
}
有没有一种合理的方法可以用Jest和/或其他东西来模拟它,所以我可以在一次测试中测试两个分支?
或者是解耦它并将平台放入例如上下文变量的智能方法?虽然总是感觉重组代码使其更容易测试是一种欺骗。
答案 0 :(得分:18)
这对我有用(Jest 21.2.1,Enzyme 3.2.0):
jest.mock('Platform', () => {
const Platform = require.requireActual('Platform');
Platform.OS = 'android';
return Platform;
});
将其放在测试的顶部,或者放在a beforeAll
中。
答案 1 :(得分:6)
反应Native 0.61更新
尽管可接受的解决方案适用于React Native 0.60及更低版本,但是React Native 0.61放弃了对Haste的支持,这会导致错误。
按照此blog post中所述的实现,我能够模拟平台检测。
实际上,according to the React team,我们现在必须模拟react-native接口。因此,您可以在 react-native.js
文件夹内创建一个 tests/__mocks__
文件,并将此代码添加到模拟平台中:
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'
答案 2 :(得分:5)
我实现模拟设置平台的方式只是直接在测试中设置:
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);
});
});
这会将平台设置为仅在测试期间在Android上运行,以确保我的功能仅调用特定功能。我在平台相关编译中包含的函数如下所示:
export default function myParentFunction() {
if (Platform.OS === 'ios') {
return fetch();
}
return NativeModules.MyAndroidOnlyModule.fetch();
}
我建议只创建两个不同的测试,一个平台设置为iOS,另一个设置为Android,因为理想情况下,一个功能应该只有一个责任。但是,我确信您可以使用它来运行第一个测试,动态设置平台并在一个函数中运行第二个测试。
答案 3 :(得分:4)
这是您需要的模拟:
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");
});
这样,您就可以在两个平台上进行测试
答案 4 :(得分:3)
如果你想在同一个测试套件和中模拟不同的操作系统,那么其他答案将不起作用,这是另一种方法。不要在代码中直接使用Platform.OS
,而是在某处定义辅助函数并使用它:
export function getOS() {
return Platform.OS;
}
这个函数可以然后在你的测试中被嘲笑,例如
it('does something on Android', () => {
helpers.getOS = jest.fn().mockImplementationOnce(() => 'android');
// ...
}
it('does something else on iOS', () => {
helpers.getOS = jest.fn().mockImplementationOnce(() => 'ios');
// ...
}
这个想法归功于this GitHub issue comment。
答案 5 :(得分:3)
这对我有用...
jest.mock('react-native/Libraries/Utilities/Platform', () => {
const Platform = require.requireActual(
'react-native/Libraries/Utilities/Platform'
)
Platform.OS = 'android'
return Platform
})
答案 6 :(得分:1)
使用jest.doMock和jest.resetModules
jest.resetModules()
jest.doMock('react-native', () => ({ Platform: { OS: 'android' }}))
答案 7 :(得分:1)
我正在使用此github问题https://github.com/facebook/jest/issues/1370#issuecomment-352597475
中的解决方案我将jest配置从package.json
移动到单独的文件。
到目前为止,一切似乎都很好,包括:
a)根据平台导入正确的文件。例如,在ios:.ios.tsx上,然后是.native.tsx,然后是.tsx
b)PLATFORM.IOS在运行test-ios时返回true,不需要模拟任何东西
// package.json
"scripts": {
"test": "cross-env NODE_ENV=test jest --config config/jest.desktop.json",
"test-ios": "cross-env NODE_ENV=test jest --config config/jest.ios.json",
"test-android": "cross-env NODE_ENV=test jest --config config/jest.android.json"
}
// config/jest.web.json
{
...
}
// config/jest.ios.json
{
...
"preset": "react-native",
"haste": {
"defaultPlatform": "ios",
"platforms": [
"android",
"ios",
"native"
],
"providesModuleNodeModules": [
"react-native"
]
},
}
// config/jest.android.json
{
...
"preset": "react-native",
"haste": {
"defaultPlatform": "android",
"platforms": [
"android",
"ios",
"native"
],
"providesModuleNodeModules": [
"react-native"
]
},
}
答案 8 :(得分:1)
也许是“导入”方法中的问题,请检查以下内容:
const isAndroid = require('app/helpers/is_android');
//import isAndroid from 'app/helpers/is_android'
使用“导入”功能将无法使用,需要使用“要求”。
beforeEach(() => {
jest.resetModules();
});
it("should be true when Android", () => {
jest.mock('Platform', () => {
return { OS: 'android' };
});
expect(isAndroid).toBe(true);
});
答案 9 :(得分:1)
对于较新版本
“ react-native”:“ 0.62.2”
“酶”:“ ^ 3.11.0”
“笑话”:“ 24.5.0”
将其放在测试的顶部
Object.defineProperty(Platform, 'OS', { get: jest.fn(() => 'ios') })
答案 10 :(得分:0)
我实现了一个小模拟程序,使您可以在同一测试文件中的测试过程中更改Platform
。
将此添加到您的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
});
然后,您可以在测试中轻松更改Platform
。如果您使用的是Platform.select
,它也将按预期运行!
import { Platform } from 'react-native'
describe('When Android', () => {
it('should ...', () => {
Platform.OS = 'android'
...
})
})
describe('When iOS', () => {
it('should ...', () => {
Platform.OS = 'ios'
...
})
})
答案 11 :(得分:0)
你可以像React-Native
这样嘲笑你想要的任何东西:
describe('notifications actions tests', () => {
let Platform;
beforeEach(() => {
jest.mock('react-native', () => ({
Platform: {
...
}));
Platform = require('react-native').Platform; // incase u would like to refer to Platform in your tests
});
答案 12 :(得分:0)
jest: ^26.5.3
请参阅此article
的底部import { Platform } from 'react-native';
describe('Android', () => {
it('renders Element if Android', () => {
Platform.OS = 'android';
renderIfAndroid();
expect(wrapper.find(Element)).exists()).toBe(true);
});
});
describe('IOS', () => {
it('renders Element if IOS', () => {
Platform.OS = 'ios';
renderIfIOS();
expect(wrapper.find(Element)).exists()).toBe(true);
});
});
答案 13 :(得分:0)
如果有人在嘲笑A[2:]
。以下代码可以解决您的问题。
A[:2]
并同时嘲笑B
和Platform.select
。请参考下面的代码。
const mockedData = 'MOCKED-DATA'
jest.mock('react-native', () => ({
Platform: {
select: jest.fn(() => {
return { mockedData } // Your Mocked Value
}),
}
}));
答案 14 :(得分:0)
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();
});
});
答案 15 :(得分:-1)
可以为每个测试直接设置OS
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()
})
答案 16 :(得分:-2)
您必须模拟模块并将其导入测试。然后,您可以使用mockImplementation
将其设置为android
或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
})