Skip to content

Commit

Permalink
improved stress tests to check RN flakiness
Browse files Browse the repository at this point in the history
  • Loading branch information
talkol committed Aug 14, 2016
1 parent 19d519a commit 0da043d
Show file tree
Hide file tree
Showing 9 changed files with 155 additions and 72 deletions.
39 changes: 25 additions & 14 deletions detox/test/e2e/c-stress-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,37 @@ describe.skip('Stress Tests', function () {

beforeEach(function () {
element(by.label('Stress')).tap();
})
});

it('should handle tap during busy bridge (one way)', function () {
element(by.label('Bridge OneWay Stress')).tap();
element(by.label('Next')).tap();
expect(element(by.label('BridgeOneWay'))).toBeVisible();
});

it('should handle tap during busy bridge (two way)', function () {
element(by.label('Bridge TwoWay Stress')).tap();
element(by.label('Next')).tap();
expect(element(by.label('BridgeTwoWay'))).toBeVisible();
});

it('should handle tap during busy bridge', function () {
element(by.label('Bridge Stress')).tap();
expect(element(by.label('Hello World!!!'))).toBeVisible();
it('should handle tap during busy bridge (setState)', function () {
element(by.label('Bridge setState Stress')).tap();
element(by.label('Next')).tap();
expect(element(by.label('BridgeSetState'))).toBeVisible();
});

it('should handle tap during busy JS event loop', function () {
element(by.label('Events Stress')).tap();
expect(element(by.label('Hello World!!!'))).toBeVisible();
element(by.label('EventLoop Stress')).tap();
element(by.label('Next')).tap();
expect(element(by.label('EventLoop'))).toBeVisible();
});

describe('Consecutive Test', function () {
const MULTI_TEST_COUNT = 20;
for (let i = 0; i < MULTI_TEST_COUNT; i++) {
it(`should handle tap in consecutive test #${i+1}`, function () {
element(by.label('Say Hello')).tap();
expect(element(by.label('Hello!!!'))).toBeVisible();
});
};
it('should handle consecutive taps', function () {
const TAP_COUNT = 50;
for (let i = 1 ; i <= TAP_COUNT ; i++) {
element(by.label('Consecutive Stress ' + i)).tap();
}
});

});
2 changes: 2 additions & 0 deletions detox/test/index.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import * as Screens from './src/screens'

class example extends Component {

constructor(props) {
super(props);
this.state = {
Expand Down Expand Up @@ -42,6 +43,7 @@ class example extends Component {
<Screen />
);
}

}

AppRegistry.registerComponent('example', () => example);
6 changes: 6 additions & 0 deletions detox/test/ios/example.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
CC0F35311D461096008BB94F /* Detox.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CCFA7DF51D11D25A00E15EDF /* Detox.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
CC17D3321D60A24300267B0C /* NativeModule.m in Sources */ = {isa = PBXBuildFile; fileRef = CC17D3311D60A24300267B0C /* NativeModule.m */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -162,6 +163,8 @@
146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = "../node_modules/react-native/React/React.xcodeproj"; sourceTree = "<group>"; };
78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = "../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj"; sourceTree = "<group>"; };
832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = "../node_modules/react-native/Libraries/Text/RCTText.xcodeproj"; sourceTree = "<group>"; };
CC17D3301D60A24300267B0C /* NativeModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NativeModule.h; path = example/NativeModule.h; sourceTree = "<group>"; };
CC17D3311D60A24300267B0C /* NativeModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NativeModule.m; path = example/NativeModule.m; sourceTree = "<group>"; };
CCFA7DEF1D11D25A00E15EDF /* Detox.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Detox.xcodeproj; path = ../node_modules/detox/ios/Detox.xcodeproj; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -276,6 +279,8 @@
13B07FB61A68108700A75B9A /* Info.plist */,
13B07FB11A68108700A75B9A /* LaunchScreen.xib */,
13B07FB71A68108700A75B9A /* main.m */,
CC17D3301D60A24300267B0C /* NativeModule.h */,
CC17D3311D60A24300267B0C /* NativeModule.m */,
);
name = example;
sourceTree = "<group>";
Expand Down Expand Up @@ -610,6 +615,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
CC17D3321D60A24300267B0C /* NativeModule.m in Sources */,
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
13B07FC11A68108700A75B9A /* main.m in Sources */,
);
Expand Down
9 changes: 0 additions & 9 deletions detox/test/ios/example/AppDelegate.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>
Expand Down
9 changes: 0 additions & 9 deletions detox/test/ios/example/AppDelegate.m
Original file line number Diff line number Diff line change
@@ -1,12 +1,3 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/

#import "AppDelegate.h"
#import "RCTRootView.h"
#import "DetoxLoader.h"
Expand Down
6 changes: 6 additions & 0 deletions detox/test/ios/example/NativeModule.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#import "RCTBridgeModule.h"
#import <Foundation/Foundation.h>

@interface NativeModule : NSObject <RCTBridgeModule>

@end
20 changes: 20 additions & 0 deletions detox/test/ios/example/NativeModule.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#import "NativeModule.h"

@implementation NativeModule

RCT_EXPORT_MODULE();

RCT_EXPORT_METHOD(echoWithoutResponse:(NSString *)str)
{
NSLog(@"NativeModule echoWithoutResponse called");
}

RCT_EXPORT_METHOD(echoWithResponse:(NSString *)str
resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject)
{
resolve(str);
NSLog(@"NativeModule echoWithResponse called");
}

@end
2 changes: 2 additions & 0 deletions detox/test/src/Screens/SanityScreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
} from 'react-native';

export default class SanityScreen extends Component {

constructor(props) {
super(props);
this.state = {
Expand Down Expand Up @@ -34,6 +35,7 @@ export default class SanityScreen extends Component {
</View>
);
}

renderAfterButton() {
return (
<View style={{flex: 1, paddingTop: 20, justifyContent: 'center', alignItems: 'center'}}>
Expand Down
134 changes: 94 additions & 40 deletions detox/test/src/Screens/StressScreen.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,37 @@ import React, { Component } from 'react';
import {
Text,
View,
TouchableOpacity
TouchableOpacity,
NativeModules
} from 'react-native';

const STRESSFUL_STRING_LENGTH = 48000; // Min: 32000
const STRESSFUL_EVENTS_COUNT = 570; // Min: 380
const NativeModule = NativeModules.NativeModule;

function buildStringByLength(length) {
str = "";
charcode = 65;
for (let i=0; i < length; i++) {
str += String.fromCharCode(charcode);
charcode ++;
if (charcode == 91) charcode = 65;
const BRIDGE_ONEWAY_CALLS = 10;
const BRIDGE_ONEWAY_STR_CHUNK_LEN = 20;
const BRIDGE_TWOWAY_CALLS = 10;
const BRIDGE_TWOWAY_STR_CHUNK_LEN = 20;
const BRIDGE_SETSTATE_STR_CHUNK_LEN = 20;
const EVENT_LOOP_COUNT = 10;
const EVENT_LOOP_STR_CHUNK_LEN = 20;

function getStringByLength(chunks) {
let res = '';
for (let i = 0; i < chunks ; i++) {
res += 'EqtCfLH6DYnLT4WjBcLfR9M33uxSEEBMphVSTnpKpEfHCBNn3oxVMpEQ0Rzqlx8BiiyCIF5WnkEhJyGsGhHtVfjgwCueY0DQXmat';
}
return str;
return res;
}

export default class StressScreen extends Component {

constructor(props) {
super(props);
this.state = {
greeting: undefined,
passToBridge: undefined
phase1: undefined,
phase2: undefined,
extraData: undefined,
counter: 1
};
}

Expand All @@ -37,56 +45,102 @@ export default class StressScreen extends Component {
}

render() {
if (this.state.greeting) return this.renderAfterButton();
if (this.state.phase2) return this.renderPhase2();
if (this.state.phase1) return this.renderPhase1();
return (
<View style={{flex: 1, paddingTop: 20, justifyContent: 'center', alignItems: 'center'}}>
<Text style={{fontSize: 25, marginBottom: 30}}>
Welcome
</Text>
{this.renderTestButton('Say Hello', this.onButtonPress.bind(this, 'Hello'))}
{this.renderTestButton('Say World', this.onButtonPress.bind(this, 'World'))}
{this.renderTestButton('Bridge Stress', this.bridgeStressButtonPressed.bind(this, 'Hello World'))}
{this.renderTestButton('Events Stress', this.eventsStressButtonPressed.bind(this, 'Hello World'))}
{this.renderTestButton('Bridge OneWay Stress', this.bridgeOneWayStressButtonPressed.bind(this))}
{this.renderTestButton('Bridge TwoWay Stress', this.bridgeTwoWayStressButtonPressed.bind(this))}
{this.renderTestButton('Bridge setState Stress', this.bridgeSetStateStressButtonPressed.bind(this))}
{this.renderTestButton('EventLoop Stress', this.eventLoopStressButtonPressed.bind(this))}
{this.renderTestButton(`Consecutive Stress ${this.state.counter}`, this.consecutiveStressButtonPressed.bind(this))}
</View>
);
}
renderAfterButton() {

renderPhase2() {
return (
<View style={{flex: 1, paddingTop: 20, justifyContent: 'center', alignItems: 'center'}}>
<Text style={{fontSize: 10, width: 0, height: 0}}>
Bridge: {this.state.passToBridge}
</Text>
<Text style={{fontSize: 25}}>
{this.state.greeting}!!!
<Text style={{fontSize: 25, marginBottom: 20}}>
{this.state.phase2}
</Text>
{
!this.state.extraData ? false :
<Text style={{fontSize: 10, width: 100, height: 20}}>
Extra Data: {this.state.extraData}
</Text>
}
</View>
);
}

onButtonPress(greeting) {
renderPhase1() {
return (
<View style={{flex: 1, paddingTop: 20, justifyContent: 'center', alignItems: 'center'}}>
<TouchableOpacity onPress={this.onButtonPress.bind(this)}>
<Text style={{color: 'blue', marginBottom: 20}}>Next</Text>
</TouchableOpacity>
</View>
);
}

onButtonPress() {
this.setState({
phase2: this.state.phase1
});
}

bridgeOneWayStressButtonPressed() {
this.setState({
greeting: greeting
phase1: 'BridgeOneWay'
});
setImmediate(() => {
const str = getStringByLength(BRIDGE_ONEWAY_STR_CHUNK_LEN);
for (let i = 0 ; i < BRIDGE_ONEWAY_CALLS ; i++) {
NativeModule.echoWithoutResponse(str);
}
});
}

bridgeStressButtonPressed(greeting) {
this.onButtonPress(greeting)
bridgeTwoWayStressButtonPressed() {
this.setState({
phase1: 'BridgeTwoWay'
});
setImmediate(() => {
const str = getStringByLength(BRIDGE_TWOWAY_STR_CHUNK_LEN);
for (let i = 0 ; i < BRIDGE_TWOWAY_CALLS ; i++) {
NativeModule.echoWithResponse(str);
}
});
}

const data = buildStringByLength(STRESSFUL_STRING_LENGTH);
bridgeSetStateStressButtonPressed() {
this.setState({
passToBridge: data,
greeting: greeting
phase1: 'BridgeSetState'
});
setImmediate(() => {
const str = getStringByLength(BRIDGE_SETSTATE_STR_CHUNK_LEN);
this.setState({
extraData: str
});
});
}

eventsStressButtonPressed(greeting) {
// Stress:
for (let i =0; i < STRESSFUL_EVENTS_COUNT; i++) {
let myString = "";
setImmediate(() => { myString = buildStringByLength(1000) });
eventLoopStressButtonPressed() {
this.setState({
phase1: 'EventLoop'
});
for (let i = 0 ; i < EVENT_LOOP_COUNT ; i++) {
setImmediate(() => {
let str = getStringByLength(EVENT_LOOP_STR_CHUNK_LEN);
});
}
}

setImmediate(() => { this.onButtonPress(greeting) });
consecutiveStressButtonPressed() {
this.setState({
counter: this.state.counter + 1
});
}

}

0 comments on commit 0da043d

Please sign in to comment.