From 189a4181a654eb7abae3d24c7fbd398e77558839 Mon Sep 17 00:00:00 2001 From: unknown Date: Wed, 25 Feb 2026 12:43:21 -0500 Subject: [PATCH 1/2] Replace boilerplate README with library documentation Co-Authored-By: Claude Sonnet 4.6 --- README.md | 127 +++++++++++++++++++++++++++++------------------------- 1 file changed, 69 insertions(+), 58 deletions(-) diff --git a/README.md b/README.md index 3e2c3f8..7e5fe66 100644 --- a/README.md +++ b/README.md @@ -1,97 +1,108 @@ -This is a new [**React Native**](https://reactnative.dev) project, bootstrapped using [`@react-native-community/cli`](https://github.com/react-native-community/cli). +# rn-storybook-auto-screenshots -# Getting Started +Automatically generate screenshot tests for every Storybook story in your React Native app. -> **Note**: Make sure you have completed the [Set Up Your Environment](https://reactnative.dev/docs/set-up-your-environment) guide before proceeding. +## How it works -## Step 1: Start Metro +1. On first test run, the library launches your app and lets React Native register all Storybook stories with a native module (`StorybookRegistry`) +2. The native module writes a `storybook_stories.json` manifest to device storage +3. The test runner reads the manifest and launches a `StoryRendererActivity` for each story, capturing a screenshot with [screenshot-tests-for-android](https://github.com/screenshotbot/screenshot-tests-for-android) -First, you will need to run **Metro**, the JavaScript build tool for React Native. +No manual list of stories needed — add a story to Storybook and it gets tested automatically. -To start the Metro dev server, run the following command from the root of your React Native project: +## Installation ```sh -# Using npm -npm start - -# OR using Yarn -yarn start +npm install rn-storybook-auto-screenshots ``` -## Step 2: Build and run your app +## Setup -With Metro running, open a new terminal window/pane from the root of your React Native project, and use one of the following commands to build and run your Android or iOS app: +### 1. JS side — configure and register -### Android +In your app's entry point (e.g. `index.js`): -```sh -# Using npm -npm run android +```js +import { AppRegistry } from 'react-native'; +import { configure, StoryRenderer } from 'rn-storybook-auto-screenshots'; +import { view } from './.rnstorybook/storybook.requires'; -# OR using Yarn -yarn android -``` +configure(view); -### iOS +AppRegistry.registerComponent('StoryRenderer', () => StoryRenderer); +AppRegistry.registerComponent('YourApp', () => YourApp); +``` -For iOS, remember to install CocoaPods dependencies (this only needs to be run on first clone or after updating native deps). +### 2. Android — create the activity -The first time you create a new project, run the Ruby bundler to install CocoaPods itself: +In your app's `android/app/src/main/java/…` directory: -```sh -bundle install +```kotlin +class StoryRendererActivity : BaseStoryRendererActivity() ``` -Then, and every time you update your native dependencies, run: +Register it in `AndroidManifest.xml`: -```sh -bundle exec pod install +```xml + ``` -For more information, please visit [CocoaPods Getting Started guide](https://guides.cocoapods.org/using/getting-started.html). - -```sh -# Using npm -npm run ios +Add the native module to your React Native package list: -# OR using Yarn -yarn ios +```kotlin +// In your MainApplication +override fun getPackages() = listOf( + RNStorybookAutoScreenshotsPackage(), + // ... your other packages +) ``` -If everything is set up correctly, you should see your new app running in the Android Emulator, iOS Simulator, or your connected device. - -This is one way to run your app — you can also build it directly from Android Studio or Xcode. +### 3. Android — create the test -## Step 3: Modify your app +In `android/app/src/androidTest/java/…`: -Now that you have successfully run the app, let's make changes! +```kotlin +@RunWith(AndroidJUnit4::class) +class StoryScreenshotTest : BaseStoryScreenshotTest() { + override fun getStoryRendererActivityClass() = StoryRendererActivity::class.java +} +``` -Open `App.tsx` in your text editor of choice and make some changes. When you save, your app will automatically update and reflect these changes — this is powered by [Fast Refresh](https://reactnative.dev/docs/fast-refresh). +### 4. Run the tests -When you want to forcefully reload, for example to reset the state of your app, you can perform a full reload: +```sh +./gradlew screenshotTests +``` -- **Android**: Press the R key twice or select **"Reload"** from the **Dev Menu**, accessed via Ctrl + M (Windows/Linux) or Cmd ⌘ + M (macOS). -- **iOS**: Press R in iOS Simulator. +## Customization -## Congratulations! :tada: +Override methods in `BaseStoryScreenshotTest` to customize behavior: -You've successfully run and modified your React Native App. :partying_face: +```kotlin +class StoryScreenshotTest : BaseStoryScreenshotTest() { + override fun getStoryRendererActivityClass() = StoryRendererActivity::class.java -### Now what? + // Skip stories you don't want to screenshot + override fun shouldScreenshotStory(storyInfo: StoryInfo): Boolean { + return storyInfo.title != "Internal" + } -- If you want to add this new React Native code to an existing application, check out the [Integration guide](https://reactnative.dev/docs/integration-with-existing-apps). -- If you're curious to learn more about React Native, check out the [docs](https://reactnative.dev/docs/getting-started). + // Adjust timeout if stories are slow to load (default: 5000ms) + override fun getLoadTimeoutMs() = 8000L +} +``` -# Troubleshooting +## JS API -If you're having issues getting the above steps to work, see the [Troubleshooting](https://reactnative.dev/docs/troubleshooting) page. +```ts +import { configure, StoryRenderer, getAllStories, getAllStoryIds, storyNameToId } from 'rn-storybook-auto-screenshots'; -# Learn More +configure(view); // Must be called once with your Storybook view instance +getAllStories(); // Returns [{ id, title, name }] +getAllStoryIds(); // Returns string[] +storyNameToId('Foo/Bar'); // Converts "ComponentName/StoryName" to a Storybook ID +``` -To learn more about React Native, take a look at the following resources: +## License -- [React Native Website](https://reactnative.dev) - learn more about React Native. -- [Getting Started](https://reactnative.dev/docs/environment-setup) - an **overview** of React Native and how setup your environment. -- [Learn the Basics](https://reactnative.dev/docs/getting-started) - a **guided tour** of the React Native **basics**. -- [Blog](https://reactnative.dev/blog) - read the latest official React Native **Blog** posts. -- [`@facebook/react-native`](https://github.com/facebook/react-native) - the Open Source; GitHub **repository** for React Native. +Apache-2.0 From 86279c4e664c7b70cd65f32b9e4de14786a3ba8a Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 16 Mar 2026 14:26:43 -0400 Subject: [PATCH 2/2] Pin @storybook/react-native peer dep and document internal API usage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Narrow peerDependency from "*" to ">=10.0.0 <11.0.0" — the View class internals we depend on (_storyIndex, _idToPrepared, _preview) are not part of a public API contract, so accepting any version silently risks breakage. Add a comment explaining why we use these internals and that there is currently no public alternative. Co-Authored-By: Claude Sonnet 4.6 --- packages/rn-storybook-auto-screenshots/package.json | 2 +- .../rn-storybook-auto-screenshots/src/StoryRenderer.tsx | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/rn-storybook-auto-screenshots/package.json b/packages/rn-storybook-auto-screenshots/package.json index b023105..3ac537f 100644 --- a/packages/rn-storybook-auto-screenshots/package.json +++ b/packages/rn-storybook-auto-screenshots/package.json @@ -29,7 +29,7 @@ "author": "Screenshotbot", "license": "Apache-2.0", "peerDependencies": { - "@storybook/react-native": "*", + "@storybook/react-native": ">=10.0.0 <11.0.0", "react": "*", "react-native": "*" }, diff --git a/packages/rn-storybook-auto-screenshots/src/StoryRenderer.tsx b/packages/rn-storybook-auto-screenshots/src/StoryRenderer.tsx index d322044..a89ca54 100644 --- a/packages/rn-storybook-auto-screenshots/src/StoryRenderer.tsx +++ b/packages/rn-storybook-auto-screenshots/src/StoryRenderer.tsx @@ -140,6 +140,13 @@ export function StoryRenderer({ storyName = 'MyFeature/Initial' }: StoryRenderer ); } +// NOTE: _storyIndex, _idToPrepared, _preview, and createPreparedStoryMapping are +// internal APIs on the View class (underscore-prefixed). @storybook/react-native does +// not expose a public API for programmatic story rendering — getStorybookUI() is the +// only public rendering path. We rely on these internals because there is no alternative. +// Verified against @storybook/react-native ^10.0.0. If Storybook exposes a public API +// in a future version, we should migrate to it. + /** * Get all available story IDs from Storybook's registry. */