@@ -8,9 +8,9 @@ assumed to be promises.
8
8
9
9
## Rule Details
10
10
11
- Jest considered a test to have failed if it throws an error, rather than on if
12
- any particular function is called, meaning conditional calls to ` expect ` could
13
- result in tests silently being skipped .
11
+ Jest only considers a test to have failed if it throws an error, meaning if
12
+ calls to assertion functions like ` expect ` occur in conditional code such as a
13
+ ` catch ` statement, tests can end up passing but not actually test anything .
14
14
15
15
Additionally, conditionals tend to make tests more brittle and complex, as they
16
16
increase the amount of mental thinking needed to understand what is actually
@@ -79,3 +79,57 @@ it('throws an error', async () => {
79
79
await expect (foo).rejects .toThrow (Error );
80
80
});
81
81
```
82
+
83
+ ### How to catch a thrown error for testing without violating this rule
84
+
85
+ A common situation that comes up with this rule is when wanting to test
86
+ properties on a thrown error, as Jest's ` toThrow ` matcher only checks the
87
+ ` message ` property.
88
+
89
+ Most people write something like this:
90
+
91
+ ``` typescript
92
+ describe (' when the http request fails' , () => {
93
+ it (' includes the status code in the error' , async () => {
94
+ try {
95
+ await makeRequest (url );
96
+ } catch (error ) {
97
+ expect (error ).toHaveProperty (' statusCode' , 404 );
98
+ }
99
+ });
100
+ });
101
+ ```
102
+
103
+ As stated above, the problem with this is that if ` makeRequest() ` doesn't throw
104
+ the test will still pass as if the ` expect ` had been called.
105
+
106
+ While you can use ` expect.assertions ` & ` expect.hasAssertions ` for these
107
+ situations, they only work with ` expect ` .
108
+
109
+ A better way to handle this situation is to introduce a wrapper to handle the
110
+ catching, and otherwise returns a specific "no error thrown" error if nothing is
111
+ thrown by the wrapped function:
112
+
113
+ ``` typescript
114
+ class NoErrorThrownError extends Error {}
115
+
116
+ const getError = async <TError >(call : () => unknown ): Promise <TError > => {
117
+ try {
118
+ await call ();
119
+
120
+ throw new NoErrorThrownError ();
121
+ } catch (error : unknown ) {
122
+ return error as TError ;
123
+ }
124
+ };
125
+
126
+ describe (' when the http request fails' , () => {
127
+ it (' includes the status code in the error' , async () => {
128
+ const error = await getError (async () => makeRequest (url ));
129
+
130
+ // check that the returned error wasn't that no error was thrown
131
+ expect (error ).not .toBeInstanceOf (NoErrorThrownError );
132
+ expect (error ).toHaveProperty (' statusCode' , 404 );
133
+ });
134
+ });
135
+ ```
0 commit comments