mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-15 14:16:16 +00:00
refactor: replace custom test runner with Node.js assert
- Simplify test files by removing custom TestRunner class - Use standard Node.js assert module across all unit tests - Update CLAUDE.md with streamlined development instructions - Update tests/README.md with current testing approach - Reduce boilerplate in delegation and GLMT test suites (652 lines removed)
This commit is contained in:
1 parent
ce9d60d0ca
commit
cb7e38d2b1
13 files changed
+1656
-2308
No files matched your search
+103
-137
@@ -1,144 +1,110 @@
|
||||
#!/usr/bin/env node
|
||||
'use strict';
|
||||
const assert = require('assert');
|
||||
const { SSEParser } = require('../../../dist/glmt/sse-parser');
|
||||
|
||||
const SSEParser = require('../../../dist/glmt/sse-parser').default;
|
||||
describe('SSEParser', () => {
|
||||
describe('Basic parsing', () => {
|
||||
it('parses single event', () => {
|
||||
const parser = new SSEParser();
|
||||
const events = parser.parse('data: {"test": "value"}\n\n');
|
||||
assert.strictEqual(events.length, 1, `Expected 1 event, got ${events.length}`);
|
||||
assert.strictEqual(events[0].data.test, 'value');
|
||||
});
|
||||
|
||||
console.log('[TEST] SSEParser unit tests');
|
||||
console.log('');
|
||||
it('parses multiple events in one chunk', () => {
|
||||
const parser = new SSEParser();
|
||||
const events = parser.parse('data: {"a": 1}\n\ndata: {"b": 2}\n\n');
|
||||
assert.strictEqual(events.length, 2, `Expected 2 events, got ${events.length}`);
|
||||
assert.strictEqual(events[0].data.a, 1);
|
||||
assert.strictEqual(events[1].data.b, 2);
|
||||
});
|
||||
|
||||
let passedTests = 0;
|
||||
let failedTests = 0;
|
||||
it('handles event split across chunks', () => {
|
||||
const parser = new SSEParser();
|
||||
const events1 = parser.parse('data: {"test":');
|
||||
assert.strictEqual(events1.length, 0, 'Should not emit incomplete event');
|
||||
const events2 = parser.parse('"value"}\n\n');
|
||||
assert.strictEqual(events2.length, 1, `Expected 1 event after completion, got ${events2.length}`);
|
||||
assert.strictEqual(events2[0].data.test, 'value');
|
||||
});
|
||||
|
||||
function test(name, fn) {
|
||||
try {
|
||||
fn();
|
||||
console.log(`[PASS] ${name}`);
|
||||
passedTests++;
|
||||
} catch (error) {
|
||||
console.log(`[FAIL] ${name}`);
|
||||
console.log(` Error: ${error.message}`);
|
||||
failedTests++;
|
||||
}
|
||||
}
|
||||
it('handles empty lines between events', () => {
|
||||
const parser = new SSEParser();
|
||||
const events = parser.parse('data: {"a": 1}\n\n\n\ndata: {"b": 2}\n\n');
|
||||
assert.strictEqual(events.length, 2, `Expected 2 events, got ${events.length}`);
|
||||
});
|
||||
});
|
||||
|
||||
function assert(condition, message) {
|
||||
if (!condition) {
|
||||
throw new Error(message || 'Assertion failed');
|
||||
}
|
||||
}
|
||||
describe('[DONE] marker', () => {
|
||||
it('detects [DONE] marker', () => {
|
||||
const parser = new SSEParser();
|
||||
const events = parser.parse('data: [DONE]\n\n');
|
||||
assert.strictEqual(events.length, 1, `Expected 1 event, got ${events.length}`);
|
||||
assert.strictEqual(events[0].event, 'done');
|
||||
assert.strictEqual(events[0].data, null);
|
||||
});
|
||||
|
||||
// Test: Single event
|
||||
test('Single event parsing', () => {
|
||||
const parser = new SSEParser();
|
||||
const events = parser.parse('data: {"test": "value"}\n\n');
|
||||
assert(events.length === 1, `Expected 1 event, got ${events.length}`);
|
||||
assert(events[0].data.test === 'value', `Expected test=value, got ${events[0].data.test}`);
|
||||
it('handles mixed events with [DONE]', () => {
|
||||
const parser = new SSEParser();
|
||||
const events = parser.parse('data: {"msg": "hello"}\n\ndata: [DONE]\n\n');
|
||||
assert.strictEqual(events.length, 2, `Expected 2 events, got ${events.length}`);
|
||||
assert.strictEqual(events[0].data.msg, 'hello');
|
||||
assert.strictEqual(events[1].event, 'done');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Error handling', () => {
|
||||
it('handles malformed JSON gracefully', () => {
|
||||
const parser = new SSEParser();
|
||||
const events = parser.parse('data: {invalid json}\n\ndata: {"valid": true}\n\n');
|
||||
assert.strictEqual(events.length, 1, `Expected 1 valid event, got ${events.length}`);
|
||||
assert.strictEqual(events[0].data.valid, true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Event fields', () => {
|
||||
it('parses event with ID field', () => {
|
||||
const parser = new SSEParser();
|
||||
const events = parser.parse('id: 123\ndata: {"test": true}\n\n');
|
||||
assert.strictEqual(events.length, 1);
|
||||
assert.strictEqual(events[0].id, '123');
|
||||
assert.strictEqual(events[0].data.test, true);
|
||||
});
|
||||
|
||||
it('parses custom event type', () => {
|
||||
const parser = new SSEParser();
|
||||
const events = parser.parse('event: custom\ndata: {"test": true}\n\n');
|
||||
assert.strictEqual(events.length, 1);
|
||||
assert.strictEqual(events[0].event, 'custom');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Reset functionality', () => {
|
||||
it('resets parser state', () => {
|
||||
const parser = new SSEParser();
|
||||
parser.parse('data: {"test": 1}\n\n');
|
||||
assert.strictEqual(parser.eventCount, 1);
|
||||
parser.reset();
|
||||
assert.strictEqual(parser.eventCount, 0);
|
||||
assert.strictEqual(parser.buffer, '');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Z.AI stream format', () => {
|
||||
it('parses real Z.AI stream format', () => {
|
||||
const parser = new SSEParser();
|
||||
const chunk = 'data: {"choices":[{"delta":{"role":"assistant","reasoning_content":"test"}}]}\n\n';
|
||||
const events = parser.parse(chunk);
|
||||
assert.strictEqual(events.length, 1);
|
||||
assert.strictEqual(events[0].data.choices[0].delta.reasoning_content, 'test');
|
||||
});
|
||||
|
||||
it('parses multiple Z.AI deltas', () => {
|
||||
const parser = new SSEParser();
|
||||
const chunk = 'data: {"choices":[{"delta":{"reasoning_content":"chunk1"}}]}\n\ndata: {"choices":[{"delta":{"reasoning_content":"chunk2"}}]}\n\n';
|
||||
const events = parser.parse(chunk);
|
||||
assert.strictEqual(events.length, 2);
|
||||
assert.strictEqual(events[0].data.choices[0].delta.reasoning_content, 'chunk1');
|
||||
assert.strictEqual(events[1].data.choices[0].delta.reasoning_content, 'chunk2');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Test: Multiple events
|
||||
test('Multiple events in one chunk', () => {
|
||||
const parser = new SSEParser();
|
||||
const events = parser.parse('data: {"a": 1}\n\ndata: {"b": 2}\n\n');
|
||||
assert(events.length === 2, `Expected 2 events, got ${events.length}`);
|
||||
assert(events[0].data.a === 1, 'First event data incorrect');
|
||||
assert(events[1].data.b === 2, 'Second event data incorrect');
|
||||
});
|
||||
|
||||
// Test: Split across chunks
|
||||
test('Event split across chunks', () => {
|
||||
const parser = new SSEParser();
|
||||
const events1 = parser.parse('data: {"test":');
|
||||
assert(events1.length === 0, 'Should not emit incomplete event');
|
||||
const events2 = parser.parse('"value"}\n\n');
|
||||
assert(events2.length === 1, `Expected 1 event after completion, got ${events2.length}`);
|
||||
assert(events2[0].data.test === 'value', 'Split event data incorrect');
|
||||
});
|
||||
|
||||
// Test: [DONE] marker
|
||||
test('[DONE] marker detection', () => {
|
||||
const parser = new SSEParser();
|
||||
const events = parser.parse('data: [DONE]\n\n');
|
||||
assert(events.length === 1, `Expected 1 event, got ${events.length}`);
|
||||
assert(events[0].event === 'done', `Expected event=done, got ${events[0].event}`);
|
||||
assert(events[0].data === null, 'Expected null data for [DONE]');
|
||||
});
|
||||
|
||||
// Test: Mixed content and [DONE]
|
||||
test('Mixed events with [DONE]', () => {
|
||||
const parser = new SSEParser();
|
||||
const events = parser.parse('data: {"msg": "hello"}\n\ndata: [DONE]\n\n');
|
||||
assert(events.length === 2, `Expected 2 events, got ${events.length}`);
|
||||
assert(events[0].data.msg === 'hello', 'First event data incorrect');
|
||||
assert(events[1].event === 'done', 'Second event should be done');
|
||||
});
|
||||
|
||||
// Test: Malformed JSON (should skip gracefully)
|
||||
test('Malformed JSON handling', () => {
|
||||
const parser = new SSEParser();
|
||||
const events = parser.parse('data: {invalid json}\n\ndata: {"valid": true}\n\n');
|
||||
// Should skip malformed, parse valid
|
||||
assert(events.length === 1, `Expected 1 valid event, got ${events.length}`);
|
||||
assert(events[0].data.valid === true, 'Valid event data incorrect');
|
||||
});
|
||||
|
||||
// Test: Empty lines handling
|
||||
test('Empty lines between events', () => {
|
||||
const parser = new SSEParser();
|
||||
const events = parser.parse('data: {"a": 1}\n\n\n\ndata: {"b": 2}\n\n');
|
||||
assert(events.length === 2, `Expected 2 events, got ${events.length}`);
|
||||
});
|
||||
|
||||
// Test: Event with ID field
|
||||
test('Event with ID field', () => {
|
||||
const parser = new SSEParser();
|
||||
const events = parser.parse('id: 123\ndata: {"test": true}\n\n');
|
||||
assert(events.length === 1, `Expected 1 event, got ${events.length}`);
|
||||
assert(events[0].id === '123', `Expected id=123, got ${events[0].id}`);
|
||||
assert(events[0].data.test === true, 'Event data incorrect');
|
||||
});
|
||||
|
||||
// Test: Custom event type
|
||||
test('Custom event type', () => {
|
||||
const parser = new SSEParser();
|
||||
const events = parser.parse('event: custom\ndata: {"test": true}\n\n');
|
||||
assert(events.length === 1, `Expected 1 event, got ${events.length}`);
|
||||
assert(events[0].event === 'custom', `Expected event=custom, got ${events[0].event}`);
|
||||
});
|
||||
|
||||
// Test: Reset functionality
|
||||
test('Parser reset', () => {
|
||||
const parser = new SSEParser();
|
||||
parser.parse('data: {"test": 1}\n\n');
|
||||
assert(parser.eventCount === 1, 'Event count should be 1');
|
||||
parser.reset();
|
||||
assert(parser.eventCount === 0, 'Event count should be 0 after reset');
|
||||
assert(parser.buffer === '', 'Buffer should be empty after reset');
|
||||
});
|
||||
|
||||
// Test: Real Z.AI stream format
|
||||
test('Real Z.AI stream format', () => {
|
||||
const parser = new SSEParser();
|
||||
const chunk = 'data: {"choices":[{"delta":{"role":"assistant","reasoning_content":"test"}}]}\n\n';
|
||||
const events = parser.parse(chunk);
|
||||
assert(events.length === 1, `Expected 1 event, got ${events.length}`);
|
||||
assert(events[0].data.choices[0].delta.reasoning_content === 'test', 'Z.AI format parsing incorrect');
|
||||
});
|
||||
|
||||
// Test: Multiple Z.AI deltas
|
||||
test('Multiple Z.AI deltas', () => {
|
||||
const parser = new SSEParser();
|
||||
const chunk = 'data: {"choices":[{"delta":{"reasoning_content":"chunk1"}}]}\n\ndata: {"choices":[{"delta":{"reasoning_content":"chunk2"}}]}\n\n';
|
||||
const events = parser.parse(chunk);
|
||||
assert(events.length === 2, `Expected 2 events, got ${events.length}`);
|
||||
assert(events[0].data.choices[0].delta.reasoning_content === 'chunk1', 'First delta incorrect');
|
||||
assert(events[1].data.choices[0].delta.reasoning_content === 'chunk2', 'Second delta incorrect');
|
||||
});
|
||||
|
||||
console.log('');
|
||||
console.log('═══════════════════════════════════════');
|
||||
console.log(`TESTS: ${passedTests} passed, ${failedTests} failed`);
|
||||
console.log('═══════════════════════════════════════');
|
||||
|
||||
if (failedTests > 0) {
|
||||
process.exit(1);
|
||||
}
|
||||
Reference in new issue
Block a user