Case Study: Getting Started with Detox for End-to-End Testing in React Native
Posted in detox, end-to-end-testing, quality-assurance on August 16, 2023 by Hemanta Sapkota ‐ 7 min read
As a React Native developer, you understand the importance of testing in the development process. To ensure that your app works as intended, end-to-end integration testing plays a crucial role. Fortunately, Detox is a powerful testing framework that allows you to write and execute these tests for your React Native app.
In this blog post, we will explore how to start using Detox for end-to-end integration testing in your React Native project, with a real-world example from my project - Yolmo: Learn to Code. We will also discuss how I use Detox to support automation.
What is Detox
Detox is a mobile app testing and automation library that uses gray box end-to-end testing. This method tests the application’s functionality from start to finish, while still maintaining some level of security and confidentiality regarding the application’s code and architecture. Testers have access to some knowledge of the internal components, but not full access, allowing for more comprehensive testing than black box testing.
Installing Detox
Before we begin, please ensure that you have Node.js and npm installed on your system. For complete instructions on how to set up your environment to work with Detox, please visit: https://wix.github.io/Detox/docs/introduction/getting-started.
Preparing Your Project to Support Detox
To prepare your project to support Detox, you need to install detox-cli
and jest
. You also need to configure your project by adding a detox
section to your package.json
file. This section specifies the configurations
object, which contains settings for each test environment. Finally, you need to create a detox.init.js
file in your project’s root directory, which exports a configuration object that specifies the path to your app’s binary file and other settings.
Please visit https://wix.github.io/Detox/docs/introduction/project-setup for complete instructions.
What does a Detox test look like
Now that Detox is installed, let’s look at a sample detox test case.
describe('Example', () => {
beforeEach(async () => {
await device.reloadReactNative();
});
it('should have welcome screen', async () => {
await expect(element(by.id('welcome'))).toBeVisible();
});
});
This is a sample Detox test case written in JSX. It checks that an element with the ID welcome
is visible on the welcome screen. To run the test, the command detox test
is used. The test suite is defined using the describe
block and takes a string argument to describe the suite. The beforeEach
block is defined inside the describe
block and reloads the React Native app before each test. The it
block defines a single test case with a string argument to describe the test. The test is asynchronous and uses the expect
function to check if the element is visible. The Detox-specific selectors element
and by
are used to locate the element in the app.
Case Study: Automating Yolmo’s Sign-In Process with Detox
Now that we have taken care of the prerequisites, let’s explore how we can automate the sign-in process for Yolmo.
Yolmo is a user-friendly learning app that offers an interactive and enjoyable way for people of all ages to learn how to code. Yolmo’s programming playgrounds are designed to make coding more engaging, and the is accessible to everyone. Visit https://yolmo.com to learn more.
Yolmo E2E Video walkthrough
The video linked below demonstrates how our automated sign-in process works. It includes launching the intro screen, logging in with valid credentials, navigating to the Account tab, and logging out.
The flows you see in the video are executed automatically through our test cases, without any human intervention. Let’s take a closer look at those test cases.
Planning Yolmo’s test cases
Identify the test cases
It’s important to identify the test cases first to ensure that the end-to-end integration testing covers all the necessary scenarios and functions of the app. The following table summarises the test cases for Yolmo’s login flow.
Test Case | Description |
---|---|
Launch the intro screen | This test case checks that the intro screen loads successfully upon launching the Yolmo app. |
Login with valid credentials | This test case verifies that users can successfully log in to the Yolmo app using valid credentials. |
Find the Account tab | This test case ensures that the user can navigate to the Account tab in the Yolmo app. |
Logout | This test case verifies that users can successfully log out of the Yolmo app. |
Please note that the actual implementation of the end-to-end integration testing process may diverge from the plan laid out here due to various factors. This may result in grouping or splitting test cases differently than originally planned.
Updating Test Ids
A test ID is a unique identifier assigned to an element in an application’s user interface. It is used to locate the element in automated tests and ensure that the tests remain reliable even if the UI changes.
The screenshot below provides a visual mapping of elements in Yolmo’s introduction and sign-in screen, along with their corresponding test IDs in the code.
It’s important to update the test IDs for each of the test cases listed above to ensure that they remain unique and consistent with the current state of the app. This helps to avoid test failures due to changes in the UI or other updates to the app.
Implementing the test cases
TEST001: Launch the intro screen
const checkIntroScreenIsVisible = async () =>
await expect(element(by.id('intro-screen'))).toBeVisible();
This code block defines a function called checkIntroScreenIsVisible which is an asynchronous arrow function that returns a promise. This function uses Detox-specific selectors (element and by) to locate an element with the id of intro-screen and checks if it is visible using the expect function and the Detox-specific toBeVisible matcher.
TEST002: Login with valid credentials
const signIn = async () => {
await element(by.id('intro_screen_sign_in_button')).tap();
await element(by.id('email_address')).typeText(email);
await element(by.id('password')).typeText(password);
await element(by.text('Sign in with email')).atIndex(1).tap();
};
This code block simulates the user input of logging in with valid credentials and verifies that the sign-in process is working as intended.
TEST003: Find the Account tab & Logout
const navigateToAccountTabAndLogout = async () => {
await element(by.id('account_tab')).tap();
await element(by.id('account_section')).tap();
await element(by.id('accountScreenScrollView')).scrollTo('bottom');
await element(by.text('Logout')).tap();
};
This code block defines a function called navigateToAccountTabAndLogout which is an asynchronous arrow function that scrolls to the bottom of the account screen and logs out of the Yolmo app. It locates the account_tab element and taps on it to navigate to the account screen. Then, it locates the account_section element and taps on it to open the account section. It then scrolls to the bottom of the screen using the accountScreenScrollView element and taps on the Logout button using the Detox-specific by.text selector.
Ordering the test cases in Detox
Now that we have identified, planned, and implemented all the code blocks and test cases, it’s time to put them together in a sequential order in Detox.
describe('Yolmo E2E Tests', () => {
beforeAll(async () => {
await device.launchApp({
permissions: {userTracking: 'YES'},
});
});
// Login
it('should check the intro screen', checkIntroScreenIsVisible);
it('should sign in', signIn);
it('should navigate to account tab and log out', navigateToAccountTabAndLogout);
});
Running the E2E flow with Detox
The detox build
command is a prerequisite to running Detox tests, as it generates a binary that is used by the detox test
command to launch the test-runner app and execute the tests.
detox build --configuration ios.sim.debug
Detox uses a separate test-runner app to communicate with the tested app and run the tests. The test-runner app is installed on the simulator along with the tested app, and it acts as a bridge between the test environment and the app being tested.
detox test --configuration ios.sim.debug
This command launches the Detox test runner app on the iOS simulator and executes the tests defined in the test files. The test runner app communicates with the tested app and drives it through the test flow. The test results are reported in the console output, and a detailed report is generated in HTML format.
Conclusion
In this blog post, I provide an introduction to Detox, a powerful testing framework that allows React Native developers to write and execute end-to-end integration tests for their apps. I cover the installation and configuration of Detox, as well as how to write and automate tests. To demonstrate how to automate the sign-in process, I use a real-world example from my project, Yolmo: Learn to Code. Additionally, I provide tips for planning and implementing test cases, as well as ordering them in Detox.
Don’t forget to leave a comment on the blog post if you found it helpful or have any additional tips to share!
comments powered by Disqus