Skip to content

Commit 8f8dfd9

Browse files
committed
Add comprehensive tests for new utility modules
1 parent 56403d3 commit 8f8dfd9

3 files changed

Lines changed: 645 additions & 0 deletions

File tree

test/registry/cacache.test.mts

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import { afterEach, describe, expect, it } from 'vitest'
2+
3+
import {
4+
clear,
5+
get,
6+
put,
7+
remove,
8+
safeGet,
9+
withTmp,
10+
} from '../../registry/dist/lib/cacache.js'
11+
12+
// Test key for cache operations.
13+
const TEST_KEY = 'test-cacache-key'
14+
const TEST_DATA = 'test data content'
15+
16+
describe('cacache module', () => {
17+
afterEach(async () => {
18+
// Clean up test entries after each test.
19+
try {
20+
await remove(TEST_KEY)
21+
} catch {
22+
// Ignore cleanup errors.
23+
}
24+
})
25+
26+
describe('clear', () => {
27+
it('should clear all cache entries', async () => {
28+
await put(TEST_KEY, TEST_DATA)
29+
await clear()
30+
31+
const entry = await safeGet(TEST_KEY)
32+
expect(entry).toBeUndefined()
33+
})
34+
})
35+
36+
describe('get', () => {
37+
it('should retrieve data from cache', async () => {
38+
await put(TEST_KEY, TEST_DATA)
39+
const entry = await get(TEST_KEY)
40+
41+
expect(entry).toBeDefined()
42+
expect(entry.data).toBeInstanceOf(Buffer)
43+
expect(entry.data.toString()).toBe(TEST_DATA)
44+
expect(entry.integrity).toBeTruthy()
45+
expect(entry.size).toBe(TEST_DATA.length)
46+
})
47+
48+
it('should support Buffer data', async () => {
49+
const buffer = Buffer.from(TEST_DATA)
50+
await put(TEST_KEY, buffer)
51+
const entry = await get(TEST_KEY)
52+
53+
expect(entry.data.toString()).toBe(TEST_DATA)
54+
})
55+
56+
it('should throw when getting non-existent key', async () => {
57+
await expect(get('non-existent-key')).rejects.toThrow()
58+
})
59+
})
60+
61+
describe('put', () => {
62+
it('should store data in cache', async () => {
63+
await put(TEST_KEY, TEST_DATA)
64+
65+
const entry = await get(TEST_KEY)
66+
expect(entry.data.toString()).toBe(TEST_DATA)
67+
})
68+
69+
it('should accept PutOptions with metadata', async () => {
70+
const metadata = { foo: 'bar', timestamp: Date.now() }
71+
await put(TEST_KEY, TEST_DATA, { metadata })
72+
73+
const entry = await get(TEST_KEY)
74+
expect(entry.metadata).toEqual(metadata)
75+
})
76+
})
77+
78+
describe('remove', () => {
79+
it('should remove cache entry', async () => {
80+
await put(TEST_KEY, TEST_DATA)
81+
await remove(TEST_KEY)
82+
83+
const entry = await safeGet(TEST_KEY)
84+
expect(entry).toBeUndefined()
85+
})
86+
})
87+
88+
describe('safeGet', () => {
89+
it('should return undefined for non-existent key', async () => {
90+
const entry = await safeGet('non-existent-key')
91+
expect(entry).toBeUndefined()
92+
})
93+
94+
it('should return entry for existing key', async () => {
95+
await put(TEST_KEY, TEST_DATA)
96+
const entry = await safeGet(TEST_KEY)
97+
98+
expect(entry).toBeDefined()
99+
expect(entry?.data.toString()).toBe(TEST_DATA)
100+
})
101+
})
102+
103+
describe('withTmp', () => {
104+
it('should provide temporary directory for callback', async () => {
105+
let tmpDir: string | undefined
106+
const result = await withTmp(async tmpDirPath => {
107+
tmpDir = tmpDirPath
108+
expect(tmpDirPath).toBeTruthy()
109+
expect(typeof tmpDirPath).toBe('string')
110+
return 'test-result'
111+
})
112+
113+
expect(result).toBe('test-result')
114+
expect(tmpDir).toBeTruthy()
115+
})
116+
117+
it('should return callback result', async () => {
118+
const result = await withTmp(async () => {
119+
return { value: 42 }
120+
})
121+
122+
expect(result).toEqual({ value: 42 })
123+
})
124+
})
125+
})

test/registry/dlx.test.mts

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
import { promises as fs } from 'node:fs'
2+
import os from 'node:os'
3+
import path from 'node:path'
4+
5+
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
6+
7+
import {
8+
clearDlx,
9+
clearDlxSync,
10+
dlxDirExists,
11+
dlxDirExistsAsync,
12+
ensureDlxDir,
13+
ensureDlxDirSync,
14+
getDlxInstalledPackageDir,
15+
getDlxPackageDir,
16+
getDlxPackageJsonPath,
17+
getDlxPackageNodeModulesDir,
18+
isDlxPackageInstalled,
19+
isDlxPackageInstalledAsync,
20+
listDlxPackages,
21+
listDlxPackagesAsync,
22+
removeDlxPackage,
23+
removeDlxPackageSync,
24+
} from '../../registry/dist/lib/dlx.js'
25+
26+
// Test package names.
27+
const TEST_PKG = 'test-package'
28+
const TEST_PKG_2 = 'test-package-2'
29+
30+
describe('dlx module', () => {
31+
let originalSocketDir: string | undefined
32+
let testDlxDir: string
33+
34+
beforeEach(async () => {
35+
// Create a temporary DLX directory for testing.
36+
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'socket-dlx-test-'))
37+
testDlxDir = path.join(tmpDir, '_dlx')
38+
39+
// Override the Socket directory for testing.
40+
originalSocketDir = process.env['SOCKET_USER_DIR']
41+
process.env['SOCKET_USER_DIR'] = tmpDir
42+
43+
await ensureDlxDir()
44+
})
45+
46+
afterEach(async () => {
47+
// Clean up all packages first.
48+
try {
49+
const packages = await listDlxPackagesAsync()
50+
await Promise.all(packages.map(pkg => removeDlxPackage(pkg)))
51+
} catch {
52+
// Ignore cleanup errors.
53+
}
54+
55+
// Restore original environment.
56+
if (originalSocketDir === undefined) {
57+
delete process.env['SOCKET_USER_DIR']
58+
} else {
59+
process.env['SOCKET_USER_DIR'] = originalSocketDir
60+
}
61+
62+
// Clean up test directory.
63+
try {
64+
const parentDir = path.dirname(testDlxDir)
65+
await fs.rm(parentDir, { recursive: true, force: true })
66+
} catch {
67+
// Ignore cleanup errors.
68+
}
69+
})
70+
71+
describe('clearDlx', () => {
72+
it('should remove all packages', async () => {
73+
// Create test packages.
74+
await fs.mkdir(getDlxPackageDir(TEST_PKG), { recursive: true })
75+
await fs.mkdir(getDlxPackageDir(TEST_PKG_2), { recursive: true })
76+
77+
await clearDlx()
78+
79+
const packages = await listDlxPackagesAsync()
80+
expect(packages).toEqual([])
81+
})
82+
83+
it('should handle empty dlx directory', async () => {
84+
await expect(clearDlx()).resolves.toBeUndefined()
85+
})
86+
})
87+
88+
describe('clearDlxSync', () => {
89+
it('should remove all packages synchronously', () => {
90+
// Create test packages synchronously.
91+
const { mkdirSync } = require('node:fs')
92+
mkdirSync(getDlxPackageDir(TEST_PKG), { recursive: true })
93+
mkdirSync(getDlxPackageDir(TEST_PKG_2), { recursive: true })
94+
95+
clearDlxSync()
96+
97+
const packages = listDlxPackages()
98+
expect(packages).toEqual([])
99+
})
100+
})
101+
102+
describe('dlxDirExists and dlxDirExistsAsync', () => {
103+
it('should return true when dlx directory exists', () => {
104+
expect(dlxDirExists()).toBe(true)
105+
})
106+
107+
it('should return true when dlx directory exists asynchronously', async () => {
108+
expect(await dlxDirExistsAsync()).toBe(true)
109+
})
110+
})
111+
112+
describe('ensureDlxDir and ensureDlxDirSync', () => {
113+
it('should create dlx directory if it does not exist', async () => {
114+
await fs.rm(testDlxDir, { recursive: true, force: true })
115+
116+
await ensureDlxDir()
117+
118+
expect(dlxDirExists()).toBe(true)
119+
})
120+
121+
it('should create dlx directory synchronously if it does not exist', async () => {
122+
await fs.rm(testDlxDir, { recursive: true, force: true })
123+
124+
ensureDlxDirSync()
125+
126+
expect(dlxDirExists()).toBe(true)
127+
})
128+
129+
it('should not error if directory already exists', async () => {
130+
await expect(ensureDlxDir()).resolves.toBeUndefined()
131+
expect(() => ensureDlxDirSync()).not.toThrow()
132+
})
133+
})
134+
135+
describe('getDlxInstalledPackageDir', () => {
136+
it('should return correct path for installed package', () => {
137+
const dir = getDlxInstalledPackageDir(TEST_PKG)
138+
expect(dir).toContain('_dlx')
139+
expect(dir).toContain('node_modules')
140+
expect(dir).toContain(TEST_PKG)
141+
})
142+
})
143+
144+
describe('getDlxPackageDir', () => {
145+
it('should return correct path for package', () => {
146+
const dir = getDlxPackageDir(TEST_PKG)
147+
expect(dir).toContain('_dlx')
148+
expect(dir).toContain(TEST_PKG)
149+
expect(dir).not.toContain('node_modules')
150+
})
151+
})
152+
153+
describe('getDlxPackageJsonPath', () => {
154+
it('should return correct path for package.json', () => {
155+
const jsonPath = getDlxPackageJsonPath(TEST_PKG)
156+
expect(jsonPath).toContain('_dlx')
157+
expect(jsonPath).toContain('node_modules')
158+
expect(jsonPath).toContain(TEST_PKG)
159+
expect(jsonPath).toContain('package.json')
160+
})
161+
})
162+
163+
describe('getDlxPackageNodeModulesDir', () => {
164+
it('should return correct path for node_modules', () => {
165+
const dir = getDlxPackageNodeModulesDir(TEST_PKG)
166+
expect(dir).toContain('_dlx')
167+
expect(dir).toContain(TEST_PKG)
168+
expect(dir).toContain('node_modules')
169+
})
170+
})
171+
172+
describe('isDlxPackageInstalled and isDlxPackageInstalledAsync', () => {
173+
it('should return true when package is installed', async () => {
174+
await fs.mkdir(getDlxInstalledPackageDir(TEST_PKG), { recursive: true })
175+
176+
expect(isDlxPackageInstalled(TEST_PKG)).toBe(true)
177+
expect(await isDlxPackageInstalledAsync(TEST_PKG)).toBe(true)
178+
})
179+
180+
it('should return false when package is not installed', () => {
181+
expect(isDlxPackageInstalled('non-existent-package')).toBe(false)
182+
})
183+
184+
it('should return false when package is not installed asynchronously', async () => {
185+
expect(await isDlxPackageInstalledAsync('non-existent-package')).toBe(
186+
false,
187+
)
188+
})
189+
})
190+
191+
describe('listDlxPackages and listDlxPackagesAsync', () => {
192+
it('should list all installed packages', async () => {
193+
await fs.mkdir(getDlxPackageDir(TEST_PKG), { recursive: true })
194+
await fs.mkdir(getDlxPackageDir(TEST_PKG_2), { recursive: true })
195+
196+
const packages = listDlxPackages()
197+
const packagesAsync = await listDlxPackagesAsync()
198+
199+
expect(packages).toEqual([TEST_PKG, TEST_PKG_2])
200+
expect(packagesAsync).toEqual([TEST_PKG, TEST_PKG_2])
201+
})
202+
203+
it('should return empty array when no packages installed', () => {
204+
const packages = listDlxPackages()
205+
expect(packages).toEqual([])
206+
})
207+
208+
it('should return empty array when no packages installed asynchronously', async () => {
209+
const packages = await listDlxPackagesAsync()
210+
expect(packages).toEqual([])
211+
})
212+
213+
it('should return empty array when dlx directory does not exist', async () => {
214+
await fs.rm(testDlxDir, { recursive: true, force: true })
215+
216+
const packages = listDlxPackages()
217+
const packagesAsync = await listDlxPackagesAsync()
218+
219+
expect(packages).toEqual([])
220+
expect(packagesAsync).toEqual([])
221+
})
222+
})
223+
224+
describe('removeDlxPackage and removeDlxPackageSync', () => {
225+
it('should remove package directory', async () => {
226+
await fs.mkdir(getDlxPackageDir(TEST_PKG), { recursive: true })
227+
228+
await removeDlxPackage(TEST_PKG)
229+
230+
expect(isDlxPackageInstalled(TEST_PKG)).toBe(false)
231+
})
232+
233+
it('should remove package directory synchronously', async () => {
234+
const { mkdirSync } = require('node:fs')
235+
mkdirSync(getDlxPackageDir(TEST_PKG), { recursive: true })
236+
237+
removeDlxPackageSync(TEST_PKG)
238+
239+
expect(isDlxPackageInstalled(TEST_PKG)).toBe(false)
240+
})
241+
242+
it('should throw error with cause when removal fails', async () => {
243+
// Try to remove a non-existent package (force: true means it won't error).
244+
// Instead, try to remove with invalid path characters.
245+
await expect(removeDlxPackage('\0invalid')).rejects.toThrow(
246+
/Failed to remove DLX package/,
247+
)
248+
})
249+
250+
it('should throw error with cause when sync removal fails', () => {
251+
expect(() => removeDlxPackageSync('\0invalid')).toThrow(
252+
/Failed to remove DLX package/,
253+
)
254+
})
255+
})
256+
})

0 commit comments

Comments
 (0)