@@ -102,6 +102,7 @@ it('handles the request', async () => {
102102// Good: asserts on the observable outcome
103103it (' sets transaction name from route path' , () => {
104104 responseHandler (createMockContext (200 ));
105+
105106 expect (mockSetTransactionName ).toHaveBeenCalledWith (' GET /test' );
106107});
107108```
@@ -111,9 +112,9 @@ it('sets transaction name from route path', () => {
111112Default to exact matching. ` toMatchObject ` , ` expect.objectContaining ` , and ` expect.arrayContaining `
112113silently ignore fields that matter. This has caused real bugs to ship in this codebase.
113114
114- ** Use ` toEqual ` unless you have a specific reason not to .** The same applies to
115- ` toHaveBeenCalledWith ` — spell out every argument rather than wrapping in ` objectContaining ` .
116- This is the single most common place where loose assertions creep in:
115+ ** Use ` toEqual ` by default .** The same applies to ` toHaveBeenCalledWith ` — spell out every
116+ argument rather than wrapping in ` objectContaining ` . This is the single most common place where
117+ loose assertions creep in:
117118
118119``` typescript
119120// Bad: silently ignores any missing or extra properties in the call
@@ -129,8 +130,13 @@ expect(startSpan).toHaveBeenCalledWith({
129130});
130131```
131132
132- When you genuinely can't enumerate all fields (e.g., a large framework-generated object), fall
133- back to individual ` .toBe() ` checks on the fields that matter:
133+ The only valid reasons to use ` toMatchObject ` or ` objectContaining ` are: ** (1)** the object is
134+ generated by a framework or third-party library and contains fields you don't control (timestamps,
135+ random IDs, internal framework state), or ** (2)** the object has 10+ fields and the test only
136+ cares about 2–3 of them (in which case individual ` .toBe() ` checks on those fields are still
137+ preferred). If you wrote the object being asserted, you can spell it out — use ` toEqual ` .
138+
139+ When you do fall back, prefer individual ` .toBe() ` checks over ` objectContaining ` :
134140
135141``` typescript
136142expect (event .transaction ).toBe (' GET /users/:id' );
@@ -183,7 +189,7 @@ const url = 'https://api.example.com/users/42?include=profile&format=json';
183189
184190### Boundary Value Analysis
185191
186- If the valid range is 1–100, test 0, 1, 2, 99, 100, 101. Bugs cluster at boundaries — off-by-one
192+ If the valid range is 1–100, test -2, -1, 0, 1, 2, 99, 100, 101, Number.POSITIVE_INFINITY . Bugs cluster at boundaries — off-by-one
187193errors, inclusive/exclusive confusion, type coercion.
188194
189195### Test the unhappy path as hard as the happy path
@@ -203,7 +209,8 @@ Each edge case gets its own test with a descriptive name.
203209
204210- Name test files ` *.test.ts ` , mirroring the source path: ` src/shared/patchRoute.ts ` →
205211 ` test/shared/patchRoute.test.ts ` .
206- - Import from the source path (` ../../src/... ` ), not from the package's published API.
212+ - Import the module under test from its source path (` ../../src/... ` ). But when importing from a _ different_ package
213+ (e.g., ` @sentry/core ` in a ` @sentry/node ` test), use the package name — that's a real dependency, not the code under test.
207214- For browser-environment tests: ` /** @vitest-environment jsdom */ ` at top of file.
208215
209216### Mocking
@@ -279,7 +286,7 @@ beforeEach(() => {
279286
280287### Grouping
281288
282- Two levels of ` describe ` is usually enough. Deeper nesting makes tests harder to find and read.
289+ 1-2 levels of ` describe ` is usually enough. Deeper nesting makes tests harder to find and read.
283290
284291``` typescript
285292describe (' patchRoute' , () => {
0 commit comments