Skip to content

Commit 1cd0abf

Browse files
authored
docs(react testing): Update testing docs to demo nested route fields (#15069)
This documents some new nested-route fields that were added in getsentry/sentry#100481 <!-- CURSOR_SUMMARY --> --- > [!NOTE] > Extend RTL testing docs with outlet context configuration and nested routes examples, plus a clarified route param section. > > - **Docs (Using React Testing Library)**: > - **Route Param Values**: Add a dedicated heading and example clarifying use of `route` for `useParams()`. > - **Outlet Context**: Document passing `initialRouterConfig.outletContext` and consuming via `useOutletContext()`. > - **Nested Routes**: > - Show configuring an in-memory route tree via `initialRouterConfig.children`. > - Add wrapper `Outlet` with typed context and custom hook, plus examples for index and param child routes. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit c139854. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent cd3e2ec commit 1cd0abf

File tree

1 file changed

+102
-0
lines changed

1 file changed

+102
-0
lines changed

develop-docs/frontend/using-rtl.mdx

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ router.navigate('/new/path/');
7777
router.navigate(-1); // Simulates clicking the back button
7878
```
7979

80+
### Route Param Values
81+
8082
If you need to test route param values (as in `useParams()`), the `route` will need to be provided in the config:
8183

8284
```tsx
@@ -97,6 +99,106 @@ const {router} = render(<TestComponent />, {
9799
expect(screen.getByText('123')).toBeInTheDocument();
98100
```
99101

102+
### Outlet Context
103+
104+
If you need to test outlet param values (as in `useOutletContext()`), you can pass them inside the `initialRouterConfig` object.
105+
106+
```tsx
107+
function TestComponent() {
108+
const { id } = useOutletContext();
109+
return <div>{id}</div>;
110+
}
111+
112+
const { router } = render(<TestComponent />, {
113+
initialRouterConfig: {
114+
outletContext: { id: '123' },
115+
},
116+
});
117+
118+
expect(screen.getByText('123')).toBeInTheDocument();
119+
```
120+
121+
### Nested Routes
122+
123+
If directly setting outlet context isn't enough, instead you want to render some nested routes you can do that too!
124+
125+
Suppose routes.tsx defines some nested routes like:
126+
```tsx
127+
{
128+
path: 'settings/',
129+
component: SettingsWrapper,
130+
children: [
131+
{index: true, component: SettingsIndex},
132+
{path: ':projectId/', component: ProjectSettings},
133+
]
134+
}
135+
```
136+
137+
We can configure the in-memory router to know about just the route tree that you need. Remember to render the wrapper component itself, and the router + route child components will render themsevles.
138+
```tsx
139+
// settingsWrapper.tsx
140+
interface OutletContext {
141+
name: string;
142+
}
143+
144+
export function useCustomOutletContext() {
145+
return useOutletContext<OutletContext>();
146+
}
147+
148+
export default function SettingsWrapper() {
149+
const context: OutletContext = {name: "Default"};
150+
return <Outlet context={context} />;
151+
}
152+
153+
// settingsIndex.tsx
154+
function SettingsIndex() {
155+
const {name} = useCustomOutletContext();
156+
return <div>Settings > {name}</div>;
157+
}
158+
159+
// projectSettings.tsx
160+
function ProjectSettings() {
161+
const {name} = useCustomOutletContext();
162+
const {projectId} = useParams();
163+
return <div>Settings > {name} > Project: {projectId}</div>;
164+
}
165+
166+
// settingsIndex.spec.tsx
167+
render(<SettingsWrapper />, {
168+
initialRouterConfig: {
169+
location: {
170+
pathname: '/settings/',
171+
},
172+
route: '/settings/',
173+
children: [
174+
{
175+
index: true,
176+
element: <SettingsIndex />,
177+
},
178+
],
179+
},
180+
});
181+
expect(screen.getByText('Settings > Default')).toBeInTheDocument();
182+
183+
// projectSettings.spec.tsx
184+
render(<SettingsWrapper />, {
185+
initialRouterConfig: {
186+
location: {
187+
pathname: '/settings/123/',
188+
},
189+
route: '/settings/:projectId',
190+
children: [
191+
{
192+
path: ':projectId/',
193+
element: <ProjectSettings />,
194+
},
195+
],
196+
},
197+
});
198+
expect(screen.getByText('Settings > Default > Project: 123')).toBeInTheDocument();
199+
```
200+
201+
100202
## Querying
101203

102204
- use `getBy...` as much as possible

0 commit comments

Comments
 (0)