Skip to content

Conversation

@fi3ework
Copy link
Member

@fi3ework fi3ework commented Jan 5, 2026

Summary

  • New package @rstest/browser-react: Lightweight React testing utilities for browser mode
    • render() - Render React components with act() support
    • renderHook() - Test custom React hooks
    • cleanup() - Clean up mounted components between tests
    • configure() - Configure React StrictMode wrapper
    • act() - Async-aware act() wrapper with IS_REACT_ACT_ENVIRONMENT management

Checklist

  • Tests updated (or not required).
  • Documentation updated (or not required).

@netlify
Copy link

netlify bot commented Jan 5, 2026

Deploy Preview for rstest-dev ready!

Name Link
🔨 Latest commit c8f09ee
🔍 Latest deploy log https://app.netlify.com/projects/rstest-dev/deploys/695e03b0d3d1e200089cfcd9
😎 Deploy Preview https://deploy-preview-831--rstest-dev.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@fi3ework fi3ework changed the title # feat(browser): add @rstest/browser-react package for React component testing feat(browser): add @rstest/browser-react package for React component testing Jan 5, 2026
@fi3ework fi3ework force-pushed the browser-react branch 6 times, most recently from 3fc0f38 to ab2829b Compare January 7, 2026 05:30
@fi3ework fi3ework marked this pull request as ready for review January 7, 2026 07:13
Copilot AI review requested due to automatic review settings January 7, 2026 07:13
@fi3ework fi3ework merged commit d73f96c into main Jan 7, 2026
15 checks passed
@fi3ework fi3ework deleted the browser-react branch January 7, 2026 07:13
Copy link
Contributor

Copilot AI left a 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-react package with render(), renderHook(), cleanup(), act(), and configure() utilities
  • Updated @rstest/core to re-export @rsbuild/core to avoid duplicate dependencies and enable sourcemap support for inline snapshots
  • Enhanced @rstest/browser to 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",
Copy link

Copilot AI Jan 7, 2026

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).

Copilot uses AI. Check for mistakes.
"test": "rstest"
},
"peerDependencies": {
"@rstest/core": "workspace:^",
Copy link

Copilot AI Jan 7, 2026

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.

Suggested change
"@rstest/core": "workspace:^",
"@rstest/core": "^0.7.8",

Copilot uses AI. Check for mistakes.
container,
baseElement,
unmount: async () => {
await act(() => root.unmount());
Copy link

Copilot AI Jan 7, 2026

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.

Suggested change
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);
}

Copilot uses AI. Check for mistakes.
Comment on lines +161 to +163
React.useEffect(() => {
result.current = value;
});
Copy link

Copilot AI Jan 7, 2026

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.

Suggested change
React.useEffect(() => {
result.current = value;
});
result.current = value;

Copilot uses AI. Check for mistakes.
@9aoy 9aoy mentioned this pull request Jan 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants