我尝试使用 Jest for React-Native 测试 Animated.View
。当我将属性 visible
设置为 true 时,它应该将我的 View 从 opacity 0
动画化为 opacity 1
。
这是我的组件呈现的内容:
<Animated.View
style={{
opacity: opacityValue,
}}
>
<Text>{message}</Text>
</Animated.View>
opacityValue
在 props visible
改变时更新:
Animated.timing(
this.opacityValue, {
toValue: this.props.visible ? 1 : 0,
duration: 350,
},
).start(),
当我设置属性 visible=true
时,我想确保我的 View 可见。尽管 View 变得可见需要一些时间,并且随着测试的运行,不透明度等于 0
。
这是我的测试吧:
it('Becomes visible when visible=true', () => {
const tree = renderer.create(
<MessageBar
visible={true}
/>
).toJSON();
expect(tree).toMatchSnapshot();
});
我在想我怎么能让 Jest 等?或者我如何测试它以确保当我将 Prop 设置为 true 时 View 变得可见?
谢谢。
最佳答案
我通过为测试创建一个动画 stub 解决了这个问题。
我看到您正在使用 visible 作为属性,所以一个有效的例子是:
组件代码
import React from 'react';
import { Animated, Text, View, TouchableOpacity } from 'react-native';
// This class will control the visible prop
class AnimatedOpacityController extends React.Component {
constructor(props, ctx) {
super(props, ctx);
this.state = {
showChild: false,
};
}
render() {
const { showChild } = this.state;
return (
<View>
<AnimatedOpacity visible={this.state.showChild} />
<TouchableOpacity onPress={() => this.setState({ showChild: !showChild })}>
<Text>{showChild ? 'Hide' : 'Show' } greeting</Text>
</TouchableOpacity>
</View>
);
}
}
// This is your animated Component
class AnimatedOpacity extends React.Component {
constructor(props, ctx) {
super(props, ctx);
this.state = {
opacityValue: new Animated.Value(props.visible ? 1 : 0),
};
}
componentWillReceiveProps(nextProps) {
if (nextProps.visible !== this.props.visible) {
this._animate(nextProps.visible);
}
}
_animate(visible) {
Animated.timing(this.state.opacityValue, {
toValue: visible ? 1 : 0,
duration: 350,
}).start();
}
render() {
return (
<Animated.View style={{ opacity: this.state.opacityValue }}>
<Text>Hello World</Text>
</Animated.View>
);
}
}
export { AnimatedOpacityController, AnimatedOpacity };
现在开始测试
import React from 'react';
import renderer from 'react-test-renderer';
import { shallow } from 'enzyme';
import { AnimatedOpacityController, AnimatedOpacity } from '../AnimatedOpacity';
jest.mock('Animated', () => {
const ActualAnimated = require.requireActual('Animated');
return {
...ActualAnimated,
timing: (value, config) => {
return {
start: (callback) => {
value.setValue(config.toValue);
callback && callback()
},
};
},
};
});
it('renders visible', () => {
expect(
renderer.create(
<AnimatedOpacity visible={true} />
).toJSON()
).toMatchSnapshot();
});
it('renders invisible', () => {
expect(
renderer.create(
<AnimatedOpacity visible={false} />
).toJSON()
).toMatchSnapshot();
});
it('makes transition', () => {
const component = shallow(<AnimatedOpacityController />);
expect(renderer.create(component.node).toJSON()).toMatchSnapshot();
component.find('TouchableOpacity').simulate('press');
expect(renderer.create(component.node).toJSON()).toMatchSnapshot();
component.find('TouchableOpacity').simulate('press');
expect(renderer.create(component.node).toJSON()).toMatchSnapshot();
});
现在生成的快照将具有预期的不透明度值。
如果你经常使用动画,你可以将你的模拟移动到 js/config/jest
并编辑你的 package.json 以在你的所有测试中使用它,然后对你的 stub 所做的任何更改都可以用于所有测试。
编辑:
上面的解只能从头到尾解决。更精细的解决方案是:
- 不要 mock 动画
- 在 Jest 配置中使
global.requestAnimationFrame = null
- 使用 mockdate 模拟日期
- 使用 jest.runTimersToTime 进行时间旅行
时间旅行函数是
const timeTravel = (ms, step = 100) => {
const tickTravel = v => {
jest.runTimersToTime(v);
const now = Date.now();
MockDate.set(new Date(now + v));
}
let done = 0;
while (ms - done > step) {
tickTravel(step);
done += step;
}
tickTravel(ms - done);
};
由于动画内部行为,将步骤分成小块很重要。
关于javascript - 为 React-Native 应用开 Jest 测试 Animated.View,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42268673/