Rules Hub
Coding Rules Library
Wrap global mutations in try-finally during tests
When a test modifies the global environment (like prototypes or global variables), use a try-finally block to guarantee the environment is restored even if assertions fail.
Bad example
| 1 | it('works without String.prototype.isWellFormed', () => { |
| 2 | const original = String.prototype.isWellFormed; |
| 3 | |
| 4 | // Mutate global environment |
| 5 | Reflect.deleteProperty(String.prototype, 'isWellFormed'); |
| 6 | |
| 7 | // If this assertion fails, the cleanup below never executes |
| 8 | expect(myPolyfillUtil('input')).toBe('safe'); |
| 9 |
|
| 10 | // Manual cleanup at the end is unsafe |
| 11 | String.prototype.isWellFormed = original; |
| 12 | }); |
Explanation (EN)
The cleanup logic is placed after the assertions. If an assertion fails, the test function exits immediately, leaving the global `String.prototype` modified. This pollutes the environment and causes subsequent tests to fail unpredictably.
Objašnjenje (HR)
Logika za čišćenje (cleanup) nalazi se nakon asercija. Ako asercija ne prođe, test funkcija se odmah prekida, a globalni `String.prototype` ostaje modificiran. To zagađuje okolinu i uzrokuje nepredvidive padove u idućim testovima.
Good example
| 1 | it('works without String.prototype.isWellFormed', () => { |
| 2 | const descriptor = Object.getOwnPropertyDescriptor(String.prototype, 'isWellFormed'); |
| 3 |
|
| 4 | try { |
| 5 | // Mutate global environment safely |
| 6 | Reflect.deleteProperty(String.prototype, 'isWellFormed'); |
| 7 | |
| 8 | expect(myPolyfillUtil('input')).toBe('safe'); |
| 9 | } finally { |
| 10 | // Cleanup ensures environment is restored even if test fails |
| 11 | if (descriptor) { |
| 12 | Object.defineProperty(String.prototype, 'isWellFormed', descriptor); |
| 13 | } |
| 14 | } |
| 15 | }); |
Explanation (EN)
The test wraps the mutation and assertions in a `try-finally` block. This guarantees that the original environment is restored in the `finally` clause, regardless of whether the test passes, fails, or throws an error, keeping tests isolated.
Objašnjenje (HR)
Test omata mutaciju i asercije u `try-finally` blok. Ovo garantira da će se originalna okolina vratiti u prvobitno stanje unutar `finally` dijela, bez obzira na to hoće li test proći, pasti ili baciti grešku, čime testovi ostaju izolirani.
Notes (EN)
This pattern is preferred over `afterEach` for one-off, invasive mutations (like deleting a prototype method) to keep the test self-contained and avoid accidental pollution if lifecycle hooks are misconfigured.
Bilješke (HR)
Ovaj uzorak je poželjniji od `afterEach` za jednokratne, invazivne mutacije (poput brisanja metode prototipa) kako bi test ostao samostalan i kako bi se izbjeglo slučajno zagađenje ako su 'lifecycle' kuke pogrešno konfigurirane.