mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-04-08 18:33:28 +08:00
fix: 2 bugs fixed, 17 tests added for hook scripts
Bug fixes: - evaluate-session.js: whitespace-tolerant regex for counting user messages in JSONL transcripts (/"type":"user"/ → /"type"\s*:\s*"user"/) - session-end.js: guard against null elements in content arrays (c.text → (c && c.text) to prevent TypeError) New tests (17): - evaluate-session: whitespace JSON regression test - session-end: null content array elements regression test - post-edit-console-warn: 5 tests (warn, skip non-JS, clean files, missing file, stdout passthrough) - post-edit-format: 3 tests (empty stdin, non-JS skip, invalid JSON) - post-edit-typecheck: 4 tests (empty stdin, non-TS skip, missing file, no tsconfig) Total test count: 191 (up from 164)
This commit is contained in:
@@ -81,8 +81,8 @@ async function main() {
|
|||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count user messages in session
|
// Count user messages in session (allow optional whitespace around colon)
|
||||||
const messageCount = countInFile(transcriptPath, /"type":"user"/g);
|
const messageCount = countInFile(transcriptPath, /"type"\s*:\s*"user"/g);
|
||||||
|
|
||||||
// Skip short sessions
|
// Skip short sessions
|
||||||
if (messageCount < minSessionLength) {
|
if (messageCount < minSessionLength) {
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ function extractSessionSummary(transcriptPath) {
|
|||||||
const text = typeof entry.content === 'string'
|
const text = typeof entry.content === 'string'
|
||||||
? entry.content
|
? entry.content
|
||||||
: Array.isArray(entry.content)
|
: Array.isArray(entry.content)
|
||||||
? entry.content.map(c => c.text || '').join(' ')
|
? entry.content.map(c => (c && c.text) || '').join(' ')
|
||||||
: '';
|
: '';
|
||||||
if (text.trim()) {
|
if (text.trim()) {
|
||||||
userMessages.push(text.trim().slice(0, 200));
|
userMessages.push(text.trim().slice(0, 200));
|
||||||
|
|||||||
@@ -262,6 +262,155 @@ async function runTests() {
|
|||||||
cleanupTestDir(testDir);
|
cleanupTestDir(testDir);
|
||||||
})) passed++; else failed++;
|
})) passed++; else failed++;
|
||||||
|
|
||||||
|
// evaluate-session.js: whitespace tolerance regression test
|
||||||
|
if (await asyncTest('counts user messages with whitespace in JSON (regression)', async () => {
|
||||||
|
const testDir = createTestDir();
|
||||||
|
const transcriptPath = path.join(testDir, 'transcript.jsonl');
|
||||||
|
|
||||||
|
// Create transcript with whitespace around colons (pretty-printed style)
|
||||||
|
const lines = [];
|
||||||
|
for (let i = 0; i < 15; i++) {
|
||||||
|
lines.push('{ "type" : "user", "content": "message ' + i + '" }');
|
||||||
|
}
|
||||||
|
fs.writeFileSync(transcriptPath, lines.join('\n'));
|
||||||
|
|
||||||
|
const stdinJson = JSON.stringify({ transcript_path: transcriptPath });
|
||||||
|
const result = await runScript(path.join(scriptsDir, 'evaluate-session.js'), stdinJson);
|
||||||
|
|
||||||
|
assert.ok(
|
||||||
|
result.stderr.includes('15 messages'),
|
||||||
|
'Should count user messages with whitespace in JSON, got: ' + result.stderr.trim()
|
||||||
|
);
|
||||||
|
|
||||||
|
cleanupTestDir(testDir);
|
||||||
|
})) passed++; else failed++;
|
||||||
|
|
||||||
|
// session-end.js: content array with null elements regression test
|
||||||
|
if (await asyncTest('handles transcript with null content array elements (regression)', async () => {
|
||||||
|
const testDir = createTestDir();
|
||||||
|
const transcriptPath = path.join(testDir, 'transcript.jsonl');
|
||||||
|
|
||||||
|
// Create transcript with null elements in content array
|
||||||
|
const lines = [
|
||||||
|
'{"type":"user","content":[null,{"text":"hello"},null,{"text":"world"}]}',
|
||||||
|
'{"type":"user","content":"simple string message"}',
|
||||||
|
'{"type":"user","content":[{"text":"normal"},{"text":"array"}]}',
|
||||||
|
'{"type":"tool_use","tool_name":"Edit","tool_input":{"file_path":"/test.js"}}',
|
||||||
|
];
|
||||||
|
fs.writeFileSync(transcriptPath, lines.join('\n'));
|
||||||
|
|
||||||
|
const stdinJson = JSON.stringify({ transcript_path: transcriptPath });
|
||||||
|
const result = await runScript(path.join(scriptsDir, 'session-end.js'), stdinJson);
|
||||||
|
|
||||||
|
// Should not crash (exit 0)
|
||||||
|
assert.strictEqual(result.code, 0, 'Should handle null content elements without crash');
|
||||||
|
})) passed++; else failed++;
|
||||||
|
|
||||||
|
// post-edit-console-warn.js tests
|
||||||
|
console.log('\npost-edit-console-warn.js:');
|
||||||
|
|
||||||
|
if (await asyncTest('warns about console.log in JS files', async () => {
|
||||||
|
const testDir = createTestDir();
|
||||||
|
const testFile = path.join(testDir, 'test.js');
|
||||||
|
fs.writeFileSync(testFile, 'const x = 1;\nconsole.log(x);\nreturn x;');
|
||||||
|
|
||||||
|
const stdinJson = JSON.stringify({ tool_input: { file_path: testFile } });
|
||||||
|
const result = await runScript(path.join(scriptsDir, 'post-edit-console-warn.js'), stdinJson);
|
||||||
|
|
||||||
|
assert.ok(result.stderr.includes('console.log'), 'Should warn about console.log');
|
||||||
|
cleanupTestDir(testDir);
|
||||||
|
})) passed++; else failed++;
|
||||||
|
|
||||||
|
if (await asyncTest('does not warn for non-JS files', async () => {
|
||||||
|
const testDir = createTestDir();
|
||||||
|
const testFile = path.join(testDir, 'test.md');
|
||||||
|
fs.writeFileSync(testFile, 'Use console.log for debugging');
|
||||||
|
|
||||||
|
const stdinJson = JSON.stringify({ tool_input: { file_path: testFile } });
|
||||||
|
const result = await runScript(path.join(scriptsDir, 'post-edit-console-warn.js'), stdinJson);
|
||||||
|
|
||||||
|
assert.ok(!result.stderr.includes('console.log'), 'Should not warn for non-JS files');
|
||||||
|
cleanupTestDir(testDir);
|
||||||
|
})) passed++; else failed++;
|
||||||
|
|
||||||
|
if (await asyncTest('does not warn for clean JS files', async () => {
|
||||||
|
const testDir = createTestDir();
|
||||||
|
const testFile = path.join(testDir, 'clean.ts');
|
||||||
|
fs.writeFileSync(testFile, 'const x = 1;\nreturn x;');
|
||||||
|
|
||||||
|
const stdinJson = JSON.stringify({ tool_input: { file_path: testFile } });
|
||||||
|
const result = await runScript(path.join(scriptsDir, 'post-edit-console-warn.js'), stdinJson);
|
||||||
|
|
||||||
|
assert.ok(!result.stderr.includes('WARNING'), 'Should not warn for clean files');
|
||||||
|
cleanupTestDir(testDir);
|
||||||
|
})) passed++; else failed++;
|
||||||
|
|
||||||
|
if (await asyncTest('handles missing file gracefully', async () => {
|
||||||
|
const stdinJson = JSON.stringify({ tool_input: { file_path: '/nonexistent/file.ts' } });
|
||||||
|
const result = await runScript(path.join(scriptsDir, 'post-edit-console-warn.js'), stdinJson);
|
||||||
|
|
||||||
|
assert.strictEqual(result.code, 0, 'Should not crash on missing file');
|
||||||
|
})) passed++; else failed++;
|
||||||
|
|
||||||
|
if (await asyncTest('passes through original data on stdout', async () => {
|
||||||
|
const stdinJson = JSON.stringify({ tool_input: { file_path: '/test.py' } });
|
||||||
|
const result = await runScript(path.join(scriptsDir, 'post-edit-console-warn.js'), stdinJson);
|
||||||
|
|
||||||
|
assert.ok(result.stdout.includes('tool_input'), 'Should pass through stdin data');
|
||||||
|
})) passed++; else failed++;
|
||||||
|
|
||||||
|
// post-edit-format.js tests
|
||||||
|
console.log('\npost-edit-format.js:');
|
||||||
|
|
||||||
|
if (await asyncTest('runs without error on empty stdin', async () => {
|
||||||
|
const result = await runScript(path.join(scriptsDir, 'post-edit-format.js'));
|
||||||
|
assert.strictEqual(result.code, 0, 'Should exit 0 on empty stdin');
|
||||||
|
})) passed++; else failed++;
|
||||||
|
|
||||||
|
if (await asyncTest('skips non-JS/TS files', async () => {
|
||||||
|
const stdinJson = JSON.stringify({ tool_input: { file_path: '/test.py' } });
|
||||||
|
const result = await runScript(path.join(scriptsDir, 'post-edit-format.js'), stdinJson);
|
||||||
|
assert.strictEqual(result.code, 0, 'Should exit 0 for non-JS files');
|
||||||
|
assert.ok(result.stdout.includes('tool_input'), 'Should pass through stdin data');
|
||||||
|
})) passed++; else failed++;
|
||||||
|
|
||||||
|
if (await asyncTest('passes through data for invalid JSON', async () => {
|
||||||
|
const result = await runScript(path.join(scriptsDir, 'post-edit-format.js'), 'not json');
|
||||||
|
assert.strictEqual(result.code, 0, 'Should exit 0 for invalid JSON');
|
||||||
|
})) passed++; else failed++;
|
||||||
|
|
||||||
|
// post-edit-typecheck.js tests
|
||||||
|
console.log('\npost-edit-typecheck.js:');
|
||||||
|
|
||||||
|
if (await asyncTest('runs without error on empty stdin', async () => {
|
||||||
|
const result = await runScript(path.join(scriptsDir, 'post-edit-typecheck.js'));
|
||||||
|
assert.strictEqual(result.code, 0, 'Should exit 0 on empty stdin');
|
||||||
|
})) passed++; else failed++;
|
||||||
|
|
||||||
|
if (await asyncTest('skips non-TypeScript files', async () => {
|
||||||
|
const stdinJson = JSON.stringify({ tool_input: { file_path: '/test.js' } });
|
||||||
|
const result = await runScript(path.join(scriptsDir, 'post-edit-typecheck.js'), stdinJson);
|
||||||
|
assert.strictEqual(result.code, 0, 'Should exit 0 for non-TS files');
|
||||||
|
assert.ok(result.stdout.includes('tool_input'), 'Should pass through stdin data');
|
||||||
|
})) passed++; else failed++;
|
||||||
|
|
||||||
|
if (await asyncTest('handles nonexistent TS file gracefully', async () => {
|
||||||
|
const stdinJson = JSON.stringify({ tool_input: { file_path: '/nonexistent/file.ts' } });
|
||||||
|
const result = await runScript(path.join(scriptsDir, 'post-edit-typecheck.js'), stdinJson);
|
||||||
|
assert.strictEqual(result.code, 0, 'Should exit 0 for missing file');
|
||||||
|
})) passed++; else failed++;
|
||||||
|
|
||||||
|
if (await asyncTest('handles TS file with no tsconfig gracefully', async () => {
|
||||||
|
const testDir = createTestDir();
|
||||||
|
const testFile = path.join(testDir, 'test.ts');
|
||||||
|
fs.writeFileSync(testFile, 'const x: number = 1;');
|
||||||
|
|
||||||
|
const stdinJson = JSON.stringify({ tool_input: { file_path: testFile } });
|
||||||
|
const result = await runScript(path.join(scriptsDir, 'post-edit-typecheck.js'), stdinJson);
|
||||||
|
assert.strictEqual(result.code, 0, 'Should exit 0 when no tsconfig found');
|
||||||
|
cleanupTestDir(testDir);
|
||||||
|
})) passed++; else failed++;
|
||||||
|
|
||||||
// hooks.json validation
|
// hooks.json validation
|
||||||
console.log('\nhooks.json Validation:');
|
console.log('\nhooks.json Validation:');
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user