new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Expo & React Native · all subjects

debugging

134 notes in this subject, read out of this brain and free to use. This is page 1 of 3.

Yellowbox warning display in Expo

A Yellowbox warning is displayed to inform you that there is a possible issue and you should probably resolve it before shipping your app. It is provided by LogBox in React Native.

Triggering redbox with uncaught errors in Expo

You can trigger the redbox by throwing an error and not catching it, for example: throw Error("Error message").

Stack trace display locations in Expo

When you encounter an error during development with Expo, the stack trace is shown both in your terminal and in the Expo Go app or in a development build you have created.

Redbox error display in Expo

A Redbox error is displayed when a fatal error prevents your app from running. It is provided by LogBox in React Native.

Creating warnings and errors in Expo with console

You can create warnings and errors in your Expo app using console.warn("Warning message") for warnings and console.error("Error message") for errors.

Stack trace value for debugging in Expo

A stack trace is a report of the recent calls your application made when it crashed. It is extremely valuable for debugging because it gives you the location of the error's occurrence, including the file name and line number where the error was raised.

Dev tools plugin distribution and structure

Plugins can be distributed on npm or included inside your app's monorepo. They typically export a single hook that can be used in your app's root component to initiate two-way communication with the web interface when your app is running in debug mode.

Dev tools plugin definition and key elements

A dev tools plugin runs in your web browser in your local development environment and connects to your Expo app. A plugin consists of three key elements: an Expo app to display the dev tools web user interface, an expo-module.config.json for Expo CLI recognition, and calls to expo/devtools API for the app to communicate back and forth with the dev tool's web interface.

Build dev tools plugin for distribution

Prepare a dev tools plugin for distribution or use within a monorepo by running npm run build:all (npm), yarn run build:all (yarn), pnpm run build:all (pnpm), or bun run build:all (bun). This builds the hook code into the build directory and the web user interface into the dist directory.

Use dev tools plugin in app

To use a dev tools plugin, import the plugin's hook into your app's root component and call it to connect your app to the plugin. For example: import { useMyDevToolsPlugin } from 'my-devtools-plugin'; then call useMyDevToolsPlugin() in the root component.

Create a dev tools plugin project

Use create-dev-plugin to set up a new plugin project. Run npx create-dev-plugin@latest (npm), yarn create dev-plugin (yarn), pnpm create dev-plugin (pnpm), or bun create dev-plugin (bun). The tool will prompt you for the plugin name, description, and hook name.

Dev tools plugin hook example

Example of a plugin hook implementation: import { useDevToolsPluginClient } from 'expo/devtools'; export function useMyDevToolsPlugin() { const client = useDevToolsPluginClient('my-devtools-plugin'); const sendPing = () => { client?.sendMessage('ping', { from: 'app' }); }; return { sendPing, }; }

Test dev tools plugin locally

Test a dev tools plugin by running it in local development mode using npm run web:dev (npm), yarn run web:dev (yarn), pnpm run web:dev (pnpm), or bun run web:dev (bun). The plugin web UI is an Expo app that runs in the browser only.

Dev tools plugin web UI example

Example of a web UI component using useDevToolsPluginClient: import { useDevToolsPluginClient, type EventSubscription } from 'expo/devtools'; import { useEffect } from 'react'; export default function App() { const client = useDevToolsPluginClient('my-devtools-plugin'); useEffect(() => { const subscriptions: EventSubscription[] = []; subscriptions.push( client?.addMessageListener('ping', data => { alert(`Received ping from ${data.from}`); }) ); return () => { for (const subscription of subscriptions) { subscription?.remove(); } }; }, [client]); }

Dev tools plugin app usage example

Example of using a dev tools plugin in an app: import { useMyDevToolsPlugin } from 'my-devtools-plugin'; import { Button } from 'react-native'; export default function App() { const { sendPing } = useMyDevToolsPlugin(); return ( <View style={styles.container}> <Button title="Ping" onPress={() => { sendPing(); }} /> </View> ); }

useDevToolsPluginClient hook API

The useDevToolsPluginClient hook, imported from expo/devtools, provides two key methods: addMessageListener(messageType, callback) listens for a message matching the typed string and invokes the callback with the message data; sendMessage(messageType, data) sends a message to the dev tools plugin web interface.

Dev tools plugin project structure

A plugin project contains src directory that exports the hook used inside the consuming app to connect it to the plugin, and webui directory that contains the web user interface for the plugin.

Dev tools plugin no-op functions for production

When updating a hook to return functions called by the app, update src/index.ts to export no-op functions when the app is not running in debug mode. Check if process.env.NODE_ENV is not 'production' before importing the actual hook, otherwise export stub functions that do nothing.

Check platform-specific crash reports for production crashes

When a production app crashes: For Android apps on Google Play Store, refer to the crashes section of Google Play Console. For iOS apps on TestFlight or the App Store, use the Crashes Organizer in Xcode and Apple's Diagnosing Issues Using Crash Reports and Device Logs guide.

Native logs reveal information beyond JavaScript errors

When an app crashes or behaves unexpectedly, JavaScript error output does not always tell the full story. Native logs from Android and iOS reveal crash reasons, native module errors, and system-level warnings that do not surface in the Metro bundler or React Native DevTools.

Reproduce production errors locally first

The best first step in addressing a production error is to reproduce it locally. Once reproduced, follow the development debugging process to isolate and address the root cause.

View native logs with adb logcat

Connect an Android device or emulator and run `adb logcat` to view streaming logs from the Android Debug Bridge. This reveals crash reasons, native module errors, and system-level warnings. WebADB can be used in Chrome as an alternative to installing the Android SDK.

Native debugging with Android Studio

To perform native debugging in Android Studio: (1) Generate native code by running `npx expo prebuild -p android`, which adds an android directory; (2) Open the project in Android Studio by running `open -a "/Applications/Android Studio.app" ./android`; (3) Build the app and connect the debugger using Google's documentation. Delete the android directory when done to keep the project managed by Expo CLI.

Native debugging with Xcode

To perform native debugging in Xcode on macOS with Xcode installed: (1) Generate native code by running `npx expo prebuild -p ios`, which adds an ios directory; (2) Open the project in Xcode by running `xed ios`; (3) Build with Cmd+R or the play button; (4) Use Low-level debugger (LLDB) and Xcode debugging tools to examine the native runtime. Delete or gitignore the ios directory when done to keep the project managed by Expo CLI.

Create minimal reproducible examples

When debugging large complex apps, extract the functionality you are trying to add in a blank `npx create-expo-app` project. This helps isolate the issue and identify exactly where the problem occurs.

View native logs with Xcode Console app

To access the Console app in Xcode for iOS devices or simulators: (1) Open Xcode and press Shift+Cmd+2 to open the Devices and Simulators window; (2) Select your physical device under Devices or a simulator under Simulators; (3) Click the Open Console button to view logs.

Use console.log and breakpoints for debugging

Use breakpoints or console.log statements to verify that a piece of code is being run or that a variable has an expected value. While not considered best practice, console.log is fast, easy, and often provides illuminating information.

Development vs production error categories

Errors split into two categories: errors encountered during development, and errors that users encounter in production.

Use crash reporting services like Sentry or BugSnag

Integrating a crash and bug reporting service in a production app provides real-time insights on production deployments, alert systems for fatal JavaScript errors, and web dashboards with details like stack traces and device information. Expo supports integration with services like Sentry and BugSnag.

Run production mode locally for debugging

Running an app in production mode locally shows errors that normally would not be thrown. Run `npx expo start --no-dev --minify` where `--no-dev` runs the server in production mode and `--minify` minifies the code the same way as production JavaScript bundles.

Simplify code to isolate errors

When isolating errors, simplify what you are doing. For example, if using a state management library like Redux, try removing it completely to determine if the issue lies in state management. This narrows down possible sources and provides better search terms for finding solutions.

App crashes on older devices may indicate performance issues

If an app crashes on certain older devices, it likely indicates a performance issue. Run the app through a profiler to identify which processes are killing the app. React Native DevTools and the included profiler make it easy to identify JavaScript performance sinks.

Debug development errors using stack traces

When debugging development errors with Expo CLI, start by examining the stack trace. For cryptic error messages, search Google and Stack Overflow, then isolate the problematic code by reverting to a working version and adding changes piece by piece.

jest-expo library setup and purpose

jest-expo is a Jest preset that mocks the native part of the Expo SDK and handles most of the configuration required for Expo projects. It is used alongside Jest for unit and snapshot testing in Expo apps.

Recommended test directory structures

Two common patterns for organizing test files: (1) Centralized: place all tests in a single __tests__ directory at the root; (2) Distributed: create __tests__ sub-directories within feature directories (e.g., src/components/__tests__/, src/utils/__tests__/). Choose the pattern that matches your project preferences.

Jest test script examples

Example Jest test scripts: "test": "jest --watch --coverage=false --changedSince=origin/main" (watch for changes and re-run tests); "testDebug": "jest -o --watch --coverage=false" (debug mode, re-run only changed files); "testFinal": "jest" (display code coverage in CLI); "updateSnapshots": "jest -u --coverage=false" (update snapshots after component changes).

Enable code coverage reports with jest-expo

In package.json under jest, set collectCoverage to true and specify collectCoverageFrom with a list of file patterns to include. Ignore coverage/, node_modules/, babel.config.js, expo-env.d.ts, and .expo/. Running npm run test generates a coverage directory with an lcov-report/index.html file viewable in a browser.

Snapshot test example

Example snapshot test: test('CustomText renders correctly', async () => { const tree = (await render(<CustomText>Some text</CustomText>)).toJSON(); expect(tree).toMatchSnapshot(); }); Running npm run test creates a snapshot in __tests__/__snapshots__ directory. For UI testing, E2E tests with Maestro are recommended over snapshot unit tests.

React Native Testing Library queries API

React Native Testing Library provides query variants for finding elements, such as getByText. Each query variant differs in its return type. Refer to the Queries API reference for detailed information on available queries and their behavior.

Unit test example with React Native Testing Library

Example unit test using React Native Testing Library: import { render } from '@testing-library/react-native'; import HomeScreen, { CustomText } from '@/app/index'; describe('<HomeScreen />', () => { test('Text renders correctly on HomeScreen', async () => { const { getByText } = await render(<HomeScreen />); getByText('Welcome!'); }); }); The getByText query finds elements and asserts their existence.

Jest test file naming convention

The jest-expo preset recognizes test files with -test.ts or -test.tsx extensions. Test files are typically placed in a __tests__ directory at the root or nested within feature directories.

react-test-renderer is deprecated

react-test-renderer is deprecated and does not support React 19 and above. Use @testing-library/react-native instead. Remove react-test-renderer from your project if currently used.

Install React Native Testing Library

Install @testing-library/react-native as a dev dependency using npx expo install @testing-library/react-native --dev (macOS/Linux) or npx expo install @testing-library/react-native "--" --dev (Windows). This provides utility functions for testing React Native components with Jest.

jest-expo transformIgnorePatterns for Bun

For Bun projects using jest-expo, set transformIgnorePatterns to: ["node_modules/(?!(.bun|(jest-)?react-native|@react-native(-community)?|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@sentry/react-native|native-base|react-native-svg))"] to transpile required node modules.

jest-expo transformIgnorePatterns for pnpm

For pnpm projects using jest-expo, set transformIgnorePatterns to: ["node_modules/(?!(.pnpm|(jest-)?react-native|@react-native(-community)?|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@sentry/react-native|native-base|react-native-svg))"] to transpile required node modules.

Code coverage .gitignore recommendation

Do not upload the coverage/index.html file to git. Add coverage/**/* to .gitignore to prevent coverage reports from being tracked in version control.

Configure Jest test script and preset

In package.json, add a test script (e.g., "test": "jest --watchAll") and set the jest preset to "jest-expo". The configuration object should be: {"jest": {"preset": "jest-expo"}}.

Enable Jest type definitions in TypeScript

For TypeScript projects, add "jest" to the types array in tsconfig.json compilerOptions to enable Jest's type definitions.

Install jest-expo and dependencies

Install jest-expo, jest, and @types/jest as dev dependencies using: npx expo install jest-expo jest @types/jest --dev (on macOS/Linux) or npx expo install jest-expo jest @types/jest "--" --dev (on Windows). If not using TypeScript, @types/jest can be skipped.

iOS Simulator dark mode toggle shortcut

In iOS Emulator locally, use Cmd ⌘ + Shift + A keyboard shortcut to toggle between light and dark modes.

Android Emulator dark mode toggle commands

Toggle dark mode in Android Emulator using: adb shell "cmd uimode night yes" to enable dark mode, or adb shell "cmd uimode night no" to disable dark mode.

Troubleshooting Hermes debugger: No compatible apps connected

If you encounter the warning 'No compatible apps connected. JavaScript Debugging can only be used with the Hermes engine', verify that: (1) Hermes is set up in the jsEngine field in app.json; (2) if your app is built by eas build, npx expo run:android, or npx expo run:ios, make sure it is a debug build; (3) the app is connected to the development server. To test debugging availability, run curl http://127.0.0.1:8081/json/list (adjust the URL to match your dev server) and the response should be an array, not empty. If empty, add either the --localhost or --tunnel flag to npx expo start.

Debugging JavaScript with Hermes in Expo

To debug JavaScript code running with Hermes, start your project with npx expo start and press the J key to open the debugger in Google Chrome or Microsoft Edge. The developer menu of development builds and Expo Go also have the Open DevTools option. Alternatively, you can use the JavaScript inspector by opening Google Chrome DevTools manually.

Remote debugging limitation with Hermes and JSI modules

Remote debugging does not work with modules built on top of JSI (JavaScript Interface), such as react-native-reanimated version 2 or higher. Hermes uses Chrome DevTools Protocol for debugging, which provides an alternative to remote debugging.

Hermes uses Chrome DevTools Protocol instead of remote debugging

Hermes supports Chrome DevTools Protocol to debug JavaScript in place by connecting to the engine running on the device. This approach differs from remote debugging, which executes JavaScript within a desktop Chrome tab. Hermes apps use this debugging technique automatically when you open the debugger in Expo Go or a development build.

Creating mocks for Expo modules

To provide default mocks in your Expo Module, create a file with the same name as the native module you want to mock and place it in your module's mocks directory. Export the mock implementation from this file. The jest-expo preset will automatically return the exported functions because of a requireNativeModule call when running during a unit test.

Default mocks included in Expo SDK

Expo SDK includes a set of default mocks for each of its community packages. You can also mock any JS code yourself using built-in Jest APIs such as mock functions.

Mocking definition in Expo testing

Mocking means to replace the actual implementation of a function with a fake version that does not perform any actions. This approach is useful for running unit tests on a local computer by bypassing the need for native code, which can only run on an actual Android or iOS device.

jest-expo preset for unit testing Expo projects

The recommended way to write unit tests for an Expo project is to use Jest and the jest-expo preset.

Example: expo-clipboard mock implementation

For the expo-clipboard library with native module ExpoClipboard, create a file ExpoClipboard.ts in the mocks directory. Example mock implementation: export async function hasStringAsync(): Promise<boolean> { return false; } Calling ExpoClipboard.hasStringAsync() in a unit test returns false.

Give your agent this brain