fix(tests): centralize test config dir lifecycle to prevent env var pollution#242
fix(tests): centralize test config dir lifecycle to prevent env var pollution#242
Conversation
…ollution Bun runs test files sequentially in a single thread. Several test files unconditionally deleted process.env.SENTRY_CONFIG_DIR in afterEach hooks, causing the next file's module-level code to read undefined and crash with TypeError. A runner image upgrade changed file discovery order, exposing this latent bug. Introduces useTestConfigDir() helper in test/helpers.ts that creates a unique temp directory in beforeEach and restores (never deletes) the env var in afterEach. Migrates all 11 affected test files to use it.
Semver Impact of This PR🟢 Patch (bug fixes) 📋 Changelog PreviewThis is how your changes will appear in the changelog. New Features ✨
Bug Fixes 🐛Telemetry
Other
🤖 This preview updates automatically when you update the PR. |
The test preload deletes process.env.SENTRY_CLIENT_ID before oauth.ts loads, causing the module-level constant to capture an empty string. Tests that later set SENTRY_CLIENT_ID in beforeEach had no effect since the constant was already captured. This caused refreshAccessToken to throw ConfigError (not AuthError), which the ky afterResponse hook caught silently, preventing 401 retry from working. Replace the module-level constant with a getClientId() function that reads process.env at call time.
The tests mocked globalThis.fetch for /organizations/ and /projects/ endpoints but not /users/me/regions/. When getUserRegions() got a 404 from the mock, ky threw an HTTPError which listOrganizations caught and fell back to the non-region path. On certain CI runner images, this error-fallback code path fails. Adding an explicit regions mock avoids the error path entirely and makes the tests deterministic.
| // (or beforeEach hooks) may read the env var and get undefined. | ||
| if (savedConfigDir !== undefined) { | ||
| process.env[CONFIG_DIR_ENV_VAR] = savedConfigDir; | ||
| } |
There was a problem hiding this comment.
Config dir not restored when originally unset
Low Severity
useTestConfigDir() only restores process.env[CONFIG_DIR_ENV_VAR] when savedConfigDir !== undefined. If the original value was unset, afterEach leaves SENTRY_CONFIG_DIR pointing to the just-cleaned temp directory, so later tests can inherit a stale, invalid config path.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
Tests in resolver.test.ts and errors.test.ts used mock.module() to mock api-client.js, which persists across test files in Bun's single-threaded runner. When these files ran before utils.test.ts, the module mock intercepted listOrganizations/listProjects calls, returning stale mock data instead of going through the test's globalThis.fetch mock. Move these files to test/isolated/dsn/ so they run in the separate test:isolated script, matching the pattern used by resolve-target.test.ts. Also removes debug logging added in previous commits.
Codecov Results 📊✅ Patch coverage is 85.71%. Project has 4061 uncovered lines. Files with missing lines (68)
Coverage diff@@ Coverage Diff @@
## main #PR +/-##
==========================================
- Coverage 70.11% 68.74% -1.37%
==========================================
Files 105 105 —
Lines 12918 12992 +74
Branches 0 0 —
==========================================
+ Hits 9057 8931 -126
- Misses 3861 4061 +200
- Partials 0 0 —Generated by Codecov Action |


Summary
Fixes 37 test failures caused by the Ubuntu 24.04 runner image upgrade (
20260201.15.1→20260209.23.1, kernel 6.11 → 6.14) that changedreaddirordering, exposing a latent env var pollution bug.Root Cause
Bun runs test files sequentially in one thread (load → run all tests → load next file). Several test files unconditionally
delete process.env.SENTRY_CONFIG_DIRin theirafterEachhooks. When the next file loads, its module-level code capturesundefined, causingjoin(undefined, ...)→TypeError.The runner image upgrade changed the kernel which changed file discovery order, putting "deleting" files before "capturing" files.
Changes
test/helpers.ts: AddeduseTestConfigDir()helper that creates a unique temp directory inbeforeEach, pointsSENTRY_CONFIG_DIRat it, and restores (never deletes) the original value inafterEach. Also handlescloseDatabase()and temp dir cleanup.useTestConfigDir(), eliminating:SENTRY_CONFIG_DIR(root cause)process.env[CONFIG_DIR_ENV_VAR]!capturesif (original) restore else deletepatterns (off-by-one on falsy check)afterEachAGENTS.md: Added "Test Environment Isolation" section documenting the pattern and anti-patternsNet: -87 lines (157 added, 244 removed) — less boilerplate, more safety.
Verification
bun run typecheck— passesbun run lint— passesbun run test:unit— 1545 tests pass, 0 failuresSupercedes #240