Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Animated Button block the Detox

Tags:

detox

This is what I meant about the animating button. I let it have an ID, but it can't be located by the Detox somehow.

animating_button

Detox eliminates flakiness by automatically synchronizing your tests with the app. A test cannot continue to the next line if the app is busy. The test will only resume when the app becomes idle. Detox monitors your app very closely in order to know when it's idle. It tracks several asynchronous operations and waits until they complete. This includes:

Keeping track of all network requests that are currently in-flight and waiting until they complete Keeping track of pending animations and waiting until they complete Keeping track of timers (like setTimeout) and waiting until they expire Keeping track of the React Native bridge which carries asynchronous messages Keeping track of asynchronous React Native layout and the shadow queue Keeping track of the JavaScript event loop which may contain pending asynchronous actions

So apparently there is a line saying that keeping track of pending animation, so if the button keeps animating like this. Then It will keep waiting? Thus, usually how to deal with this issue properly?

Thanks

like image 503
Hien Tran Avatar asked Nov 20 '17 11:11

Hien Tran


1 Answers

From Detox documentation:

Endless looping animations

By default, Detox will wait until animations complete. If you have an endless looping animation, this may cause Detox to hang. In this case, consider turning off the animation synchronization or remove the endless loop in your E2E build with react-native-repackager.

https://github.com/wix/detox/blob/master/docs/Troubleshooting.Synchronization.md#endless-looping-animations

General remarks

Infinite animations (looped animations) can make detox wait forever. Please consider turning looped animations off for testing. It's also a good practice to speed up all animations for testing.

https://github.com/wix/detox/blob/master/docs/More.AndroidSupportStatus.md#general-remarks

Detox provides disableSynchronization() - so you can temporarily disable synchronization to work around an animation and then turn it back on after the animation is gone. This however will not work for all cases. For example if you are using react-navigation and the on press button pushes new screen to the navigation stack the button is still going to continue animating in the background, blocking any further tests you are planning to run on the new screen.

So ideally you want to go with the other suggestion and disable these types of animations for your E2E tests. Here are 3 possible options to achieve this.

A:

Detox authors suggest using react-native-repackager for this. At the moment it only supports RN 0.51, so this might not be ideal for everyone. Please check supported version before using.

Currently supports only RN 0.51

B:

Set up React Native build environments. Based on an environment configuration variables you can then disable continues animations when building for E2E tests.

https://blog.carbonfive.com/2016/09/29/setting-up-react-native-build-environments-using-nativemodules/

C:

The easiest way I found is to use react-native-config. Here is also a good article on Managing Configuration in React Native with react-native-config, and another related question how-to-tell-detox-is-running-tests.

Install the package:

$ yarn add react-native-config

Link the library:

$ react-native link react-native-config

To test this solution I created 2 files, .env.production and .env.testing in the root React Native app directory. I am then using IS_ANIMATE config variable to toggle animation depending on the build environment. You need to add ENVFILE=.env.testing and ENVFILE=.env.production to your detox build config.

.env.production

ENV_TYPE=Production
IS_ANIMATE=1

.env.testing

ENV_TYPE=Testing
IS_ANIMATE=0

app.js

import Config from 'react-native-config'

import React, { Component } from 'react'
import {
  AppRegistry,
  StyleSheet,
  Alert,
  Animated,
  View,
  TouchableOpacity,
  Text
} from 'react-native'

class example extends Component {
  constructor(props) {
    super(props)

    this.state = {
      radius: new Animated.Value(1)
    }
  }

  componentDidMount() {
    // only enable animation for production
    if (Config.IS_ANIMATE == true) {
      this.cycleAnimation()
    }
  }

  cycleAnimation() {
    Animated.loop(
      Animated.sequence([
        Animated.timing(this.state.radius, {
          toValue: 2,
          duration: 500,
          delay: 1000
        }),
        Animated.timing(this.state.radius, {
          toValue: 1,
          duration: 500
        })
      ])
    ).start()
  }

  render() {
    return (
      <View testID='container' style={styles.container}>
        <Text>{Config.ENV_TYPE}</Text>
        <TouchableOpacity
          testID='button'
          onPress={() => Alert.alert("I was pressed")}
        >
          <Animated.View
            style={[
              styles.button,
              {transform: [
                {scale: this.state.radius},
              ]}
            ]}
          >
            <Text>START DIARY</Text>
          </Animated.View>
        </TouchableOpacity>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  },
  button: {
    justifyContent: 'center',
    alignItems: 'center',
    borderRadius: 60,
    width: 120,
    height: 120,
    backgroundColor: 'green'
  },
  text: {
    padding: 5,
    fontSize: 14
  }
})

AppRegistry.registerComponent('example', () => example)

example.spec.js

it('Animated Button', async () => {
  const buttonElement = element(by.id('button'));
  await expect(buttonElement).toBeVisible();
  await buttonElement.tap();
});

package.json

"detox": {
  "specs": "e2e",
  "configurations": {
    "ios.sim.release": {
      "binaryPath": "ios/build/Build/Products/Release-iphonesimulator/example.app",
      "build": "ENVFILE=.env.production export RCT_NO_LAUNCH_PACKAGER=true && xcodebuild -project ios/example.xcodeproj -scheme example -configuration Release -sdk iphonesimulator -derivedDataPath ios/build",
      "type": "ios.simulator",
      "name": "iPhone 5s, iOS 10.3"
    },
    "ios.sim.test": {
      "binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/example.app",
      "build": "ENVFILE=.env.testing xcodebuild -project ios/example.xcodeproj -scheme example -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build -arch x86_64",
      "type": "ios.simulator",
      "name": "iPhone 5s, iOS 10.3"
    }
  }
}

The release build will hang: detox build --configuration ios.sim.release && detox test --configuration ios.sim.release

detox_hangs

The test build will pass: detox build --configuration ios.sim.test && detox test --configuration ios.sim.test

detox_passes

like image 135
Antoni4 Avatar answered Oct 22 '22 16:10

Antoni4