test: add 3 tests for scoped pkg detection, empty env var, and tools-without-files (Round 94)

- detectFromPackageJson with scoped package name (@scope/pkg@version)
  returns null because split('@')[0] yields empty string
- getPackageManager skips empty string CLAUDE_PACKAGE_MANAGER via
  falsy short-circuit (distinct from unknown PM name test)
- session-end buildSummarySection includes Tools Used but omits
  Files Modified when transcript has only Read/Grep tools

Total tests: 842
This commit is contained in:
Affaan Mustafa
2026-02-13 14:44:40 -08:00
parent 910ffa5530
commit a95fb54ee4
2 changed files with 86 additions and 0 deletions

View File

@@ -3621,6 +3621,49 @@ Some random content without the expected ### Context to Load section
});
})) passed++; else failed++;
// ── Round 94: session-end.js tools used but no files modified ──
console.log('\nRound 94: session-end.js (tools used without files modified):');
if (await asyncTest('session file includes Tools Used but omits Files Modified when only Read/Grep used', async () => {
// session-end.js buildSummarySection (lines 217-228):
// filesModified.length > 0 → include "### Files Modified" section
// toolsUsed.length > 0 → include "### Tools Used" section
// Previously tested: BOTH present (Round ~10) and NEITHER present (Round ~10).
// Untested combination: toolsUsed present, filesModified empty.
// Transcript with Read/Grep tools (don't add to filesModified) and user messages.
const testDir = createTestDir();
const transcriptPath = path.join(testDir, 'transcript.jsonl');
const lines = [
'{"type":"user","content":"Search the codebase for auth handlers"}',
'{"type":"tool_use","tool_name":"Read","tool_input":{"file_path":"/src/auth.ts"}}',
'{"type":"tool_use","tool_name":"Grep","tool_input":{"pattern":"handler"}}',
'{"type":"user","content":"Check the test file too"}',
'{"type":"tool_use","tool_name":"Read","tool_input":{"file_path":"/tests/auth.test.ts"}}',
];
fs.writeFileSync(transcriptPath, lines.join('\n'));
const stdinJson = JSON.stringify({ transcript_path: transcriptPath });
const result = await runScript(path.join(scriptsDir, 'session-end.js'), stdinJson, {
HOME: testDir
});
assert.strictEqual(result.code, 0, 'Should exit 0');
const claudeDir = path.join(testDir, '.claude', 'sessions');
if (fs.existsSync(claudeDir)) {
const files = fs.readdirSync(claudeDir).filter(f => f.endsWith('.tmp'));
if (files.length > 0) {
const content = fs.readFileSync(path.join(claudeDir, files[0]), 'utf8');
assert.ok(content.includes('### Tools Used'), 'Should include Tools Used section');
assert.ok(content.includes('Read'), 'Should list Read tool');
assert.ok(content.includes('Grep'), 'Should list Grep tool');
assert.ok(!content.includes('### Files Modified'),
'Should NOT include Files Modified section (Read/Grep do not modify files)');
}
}
cleanupTestDir(testDir);
})) passed++; else failed++;
// Summary
console.log('\n=== Test Results ===');
console.log(`Passed: ${passed}`);

View File

@@ -1412,6 +1412,49 @@ function runTests() {
cleanupTestDir(testDir);
})) passed++; else failed++;
// ── Round 94: detectFromPackageJson with scoped package name ──
console.log('\nRound 94: detectFromPackageJson (scoped package name @scope/pkg@version):');
if (test('detectFromPackageJson returns null for scoped package name (@scope/pkg@version)', () => {
// package-manager.js line 116: pmName = pkg.packageManager.split('@')[0]
// For "@pnpm/exe@8.0.0", split('@') → ['', 'pnpm/exe', '8.0.0'], so [0] = ''
// PACKAGE_MANAGERS[''] is undefined → returns null.
// Scoped npm packages like @pnpm/exe are a real-world pattern but the
// packageManager field spec uses unscoped names (e.g., "pnpm@8"), so returning
// null is the correct defensive behaviour for this edge case.
const testDir = createTestDir();
fs.writeFileSync(
path.join(testDir, 'package.json'),
JSON.stringify({ name: 'test', packageManager: '@pnpm/exe@8.0.0' }));
const result = pm.detectFromPackageJson(testDir);
assert.strictEqual(result, null,
'Scoped package name should return null (split("@")[0] is empty string)');
cleanupTestDir(testDir);
})) passed++; else failed++;
// ── Round 94: getPackageManager with empty string CLAUDE_PACKAGE_MANAGER ──
console.log('\nRound 94: getPackageManager (empty string CLAUDE_PACKAGE_MANAGER env var):');
if (test('getPackageManager skips empty string CLAUDE_PACKAGE_MANAGER (falsy short-circuit)', () => {
// package-manager.js line 168: if (envPm && PACKAGE_MANAGERS[envPm])
// Empty string '' is falsy — the && short-circuits before checking PACKAGE_MANAGERS.
// This is distinct from the 'totally-fake-pm' test (truthy but unknown PM).
const originalEnv = process.env.CLAUDE_PACKAGE_MANAGER;
try {
process.env.CLAUDE_PACKAGE_MANAGER = '';
const result = pm.getPackageManager();
assert.notStrictEqual(result.source, 'environment',
'Empty string env var should NOT be treated as environment source');
assert.ok(result.name, 'Should still return a valid package manager name');
} finally {
if (originalEnv !== undefined) {
process.env.CLAUDE_PACKAGE_MANAGER = originalEnv;
} else {
delete process.env.CLAUDE_PACKAGE_MANAGER;
}
}
})) passed++; else failed++;
// Summary
console.log('\n=== Test Results ===');
console.log(`Passed: ${passed}`);