How to Test React Native UI Visually with Storybook and Chromatic
Why Visual Testing Matters for React Native Apps
Let's be honest. You've shipped a React Native update, tested it on a device, everything looked fine — then a user sends a screenshot of a button that's shifted three pixels to the left on their Android. Sound familiar?
That's the reality of mobile UI development. Unit tests verify logic. They tell you if a function returns the right value. But they won't catch a layout shift, a color mismatch, or a font that renders differently on iOS vs Android. Those are visual bugs, and they're everywhere.
The problem with manual UI checks
Most teams rely on developers squinting at screens during code review. Or worse, QA manually clicking through every screen before a release. This approach doesn't scale. A team of five might catch 80% of visual regressions. A team of twenty? Maybe 60%. Fatigue sets in. Humans miss things.
And here's the kicker: visual regression testing finds bugs that unit tests and integration tests completely ignore. A 1px padding change? Invisible to Jest. A font-weight that reverts to default? Your test suite won't blink. But your users will notice.
How visual regression testing saves time
Automated visual testing works by taking screenshots of your UI components and comparing them against a baseline. When you make changes, the tool highlights every pixel difference. You approve or reject those changes. No more manual hunting.
For React Native specifically, tools like Storybook combined with Chromatic give you a workflow that fits right into your existing development cycle. You write stories for your components, Chromatic captures the screenshots, and your CI pipeline flags anything unexpected. It's that straightforward.
So what exactly will you learn here? By the end of this guide, you'll have a fully working setup to test React Native UI visually — from installing Storybook to automating checks in CI. Let's get into it.
Prerequisites: What You Need Before Starting
Before we jump into the setup, make sure you've got the basics covered. Nothing worse than hitting a wall because you're missing a dependency.
React Native project setup
- A working React Native project — either Expo or bare workflow. Both work fine with this setup.
- Node.js 16+ and either npm or yarn installed.
- Basic familiarity with React Native components and how your project is structured.
If you're starting from scratch, run npx react-native init MyVisualTestApp (or npx create-expo-app if you prefer Expo). Either way works.
Storybook for React Native
Storybook is the backbone here. It lets you develop and test UI components in isolation. You don't need to be an expert — just understand that a "story" is basically a function that renders your component with specific props. We'll use @storybook/react-native.
One thing to note: Storybook for React Native isn't the same as the web version. The setup is slightly different, and you'll run it on a device or simulator. But the concepts are identical.
Step 1: Install and Configure Storybook in React Native
This is where the rubber meets the road. Let's get Storybook running in your project.
Adding Storybook to your project
Run this command in your project root:
npx sb@latest init --type react_native
This scaffolds everything you need — a .storybook directory, configuration files, and a few example stories. If you get prompted about overwriting files, say yes unless you have custom config you want to keep.
After the install finishes, you'll see a .storybook folder containing main.js and preview.js. These control which stories get loaded and how they render. The default config usually points to ./src/stories or similar. You can change this later.
Creating your first component story
Let's write a simple story for a Button component. Create a file called Button.stories.tsx inside your stories folder:
import React from 'react';
import { Button } from 'react-native';
import { ComponentStory, ComponentMeta } from '@storybook/react-native';
export default {
title: 'Button',
component: Button,
} as ComponentMeta;
const Template: ComponentStory = (args) => ;
export const Primary = Template.bind({});
Primary.args = {
title: 'Press me',
color: '#007AFF',
};
Now run Storybook on your device or simulator:
npx storybook start
You should see your Button story rendered. If it works, you're ready for the next step. If not, double-check your main.js config — make sure it's pointing to the right directory.
Pro tip: Keep your stories co-located with your components. Instead of a separate stories folder, put Button.stories.tsx right next to Button.tsx. It makes maintenance easier.
Step 2: Integrate Chromatic for Visual Testing
Storybook gives you isolated component rendering. But that alone doesn't catch visual regressions. You need a tool that compares screenshots across builds. That's where Chromatic comes in.
Setting up a Chromatic project
Head over to chromatic.com and sign up. Create a new project — you'll need to connect it to your Git repository (GitHub, GitLab, or Bitbucket). Once done, Chromatic gives you a project token. Copy it. You'll need it in a moment. Connecting Chromatic to your Storybook Install the Chromatic package: npm install --save-dev chromatic Now add a script to your package.json: "chromatic": "npx chromatic --project-token=<YOUR_TOKEN>" Replace <YOUR_TOKEN> with the actual token from Chromatic. Do not commit this token to your repository. Use environment variables instead — we'll cover that in the CI section. That's it for setup. Seriously. Chromatic picks up your Storybook configuration automatically. It knows where your stories live and how to render them. Warning: If you're using Expo, you might need to adjust the build command. Chromatic expects a web-compatible Storybook build. For React Native, this usually means using @storybook/react-native with the getStorybookUI export. Check Chromatic's docs for the exact Expo setup — it's well-documented. Step 3: Run Your First Visual Test and Review Results Time to see this thing in action. Capturing baseline screenshots Run the Chromatic script: npm run chromatic Chromatic will start a local Storybook instance, render each of your stories, take screenshots, and upload them. The first run creates a baseline — a set of "correct" screenshots that future builds will be compared against. This first run might take a minute or two. Be patient. Once it finishes, you'll get a URL pointing to your Chromatic project dashboard. Reviewing changes in the Chromatic UI Now make a change to your Button component. Change the color from #007AFF to #FF3B30. Run npm run chromatic again. Open the dashboard. You'll see a side-by-side comparison: the baseline image on the left, the new build on the right. Any pixel differences are highlighted in pink. Chromatic shows you exactly what changed — the button color is now red instead of blue. From here, you have two options: Accept the change if it's intentional (you wanted to update the color). Reject it if it's a regression (someone accidentally changed the color). Rejected changes block your CI pipeline. That's the whole point — visual regression testing catches bugs before they reach production.
One thing I've learned: don't accept changes blindly. Review each diff carefully. Sometimes a 1px shift is actually a real bug hiding in plain sight.
Step 4: Automate Visual Testing in CI/CD
Running Chromatic manually is fine for a one-off test. But the real power comes when you automate it. Every pull request should trigger a visual check.
Adding Chromatic to GitHub Actions
Create a workflow file at .github/workflows/chromatic.yml:
name: Chromatic
on: push
jobs:
chromatic:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 18
- run: npm ci
- uses: chromaui/action@v1
with:
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
token: ${{ secrets.GITHUB_TOKEN }}
Add your Chromatic project token as a secret in your GitHub repository settings (Settings > Secrets and variables > Actions). Name it CHROMATIC_PROJECT_TOKEN.
Now every push runs Chromatic automatically. Pull requests show a check status — pass or fail. Your team can see visual diffs directly in the PR without leaving GitHub.
Best practices for team workflows
Here's what works in practice:
- Set pixel thresholds. Chromatic lets you ignore tiny differences (like anti-aliasing). Start with a 0.1% threshold and adjust if you get too many false positives.
- Review in pairs. Have one person approve UI changes, another review the code. Keeps both quality and consistency in check.
- Combine with Sherlo's visual testing tools for deeper component-level analysis. Sherlo.io integrates seamlessly with React Native and gives you faster feedback loops — especially useful when you're iterating quickly on UI components.
Look, Chromatic handles the screenshot comparison well. But for more granular control — like testing component states, interactions, or animations — Sherlo's approach gives you an extra layer of confidence. It's worth exploring if you're serious about automated visual testing.
Troubleshooting Common Issues
No tool is perfect. Here are the most common problems you'll hit and how to fix them.
Handling platform-specific differences
iOS and Android render things differently. A button that looks perfect on iOS might have extra padding on Android. Chromatic will flag this as a diff — but it's not a real regression.
Solution: use platform-specific stories. Create Button.ios.stories.tsx and Button.android.stories.tsx with platform-appropriate props. Chromatic treats them as separate stories, so you won't get false positives.
Dealing with flaky snapshots
Dynamic content is the enemy of visual testing. Dates, random IDs, user avatars — they change every time, causing false diffs.
Wrap your stories in a decorator that mocks dynamic data. For example:
const withMockedDate = (Story) => {
const MockDate = new Date('2025-01-01');
jest.useFakeTimers().setSystemTime(MockDate);
return ;
};
For animations, disable them entirely during testing. Add a global decorator in preview.js that sets useNativeDriver: false and reduces duration to 0.
Another gotcha: If your snapshots vary between runs on different machines, check for font rendering differences. Install the same fonts on your CI runner as on your local machine. This is a pain, but it matters.
Summary: Ship Confident UIs with Visual Testing
Let's recap what you've learned:
- Why visual testing matters — unit tests miss layout bugs, but visual regression testing catches them.
- Set up Storybook in your React Native project to render components in isolation.
- Integrate Chromatic to capture baseline screenshots and compare future builds.
- Run your first test — accept or reject visual changes from the dashboard.
- Automate in CI so every PR gets checked without manual effort.
- Troubleshoot common issues like platform differences and flaky snapshots.
The whole setup takes under an hour. And honestly? It pays for itself in the first week. You'll catch regressions that would have slipped through code review. Your QA team will thank you. Your users will never see that misaligned button.
For teams that want to go further, Sherlo.io offers integrated visual testing built specifically for React Native. It complements the Storybook + Chromatic workflow with deeper component analysis and faster feedback loops. Check it out if you're ready to level up your visual testing tools.
Now go ship that UI with confidence.