2017-02-16 19 views
4

私はAnimated.ViewをJest for React-Nativeでテストしようとしています。私がプロパティーvisibleをtrueに設定すると、ビューがopacity 0からopacity 1にアニメーション化されるはずです。JestテストAnimated.View for React-Nativeアプリケーション

これは私のコンポーネントのレンダリングです:

小道具 visible変更する場合 opacityValueが更新さ
<Animated.View 
    style={{ 
     opacity: opacityValue, 
    }} 
> 
    <Text>{message}</Text> 
</Animated.View> 

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(); 
}); 

私は待つように冗談を持っている可能性がどのように不思議でしたか?あるいは、私はこれをテストして、小道具を真に設定したときにビューが見えるようにすることができましたか?

ありがとうございました。

答えて

11

この問題は、テスト用のアニメーションスタブを作成することで解決しました。

私は働く例があり、あなたがプロパティとして見える使用している参照してください。

コンポーネントのコード今すぐ生成したスナップショットがありますテスト

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();                                 
});                                                 

に移動

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 }; 

不透明度の値を期待どおりにします。 多くのアニメーションを使用している場合は、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