or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

data-manipulation.mderror-handling.mdfile-system.mdgarbage-collection.mdglobal-environment.mdindex.mdmodule-loading.mdstring-path.mdterminal.mdtype-checking.md
tile.json

error-handling.mddocs/

0

# Error Handling

1

2

Enhanced error handling with custom stack trace management for better test debugging. The ErrorWithStack class provides improved error reporting by excluding specific functions from stack traces and optimizing stack trace capture.

3

4

## Capabilities

5

6

### ErrorWithStack Class

7

8

Error class that captures stack traces while excluding a specific callsite function, providing cleaner and more useful stack traces for debugging.

9

10

```typescript { .api }

11

/**

12

* Error class with custom stack trace callsite exclusion

13

*/

14

class ErrorWithStack extends Error {

15

/**

16

* Creates an Error with enhanced stack trace handling

17

* @param message - Error message (can be undefined)

18

* @param callsite - Function to exclude from stack trace

19

* @param stackLimit - Optional stack trace limit for performance

20

*/

21

constructor(

22

message: string | undefined,

23

callsite: (...args: Array<any>) => unknown,

24

stackLimit?: number

25

);

26

}

27

```

28

29

**Usage Examples:**

30

31

```typescript

32

import { ErrorWithStack } from "jest-util";

33

34

// Basic usage - exclude current function from stack

35

function validateTestInput(input: any) {

36

if (input == null) {

37

throw new ErrorWithStack("Input cannot be null", validateTestInput);

38

}

39

}

40

41

// The stack trace will start from the caller of validateTestInput,

42

// not from within validateTestInput itself

43

44

// Jest assertion helper

45

function expectToBeTruthy(value: any, message?: string) {

46

if (!value) {

47

throw new ErrorWithStack(

48

message || `Expected ${value} to be truthy`,

49

expectToBeTruthy

50

);

51

}

52

}

53

54

// Usage in test

55

test("should validate user input", () => {

56

const userData = null;

57

expectToBeTruthy(userData, "User data is required");

58

// Stack trace points to this line, not inside expectToBeTruthy

59

});

60

61

// Custom test framework utilities

62

function createAssertion(name: string, predicate: (value: any) => boolean) {

63

return function assertion(value: any) {

64

if (!predicate(value)) {

65

throw new ErrorWithStack(

66

`Assertion failed: ${name}`,

67

assertion

68

);

69

}

70

};

71

}

72

73

const shouldBePositive = createAssertion("should be positive", x => x > 0);

74

shouldBePositive(-5); // Stack trace excludes the assertion function

75

76

// Performance optimization with stack limit

77

function createPerformantError(message: string, callsite: Function) {

78

return new ErrorWithStack(message, callsite, 10); // Limit stack to 10 frames

79

}

80

```

81

82

**Advanced Usage:**

83

84

```typescript

85

// Test helper with multiple levels

86

function deepTestHelper(value: any) {

87

return intermediateHelper(value);

88

}

89

90

function intermediateHelper(value: any) {

91

if (typeof value !== "string") {

92

// Exclude the original calling function, not intermediate ones

93

throw new ErrorWithStack("Expected string", deepTestHelper);

94

}

95

}

96

97

// Custom error factory

98

class ValidationError extends ErrorWithStack {

99

constructor(field: string, value: any, validator: Function) {

100

super(

101

`Validation failed for field '${field}' with value: ${value}`,

102

validator

103

);

104

this.name = "ValidationError";

105

}

106

}

107

108

function validateEmail(email: string) {

109

if (!email.includes("@")) {

110

throw new ValidationError("email", email, validateEmail);

111

}

112

}

113

114

// Error aggregation for test suites

115

function collectTestErrors(tests: Array<() => void>): ErrorWithStack[] {

116

const errors: ErrorWithStack[] = [];

117

118

tests.forEach((test, index) => {

119

try {

120

test();

121

} catch (error) {

122

if (error instanceof ErrorWithStack) {

123

errors.push(error);

124

} else {

125

errors.push(new ErrorWithStack(

126

`Test ${index} failed: ${error.message}`,

127

collectTestErrors

128

));

129

}

130

}

131

});

132

133

return errors;

134

}

135

```

136

137

**Stack Trace Behavior:**

138

139

```typescript

140

// Without ErrorWithStack

141

function regularError() {

142

throw new Error("Regular error");

143

}

144

145

function callRegularError() {

146

regularError(); // This will show in stack trace

147

}

148

149

// Stack trace shows:

150

// Error: Regular error

151

// at regularError (file.js:2:9)

152

// at callRegularError (file.js:6:3)

153

// at ...

154

155

// With ErrorWithStack

156

function betterError() {

157

throw new ErrorWithStack("Better error", betterError);

158

}

159

160

function callBetterError() {

161

betterError(); // ErrorWithStack excludes betterError from trace

162

}

163

164

// Stack trace shows:

165

// ErrorWithStack: Better error

166

// at callBetterError (file.js:16:3)

167

// at ...

168

// Notice betterError function is excluded

169

```

170

171

**Performance Features:**

172

173

- **Stack Limit Control**: Optional `stackLimit` parameter prevents excessive stack capture

174

- **Efficient Capture**: Uses `Error.captureStackTrace()` when available (V8 engines)

175

- **Temporary Limit Adjustment**: Temporarily increases `Error.stackTraceLimit` during capture for better traces

176

- **Memory Optimization**: Limits stack depth to prevent memory issues in deep call stacks

177

178

**Integration with Testing Frameworks:**

179

180

```typescript

181

// Jest custom matcher

182

expect.extend({

183

toBeValidUser(received) {

184

if (!received || !received.id || !received.name) {

185

throw new ErrorWithStack(

186

`Expected valid user object, received: ${JSON.stringify(received)}`,

187

this.toBeValidUser

188

);

189

}

190

return { pass: true, message: () => "User is valid" };

191

}

192

});

193

194

// Chai-style assertion

195

function expect(value: any) {

196

return {

197

toBe(expected: any) {

198

if (value !== expected) {

199

throw new ErrorWithStack(

200

`Expected ${value} to be ${expected}`,

201

this.toBe

202

);

203

}

204

}

205

};

206

}

207

```

208

209

## Error Message Best Practices

210

211

When using ErrorWithStack, follow these patterns for clear error messages:

212

213

- **Be Specific**: Include actual and expected values when possible

214

- **Provide Context**: Mention what operation was being performed

215

- **Use Consistent Format**: Follow a standard message pattern across your tests

216

- **Include Debugging Info**: Add relevant details that help identify the issue

217

218

```typescript

219

// Good error messages

220

throw new ErrorWithStack(

221

`Expected array to have length 3, but got length ${arr.length}`,

222

validateArrayLength

223

);

224

225

throw new ErrorWithStack(

226

`User validation failed: missing required field 'email'`,

227

validateUser

228

);

229

230

// Less helpful messages

231

throw new ErrorWithStack("Invalid input", someFunction);

232

throw new ErrorWithStack("Error occurred", someFunction);

233

```