Our Experience Adding E2E Testing to React Native with Maestro

We added end-to-end testing to a React Native project using Maestro. Here's what we liked, what we ran into and whether we'd recommend it.

| 6 min read
Our Experience Adding E2E Testing to React Native with Maestro blog post header image

At Add Jam we're always looking for ways to improve our development processes. We've written before about improving our React Native testing with Jest snapshots and that's been a great addition to our workflow. But snapshot tests only get you so far. They're brilliant at catching unintended UI changes, but they don't tell you whether your app actually works from a user's perspective.

That's why on a recent client React Native project we decided to add end-to-end testing to our process. After some research and past experience with other tools, we landed on Maestro.

What is Maestro?

In short, Maestro is an end-to-end testing framework for mobile apps. It supports iOS and Android, works with React Native, Flutter and native apps, and the tests themselves are written in YAML. It also comes with Maestro Studio, a visual IDE for building and inspecting tests, which is a nice touch for getting started quickly.

The thing that caught our attention though was that Maestro is completely platform agnostic. You don't need to install any packages in your React Native project to use it. It sits entirely outside your codebase and interacts with your app the way a real user would.

Why not Detox?

We'd previously used Detox for E2E testing on React Native projects. It works, but honestly it required a fair amount of setup and configuration to get running. Native module integration, build configuration changes and a good bit of boilerplate before you could write your first test.

Maestro was a breath of fresh air in comparison. No native dependencies, no build configuration changes, no faffing about. Install the CLI, point it at your running app, and you're writing tests.

What we liked

Reusable flows

This was probably our favourite feature. Maestro lets you break your tests into small, reusable flows. So things like logging in, logging out or navigating to a specific screen can be written once and shared across multiple tests.

This made it significantly easier to manage our test suite as it grew. Adding a new test for a feature was often just a case of composing existing flows together with a few new steps. It keeps things DRY and means if your login flow changes, you update it in one place.

YAML-based tests

The tests are written in YAML, which makes them incredibly easy to read and write. There's no JavaScript test runner to configure, no assertion library to learn. A simple flow looks something like this:

appId: com.example.app
---
- launchApp
- tapOn: "Log In"
- inputText:
    id: "email-input"
    text: "test@example.com"
- inputText:
    id: "password-input"
    text: "password123"
- tapOn: "Submit"
- assertVisible: "Welcome back"

If you can read YAML, you can read the tests. That low barrier to entry is a real advantage, especially in a team where not everyone is deeply familiar with testing frameworks.

Cross-platform

Our tests worked across both iOS and Android without any changes. Same YAML files, same flows, same assertions. For a team building cross-platform React Native apps, this is exactly what you want.

No project dependencies

This one's worth emphasising. Maestro doesn't require you to install anything in your project. No native modules, no dev dependencies, no pod installs. It's a standalone CLI tool that interacts with your app through the device itself.

Compare that with Detox where you need to add the package to your project, configure native build settings and manage those dependencies alongside everything else. Maestro staying outside your project means zero impact on your build process.

Device options and customisation

There's a good range of options for interacting with the device during tests. Beyond the usual tap and input actions, you can control device orientation, set location, manage permissions and more. It gave us the flexibility to test some of the more nuanced parts of our app without workarounds.

Screenshots and recording

The ability to take screenshots and record the full test flow was genuinely useful. When a test fails, you can see exactly what the screen looked like at the point of failure. No guessing, no "works on my machine" debates. You can watch the recording and see what went wrong. It's a small feature but it made debugging failed tests significantly faster.

What we ran into

It wouldn't be honest to pretend everything was smooth sailing. We hit a few rough edges worth mentioning.

Element interaction issues with z-index and absolute positioning

This was probably the most frustrating issue. Some elements rendered by third-party packages, particularly those using absolute positioning or a specific z-index, didn't play nicely with Maestro's element selection. We found that testID based selectors wouldn't always find these elements reliably.

The workaround was to use positional taps instead, which gets the job done but isn't ideal. It makes tests a bit more brittle if the layout changes. It's manageable, but something to be aware of if your app relies heavily on overlays or absolutely positioned elements.

Virtual keyboard quirks

We had a couple of instances where the virtual keyboard wouldn't fully dismiss between test steps. This caused subsequent taps to either hit the keyboard or miss the intended element entirely. The fix was straightforward enough, just making sure to explicitly dismiss the keyboard before moving on, but it caught us out a few times before we spotted the pattern.

LogBox getting in the way

React Native's LogBox can appear during development builds and it was occasionally blocking UI elements that our tests needed to interact with. This one was easy to solve though. Using react-native-launch-arguments we could pass a flag to disable LogBox during test runs. Quick fix, but worth knowing about upfront.

Would we use it again?

Yes. The rough edges we encountered were all workable and the overall developer experience was strong. Compared to Detox, the setup was dramatically simpler and the YAML-based approach meant we were writing meaningful tests much faster.

If you're building React Native apps and your E2E testing is either non-existent or stuck behind a heavyweight framework, Maestro is well worth a look. It slots in nicely alongside unit tests and snapshot tests as part of a broader testing strategy rather than replacing them.

For more of our React Native insights, check out our other React Native posts. And if you want to chat about testing strategy or anything else mobile, get in touch.

Daniel Taylor's avatar

Daniel Taylor

Software Engineer

Recent case studies

Here's a look at some of products we've brought to market recently

With Jack - Freelance Insurance

With Jack - Freelance Insurance

With Jack offers peace of mind and protection for UK freelance creatives and SMEs. Friendly, personable and reliable insurance.

Simple ASO Keyword Tool - Free ASO Platform

Simple ASO Keyword Tool - Free ASO Platform

We built a free, no-nonsense App Store Optimization tool that helps developers avoid common keyword mistakes and boost their app's visibility. What started as an afternoon project has evolved into a suite of free ASO tools helping app creators worldwide get their apps discovered.

PEM Diary - ME/CFS Crash Log

PEM Diary - ME/CFS Crash Log

PEM Diary is a React Native mobile app designed to help individuals with ME/CFS track and document PEM episodes. Built from personal experience, this app serves as a handy tool to understand your condition

We take products from an idea to revenue

Add Jam is your plug in team of web and mobile developers, designers and product managers. We work with you to create, ship and scale digital products that people use and love.

Hello, let's chat 👋
michael hayes avatar photo

Michael Hayes

Co-founder of Add Jam

Hey! Co-founder of Add Jam here. I'm available to chat about startups, tech, design, and development. Drop me a message or book a call in my calendar at a time that suits you.