Skip to content

Commit

Permalink
Merge pull request #150 from wix/animations_issue
Browse files Browse the repository at this point in the history
Animations issue
  • Loading branch information
silyevsk authored Jun 6, 2017
2 parents d69ad17 + 2e5c78d commit 33215d5
Show file tree
Hide file tree
Showing 10 changed files with 282 additions and 4 deletions.
8 changes: 8 additions & 0 deletions detox/ios/Detox.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@
39CEFCDB1E34E91B00A09124 /* DetoxUserNotificationDispatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 39CEFCDA1E34E91B00A09124 /* DetoxUserNotificationDispatcher.swift */; };
468731A51E6C6D0500F151BE /* EarlGrey+Detox.h in Headers */ = {isa = PBXBuildFile; fileRef = 468731A31E6C6D0500F151BE /* EarlGrey+Detox.h */; };
468731A61E6C6D0500F151BE /* EarlGrey+Detox.m in Sources */ = {isa = PBXBuildFile; fileRef = 468731A41E6C6D0500F151BE /* EarlGrey+Detox.m */; };
A7F76A151ED33DE500FFE77E /* WXAnimatedDisplayLinkIdlingResource.h in Headers */ = {isa = PBXBuildFile; fileRef = A7F76A131ED33DE500FFE77E /* WXAnimatedDisplayLinkIdlingResource.h */; };
A7F76A161ED33DE500FFE77E /* WXAnimatedDisplayLinkIdlingResource.m in Sources */ = {isa = PBXBuildFile; fileRef = A7F76A141ED33DE500FFE77E /* WXAnimatedDisplayLinkIdlingResource.m */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -217,6 +219,8 @@
39CEFCDA1E34E91B00A09124 /* DetoxUserNotificationDispatcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetoxUserNotificationDispatcher.swift; sourceTree = "<group>"; };
468731A31E6C6D0500F151BE /* EarlGrey+Detox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "EarlGrey+Detox.h"; sourceTree = "<group>"; };
468731A41E6C6D0500F151BE /* EarlGrey+Detox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "EarlGrey+Detox.m"; sourceTree = "<group>"; };
A7F76A131ED33DE500FFE77E /* WXAnimatedDisplayLinkIdlingResource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WXAnimatedDisplayLinkIdlingResource.h; sourceTree = "<group>"; };
A7F76A141ED33DE500FFE77E /* WXAnimatedDisplayLinkIdlingResource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WXAnimatedDisplayLinkIdlingResource.m; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -353,6 +357,8 @@
394767CA1DBF98D900D72256 /* WXJSTimerObservationIdlingResource.m */,
394767CB1DBF98D900D72256 /* WXRunLoopIdlingResource.h */,
394767CC1DBF98D900D72256 /* WXRunLoopIdlingResource.m */,
A7F76A131ED33DE500FFE77E /* WXAnimatedDisplayLinkIdlingResource.h */,
A7F76A141ED33DE500FFE77E /* WXAnimatedDisplayLinkIdlingResource.m */,
);
name = ReactNativeSupport;
sourceTree = "<group>";
Expand Down Expand Up @@ -400,6 +406,7 @@
391FA5E91E7FD96D0056F82F /* GREYIdlingResourcePrettyPrint.h in Headers */,
39A34C711E30F10D00BEBB59 /* DetoxAppDelegateProxy.h in Headers */,
397EC9B51E7EDE0B00D5F2BB /* EarlGreyStatistics.h in Headers */,
A7F76A151ED33DE500FFE77E /* WXAnimatedDisplayLinkIdlingResource.h in Headers */,
394767AE1DBF987E00D72256 /* DetoxManager.h in Headers */,
468731A51E6C6D0500F151BE /* EarlGrey+Detox.h in Headers */,
394767CD1DBF98D900D72256 /* ReactNativeHeaders.h in Headers */,
Expand Down Expand Up @@ -631,6 +638,7 @@
394767B51DBF987E00D72256 /* TestRunner.m in Sources */,
394767D31DBF98D900D72256 /* WXJSTimerObservationIdlingResource.m in Sources */,
394767C01DBF98A700D72256 /* GREYCondition+Detox.m in Sources */,
A7F76A161ED33DE500FFE77E /* WXAnimatedDisplayLinkIdlingResource.m in Sources */,
394767D11DBF98D900D72256 /* WXJSDisplayLinkIdlingResource.m in Sources */,
39A34C721E30F10D00BEBB59 /* DetoxAppDelegateProxy.m in Sources */,
394767B11DBF987E00D72256 /* MethodInvocation.m in Sources */,
Expand Down
2 changes: 2 additions & 0 deletions detox/ios/Detox/ReactNativeHeaders.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ typedef void (^RN_RCTJavaScriptCallback)(id json, NSError *error);
+ (id<RN_RCTBridge>)currentBridge;
- (void)requestReload;
- (id<RN_RCTUIManager>) uiManager;
- (id)moduleForName:(NSString *)moduleName;
- (id)moduleForClass:(Class)moduleClass;
@property (nonatomic, readonly, getter=isLoading) BOOL loading;
@property (nonatomic, readonly, getter=isValid) BOOL valid;

Expand Down
5 changes: 4 additions & 1 deletion detox/ios/Detox/ReactNativeSupport.m
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#import "WXRunLoopIdlingResource.h"
#import "WXJSDisplayLinkIdlingResource.h"
#import "WXJSTimerObservationIdlingResource.h"
#import "WXAnimatedDisplayLinkIdlingResource.h"

@import ObjectiveC;
@import Darwin;
Expand Down Expand Up @@ -84,8 +85,10 @@ void setupForTests()
// m = class_getInstanceMethod(cls, NSSelectorFromString(@"addToRunLoop:"));
// orig_addToRunLoop = (void(*)(id, SEL, NSRunLoop*))method_getImplementation(m);
// method_setImplementation(m, (IMP)swz_addToRunLoop);

[[GREYUIThreadExecutor sharedInstance] registerIdlingResource:[WXJSTimerObservationIdlingResource new]];

[[GREYUIThreadExecutor sharedInstance] registerIdlingResource:[WXAnimatedDisplayLinkIdlingResource new]];
}

@implementation ReactNativeSupport
Expand Down
14 changes: 14 additions & 0 deletions detox/ios/Detox/WXAnimatedDisplayLinkIdlingResource.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//
// WXAnimatedDisplayLinkIdlingResource.h
// Detox
//
// Created by Sergey Ilyevsky on 22/05/2017.
// Copyright © 2017 Wix. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <EarlGrey/EarlGrey.h>

@interface WXAnimatedDisplayLinkIdlingResource : NSObject <GREYIdlingResource>

@end
34 changes: 34 additions & 0 deletions detox/ios/Detox/WXAnimatedDisplayLinkIdlingResource.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// WXAnimatedDisplayLinkIdlingResource.m
// Detox
//
// Created by Sergey Ilyevsky on 22/05/2017.
// Copyright © 2017 Wix. All rights reserved.
//

#import "WXAnimatedDisplayLinkIdlingResource.h"
#import "ReactNativeHeaders.h"

@implementation WXAnimatedDisplayLinkIdlingResource {
id<RN_RCTBridge> _bridge;
}

- (NSString *)idlingResourceName
{
return NSStringFromClass([self class]);
}

- (NSString *)idlingResourceDescription
{
return @"Monitors CADisplayLink objects created by React Native Animated";
}

- (BOOL)isIdleNow
{
id<RN_RCTBridge> bridge = [NSClassFromString(@"RCTBridge") valueForKey:@"currentBridge"];
id animatedModule = [bridge moduleForClass:NSClassFromString(@"RCTNativeAnimatedModule")];
id displayLink = [animatedModule valueForKeyPath:@"_nodesManager._displayLink"];
return displayLink == nil;
}

@end
58 changes: 58 additions & 0 deletions detox/test/e2e/l-animations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
let _ = require('lodash');

describe('Animations', () => {
beforeEach(async () => {
await device.reloadReactNative();
await element(by.label('Animations')).tap();
});

async function _startTest(driver, options = {}) {
let driverControlSegment = element(by.text(driver).withAncestor(by.id('UniqueId_AnimationsScreen_useNativeDriver')));
await driverControlSegment.tap();

if(options.loops !== undefined) {
let loopSwitch = element(by.id('UniqueId_AnimationsScreen_enableLoop'));
await loopSwitch.tap();
await expect(loopSwitch).toHaveValue('1');
await element(by.id('UniqueId_AnimationsScreen_numberOfIterations')).replaceText(String(options.loops));
}

if(options.duration !== undefined) {
await element(by.id('UniqueId_AnimationsScreen_duration')).replaceText(String(options.duration));
}

if(options.delay !== undefined) {
await element(by.id('UniqueId_AnimationsScreen_delay')).replaceText(String(options.delay));
}

await element(by.id('UniqueId_AnimationsScreen_startButton')).tap();
}

_.forEach(['JS', 'Native'], (driver) => {
it(`should find element (driver: ${driver})`, async () => {
await _startTest(driver);
await expect(element(by.id('UniqueId_AnimationsScreen_afterAnimationText'))).toBeVisible();
});

it(`should detect loops with final number of iterations (driver: ${driver})`, async () => {
await _startTest(driver, {loops: 4});
await expect(element(by.id('UniqueId_AnimationsScreen_afterAnimationText'))).toBeVisible();
});

it.skip(`should not wait for infinite animations (driver: ${driver})`, async() => {
await _startTest(driver, {loops: -1});
await expect(element(by.id('UniqueId_AnimationsScreen_afterAnimationText'))).toBeVisible();
});

it(`should not wait during delays longer than 1.5s (driver: ${driver})`, async () => {
await _startTest(driver, {delay: 1600});
await expect(element(by.id('UniqueId_AnimationsScreen_afterAnimationText'))).toNotExist();
});

it(`should wait during delays shorter than 1.5s (driver: ${driver})`, async () => {
await _startTest(driver, {delay: 500});
await expect(element(by.id('UniqueId_AnimationsScreen_afterAnimationText'))).toExist();
});

});
});
1 change: 1 addition & 0 deletions detox/test/index.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class example extends Component {
{this.renderScreenButton('Switch Root', Screens.SwitchRootScreen)}
{this.renderScreenButton('Timeouts', Screens.TimeoutsScreen)}
{this.renderScreenButton('Orientation', Screens.Orientation)}
{this.renderScreenButton('Animations', Screens.AnimationsScreen)}
</View>
);
}
Expand Down
4 changes: 2 additions & 2 deletions detox/test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
"build": "detox build --configuration ios.sim.release"
},
"dependencies": {
"lodash": "^4.14.1",
"react": "16.0.0-alpha.6",
"react-native": "0.44.0"
},
"devDependencies": {
"detox": "^5.0.0",
"mocha": "^3.2.0"
"mocha": "^3.2.0",
"lodash": "^4.14.1"
},
"detox": {
"specs": "e2e",
Expand Down
156 changes: 156 additions & 0 deletions detox/test/src/Screens/AnimationsScreen.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
import React, { Component } from 'react';
import {
Text,
View,
Animated,
Button,
SegmentedControlIOS,
Switch,
TextInput
} from 'react-native';
import _ from 'lodash';


class AnimationsComponent extends Component {
constructor(props) {
super(props);

this._faidInValue = new Animated.Value(0);

this.state = {
showAfterAnimationText: false
};
}

componentDidMount() {
let fadeInAnimation = Animated.timing(this._faidInValue, {
toValue: 1,
duration: this.props.duration,
delay: this.props.delay,
useNativeDriver: this.props.useNativeDriver
});
var animation;
if(this.props.loops === undefined) {
animation = fadeInAnimation;
} else {
animation = Animated.loop(
Animated.sequence([
fadeInAnimation,
Animated.timing(this._faidInValue, {
toValue: 0.5,
duration: 0,
useNativeDriver: this.props.useNativeDriver
})
]),
{
iterations: this.props.loops
}
);
}

animation.start(() => this.setState({ showAfterAnimationText: true }));
}

render() {
return (
<View style={{ flex: 1, paddingTop: 20, justifyContent: 'center', alignItems: 'center' }}>
<Animated.Text testID='UniqueId_AnimationsScreen_animatedText' style={{
opacity: this._faidInValue,
backgroundColor: 'green'
}}
>
Fading in text
</Animated.Text>
{(() => {
if (this.state.showAfterAnimationText) return (
<Text testID='UniqueId_AnimationsScreen_afterAnimationText' style={{ marginTop: 20 }}>
After-animation-text
</Text>
)
})()}
</View>
);
}
}


export default class AnimationsScreen extends Component {
constructor(props) {
super(props);

this.state = {
useNativeDriver: undefined,
enableLoop: false,
numberOfIterations: -1,
duration: 400,
delay: 0,
testStarted: false
};
}

render() {
if (this.state.testStarted) {
return (
<AnimationsComponent
useNativeDriver={this.state.useNativeDriver}
loops={this.state.enableLoop ? this.state.numberOfIterations : undefined}
duration={this.state.duration}
delay={this.state.delay}
/>
);
}

let numOfIterationsColor = this.state.enableLoop ? 'black' : 'grey';
return (
<View style={{ flex: 1, paddingTop: 20, paddingLeft: 20, paddingRight: 20, justifyContent: 'center', alignItems: 'stretch' }}>
<View>
<Text>Driver:</Text>
<SegmentedControlIOS
testID="UniqueId_AnimationsScreen_useNativeDriver"
values={['JS', 'Native']}
selectedIndex={-1}
onValueChange={(value) => this.setState({ useNativeDriver: value === 'Native' })}
/>
</View>
<View style={{paddingTop: 20}}>
<Text>Loop:</Text>
<Switch
testID="UniqueId_AnimationsScreen_enableLoop"
value={this.state.enableLoop}
onValueChange={(value) => this.setState({enableLoop: value})}
/>
<Text style={{color: numOfIterationsColor}}>Number of iterations:</Text>
<TextInput style={{color: numOfIterationsColor, height: 20}}
testID="UniqueId_AnimationsScreen_numberOfIterations"
editable={this.state.enableLoop}
onChangeText={(value) => this.setState({numberOfIterations: Number(value)})}
placeholder={String(this.state.numberOfIterations)}
/>
</View>
<View style={{paddingTop: 20}}>
<Text>Duration:</Text>
<TextInput style={{height: 20}}
testID="UniqueId_AnimationsScreen_duration"
onChangeText={(value) => this.setState({duration: Number(value)})}
placeholder={String(this.state.duration)}
/>
</View>
<View style={{paddingTop: 20}}>
<Text>Delay:</Text>
<TextInput style={{height: 20}}
testID="UniqueId_AnimationsScreen_delay"
onChangeText={(value) => this.setState({delay: Number(value)})}
placeholder={String(this.state.delay)}
/>
</View>
<Button
style={{paddingTop: 20}}
title="Start"
testID="UniqueId_AnimationsScreen_startButton"
disabled={this.state.useNativeDriver === undefined}
onPress={() => this.setState({ testStarted: true })}
/>
</View>
);
}
}
4 changes: 3 additions & 1 deletion detox/test/src/Screens/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import StressScreen from './StressScreen';
import SwitchRootScreen from './SwitchRootScreen';
import TimeoutsScreen from './TimeoutsScreen';
import Orientation from './Orientation';
import AnimationsScreen from './AnimationsScreen';

export {
SanityScreen,
Expand All @@ -17,5 +18,6 @@ export {
StressScreen,
SwitchRootScreen,
TimeoutsScreen,
Orientation
Orientation,
AnimationsScreen
};

0 comments on commit 33215d5

Please sign in to comment.