Skip to content

Commit 7dee82d

Browse files
committed
test: add proper isolation with describe.sequential and rewire
Fix test isolation issues to prevent concurrent test interference and remove forbidden process.chdir() usage. Changes: - test/github.test.ts: use describe.sequential, remove manual resetEnv calls - test/logger.test.ts: add 4 describe.sequential blocks for shared state - test/cache-with-ttl.test.ts: use describe.sequential, add env isolation - test/dlx-binary.test.ts: use describe.sequential - test/effects/text-shimmer.test.ts: use describe.sequential - test/git-extended.test.ts: remove forbidden process.chdir() usage - test/utils/temp-file-helper.mts: use setEnv/clearEnv from rewire
1 parent c7d6f6b commit 7dee82d

7 files changed

Lines changed: 109 additions & 85 deletions

File tree

test/cache-with-ttl.test.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,25 @@
22
* @fileoverview Unit tests for TTL cache utilities.
33
*/
44

5+
import { tmpdir } from 'node:os'
6+
import * as path from 'node:path'
7+
58
import { createTtlCache } from '@socketsecurity/lib/cache-with-ttl'
9+
import { resetEnv, setEnv } from '@socketsecurity/lib/env/rewire'
610
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
711

8-
describe('cache-with-ttl', () => {
12+
describe.sequential('cache-with-ttl', () => {
913
let cache: ReturnType<typeof createTtlCache>
14+
let testCacheDir: string
1015

1116
beforeEach(() => {
17+
// Create a unique cache directory for each test to ensure isolation
18+
testCacheDir = path.join(
19+
tmpdir(),
20+
`socket-test-cache-${Date.now()}-${Math.random().toString(36).slice(2)}`,
21+
)
22+
setEnv('SOCKET_CACACHE_DIR', testCacheDir)
23+
1224
// Create a fresh cache instance for each test
1325
cache = createTtlCache({
1426
ttl: 1000, // 1 second for tests
@@ -20,6 +32,8 @@ describe('cache-with-ttl', () => {
2032
afterEach(async () => {
2133
// Clean up after each test
2234
await cache.clear()
35+
// Reset environment overrides
36+
resetEnv()
2337
})
2438

2539
describe('createTtlCache', () => {

test/dlx-binary.test.ts

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ afterAll(async () => {
8585
})
8686
})
8787

88-
describe('dlx-binary', () => {
88+
describe.sequential('dlx-binary', () => {
8989
describe('getDlxCachePath', () => {
9090
it('should return normalized cache path', () => {
9191
const cachePath = getDlxCachePath()
@@ -367,7 +367,10 @@ describe('dlx-binary', () => {
367367
await result1.spawnPromise.catch(() => {})
368368

369369
// Corrupt metadata
370-
const cacheKey = createHash('sha256').update(url).digest('hex')
370+
const name = 'invalid-meta-binary'
371+
const cacheKey = createHash('sha256')
372+
.update(`${url}:${name}`)
373+
.digest('hex')
371374
const cachePath = getDlxCachePath()
372375
const metaPath = path.join(cachePath, cacheKey, '.dlx-metadata.json')
373376
await fs.writeFile(metaPath, 'invalid json', 'utf8')
@@ -401,7 +404,10 @@ describe('dlx-binary', () => {
401404
await result1.spawnPromise.catch(() => {})
402405

403406
// Delete metadata
404-
const cacheKey = createHash('sha256').update(url).digest('hex')
407+
const name = 'missing-meta-binary'
408+
const cacheKey = createHash('sha256')
409+
.update(`${url}:${name}`)
410+
.digest('hex')
405411
const cachePath = getDlxCachePath()
406412
const metaPath = path.join(cachePath, cacheKey, '.dlx-metadata.json')
407413
await fs.unlink(metaPath)
@@ -435,7 +441,10 @@ describe('dlx-binary', () => {
435441
await result1.spawnPromise.catch(() => {})
436442

437443
// Write array as metadata (invalid)
438-
const cacheKey = createHash('sha256').update(url).digest('hex')
444+
const name = 'array-meta-binary'
445+
const cacheKey = createHash('sha256')
446+
.update(`${url}:${name}`)
447+
.digest('hex')
439448
const cachePath = getDlxCachePath()
440449
const metaPath = path.join(cachePath, cacheKey, '.dlx-metadata.json')
441450
await fs.writeFile(metaPath, JSON.stringify([]), 'utf8')
@@ -469,7 +478,10 @@ describe('dlx-binary', () => {
469478
await result1.spawnPromise.catch(() => {})
470479

471480
// Write metadata without checksum
472-
const cacheKey = createHash('sha256').update(url).digest('hex')
481+
const name = 'no-checksum-meta-binary'
482+
const cacheKey = createHash('sha256')
483+
.update(`${url}:${name}`)
484+
.digest('hex')
473485
const cachePath = getDlxCachePath()
474486
const metaPath = path.join(cachePath, cacheKey, '.dlx-metadata.json')
475487
await fs.writeFile(
@@ -1227,7 +1239,10 @@ describe('dlx-binary', () => {
12271239
await result1.spawnPromise.catch(() => {})
12281240

12291241
// Make metadata unreadable (change permissions)
1230-
const cacheKey = createHash('sha256').update(url).digest('hex')
1242+
const name = 'read-error-binary'
1243+
const cacheKey = createHash('sha256')
1244+
.update(`${url}:${name}`)
1245+
.digest('hex')
12311246
const cachePath = getDlxCachePath()
12321247
const metaPath = path.join(cachePath, cacheKey, '.dlx-metadata.json')
12331248

test/effects/text-shimmer.test.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { stripAnsi } from '@socketsecurity/lib/ansi'
2-
import { CI } from '@socketsecurity/lib/env/ci'
2+
import { getCI } from '@socketsecurity/lib/env/ci'
33
import {
44
applyShimmer,
55
DIR_LTR,
@@ -8,8 +8,8 @@ import {
88
} from '@socketsecurity/lib/effects/text-shimmer'
99
import { beforeEach, describe, expect, it } from 'vitest'
1010

11-
describe('text-shimmer', () => {
12-
describe('applyShimmer()', () => {
11+
describe.sequential('text-shimmer', () => {
12+
describe.sequential('applyShimmer()', () => {
1313
let state: ShimmerState
1414

1515
beforeEach(() => {
@@ -40,7 +40,7 @@ describe('text-shimmer', () => {
4040

4141
// In CI: step should not advance (shimmer disabled)
4242
// In non-CI: step should advance (shimmer enabled)
43-
if (CI) {
43+
if (getCI()) {
4444
expect(state.step).toBe(0)
4545
} else {
4646
expect(state.step).toBeGreaterThan(0)
@@ -69,7 +69,7 @@ describe('text-shimmer', () => {
6969

7070
// In CI: step should not advance (shimmer disabled)
7171
// In non-CI: step should advance (shimmer enabled)
72-
if (CI) {
72+
if (getCI()) {
7373
expect(testState.step).toBe(0)
7474
} else {
7575
expect(testState.step).toBeGreaterThan(0)
@@ -93,7 +93,7 @@ describe('text-shimmer', () => {
9393

9494
// In CI: step should not advance (shimmer disabled)
9595
// In non-CI: step should advance (shimmer enabled)
96-
if (CI) {
96+
if (getCI()) {
9797
expect(state.step).toBe(0)
9898
} else {
9999
expect(state.step).toBeGreaterThan(0)
@@ -114,7 +114,7 @@ describe('text-shimmer', () => {
114114
direction: DIR_LTR,
115115
})
116116

117-
if (CI) {
117+
if (getCI()) {
118118
// In CI: step should not advance (shimmer disabled)
119119
expect(state1.step).toBe(0)
120120
} else {
@@ -166,7 +166,7 @@ describe('text-shimmer', () => {
166166

167167
// In CI: step should not advance (shimmer disabled)
168168
// In non-CI: step should advance (shimmer enabled)
169-
if (CI) {
169+
if (getCI()) {
170170
expect(testState.step).toBe(0)
171171
} else {
172172
expect(testState.step).toBeGreaterThan(0)

test/git-extended.test.ts

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import {
2121
isUnstagedSync,
2222
} from '@socketsecurity/lib/git'
2323
import { spawnSync } from '@socketsecurity/lib/spawn'
24-
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
24+
import { describe, expect, it } from 'vitest'
2525
import { runWithTempDir } from './utils/temp-file-helper.mjs'
2626

2727
describe('git extended tests', () => {
@@ -192,15 +192,7 @@ describe('git extended tests', () => {
192192
})
193193

194194
describe('real git operations', () => {
195-
let originalCwd: string
196-
197-
beforeEach(async () => {
198-
originalCwd = process.cwd()
199-
})
200-
201-
afterEach(async () => {
202-
process.chdir(originalCwd)
203-
})
195+
// Note: No need to save/restore cwd - we always use explicit cwd options
204196

205197
it('should work with a temporary git repository', async () => {
206198
await runWithTempDir(async tmpDir => {

test/github.test.ts

Lines changed: 33 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -13,46 +13,49 @@ import {
1313
getGitHubTokenFromGitConfig,
1414
getGitHubTokenWithFallback,
1515
} from '@socketsecurity/lib/github'
16-
import { beforeEach, describe, expect, it } from 'vitest'
16+
import { resetEnv, setEnv } from '@socketsecurity/lib/env/rewire'
17+
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
1718

18-
describe('github', () => {
19+
describe.sequential('github', () => {
1920
beforeEach(() => {
2021
// Clear environment variables
21-
delete process.env.GITHUB_TOKEN
22-
delete process.env.GH_TOKEN
23-
delete process.env.SOCKET_CLI_GITHUB_TOKEN
22+
resetEnv()
2423
clearRefCache()
2524
})
2625

26+
afterEach(() => {
27+
resetEnv()
28+
})
29+
2730
describe('getGitHubToken', () => {
2831
it('should return GITHUB_TOKEN from environment', () => {
29-
process.env.GITHUB_TOKEN = 'test-token'
32+
setEnv('GITHUB_TOKEN', 'test-token')
3033
const token = getGitHubToken()
3134
expect(token).toBe('test-token')
3235
})
3336

3437
it('should return GH_TOKEN from environment', () => {
35-
process.env.GH_TOKEN = 'gh-test-token'
38+
setEnv('GH_TOKEN', 'gh-test-token')
3639
const token = getGitHubToken()
3740
expect(token).toBe('gh-test-token')
3841
})
3942

4043
it('should return SOCKET_CLI_GITHUB_TOKEN from environment', () => {
41-
process.env.SOCKET_CLI_GITHUB_TOKEN = 'cli-token'
44+
setEnv('SOCKET_CLI_GITHUB_TOKEN', 'cli-token')
4245
const token = getGitHubToken()
4346
expect(token).toBe('cli-token')
4447
})
4548

4649
it('should prefer GITHUB_TOKEN over GH_TOKEN', () => {
47-
process.env.GITHUB_TOKEN = 'github-token'
48-
process.env.GH_TOKEN = 'gh-token'
50+
setEnv('GITHUB_TOKEN', 'github-token')
51+
setEnv('GH_TOKEN', 'gh-token')
4952
const token = getGitHubToken()
5053
expect(token).toBe('github-token')
5154
})
5255

5356
it('should prefer GITHUB_TOKEN over SOCKET_CLI_GITHUB_TOKEN', () => {
54-
process.env.GITHUB_TOKEN = 'github-token'
55-
process.env.SOCKET_CLI_GITHUB_TOKEN = 'cli-token'
57+
setEnv('GITHUB_TOKEN', 'github-token')
58+
setEnv('SOCKET_CLI_GITHUB_TOKEN', 'cli-token')
5659
const token = getGitHubToken()
5760
expect(token).toBe('github-token')
5861
})
@@ -97,13 +100,13 @@ describe('github', () => {
97100

98101
describe('getGitHubTokenWithFallback', () => {
99102
it('should return token from GITHUB_TOKEN environment first', async () => {
100-
process.env.GITHUB_TOKEN = 'env-token'
103+
setEnv('GITHUB_TOKEN', 'env-token')
101104
const token = await getGitHubTokenWithFallback()
102105
expect(token).toBe('env-token')
103106
})
104107

105108
it('should return token from GH_TOKEN when GITHUB_TOKEN is not set', async () => {
106-
process.env.GH_TOKEN = 'gh-token'
109+
setEnv('GH_TOKEN', 'gh-token')
107110
const token = await getGitHubTokenWithFallback()
108111
expect(token).toBe('gh-token')
109112
})
@@ -173,42 +176,39 @@ describe('github', () => {
173176

174177
describe('token priority and fallback', () => {
175178
it('should prioritize GITHUB_TOKEN over other env vars', () => {
176-
process.env.GITHUB_TOKEN = 'token1'
177-
process.env.GH_TOKEN = 'token2'
178-
process.env.SOCKET_CLI_GITHUB_TOKEN = 'token3'
179+
setEnv('GITHUB_TOKEN', 'token1')
180+
setEnv('GH_TOKEN', 'token2')
181+
setEnv('SOCKET_CLI_GITHUB_TOKEN', 'token3')
179182

180183
const token = getGitHubToken()
181184
expect(token).toBe('token1')
182185
})
183186

184187
it('should use GH_TOKEN when GITHUB_TOKEN is not set', () => {
185-
delete process.env.GITHUB_TOKEN
186-
process.env.GH_TOKEN = 'token2'
187-
process.env.SOCKET_CLI_GITHUB_TOKEN = 'token3'
188+
setEnv('GH_TOKEN', 'token2')
189+
setEnv('SOCKET_CLI_GITHUB_TOKEN', 'token3')
188190

189191
const token = getGitHubToken()
190192
expect(token).toBe('token2')
191193
})
192194

193195
it('should use SOCKET_CLI_GITHUB_TOKEN as last resort', () => {
194-
delete process.env.GITHUB_TOKEN
195-
delete process.env.GH_TOKEN
196-
process.env.SOCKET_CLI_GITHUB_TOKEN = 'token3'
196+
setEnv('SOCKET_CLI_GITHUB_TOKEN', 'token3')
197197

198198
const token = getGitHubToken()
199199
expect(token).toBe('token3')
200200
})
201201

202202
it('should handle empty string tokens', () => {
203-
process.env.GITHUB_TOKEN = ''
204-
process.env.GH_TOKEN = 'token2'
203+
setEnv('GITHUB_TOKEN', '')
204+
setEnv('GH_TOKEN', 'token2')
205205

206206
const token = getGitHubToken()
207207
expect(token).toBe('token2')
208208
})
209209

210210
it('should handle whitespace tokens', () => {
211-
process.env.GITHUB_TOKEN = ' '
211+
setEnv('GITHUB_TOKEN', ' ')
212212
const token = getGitHubToken()
213213
expect(token).toBeTruthy()
214214
})
@@ -245,16 +245,12 @@ describe('github', () => {
245245

246246
describe('getGitHubTokenWithFallback', () => {
247247
it('should prefer environment over git config', async () => {
248-
process.env.GITHUB_TOKEN = 'env-token'
248+
setEnv('GITHUB_TOKEN', 'env-token')
249249
const token = await getGitHubTokenWithFallback()
250250
expect(token).toBe('env-token')
251251
})
252252

253253
it('should handle when both sources are unavailable', async () => {
254-
delete process.env.GITHUB_TOKEN
255-
delete process.env.GH_TOKEN
256-
delete process.env.SOCKET_CLI_GITHUB_TOKEN
257-
258254
const token = await getGitHubTokenWithFallback()
259255
expect(typeof token === 'string' || token === undefined).toBe(true)
260256
})
@@ -271,25 +267,25 @@ describe('github', () => {
271267

272268
describe('edge cases and error handling', () => {
273269
it('should handle rapid token changes', () => {
274-
process.env.GITHUB_TOKEN = 'token1'
270+
setEnv('GITHUB_TOKEN', 'token1')
275271
expect(getGitHubToken()).toBe('token1')
276272

277-
process.env.GITHUB_TOKEN = 'token2'
273+
setEnv('GITHUB_TOKEN', 'token2')
278274
expect(getGitHubToken()).toBe('token2')
279275

280-
delete process.env.GITHUB_TOKEN
276+
setEnv('GITHUB_TOKEN', undefined)
281277
expect(getGitHubToken()).toBeUndefined()
282278
})
283279

284280
it('should handle token with special characters', () => {
285-
process.env.GITHUB_TOKEN = 'ghp_abc123!@#$%^&*()'
281+
setEnv('GITHUB_TOKEN', 'ghp_abc123!@#$%^&*()')
286282
const token = getGitHubToken()
287283
expect(token).toContain('ghp_abc123')
288284
})
289285

290286
it('should handle very long tokens', () => {
291287
const longToken = `ghp_${'x'.repeat(1000)}`
292-
process.env.GITHUB_TOKEN = longToken
288+
setEnv('GITHUB_TOKEN', longToken)
293289
const token = getGitHubToken()
294290
expect(token).toBe(longToken)
295291
})
@@ -307,7 +303,7 @@ describe('github', () => {
307303

308304
describe('concurrent operations', () => {
309305
it('should handle concurrent token reads', () => {
310-
process.env.GITHUB_TOKEN = 'token'
306+
setEnv('GITHUB_TOKEN', 'token')
311307
const results = Array.from({ length: 10 }, () => getGitHubToken())
312308
expect(results).toEqual(Array(10).fill('token'))
313309
})

0 commit comments

Comments
 (0)