or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

async-testing.mdasync.mdcomponent-rendering.mdconfiguration.mdelement-queries.mdevent-simulation.mdevents.mdhook-testing.mdhooks.mdindex.mdqueries.mdquick-reference.mdrendering.md

rendering.mddocs/

0

# Component Rendering

1

2

Renders React components in a test DOM environment with queries and lifecycle control.

3

4

## API

5

6

```typescript { .api }

7

function render(ui: React.ReactNode, options?: RenderOptions): RenderResult;

8

9

interface RenderOptions {

10

/**

11

* Custom container element. If not provided, a div appended to baseElement is used.

12

* For testing elements like <tbody>, provide a table element as container.

13

*/

14

container?: HTMLElement;

15

16

/**

17

* Base element for queries. Defaults to container if specified, otherwise document.body.

18

* Also used as the element printed by debug().

19

*/

20

baseElement?: HTMLElement;

21

22

/**

23

* Wrapper component to render around the UI.

24

* Useful for providers (Context, Router, Theme, etc.).

25

*/

26

wrapper?: React.JSXElementConstructor<{ children: React.ReactNode }>;

27

28

/**

29

* Use hydration instead of normal render (ReactDOM.hydrateRoot).

30

* Useful for server-side rendering scenarios.

31

*/

32

hydrate?: boolean;

33

34

/**

35

* Force synchronous ReactDOM.render instead of concurrent mode.

36

* Only supported in React 18. Not supported in React 19+.

37

* Throws an error if used with React 19 or later.

38

*/

39

legacyRoot?: boolean;

40

41

/**

42

* Custom query set to bind. Overrides default queries from @testing-library/dom.

43

*/

44

queries?: Queries;

45

46

/**

47

* Enable React.StrictMode wrapper around the component.

48

* Overrides global reactStrictMode config if specified.

49

*/

50

reactStrictMode?: boolean;

51

52

/**

53

* React 19+ only: Callback when React catches an error in an Error Boundary.

54

* Receives the error and errorInfo with componentStack.

55

* Only available in React 19 and later.

56

*/

57

onCaughtError?: (error: Error, errorInfo: { componentStack?: string }) => void;

58

59

/**

60

* Callback when React automatically recovers from errors.

61

* Receives error and errorInfo with componentStack.

62

* Some recoverable errors may include original error cause as error.cause.

63

* Available in React 18 and later.

64

*/

65

onRecoverableError?: (error: Error, errorInfo: { componentStack?: string }) => void;

66

}

67

68

interface RenderResult {

69

/**

70

* The DOM container element where the component was rendered

71

*/

72

container: HTMLElement;

73

74

/**

75

* The base element used for queries (container or document.body)

76

*/

77

baseElement: HTMLElement;

78

79

/**

80

* Re-renders the component with new UI

81

*/

82

rerender: (ui: React.ReactNode) => void;

83

84

/**

85

* Unmounts the component and cleans up

86

*/

87

unmount: () => void;

88

89

/**

90

* Pretty-prints the DOM for debugging

91

*/

92

debug: (

93

element?: HTMLElement | HTMLElement[],

94

maxLength?: number,

95

options?: any

96

) => void;

97

98

/**

99

* Returns a DocumentFragment of the container's innerHTML

100

*/

101

asFragment: () => DocumentFragment;

102

103

// All query functions from @testing-library/dom bound to baseElement

104

getByRole: (role: string, options?: ByRoleOptions) => HTMLElement;

105

getAllByRole: (role: string, options?: ByRoleOptions) => HTMLElement[];

106

queryByRole: (role: string, options?: ByRoleOptions) => HTMLElement | null;

107

queryAllByRole: (role: string, options?: ByRoleOptions) => HTMLElement[];

108

findByRole: (role: string, options?: ByRoleOptions) => Promise<HTMLElement>;

109

findAllByRole: (role: string, options?: ByRoleOptions) => Promise<HTMLElement[]>;

110

111

getByLabelText: (text: string | RegExp, options?: SelectorMatcherOptions) => HTMLElement;

112

getAllByLabelText: (text: string | RegExp, options?: SelectorMatcherOptions) => HTMLElement[];

113

queryByLabelText: (text: string | RegExp, options?: SelectorMatcherOptions) => HTMLElement | null;

114

queryAllByLabelText: (text: string | RegExp, options?: SelectorMatcherOptions) => HTMLElement[];

115

findByLabelText: (text: string | RegExp, options?: SelectorMatcherOptions) => Promise<HTMLElement>;

116

findAllByLabelText: (text: string | RegExp, options?: SelectorMatcherOptions) => Promise<HTMLElement[]>;

117

118

getByPlaceholderText: (text: string | RegExp, options?: MatcherOptions) => HTMLElement;

119

getAllByPlaceholderText: (text: string | RegExp, options?: MatcherOptions) => HTMLElement[];

120

queryByPlaceholderText: (text: string | RegExp, options?: MatcherOptions) => HTMLElement | null;

121

queryAllByPlaceholderText: (text: string | RegExp, options?: MatcherOptions) => HTMLElement[];

122

findByPlaceholderText: (text: string | RegExp, options?: MatcherOptions) => Promise<HTMLElement>;

123

findAllByPlaceholderText: (text: string | RegExp, options?: MatcherOptions) => Promise<HTMLElement[]>;

124

125

getByText: (text: string | RegExp, options?: SelectorMatcherOptions) => HTMLElement;

126

getAllByText: (text: string | RegExp, options?: SelectorMatcherOptions) => HTMLElement[];

127

queryByText: (text: string | RegExp, options?: SelectorMatcherOptions) => HTMLElement | null;

128

queryAllByText: (text: string | RegExp, options?: SelectorMatcherOptions) => HTMLElement[];

129

findByText: (text: string | RegExp, options?: SelectorMatcherOptions) => Promise<HTMLElement>;

130

findAllByText: (text: string | RegExp, options?: SelectorMatcherOptions) => Promise<HTMLElement[]>;

131

132

getByDisplayValue: (value: string | RegExp, options?: MatcherOptions) => HTMLElement;

133

getAllByDisplayValue: (value: string | RegExp, options?: MatcherOptions) => HTMLElement[];

134

queryByDisplayValue: (value: string | RegExp, options?: MatcherOptions) => HTMLElement | null;

135

queryAllByDisplayValue: (value: string | RegExp, options?: MatcherOptions) => HTMLElement[];

136

findByDisplayValue: (value: string | RegExp, options?: MatcherOptions) => Promise<HTMLElement>;

137

findAllByDisplayValue: (value: string | RegExp, options?: MatcherOptions) => Promise<HTMLElement[]>;

138

139

getByAltText: (text: string | RegExp, options?: MatcherOptions) => HTMLElement;

140

getAllByAltText: (text: string | RegExp, options?: MatcherOptions) => HTMLElement[];

141

queryByAltText: (text: string | RegExp, options?: MatcherOptions) => HTMLElement | null;

142

queryAllByAltText: (text: string | RegExp, options?: MatcherOptions) => HTMLElement[];

143

findByAltText: (text: string | RegExp, options?: MatcherOptions) => Promise<HTMLElement>;

144

findAllByAltText: (text: string | RegExp, options?: MatcherOptions) => Promise<HTMLElement[]>;

145

146

getByTitle: (title: string | RegExp, options?: MatcherOptions) => HTMLElement;

147

getAllByTitle: (title: string | RegExp, options?: MatcherOptions) => HTMLElement[];

148

queryByTitle: (title: string | RegExp, options?: MatcherOptions) => HTMLElement | null;

149

queryAllByTitle: (title: string | RegExp, options?: MatcherOptions) => HTMLElement[];

150

findByTitle: (title: string | RegExp, options?: MatcherOptions) => Promise<HTMLElement>;

151

findAllByTitle: (title: string | RegExp, options?: MatcherOptions) => Promise<HTMLElement[]>;

152

153

getByTestId: (testId: string | RegExp, options?: MatcherOptions) => HTMLElement;

154

getAllByTestId: (testId: string | RegExp, options?: MatcherOptions) => HTMLElement[];

155

queryByTestId: (testId: string | RegExp, options?: MatcherOptions) => HTMLElement | null;

156

queryAllByTestId: (testId: string | RegExp, options?: MatcherOptions) => HTMLElement[];

157

findByTestId: (testId: string | RegExp, options?: MatcherOptions) => Promise<HTMLElement>;

158

findAllByTestId: (testId: string | RegExp, options?: MatcherOptions) => Promise<HTMLElement[]>;

159

}

160

```

161

162

## Common Patterns

163

164

### Basic Rendering

165

```typescript

166

const { container, getByRole, rerender } = render(<Counter initial={0} />);

167

168

expect(getByRole('button')).toBeInTheDocument();

169

170

// Re-render with new props

171

rerender(<Counter initial={5} />);

172

```

173

174

### With Providers

175

```typescript

176

const wrapper = ({ children }) => (

177

<ThemeProvider theme="dark">

178

<AuthProvider user={mockUser}>

179

{children}

180

</AuthProvider>

181

</ThemeProvider>

182

);

183

184

render(<App />, { wrapper });

185

```

186

187

### Custom Container

188

```typescript

189

// For testing <tr>, <td>, etc.

190

const table = document.createElement('table');

191

const tbody = document.createElement('tbody');

192

table.appendChild(tbody);

193

194

render(<TableRow />, { container: tbody });

195

```

196

197

### Hydration (SSR)

198

```typescript

199

const container = document.getElementById('root');

200

container.innerHTML = serverRenderedHTML;

201

202

render(<App />, { container, hydrate: true });

203

```

204

205

### StrictMode

206

```typescript

207

render(<App />, { reactStrictMode: true });

208

```

209

210

## Testing Patterns

211

212

### Testing Re-renders

213

```typescript

214

test('updates on prop change', () => {

215

const { rerender, getByText } = render(<Display value={1} />);

216

expect(getByText('1')).toBeInTheDocument();

217

218

rerender(<Display value={2} />);

219

expect(getByText('2')).toBeInTheDocument();

220

});

221

```

222

223

### Testing Unmount/Cleanup

224

```typescript

225

test('cleans up on unmount', () => {

226

const cleanup = jest.fn();

227

228

function Component() {

229

useEffect(() => cleanup, []);

230

return <div>Content</div>;

231

}

232

233

const { unmount } = render(<Component />);

234

unmount();

235

236

expect(cleanup).toHaveBeenCalled();

237

});

238

```

239

240

### Snapshot Testing

241

```typescript

242

test('matches snapshot', () => {

243

const { asFragment } = render(<App />);

244

expect(asFragment()).toMatchSnapshot();

245

});

246

```

247

248

### Debug Utilities

249

```typescript

250

const { debug, getByRole } = render(<App />);

251

252

debug(); // Print entire DOM

253

debug(getByRole('button')); // Print specific element

254

debug(getByRole('button'), 1000); // Limit output length

255

```

256

257

## Query Access

258

259

All queries available three ways:

260

261

```typescript

262

// 1. From render result

263

const { getByRole } = render(<Component />);

264

const button = getByRole('button');

265

266

// 2. From screen (recommended)

267

import { screen } from '@testing-library/react';

268

render(<Component />);

269

const button = screen.getByRole('button');

270

271

// 3. From within (scoped)

272

const modal = screen.getByRole('dialog');

273

const button = within(modal).getByRole('button');

274

```

275

276

## Render Modes

277

278

### Concurrent (Default React 18+)

279

```typescript

280

render(<App />); // Uses ReactDOMClient.createRoot()

281

```

282

283

### Legacy (React 18 only)

284

```typescript

285

render(<App />, { legacyRoot: true }); // Error in React 19+

286

```

287

288

### Hydration

289

```typescript

290

render(<App />, { hydrate: true }); // Uses hydrateRoot()

291

```

292

293

## Production Setup

294

295

### Custom Render Utility

296

```typescript

297

// test-utils.tsx

298

import { render, RenderOptions } from '@testing-library/react';

299

import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

300

import { BrowserRouter } from 'react-router-dom';

301

302

const queryClient = new QueryClient({

303

defaultOptions: { queries: { retry: false } }

304

});

305

306

export function renderWithProviders(

307

ui: React.ReactElement,

308

options?: Omit<RenderOptions, 'wrapper'>

309

) {

310

return render(ui, {

311

wrapper: ({ children }) => (

312

<BrowserRouter>

313

<QueryClientProvider client={queryClient}>

314

{children}

315

</QueryClientProvider>

316

</BrowserRouter>

317

),

318

...options,

319

});

320

}

321

322

// Use in tests

323

import { renderWithProviders } from './test-utils';

324

325

test('renders with providers', () => {

326

renderWithProviders(<MyComponent />);

327

});

328

```

329

330

## Additional Types

331

332

```typescript { .api }

333

type RendererableContainer = Element | DocumentFragment;

334

335

interface MatcherOptions {

336

exact?: boolean;

337

normalizer?: (text: string) => string;

338

}

339

340

interface SelectorMatcherOptions extends MatcherOptions {

341

selector?: string;

342

}

343

344

interface ByRoleOptions extends MatcherOptions {

345

name?: string | RegExp;

346

description?: string | RegExp;

347

hidden?: boolean;

348

selected?: boolean;

349

checked?: boolean;

350

pressed?: boolean;

351

current?: boolean | string;

352

expanded?: boolean;

353

level?: number;

354

queryFallbacks?: boolean;

355

}

356

357

interface Queries {

358

[key: string]: (...args: any[]) => any;

359

}

360

```

361

362

## Deprecated Types

363

364

The following type aliases are deprecated and provided for backward compatibility:

365

366

```typescript { .api }

367

/** @deprecated Use RenderOptions instead */

368

type BaseRenderOptions<Q, Container, BaseElement> = RenderOptions;

369

370

/** @deprecated Use RenderOptions with hydrate: false instead */

371

interface ClientRenderOptions<Q, Container, BaseElement> extends RenderOptions {

372

hydrate?: false | undefined;

373

}

374

375

/** @deprecated Use RenderOptions with hydrate: true instead */

376

interface HydrateOptions<Q, Container, BaseElement> extends RenderOptions {

377

hydrate: true;

378

}

379

```

380

381

## Key Notes

382

383

- Auto-cleanup runs after each test (unless using /pure import)

384

- All operations automatically wrapped in act()

385

- Use screen queries for better error messages

386

- Prefer getByRole for accessibility testing

387

- legacyRoot option only works in React 18, throws error in React 19+

388

- onCaughtError callback only available in React 19+

389