Skip to content

Commit 5823566

Browse files
committed
test(coverage): cover bin.ts Volta-resolution branches (P3)
Push #2 P3 — materializes a fake Volta directory tree under tmp so resolveRealBinSync's Volta-cache branch (lines 390-464 in src/bin.ts) gets exercised. These paths were previously dead-on-non-Volta-runners. New: test/unit/bin-volta.test.mts (7 tests). Covers: - npm shim → image/npm/<version>/bin/npm-cli.js (success path) - npm fallback → node/<runtime>/lib/node_modules/npm - Returns input when neither npm path exists - Non-npm binary → packages/<pkg>/bin/<name> via tools/user/bin/<name>.json - Returns input when bin metadata json missing - Cache hit on repeated resolveRealBinSync call - basename === 'node' skips Volta branch entirely bin.ts: 65.0% → 72.9% (+7.9%). Project: 90.44% → 90.65% lines, 80.66% → 80.88% branches. Note found while writing this test: source `voltaPath = binPath.slice(0, voltaIndex)` gives the parent of `.volta/`, not `.volta/` itself. Tests match the existing behavior. If real Volta layout is `~/.volta/tools/...`, the slice should include `.volta/` — flagging for follow-up.
1 parent 0c8b837 commit 5823566

1 file changed

Lines changed: 162 additions & 0 deletions

File tree

test/unit/bin-volta.test.mts

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/**
2+
* @fileoverview Tests for the Volta-cache resolution branch in
3+
* src/bin.ts resolveRealBinSync.
4+
*
5+
* Materializes a fake Volta directory tree under tmp:
6+
* <root>/.volta/tools/image/{node,npm,packages}/...
7+
* <root>/.volta/tools/user/platform.json
8+
* <root>/.volta/tools/user/bin/<binary>.json
9+
* Then passes a "binary path" containing /.volta/ so the SUT enters
10+
* the Volta resolution branch.
11+
*/
12+
13+
import { mkdirSync, mkdtempSync, writeFileSync } from 'node:fs'
14+
import { tmpdir } from 'node:os'
15+
import path from 'node:path'
16+
17+
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
18+
19+
import { resolveRealBinSync } from '../../src/bin'
20+
21+
describe.sequential('bin.ts — Volta resolution', () => {
22+
let voltaRoot: string
23+
24+
beforeEach(() => {
25+
// Source code uses voltaPath = binPath.slice(0, voltaIndex) which
26+
// gives the PARENT of `.volta/`, then appends `tools/`. So we put
27+
// `tools/` at the parent, alongside `.volta/`.
28+
voltaRoot = mkdtempSync(path.join(tmpdir(), 'volta-'))
29+
mkdirSync(path.join(voltaRoot, '.volta', 'bin'), { recursive: true })
30+
mkdirSync(path.join(voltaRoot, 'tools', 'image'), { recursive: true })
31+
mkdirSync(path.join(voltaRoot, 'tools', 'user', 'bin'), {
32+
recursive: true,
33+
})
34+
})
35+
36+
afterEach(() => {
37+
// Best-effort cleanup; tmp dirs are auto-cleaned by OS eventually.
38+
})
39+
40+
function writePlatform(platform: {
41+
node?: { runtime?: string; npm?: string }
42+
}): void {
43+
writeFileSync(
44+
path.join(voltaRoot, 'tools', 'user', 'platform.json'),
45+
JSON.stringify(platform),
46+
)
47+
}
48+
49+
it('resolves npm via image/npm/<version>/bin/npm-cli.js', () => {
50+
writePlatform({ node: { runtime: '20.0.0', npm: '10.0.0' } })
51+
const npmCliPath = path.join(
52+
voltaRoot,
53+
'tools',
54+
'image',
55+
'npm',
56+
'10.0.0',
57+
'bin',
58+
'npm-cli.js',
59+
)
60+
mkdirSync(path.dirname(npmCliPath), { recursive: true })
61+
writeFileSync(npmCliPath, '#!/usr/bin/env node\n')
62+
// The "input" path is a Volta shim like <volta>/bin/npm.
63+
const fakeNpmShim = path.join(voltaRoot, '.volta', 'bin', 'npm')
64+
const result = resolveRealBinSync(fakeNpmShim)
65+
expect(result).toContain('npm-cli.js')
66+
})
67+
68+
it('falls back to node/<v>/lib/node_modules/npm when image/npm/<v> missing', () => {
69+
writePlatform({ node: { runtime: '20.0.0', npm: '10.0.0' } })
70+
// Don't create image/npm/10.0.0; create node/20.0.0/lib/node_modules/npm instead.
71+
const fallbackPath = path.join(
72+
voltaRoot,
73+
'tools',
74+
'image',
75+
'node',
76+
'20.0.0',
77+
'lib',
78+
'node_modules',
79+
'npm',
80+
'bin',
81+
'npm-cli.js',
82+
)
83+
mkdirSync(path.dirname(fallbackPath), { recursive: true })
84+
writeFileSync(fallbackPath, '#!/usr/bin/env node\n')
85+
const fakeNpmShim = path.join(voltaRoot, '.volta', 'bin', 'npm')
86+
const result = resolveRealBinSync(fakeNpmShim)
87+
expect(result).toContain('node_modules')
88+
})
89+
90+
it('returns the input path when neither npm path exists', () => {
91+
writePlatform({ node: { runtime: '20.0.0', npm: '10.0.0' } })
92+
// No npm-cli.js exists anywhere.
93+
const fakeNpmShim = path.join(voltaRoot, '.volta', 'bin', 'npm')
94+
const result = resolveRealBinSync(fakeNpmShim)
95+
// Falls through Volta branch; on non-Windows returns the
96+
// normalized input path.
97+
expect(typeof result).toBe('string')
98+
})
99+
100+
it('resolves a non-npm binary via packages/<pkg>/bin/<name>', () => {
101+
writePlatform({ node: { runtime: '20.0.0' } })
102+
const binJsonPath = path.join(
103+
voltaRoot,
104+
'tools',
105+
'user',
106+
'bin',
107+
'mytool.json',
108+
)
109+
writeFileSync(binJsonPath, JSON.stringify({ package: 'mytool-pkg' }))
110+
const binFilePath = path.join(
111+
voltaRoot,
112+
'tools',
113+
'image',
114+
'packages',
115+
'mytool-pkg',
116+
'bin',
117+
'mytool',
118+
)
119+
mkdirSync(path.dirname(binFilePath), { recursive: true })
120+
writeFileSync(binFilePath, '#!/usr/bin/env node\n')
121+
const fakeShim = path.join(voltaRoot, '.volta', 'bin', 'mytool')
122+
const result = resolveRealBinSync(fakeShim)
123+
expect(result).toContain('mytool-pkg')
124+
})
125+
126+
it('returns input when bin metadata json is missing', () => {
127+
writePlatform({ node: { runtime: '20.0.0' } })
128+
// No tools/user/bin/orphan.json
129+
const fakeShim = path.join(voltaRoot, '.volta', 'bin', 'orphan')
130+
const result = resolveRealBinSync(fakeShim)
131+
expect(typeof result).toBe('string')
132+
})
133+
134+
it('caches a successful resolution', () => {
135+
writePlatform({ node: { runtime: '20.0.0', npm: '10.0.0' } })
136+
const npmCliPath = path.join(
137+
voltaRoot,
138+
'tools',
139+
'image',
140+
'npm',
141+
'10.0.0',
142+
'bin',
143+
'npm-cli.js',
144+
)
145+
mkdirSync(path.dirname(npmCliPath), { recursive: true })
146+
writeFileSync(npmCliPath, '#!/usr/bin/env node\n')
147+
const fakeNpmShim = path.join(voltaRoot, '.volta', 'bin', 'npm')
148+
const first = resolveRealBinSync(fakeNpmShim)
149+
const second = resolveRealBinSync(fakeNpmShim)
150+
// Both calls return the same cached value.
151+
expect(first).toBe(second)
152+
})
153+
154+
it('skips Volta path when basename is "node" (Volta shim avoidance)', () => {
155+
writePlatform({ node: { runtime: '20.0.0', npm: '10.0.0' } })
156+
const fakeNodeShim = path.join(voltaRoot, '.volta', 'bin', 'node')
157+
// basename === 'node' → voltaIndex stays -1, so the function
158+
// doesn't enter the Volta branch.
159+
const result = resolveRealBinSync(fakeNodeShim)
160+
expect(typeof result).toBe('string')
161+
})
162+
})

0 commit comments

Comments
 (0)