2017-02-16 87 views
4

我尝试用Jest for React-Native测试Animated.View。当我将属性visible设置为true时,它应该将我的视图从opacity 0设置为opacity 1Jest test React-Native app的动画查看

这是我的组件呈现:

<Animated.View 
    style={{ 
     opacity: opacityValue, 
    }} 
> 
    <Text>{message}</Text> 
</Animated.View> 

在当道具visible变化opacityValue得到更新:

Animated.timing(
    this.opacityValue, { 
     toValue: this.props.visible ? 1 : 0, 
     duration: 350, 
    }, 
).start(), 

我想确保我的看法是可见的,当我将它的属性visible=true。尽管视图变得可见并且测试运行需要一些时间,但不透明度等于0

这是我的测试:

it('Becomes visible when visible=true',() => { 
    const tree = renderer.create(
     <MessageBar 
      visible={true} 
     /> 
    ).toJSON(); 
    expect(tree).toMatchSnapshot(); 
}); 

我不知道我怎么可能有玩笑等待?或者我怎么能测试这个以确保当我将道具设置为true时视图变得可见?

感谢。

回答

11

我通过创建测试的动画存根来解决此问题。

我看你的财产利用可见光,这样的工作的例子是:

组件的代码

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以在所有测试中使用它,然后对您的存根进行的任何更改都将可用于所有测试。

编辑:

上述解决方案只解决了从头到尾。更细化的解决方案是:

  1. 不要模仿动画
  2. 开玩笑配置使global.requestAnimationFrame = null
  3. 使用mockdate做嘲笑的日期
  4. 使用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);                                             
};  

由于动画的内部行为,在小块中突破步骤是重要的。

+0

遇到同样的问题,无法让这个工作,你可以分享一个示例项目? 你能解释为什么它有必要设置global.requestAnimationFrame = null并嘲笑日期吗? 谢谢 – talarari