Make Fastlane Screengrab Work with React Native

fastlane screengrab
on react native app is also challengingThis is a sister article of Make Fastlane Snapshot Work with React Native. While fastlane snapshot
works with iOS app, fastlane screengrab
is its Android version that programmatically takes Android app screenshots using the UI Testing functionality supported by Android Studio. Although the screenshot requirement on Android Play Store is less stringent than that on Apple App Store (no hard requirement on dimension, can skip tablets, etc.), the journey of getting fastlane screengrab
to work with React Native is still quite a mouthful. Given that most articles on this topic that we can find are dated, we would like to share our fresh experience working with fastlane screengrab
.
Be Careful with The Documentation
The documentation on screengrab
is more up to date than the one on Android Screenshot, because the former specifies that the latest version of screengrab
is 2.0.0. The latter, however, provides a gem link to screengrab
, which says its current version is 1.0.0. Configuring screengrab
as 1.0.0 (more on this later) in the gradle dependency does not work.
Preparation for UI Testing
The documentation is not particularly detailed regarding how to modify the Android native code to prepare for UI Testing with expresso, AndroidJUnitRunner, and UI Automator. We have found that the following configurations are necessary.
app_root/android/build.gradle
minSdkVersion
must be larger or equal to 18. This is to satisfy UI Automator’s requirement.
app_root/android/app/build.gradle (updated 09/22/2021)
Modify dependencies
as follows
dependencies {
...
// fastlane screengrab, falcon is a dependency of screengrab
androidTestImplementation 'com.jraska:falcon:2.2.0'
androidTestImplementation "tools.fastlane:screengrab:2.1.0" // Espresso dependencies
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' // Hamcrest library
androidTestImplementation 'org.hamcrest:hamcrest-library:1.3'
// Core library
androidTestImplementation 'androidx.test:core:1.4.0'
// AndroidJUnitRunner and JUnit Rules
androidTestImplementation 'androidx.test:runner:1.4.0'
androidTestImplementation 'androidx.test:rules:1.4.0'
}
This configuration mainly comes from Android documentation on building instrumented unit test. However, notice that we do not include the dependency for UI Automator. This is because UI Automator is already provided by screengrab
. Including it again will lead to class duplication error. Also notice that we put version 2.1.0 for screengrab
.
Next, modify defaultConfig
as follows
android {
...
defaultConfig {
...
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
}
app_root/android/app/src/debug/AndroidManifest.xml (updated 09/22/2021)
Paste the following config in the manifest file.
<!--For fastlane screengrab use-->
<!-- Allows unlocking your device and activating its screen so UI tests can succeed -->
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/><!-- Allows for storing and retrieving screenshots -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /><!-- Allows changing locales -->
<uses-permission
android:name="android.permission.CHANGE_CONFIGURATION"
tools:ignore="ProtectedPermissions" /><!-- Indicates the use of the clean status bar feature -->
<uses-feature android:name="tools.fastlane.screengrab.cleanstatusbar"/>
<!-- Allows for changing the status bar -->
<uses-permission
android:name="android.permission.DUMP"
tools:ignore="ProtectedPermissions" />
Create UI Testing file
The UI Testing file should be created in this path
app_root/android/app/src/androidTest/java/ScreenshotTest.java
We have thus named our test file ScreenshotTest.java
. Below is a template to get one started on obtaining screenshots.
Notice that we use onView(allOf(withContentDescription(id)))
to capture a component which has id
as its accessibilityLabel
. We stumbled upon this solution in Gergő Nagygyörgy’s article. This is truly a godsend, as the method specified in the documentation simply does not work for us.
Add accessibilityLabel to Dummy Buttons
The method of programmatically capturing screenshot is the same as described in the previous article. In iOS UI Testing, TouchableHighlight
is recognizable via testID
, but in Android UI Testing, only accessibilityLabel
is recognized. This means, for example, in order to make the template shown above work, we must specify accessibilityLabel="some_api_query_button"
in the dummy button.
Setup Fastfile to run screengrab
Follow the instructions in the documentation to create a screenshot lane. Notice that we must build two APK for screengrab
, one is debug and the other AndroidTest. If any React Native code is modified, both builds must be rebuilt to reflect the change. If ScreenshotTest.java
is the only file modified, then only AndroidTest build needs to be rebuilt.
Below is our screenshot lane. We also use Screengrabfile
to configure screengrab
. For details, refer to the documentation.
desc 'Produce screenshots via screengrab'
lane :screenshots do
gradle(task: 'clean', project_dir: 'android/')
gradle(
task: 'assemble',
build_type: 'Debug',
project_dir: 'android/',
)
gradle(
task: 'assemble',
build_type: 'AndroidTest',
project_dir: 'android/',
)
screengrab
end
Keep Metro Bundler and Device Emulator Running
screengrab
requires that both the metro bundler (i.e. npx react-native start
) and a desired Android device emulator to be running when screenshots are taken. Surprisingly, these two are not automatically spun up by screengrab
. In other words, we need to manually start metro bundler and device emulator before runninng screengrab
, or write scripts to initiate them in Fastfile
. One benefit of having the device emulator up is that we can observe in real time how the actions specified in ScreenshotTest.java
are executed.
Summary
We have presented our experience working with fastlane screengrab
on a React Native app. Overall, it is less annoying as fastlane snapshot
, but there are still quite a few hurdles to jump through. The parts we think the existing documentation is unclear are:
- The native code set up for UI Testing
- The method to capture react native component during UI Testing.
We hope this write up will help those who feel a bit overwhelmed when reading the fastlane screengrab
documentation for the first time (in our case, we were so overwhelmed that we had to stare at a blank wall to re-contemplate our lives).