or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

act-utilities.mdasync-testing.mdcleanup-management.mderror-handling.mdhook-rendering.mdindex.mdserver-side-rendering.md

error-handling.mddocs/

0

# Error Handling

1

2

Error suppression and handling utilities for testing error scenarios and managing console output during tests. These utilities help create clean test environments and properly test error conditions in hooks.

3

4

## Capabilities

5

6

### suppressErrorOutput Function

7

8

Temporarily suppresses React error boundary console output, useful for testing error scenarios without cluttering test output. Returns a function to restore normal error output.

9

10

```typescript { .api }

11

/**

12

* Suppress React error boundary console output

13

* @returns Function to restore normal error output

14

*/

15

function suppressErrorOutput(): () => void;

16

```

17

18

**Usage Examples:**

19

20

```typescript

21

import { renderHook, suppressErrorOutput } from "@testing-library/react-hooks";

22

import { useState } from "react";

23

24

function useErrorHook(shouldError: boolean) {

25

const [count, setCount] = useState(0);

26

27

if (shouldError) {

28

throw new Error("Hook error occurred");

29

}

30

31

return { count, setCount };

32

}

33

34

test("testing hook errors with suppressed output", () => {

35

// Suppress error output to keep test logs clean

36

const restoreConsole = suppressErrorOutput();

37

38

try {

39

const { result } = renderHook(() => useErrorHook(true));

40

41

// This will throw, but without console noise

42

expect(result.error).toBeInstanceOf(Error);

43

expect(result.error.message).toBe("Hook error occurred");

44

} finally {

45

// Always restore console output

46

restoreConsole();

47

}

48

});

49

50

// Using suppressErrorOutput with async tests

51

test("async error handling", async () => {

52

const restoreConsole = suppressErrorOutput();

53

54

function useAsyncError() {

55

const [error, setError] = useState(null);

56

57

const triggerError = async () => {

58

await new Promise(resolve => setTimeout(resolve, 100));

59

throw new Error("Async error");

60

};

61

62

return { error, triggerError };

63

}

64

65

try {

66

const { result } = renderHook(() => useAsyncError());

67

68

await expect(result.current.triggerError()).rejects.toThrow("Async error");

69

} finally {

70

restoreConsole();

71

}

72

});

73

```

74

75

### Error Boundary Testing

76

77

Testing hooks that throw errors requires understanding how React's error boundaries work with the testing library:

78

79

```typescript

80

function useValidatedState(initialValue: string, validator: (value: string) => boolean) {

81

const [value, setValue] = useState(initialValue);

82

83

const updateValue = (newValue: string) => {

84

if (!validator(newValue)) {

85

throw new Error(`Invalid value: ${newValue}`);

86

}

87

setValue(newValue);

88

};

89

90

return { value, updateValue };

91

}

92

93

test("error boundary handling", () => {

94

const restoreConsole = suppressErrorOutput();

95

96

try {

97

const { result } = renderHook(() =>

98

useValidatedState("valid", (value) => value !== "invalid")

99

);

100

101

expect(result.current.value).toBe("valid");

102

103

// This should throw and be caught by error boundary

104

act(() => {

105

expect(() => {

106

result.current.updateValue("invalid");

107

}).toThrow("Invalid value: invalid");

108

});

109

110

// Check error state

111

expect(result.error).toBeInstanceOf(Error);

112

expect(result.error.message).toBe("Invalid value: invalid");

113

} finally {

114

restoreConsole();

115

}

116

});

117

```

118

119

### Global Error Filtering

120

121

The library provides a global configuration to disable error filtering entirely:

122

123

```javascript

124

// Import at the top of test file or in setup

125

import "@testing-library/react-hooks/disable-error-filtering";

126

127

// Or require in CommonJS

128

require("@testing-library/react-hooks/disable-error-filtering");

129

```

130

131

**Usage:**

132

133

```typescript

134

// After importing disable-error-filtering

135

import { renderHook } from "@testing-library/react-hooks";

136

137

// All console errors will be shown, even from error boundaries

138

test("with error filtering disabled", () => {

139

function useThrowingHook() {

140

throw new Error("This error will be shown in console");

141

}

142

143

const { result } = renderHook(() => useThrowingHook());

144

145

expect(result.error).toBeInstanceOf(Error);

146

// Error will appear in console output

147

});

148

```

149

150

### Error Recovery Testing

151

152

Testing hooks that can recover from errors:

153

154

```typescript

155

function useErrorRecovery() {

156

const [error, setError] = useState(null);

157

const [retryCount, setRetryCount] = useState(0);

158

const [data, setData] = useState(null);

159

160

const fetchData = async () => {

161

try {

162

setError(null);

163

164

if (retryCount < 2) {

165

setRetryCount(prev => prev + 1);

166

throw new Error("Temporary failure");

167

}

168

169

setData("Success data");

170

} catch (err) {

171

setError(err);

172

}

173

};

174

175

const retry = () => {

176

fetchData();

177

};

178

179

useEffect(() => {

180

fetchData();

181

}, []);

182

183

return { data, error, retryCount, retry };

184

}

185

186

test("error recovery mechanism", async () => {

187

const { result, waitFor } = renderHook(() => useErrorRecovery());

188

189

// Initially should have error

190

await waitFor(() => result.current.error !== null);

191

192

expect(result.current.error.message).toBe("Temporary failure");

193

expect(result.current.retryCount).toBe(1);

194

expect(result.current.data).toBe(null);

195

196

// Retry should fail again

197

act(() => {

198

result.current.retry();

199

});

200

201

await waitFor(() => result.current.retryCount === 2);

202

203

expect(result.current.error.message).toBe("Temporary failure");

204

expect(result.current.data).toBe(null);

205

206

// Third retry should succeed

207

act(() => {

208

result.current.retry();

209

});

210

211

await waitFor(() => result.current.data !== null);

212

213

expect(result.current.error).toBe(null);

214

expect(result.current.data).toBe("Success data");

215

});

216

```

217

218

### Error Context Testing

219

220

Testing hooks that provide error contexts:

221

222

```typescript

223

const ErrorContext = React.createContext({

224

error: null,

225

clearError: () => {},

226

reportError: (error) => {}

227

});

228

229

function useErrorContext() {

230

return React.useContext(ErrorContext);

231

}

232

233

function useWithErrorReporting(operation: () => void) {

234

const { reportError } = useErrorContext();

235

236

const executeOperation = () => {

237

try {

238

operation();

239

} catch (error) {

240

reportError(error);

241

}

242

};

243

244

return { executeOperation };

245

}

246

247

test("error context integration", () => {

248

const mockReportError = jest.fn();

249

const mockClearError = jest.fn();

250

251

const wrapper = ({ children }) => (

252

<ErrorContext.Provider value={{

253

error: null,

254

clearError: mockClearError,

255

reportError: mockReportError

256

}}>

257

{children}

258

</ErrorContext.Provider>

259

);

260

261

const { result } = renderHook(() =>

262

useWithErrorReporting(() => {

263

throw new Error("Operation failed");

264

}),

265

{ wrapper }

266

);

267

268

act(() => {

269

result.current.executeOperation();

270

});

271

272

expect(mockReportError).toHaveBeenCalledWith(

273

expect.objectContaining({ message: "Operation failed" })

274

);

275

});

276

```

277

278

### Best Practices for Error Testing

279

280

**Always Restore Console:**

281

```typescript

282

test("proper console restoration", () => {

283

const restoreConsole = suppressErrorOutput();

284

285

try {

286

// Test error scenarios

287

const { result } = renderHook(() => useErrorHook());

288

expect(result.error).toBeDefined();

289

} finally {

290

// Always restore, even if test fails

291

restoreConsole();

292

}

293

});

294

```

295

296

**Use Test Helpers:**

297

```typescript

298

// Helper function for error testing

299

function testHookError(hookFn, expectedError) {

300

const restoreConsole = suppressErrorOutput();

301

302

try {

303

const { result } = renderHook(hookFn);

304

expect(result.error).toBeInstanceOf(Error);

305

expect(result.error.message).toBe(expectedError);

306

} finally {

307

restoreConsole();

308

}

309

}

310

311

test("using error test helper", () => {

312

testHookError(

313

() => useValidatedState("", () => false),

314

"Invalid value: "

315

);

316

});

317

```

318

319

**Error Boundaries with Cleanup:**

320

```typescript

321

test("error boundaries with cleanup", () => {

322

const restoreConsole = suppressErrorOutput();

323

const mockCleanup = jest.fn();

324

325

addCleanup(mockCleanup);

326

327

try {

328

const { result } = renderHook(() => useErrorHook(true));

329

expect(result.error).toBeDefined();

330

} finally {

331

restoreConsole();

332

}

333

334

// Cleanup should still run despite error

335

expect(mockCleanup).toHaveBeenCalled();

336

});

337

```