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 2 of 3.

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.

Automatic mock generation with generate-ts-mocks

To automatically generate mocks for all native functions in a module's mocks directory based on Swift implementation, install SourceKitten framework, navigate to the module directory (where expo-module.config.json is located), and run the command: npx expo-modules-test-core generate-ts-mocks. This generates ExpoModuleName.ts in the mocks directory with mock implementations for each native method and view. Methods that exist only on Android (Kotlin-only APIs) will not be generated automatically and must be manually added or adjusted.

Installation for mock auto-generation

To use the generate-ts-mocks script, install SourceKitten framework first. Run: brew install sourcekitten && npx expo-modules-test-core generate-ts-mocks

Auto-generated mock file structure

An auto-generated mock file (example: example-module/mocks/ExpoModuleName.ts) contains: - A comment indicating it was auto-generated by expo-modules-test-core - Type definitions (e.g., export type URL = any) - Synchronous functions (e.g., export function hello(): any {}) - Asynchronous functions (e.g., export async function setValueAsync(value: string): Promise<any> {}) - Type definitions for component props (e.g., export type ViewProps = {...}) - Component/View functions (e.g., export function View(props: ViewProps) {})

Basic test setup for mocked modules

Create test files in a __tests__ directory next to your source files. Import your module and the mocked native module to write assertions. Example: import * as MyModule from '../MyModule'; import ExpoMyModule from '../ExpoMyModule'; describe('MyModule', () => { it('calls native module with correct parameters', async () => { await MyModule.doSomething('test-param'); expect(ExpoMyModule.doSomething).toHaveBeenCalledWith('test-param'); }); });

Testing function calls and return values in mocked modules

Use Jest's mock assertion methods to verify JavaScript functions delegate to native implementations correctly. Example patterns: describe('Module functionality', () => { it('delegates to native implementation', () => { MyModule.setData('test-data'); expect(ExpoMyModule.setDataAsync).toHaveBeenCalledWith('test-data', {}); }); it('handles async operations', async () => { await expect(MyModule.getDataAsync()).resolves.not.toThrow(); }); it('verifies call count', () => { MyModule.performAction(); MyModule.performAction(); expect(ExpoMyModule.performAction).toHaveBeenCalledTimes(2); }); });

Testing React hooks with native modules

When testing React hooks that use native modules, use React Testing Library's renderHook function. Example: import { renderHook } from '@testing-library/react-native'; import { useMyHook } from '../useMyHook'; import ExpoMyModule from '../ExpoMyModule'; jest.mock('../ExpoMyModule', () => ({ startOperation: jest.fn().mockResolvedValue(), stopOperation: jest.fn().mockResolvedValue(), })); describe('useMyHook', () => { it('calls native methods on mount and unmount', async () => { const hook = await renderHook(useMyHook); expect(ExpoMyModule.startOperation).toHaveBeenCalledTimes(1); await hook.unmount(); expect(ExpoMyModule.stopOperation).toHaveBeenCalledTimes(1); }); it('handles parameter changes', async () => { const hook = await renderHook(useMyHook, { initialProps: 'param1' }); await hook.rerender('param2'); expect(ExpoMyModule.startOperation).toHaveBeenCalledTimes(2); expect(ExpoMyModule.stopOperation).toHaveBeenCalledTimes(1); }); });

Best practices for mocking native calls in tests

Best practices include: (1) Clean up between tests using beforeEach or afterEach to reset mocks and avoid test pollution. (2) Test edge cases by verifying behavior when native functions throw errors or return unexpected values. (3) Use descriptive test names that explain the specific behavior being verified. (4) Group related tests using describe blocks to organize tests by functionality or component.

Real testing examples in Expo SDK modules

Comprehensive unit testing patterns using real testing techniques from Expo SDK modules are available at: expo-clipboard (packages/expo-clipboard/src/__tests__/Clipboard-test.native.ts), expo-screen-capture (packages/expo-screen-capture/src/__tests__/ScreenCaptureHook-test.native.js), and expo-app-integrity (packages/expo-app-integrity/src/__tests__/ExpoAppIntegrity-test.native.ts).

Debug native Android project in Android Studio

Open the native Android project in Android Studio for debugging via `open -a /Applications/Android Studio.app android`.

iOS Simulator error logging in Expo CLI

When compiling an app onto a Simulator, native error logs from the Simulator are piped to the Expo CLI terminal. This is useful for quickly spotting fatal errors like missing permissions. Error piping is not available for physical iOS devices.

Debug iOS app with Xcode and lldb

Debug iOS app using `lldb` and Apple debugging tools by opening the Xcode project with `xed ios` and rebuilding from Xcode. This allows setting native breakpoints and profiling. Track git changes in case you need to regenerate native code with `npx expo prebuild -p ios --clean`.

AppKey mismatch between JavaScript and native sides

The error can occur when there is a mismatch between the AppKey provided to AppRegistry.registerComponent on the JavaScript side and the AppKey registered on the native iOS or Android side. In projects using Continuous Native Generation (CNG), the default AppKey is 'main', handled automatically as long as the 'main' field in package.json is not changed from its default value.

Troubleshooting wrong development server connection

The 'Application has not been registered' error can occur if the app is connecting to the wrong project's local development server. Close out other Expo CLI or React Native community CLI processes using 'ps -A | grep "expo|react-native"' to verify only one development server is running.

Application has not been registered error meaning

The 'Application has not been registered' error (or 'Invariant Violation: "main" has not been registered') occurs when JavaScript code fails to load before the app can register itself. React Native has two steps: first it loads the JavaScript code and registers the application if successful, then it runs the registered application. If loading fails, the app never registers and this error appears. The error message is often a red herring distracting from the real underlying exception that prevented registration.

Common cause: multiple versions of native module dependencies

A frequent cause of the 'Application has not been registered' error is having multiple versions of a native module dependency that registers itself as a view. For example, multiple versions of react-native-safe-area-context in dependencies can trigger this error. To diagnose, look at logs before the error message to find the real exception that prevented app registration.

Customizing app entry point with registerRootComponent

To customize the app entry point in projects using Continuous Native Generation (CNG), refer to the registerRootComponent API reference. The AppKey can be customized by changing how registerRootComponent is called, but the 'main' field in package.json must match the AppKey registered on the native side.

Debugging production mode registration errors

If the 'Application has not been registered' error only occurs in the production app, run the app locally in production mode using 'npx expo start --no-dev --minify' to find the source of the error.

registerRootComponent implementation details

The registerRootComponent function, imported from 'expo', is implemented as: function registerRootComponent(component) { AppRegistry.registerComponent('main', () => component); }. It registers the app component with the AppKey 'main'. This must match the moduleName in the native AppDelegate.m file and the getMainComponentName() return value in MainActivity.java.

Native side AppKey configuration for iOS and Android

On the native iOS side in AppDelegate.m, the moduleName should match the registered AppKey: RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"main" initialProperties:nil];. On the Android side in MainActivity.java, the getMainComponentName() method should return the same name: @Override protected String getMainComponentName() { return "main"; }. By default, 'main' is used throughout both sides.

When to clear caches in Expo projects

Clearing caches can help work around issues related to stale or corrupt data and is often useful when troubleshooting and debugging Expo projects.

Cache clearing commands explained

Cache clearing commands: del node_modules clears all project dependencies; yarn cache clean clears the global Yarn cache; npm cache clean --force clears the global npm cache; yarn or npm install reinstalls all dependencies; watchman watch-del-all resets the watchman file watcher; del %localappdata%\Temp/<cache> clears the given packager/bundler cache file or directory; npx expo start --clear restarts the development server and clears the JavaScript transformation caches.

macOS proxy configuration for iOS Simulator with corporate Wi-Fi

To run Expo in the local iOS Simulator on a corporate Wi-Fi network, use a local proxy manager like Charles. Configure macOS by opening System Preferences > Network, selecting your proxy network location (not Automatic), selecting Wi-Fi/ethernet, clicking Advanced, then checking and setting Web Proxy (HTTP) to 127.0.0.1:8888 and Secure Web Proxy (HTTPS) to 127.0.0.1:8888.

git proxy configuration in ~/.gitconfig

To configure git to use a proxy, open ~/.gitconfig and set [http] proxy = http://localhost:8888 and [https] proxy = http://localhost:8888.

iOS Simulator requires proxy certificate configuration for Expo

The iOS Simulator requires special certificate handling for Expo because it is served a proxy certificate instead of the actual certificate, and does not allow it for https://exp.host/. To resolve this, install the Charles Root Certificate in the iOS Simulators through Charles Help menu > Install Charles Root Certificate in iOS Simulators.

Charles proxy external proxy settings for corporate network

In Charles, go to Proxy > External Proxy Settings and check Use external proxy servers. Check Web Proxy (HTTP) and enter your-corporate-proxy-uri:port-number. Check Proxy server requires a password and fill in Domain, Username, and Password. Repeat the same settings for Secure Web Proxy (HTTPS). In the Bypass external proxies for the following hosts text area, enter localhost and *.local, and check Always bypass external proxies for localhost.

npm proxy configuration in ~/.npmrc

To configure npm to use a proxy, open ~/.npmrc and set http_proxy=http://localhost:8888 and https_proxy=http://localhost:8888.

Command-line application proxy environment variables

To configure command-line applications like curl and brew to use a proxy, add these environment variables to ~/.bashrc, ~/.bash_profile, ~/.zshrc, or your shell's configuration file: export HTTP_PROXY="http://localhost:8888", export http_proxy="http://localhost:8888", export ALL_PROXY="http://localhost:8888", export all_proxy="http://localhost:8888", export HTTPS_PROXY="http://localhost:8888", export https_proxy="http://localhost:8888".

Reset iOS Simulator when custom proxy setup not working

If an existing iOS Simulator custom proxy setup is not working, quit the Simulator and select Simulator > Reset Content and Settings from the menu to clear the configuration.

Revert to Automatic Proxy settings in macOS

To revert from manual proxy configuration, set macOS Network Preferences to use Automatic Proxy Configuration with your-corporate-proxy-uri:port-number/proxy.pac.

Check and close development servers for version mismatch

To resolve a React Native version mismatch error, close any development servers running in your terminal. Use the `ps` command to list all terminal processes, and search for Expo CLI or React Native community CLI processes with `ps -A | grep "expo\|react-native"`.

React Native version mismatch error format

The error displays as 'React Native version mismatch.' followed by a JavaScript version and Native version number, with a message 'Make sure you have rebuilt the native code...'

Use npx expo-doctor to verify react-native version

For an Expo project, run `npx expo-doctor` to show a warning indicating which `react-native` version should be installed. If you upgraded to a newer SDK, run `npx expo install --fix` and follow the prompts so Expo CLI ensures dependency versions for packages like `expo` and `react-native` are aligned.

Verify React Native upgrade steps for existing projects

For an existing React Native project, if a React Native version mismatch error occurs right after upgrading, double-check that you have performed each of the upgrade steps correctly.

Clear bundler cache for React Native version mismatch

To resolve a React Native version mismatch error, clear your bundler caches by running: `rm -rf node_modules && npm cache clean --force && npm install && watchman watch-del-all && rm -rf $TMPDIR/haste-map-* && rm -rf $TMPDIR/metro-cache && npx expo start --clear`. This command is for macOS/Linux with npm. Windows commands and yarn alternatives are available in separate documentation.

Rebuild native projects after cache clear for React Native project

For an existing React Native project, after clearing bundler caches, run `npx pod-install`, then rebuild your native projects by running `yarn android` to rebuild for Android, and `yarn ios` to rebuild for iOS.

Sync Expo sdkVersion in app.json with package.json

For an Expo project, either remove the `sdkVersion` field from the **app.json** file, or make sure it matches the value of the `expo` dependency in your **package.json** file.

React Native version mismatch error meaning

A React Native version mismatch error occurs when the bundler running in the terminal (using `npx expo start`) is using a different JavaScript version of `react-native` than the native app on the device or emulator. This can happen after upgrading React Native or Expo SDK version, or when connecting to the wrong local development server.

Screen Inspector single device limitation

Screen Inspector currently supports only a single device due to hardcoded pipe paths. Running tests on multiple devices in parallel will cause conflicts because the pipes are shared across all simulator instances. To support parallel device testing, the pipe paths would need to be device-specific (e.g., /tmp/ios_screen_inspector_request_<deviceId>).

Screen Inspector video layer limitation

Video layers render blank when using Screen Inspector's captureView action, so video flows must continue using the full-screen screenshot pipeline instead of the in-process view capture.

Screen Inspector architecture components

Screen Inspector consists of three components: a Swift dylib (src/) that is injected into the simulator app and creates named pipes to respond to requests, a TypeScript client (ScreenInspectorIOS.ts) that communicates with the dylib via named pipes, and a build script (scripts/build.sh) that compiles the Swift code into a framework.

Screen Inspector build command

To build Screen Inspector locally, run: cd /path/to/inspector && ./scripts/build.sh. This creates the compiled framework at bin/IOSScreenInspectorFramework.framework/IOSScreenInspectorFramework.

Screen Inspector logging

Screen Inspector logs are written to system log and visible in Console.app. Look for the [ScreenInspector] prefix in logs to identify inspector-related messages.

Screen Inspector dylib purpose and capabilities

Screen Inspector is a dynamic library for iOS Simulator testing that enables fast UI element coordinate lookup and in-process view capture. It injects itself into an iOS Simulator app via xcrun simctl launch and provides two actions addressed by accessibility ID: getCoordinates for UI element coordinate lookup (faster than maestro hierarchy), and captureView which renders the element's window cropped to the element's frame and writes a PNG to the requested path.

Screen Inspector injection timing requirement

Screen Inspector injection only works at app launch time. If the app is already running, the tool cannot be used. The ScreenInspectorIOS.ts script can be run to launch the app with the Screen Inspector injected, and it will stay injected until the app is terminated.

Expo Client iOS testing with ExponentIntegrationTests

API tests from apps/test-suite can be run against the native XCTest target ExponentIntegrationTests. Ensure ExponentIntegrationTests/EXTestEnvironment.plist contains a URL to the test-suite project. In the monorepo, run powertools configure-ios-test-suite-url to set this automatically. Then open the workspace in Xcode and run Test (Cmd+U).

Cache clearing commands for Expo CLI and React Native CLI with npm and Yarn

To clear caches with Expo CLI or React Native CLI on macOS and Linux, run these commands: 1. rm -rf node_modules 2. watchman watch-del-all 3. rm -fr $TMPDIR/haste-map-* 4. rm -rf $TMPDIR/metro-cache For npm-based projects, also run: - npm cache clean --force - npm install - npx expo start --clear (for Expo CLI) - npm start -- --reset-cache (for React Native CLI) For Yarn-based projects, also run: - yarn cache clean - yarn - npx expo start --clear (for Expo CLI) - yarn start -- --reset-cache (for React Native CLI) With Yarn workspaces, you may need to delete node_modules in each workspace.

Clear bundler caches on Windows with Expo CLI or React Native CLI

To clear bundler caches on Windows, run the following commands in order: 1. rm -rf node_modules 2. Cache cleaning: - With Yarn: yarn cache clean - With npm: npm cache clean --force 3. Reinstall dependencies: - With Yarn: yarn - With npm: npm install 4. watchman watch-del-all 5. del %localappdata%\Temp\haste-map-* 6. del %localappdata%\Temp\metro-cache 7. Start the bundler with cache reset: - With Expo CLI: npx expo start --clear - With React Native CLI and Yarn: yarn start -- --reset-cache - With React Native CLI and npm: npm start -- --reset-cache With Yarn workspaces, you may need to delete node_modules in each workspace.

Console.log in DOM components forwards to terminal

By default, all console.log methods in DOM components are extended to forward logs to the terminal. This allows easy debugging of DOM components in development.

DOM component debugging in Safari

When bundling in development mode, you can debug DOM components by opening Safari > Develop > Simulator > MyComponent.tsx to see the WebView's console and inspect elements.

Android debug tool for background behavior

To debug background behavior on Android, use the adb command: adb shell am set-debug-app -w --persistent "com.brents.microfoam". The -w flag waits for the debugger, --persistent keeps the setting across reboots, and the quoted package name specifies the target app.

React Native Debugger deprecated status

React Native Debugger requires Remote JS debugging, which has been deprecated since React Native 0.73. It is incompatible with Hermes. For Expo SDK 50 and above, use React Native DevTools or Redux DevTools instead. For Expo SDK 49 and earlier, React Native Debugger can still be used.

Production app debugging with error reporting

For debugging production apps with bugs, implement a crash and bug reporting system to get real-time insights of production apps. See Using error reporting services documentation for details.

Developer menu keyboard shortcuts

Press M in the terminal where Expo CLI has started the development server to open the Developer menu on an emulator, simulator, or device connected via USB. For Android devices without USB: shake the device vertically. For Android emulator or device with USB: press Cmd ⌘ + M or Ctrl + M, or run 'adb shell input keyevent 82' in terminal. For iOS device without USB: shake the device or touch three fingers to the screen. For iOS simulator or device with USB: press Ctrl + Cmd ⌘ + Z or Cmd ⌘ + D.

Developer menu options

The Developer menu provides: Copy link (copy dev server address), Reload (reload app, usually unnecessary with Fast Refresh enabled), Go Home (navigate back to home screen), Toggle performance monitor (view performance information), Toggle element inspector (enable/disable element inspector overlay), Open DevTools (formerly Open JS debugger, opens React Native DevTools with Console, Sources, Network for Expo only, Memory, Components, and Profiler tabs for Hermes apps), and Fast Refresh (toggle automatic JS bundle refreshing).

Performance monitor information displayed

The performance monitor overlay shows: RAM usage of the project, JavaScript heap (for detecting memory leaks), two Views metrics (top indicates number of views for screen, bottom indicates number of views in component), and Frames Per Second for UI and JS threads (UI thread used for native Android or iOS UI rendering, JS thread where most logic runs including API calls and touch events).

Element inspector capabilities

The element inspector overlay has the following capabilities: Inspect (inspect elements), Perf (show performance overlay), Network (show network details), and Touchables (highlight touchable elements).

React Native DevTools replaces Chrome DevTools

Starting from React Native 0.76, React Native DevTools has replaced Chrome DevTools as the debugging tool for Expo and React Native apps.

React Native DevTools tabs and features

React Native DevTools provides access to Console (interactive terminal connected to app), Sources (set breakpoints), Network (Expo only, view fetch requests and external media), Memory (inspect heap snapshots), Components (inspect React components with props and styles), and Profiler (record and analyze JavaScript performance) tabs. Built-in support for React DevTools is included. Available for apps using Hermes via dev clients or Expo Go.

Open React Native DevTools keyboard shortcut

Press J in the terminal where Expo was started to open React Native DevTools.

Give your agent this brain