我有一个无状态组件:
export default function TripReportFooter(props) {
const { tripReport, user, toggleFavorite, navigation } = props;
handleShare = async slug => {
try {
const result = await Share.share({
message: `Check out this Trip Report:\n/p/${slug}/`
});
if (result.action === Share.sharedAction) {
if (result.activityType) {
} else {
// shared
}
} else if (result.action === Share.dismissedAction) {
}
} catch (error) {
alert(error.message);
}
};
handleFavorite = async id => {
const token = await AsyncStorage.getItem("token");
toggleFavorite(id, token);
};
return (
... // handleFavorite and handleShare called with TouchableOpacities.
);
}
它内部有两个功能,handleShare和handleFavorite。我要测试这些函数是否被调用,以及那个handleFavorite调用prop函数是否切换到收藏夹。
我尝试了wrapper.instance()。handleFavorite(),但是由于它是一个无状态组件,因此它返回null。
接下来,Stack Overflow上的某人建议使用这样的间谍:
wrapper = shallow(<TripReportFooter {...props} handleFavorite={press} />);
wrapper
.find("TouchableOpacity")
.at(0)
.simulate("press");
expect(press.called).to.equal(true);
});
,但这返回了'TypeError:无法读取未定义的属性'equal'。调用这些函数的正确方法是什么?
答案 0 :(得分:1)
您首先需要考虑要测试的内容。是实施细节还是与组件的交互?后者是一种更好的心态和立场,所以我要做的是从交互的角度测试该组件。
我会(对于handleShare
):
现在handleFavorite
:
AsyncStorage.getItem
; toggleFavorite
函数; toggleFavorite
函数已被调用如果要单独测试这些功能,则必须将它们提取到组件外部并分别进行测试。但是我不建议这样做,因为这不干净而且没有额外的工作。
希望有帮助!
答案 1 :(得分:1)
功能组件中的功能未在原型或功能组件实例上定义,您无法直接对其进行监视
这里的解决方案是测试各个功能的内部实现
例如,对于handleFavourite
函数,您可以模拟AsynStorage并将模拟函数传递给toggleFavourite,然后在TouchableOpacity onPress模拟中将其作为资产
您可以在这篇文章中检查如何模拟AsyncStore: How to test Async Storage with Jest?
const mocktToggleFavourite = jest.fn();
wrapper = shallow(<TripReportFooter {...props} toggleFavourite={mocktToggleFavourite} />);
wrapper
.find("TouchableOpacity")
.at(0)
.simulate("press");
expect(mockToggleFavourite).toHaveBeenCalled();
类似地,您可以通过首先模拟handleShare
然后检查每个条件来测试Share.share
中的各个功能。例如,您可以在window.alert上添加一个间谍,看看是否被称为>
const windowSpy = jest.spyOn(window, 'alert');
wrapper = shallow(<TripReportFooter {...props} toggleFavourite={mocktToggleFavourite} />);
//Simulate event that calls handleShare
// Mock Share to give required result
expect(windowSpy).toBeCalledWith(expectedValue);
答案 2 :(得分:0)
在上面的代码中,您将press
函数作为handleFavorite
道具传递,但是您没有使用handleFavorite
道具。为了在这种情况下使用间谍程序(调用该功能的一个不错的选择),您需要将handleFavorite
函数从组件中拉出。
jestjs
提供了一个称为模拟功能的东西,它基本上是spy
(sinonjs
的间谍具有类似的api)。
这里有一些sudo代码来描述我的意思:
// TripReporterFooter.js
import React from 'react';
const TripleReportFooter = (props) => {
return (
<TouchableOpacity onShare={props.handleShare} onFavorite={props.handleFavorite} />
);
};
然后可以将handleShare
和handleFavorite
函数作为模拟从测试中传递。
// TripReportFooter test
describe('TripReportFooter', () => {
it('calls handleFavorite', () => {
const mockHandleFavorite = jest.fn();
wrapper = shallow(<TripReportFooter handleFavorite={mockHandleFavorite} />);
wrapper
.find('TouchableOpacity')
.at(0)
.simulate('press');
expect(mockHandleFavorite.mock.calls.length).toBe(1);
});
});
使用上述代码,您将需要从handleFavorite
中提取handleShare
和TripleReporterFooter
实现,并将它们传递到呈现<TripleReporterFooter />
的任何地方。
例如:
import { handleShare, handleFavorite } from './shareAndFav'`
const TripleReporterParent = () => {
return <TripleReportFooter handleShare={handleShare} handleFavorite={handleFavorite} />
}
如果要在两个组件之间共享功能,可以始终将它们从组件中拉出到共享模块中。这是在文件中创建并在两个组件之间共享的那些函数的示例:
// A new file called shareAndFav.js (Same as the name from the TripleReporterParent).
const handleShare = async slug => {
try {
const result = await Share.share({
message: `Check out this Trip Report:\n/p/${slug}/`
});
if (result.action === Share.sharedAction) {
if (result.activityType) {
} else {
// shared
}
} else if (result.action === Share.dismissedAction) {
}
} catch (error) {
alert(error.message);
}
};
handleFavorite = async id => {
const token = await AsyncStorage.getItem("token");
toggleFavorite(id, token);
};
export { handleShare, handleFavorite } // the import from TripleReportFooterParent components can now reuse these
它们不一定需要在呈现器中(它们只是函数,您可以像上面一样在它们自己的文件中定义它们)。
将它们拉入自己的模块后,可以通过导入它们在所需的任何组件中使用它们:
import { handleShare, handleFavorite } from '<the path to shareAndFav.js>'