Анимированные кнопки блокируют детокс

Это то, что я имел в виду под кнопкой анимации. Я позволил ему иметь идентификатор, но он не может быть найден детоксом как-тоanimating_button

Детокс устраняет слабость, автоматически синхронизируя ваши тесты с приложением. Тест не может перейти к следующей строке, если приложение занято. Тест возобновится только тогда, когда приложение станет бездействующим. Детокс очень внимательно следит за вашим приложением, чтобы узнать, когда оно бездействует. Он отслеживает несколько асинхронных операций и ожидает их завершения. Это включает:

Отслеживание всех сетевых запросов, которые в данный момент находятся в полете, и ожидание их завершения Отслеживание ожидающих анимаций и ожидание их завершения Отслеживание таймеров (например, setTimeout) и ожидание их истечения Отслеживание моста React Native, который несет асинхронный Сообщения Отслеживание асинхронного макета React Native и теневой очереди Отслеживание цикла событий JavaScript, который может содержать ожидающие асинхронные действия

Так что, очевидно, есть строка, которая говорит, что отслеживает ожидающую анимацию, поэтому, если кнопка продолжает анимацию, как это. Тогда это будет ждать?

Таким образом, обычно, как правильно решить эту проблему?

Спасибо

2 ответа

Из документации Detox:

Бесконечные циклы анимации

По умолчанию Detox будет ждать завершения анимации. Если у вас есть бесконечная циклическая анимация, это может привести к зависанию Detox. В этом случае рассмотрите возможность отключения синхронизации анимации или удаления бесконечного цикла в вашей сборке E2E с помощью response-native-repackager.

https://github.com/wix/detox/blob/master/docs/Troubleshooting.Synchronization.md

Основные пометки

Бесконечные анимации (петельные анимации) могут заставить детокс ждать вечно. Пожалуйста, рассмотрите возможность отключения зацикленной анимации для тестирования. Это также хорошая практика, чтобы ускорить все анимации для тестирования.

https://github.com/wix/detox/blob/master/docs/More.AndroidSupportStatus.md

Детокс обеспечивает disableSynchronization() - так что вы можете временно отключить синхронизацию, чтобы обойти анимацию, а затем снова включить ее после того, как анимация пропала. Это, однако, не будет работать для всех случаев. Например, если вы используете реагирующую навигацию, а кнопка включения перемещает новый экран в стек навигации, кнопка все равно будет продолжать анимацию в фоновом режиме, блокируя любые дальнейшие тесты, которые вы планируете запустить на новом экране.

Так что в идеале вы хотите пойти с другим предложением и отключить эти типы анимации для ваших тестов E2E. Вот 3 возможных варианта для достижения этой цели.

A:

Авторы Detox предлагают использовать для этого реактив-native-repackager. На данный момент он поддерживает только RN 0,51, так что это не может быть идеальным для всех. Пожалуйста, проверьте поддерживаемую версию перед использованием.

В настоящее время поддерживает только RN 0,51

B:

Настройте среды сборки React Native. На основании переменных конфигурации среды вы можете затем отключить продолжение анимации при создании для тестов E2E.

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

C:

Самый простой способ, который я нашел, - это использовать response-native-config. Здесь также есть хорошая статья об управлении конфигурацией в React Native с помощью response-native-config и еще один связанный с этим вопрос, как рассказать о том, что детокс работает.

Установите пакет:

$ yarn add response-native-config

Ссылка на библиотеку:

$ реагировать на родную ссылку

Чтобы проверить это решение, я создал 2 файла, .env.production а также .env.testing в корневом каталоге приложений React Native. Затем я использую переменную конфигурации IS_ANIMATE для переключения анимации в зависимости от среды сборки. Вам нужно добавить ENVFILE=.env.testing а также ENVFILE=.env.production к вашему конфигу сборки детоксикации.

.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"
    }
  }
}

Сборка релиза будет зависать: detox build --configuration ios.sim.release && detox test --configuration ios.sim.release

detox_hangs

Тестовая сборка пройдет: detox build --configuration ios.sim.test && detox test --configuration ios.sim.test

detox_passes

Вы можете решить этот бесконечный цикл анимации, используя

      await device.disableSynchronization();

Просто поместите эту строку перед взаимодействием с анимированным элементом, а затем вы можете снова включить синхронизацию.

      await device.enableSynchronization();

В этой функции раньше была ошибка, и они просто исправили ее в этом выпуске: 18.18.0.

Другие вопросы по тегам