2017-02-16 61 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