-
-
Notifications
You must be signed in to change notification settings - Fork 17
feat(browser): add @rstest/browser-react package for React component testing #831
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
✅ Deploy Preview for rstest-dev ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
3fc0f38 to
ab2829b
Compare
ab2829b to
c8f09ee
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR introduces a new @rstest/browser-react package that provides lightweight React component testing utilities specifically designed for Rstest's browser mode. The implementation offers an alternative to @testing-library/react with minimal dependencies and first-class act() support.
Key changes:
- New
@rstest/browser-reactpackage withrender(),renderHook(),cleanup(),act(), andconfigure()utilities - Updated
@rstest/coreto re-export@rsbuild/coreto avoid duplicate dependencies and enable sourcemap support for inline snapshots - Enhanced
@rstest/browserto use the re-exported rsbuild and support extracting sourcemaps from pre-built files
Reviewed changes
Copilot reviewed 33 out of 34 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| pnpm-lock.yaml | Added workspace dependencies for the new browser-react package and moved some browser package dependencies from dev to runtime |
| packages/core/src/browser.ts | Re-exports @rsbuild/core to centralize the dependency and avoid duplication across packages |
| packages/core/rslib.config.ts | Enables sourcemap generation with specific minification settings to preserve function names for inline snapshot support |
| packages/browser/src/hostController.ts | Uses re-exported rsbuild from @rstest/core and configures extractSourceMap for inline snapshot support |
| packages/browser/src/client/sourceMapSupport.ts | Adds preloadRunnerSourceMap function to support inline snapshots in runner.js |
| packages/browser/src/client/entry.ts | Calls preloadRunnerSourceMap on startup to enable inline snapshot stack trace mapping |
| packages/browser/package.json | Moves runtime dependencies from devDependencies to dependencies for proper packaging |
| packages/browser-react/tsconfig.json | TypeScript configuration with JSX support for the new React package |
| packages/browser-react/src/pure.tsx | Core implementation providing render, renderHook, cleanup, and configure functions |
| packages/browser-react/src/index.ts | Default entry point with auto-cleanup via beforeEach hook |
| packages/browser-react/src/act.ts | React act() wrapper with IS_REACT_ACT_ENVIRONMENT management and React 17/18/19 compatibility |
| packages/browser-react/rslib.config.ts | Build configuration for the browser-react package with proper externals |
| packages/browser-react/package.json | Package manifest with peer dependencies for React and @rstest/core |
| packages/browser-react/README.md | User-facing documentation with API reference and usage examples |
| packages/browser-react/AGENTS.md | Developer guide with code patterns and project structure |
| e2e/package.json | Adds @rstest/browser-react and @testing-library/dom for e2e testing |
| e2e/browser-mode/testingLibrary.test.ts | Removed old testing-library test (replaced by browser-react tests) |
| e2e/browser-mode/react.test.ts | Removed old manual React test (replaced by browser-react tests) |
| e2e/browser-mode/fixtures/testing-library/* | Removed old testing-library fixture (consolidated into browser-react) |
| e2e/browser-mode/fixtures/react/* | Removed old manual React fixture (consolidated into browser-react) |
| e2e/browser-mode/fixtures/ports.ts | Updated port mappings, removed old ports for testing-library and react fixtures |
| e2e/browser-mode/fixtures/browser-react/tests/*.test.tsx | New comprehensive tests for render, renderHook, cleanup, and testing-library/dom integration |
| e2e/browser-mode/fixtures/browser-react/src/App.tsx | React components for testing with explicit JSX.Element return types |
| e2e/browser-mode/fixtures/browser-react/src/useCounter.ts | Custom hook for testing renderHook functionality |
| e2e/browser-mode/fixtures/browser-react/rstest.config.ts | Configuration for running browser-react e2e tests |
| e2e/browser-mode/browserReact.test.ts | E2E test that validates the browser-react package works end-to-end |
Files not reviewed (1)
- pnpm-lock.yaml: Language not supported
Comments suppressed due to low confidence (1)
packages/browser/src/hostController.ts:1241
- The value assigned to containerContext here is unused.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ], | ||
| "scripts": { | ||
| "build": "rslib build", | ||
| "dev": "cross-env SOURCEMAP=true rslib build --watch", |
Copilot
AI
Jan 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The dev script uses cross-env but it's not listed in devDependencies. While this might work if it's available from the workspace root, it's a best practice to explicitly declare all dependencies used in package scripts. Add cross-env to devDependencies or use an alternative approach that doesn't require cross-env (such as using package.json scripts that work cross-platform without the tool).
| "test": "rstest" | ||
| }, | ||
| "peerDependencies": { | ||
| "@rstest/core": "workspace:^", |
Copilot
AI
Jan 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The peerDependency uses "workspace:^" for @rstest/core, but when this package is published to npm, workspace: protocol won't be valid. This should be changed to a standard semver range like "^0.7.8" or "workspace:^" should be transformed during the publish process. Check that your build/publish pipeline properly resolves workspace: dependencies to actual version numbers, or use a standard version range.
| "@rstest/core": "workspace:^", | |
| "@rstest/core": "^0.7.8", |
| container, | ||
| baseElement, | ||
| unmount: async () => { | ||
| await act(() => root.unmount()); |
Copilot
AI
Jan 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The unmount function doesn't remove the container from the tracking arrays (mountedContainers and mountedRootEntries). This creates a memory leak where unmounted containers remain tracked. When a user calls unmount directly (instead of relying on cleanup), the container and root stay in memory, and subsequent cleanup calls will attempt to unmount already-unmounted roots. The unmount function should remove the container from both mountedContainers Set and mountedRootEntries array after unmounting.
| await act(() => root.unmount()); | |
| await act(() => root.unmount()); | |
| // Keep tracking collections in sync when unmount is called directly | |
| mountedContainers.delete(container); | |
| const index = mountedRootEntries.findIndex( | |
| (entry) => entry.container === container, | |
| ); | |
| if (index !== -1) { | |
| mountedRootEntries.splice(index, 1); | |
| } |
| React.useEffect(() => { | ||
| result.current = value; | ||
| }); |
Copilot
AI
Jan 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The renderHook implementation updates result.current inside a useEffect, which runs after the initial render. This means result.current will be undefined immediately after the first render, until the useEffect fires. This could cause issues if tests access result.current synchronously before effects run. The value should be assigned synchronously during render, not in useEffect. Change the implementation to assign result.current directly: result.current = value; instead of wrapping it in useEffect.
| React.useEffect(() => { | |
| result.current = value; | |
| }); | |
| result.current = value; |
Summary
@rstest/browser-react: Lightweight React testing utilities for browser moderender()- Render React components with act() supportrenderHook()- Test custom React hookscleanup()- Clean up mounted components between testsconfigure()- Configure React StrictMode wrapperact()- Async-aware act() wrapper with IS_REACT_ACT_ENVIRONMENT managementChecklist