Sse event parser
This commit is contained in:
147
test/sse-session/sse-event-parser.test.ts
Normal file
147
test/sse-session/sse-event-parser.test.ts
Normal file
@@ -0,0 +1,147 @@
|
||||
import { expect, test } from 'vitest';
|
||||
import { SSEEventParser } from '../../source/sse-session/sse-event-parser.ts';
|
||||
import type { SSEvent } from '../../source/sse-session/types.ts';
|
||||
|
||||
import {
|
||||
edgeCases,
|
||||
priceOracleEvents,
|
||||
storageEvents,
|
||||
priceOracleEventsCombined,
|
||||
storageEventsCombined,
|
||||
edgeCasesCombined,
|
||||
} from './fixtures/events.fixtures.ts';
|
||||
|
||||
/** Shared encoder for turning fixture strings into stream bytes. */
|
||||
const textEncoder = new TextEncoder();
|
||||
|
||||
/**
|
||||
* Tests that SSEEventParser parses a simple data event.
|
||||
*/
|
||||
const testSseEventParserParsesSimpleEvent = (): void => {
|
||||
const parser = new SSEEventParser();
|
||||
|
||||
const events = parser.parseEvents(textEncoder.encode('data: test\n\n'));
|
||||
|
||||
expect(events).toEqual([{ data: 'test' }]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Tests that SSEEventParser parses all fixture events correctly.
|
||||
*/
|
||||
const testSseEventParserParsesAllFixtures = (): void => {
|
||||
const parser = new SSEEventParser();
|
||||
|
||||
// Combine all individual event fixtures from each domain.
|
||||
const combinedEvents = [ ...priceOracleEvents, ...storageEvents, ...edgeCases ];
|
||||
|
||||
// Iterate over each combined fixture and test that the parser parses all events correctly.
|
||||
for (const { raw, parsed } of combinedEvents) {
|
||||
const events = parser.parseEvents(textEncoder.encode(raw));
|
||||
|
||||
expect(events).toEqual(parsed);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Tests that SSEEventParser handles multiple events in the same chunk.
|
||||
*/
|
||||
const testSseEventParserHandlesMultipleEventsInOneChunk = (): void => {
|
||||
const parser = new SSEEventParser();
|
||||
|
||||
// Each combined fixture packs several events into one raw payload.
|
||||
const allEvents = [ priceOracleEventsCombined, storageEventsCombined, edgeCasesCombined ];
|
||||
|
||||
// Iterate over each combined fixture and test that the parser handles the multiple events in one chunk correctly.
|
||||
for (const { raw, parsed } of allEvents) {
|
||||
const bytes = textEncoder.encode(raw);
|
||||
const events = parser.parseEvents(bytes);
|
||||
|
||||
expect(events).toEqual(parsed);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Tests that SSEEventParser handles partial chunks delivered one character at a time.
|
||||
*/
|
||||
const testSseEventParserHandlesPartialChunks = (): void => {
|
||||
const fixtures = [ ...priceOracleEvents, ...storageEvents, ...edgeCases ];
|
||||
|
||||
// Iterate over each fixture and test that the parser handles the partial chunks correctly.
|
||||
for (const { raw, parsed } of fixtures) {
|
||||
const parser = new SSEEventParser();
|
||||
const finalEvents: SSEvent[] = [];
|
||||
|
||||
// Iterate over each character in the raw string and try to parse the events in its buffer
|
||||
for (const character of raw) {
|
||||
const bytes = textEncoder.encode(character);
|
||||
const events = parser.parseEvents(bytes);
|
||||
|
||||
finalEvents.push(...events);
|
||||
}
|
||||
|
||||
// Verify the events match the expected events.
|
||||
expect(finalEvents).toEqual(parsed ?? []);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Tests that SSEEventParser handles partial byte chunks delivered one byte at a time.
|
||||
* This tests that unicode characters (like emojis) are still parsed correctly despite being split between two "chunks".
|
||||
*/
|
||||
const testSseEventParserHandlesPartialByteChunks = (): void => {
|
||||
// Combine all individual event fixtures from each domain.
|
||||
const fixtures = [ ...priceOracleEvents, ...storageEvents, ...edgeCases ];
|
||||
|
||||
// Iterate over each fixture and test that the parser handles the partial byte chunks correctly.
|
||||
for (const { raw, parsed } of fixtures) {
|
||||
const parser = new SSEEventParser();
|
||||
const finalEvents: SSEvent[] = [];
|
||||
const bytes = textEncoder.encode(raw);
|
||||
|
||||
// Iterate over each byte in the raw string and try to parse the events in its buffer
|
||||
for (const byte of bytes) {
|
||||
const uint8Bytes = Uint8Array.of(byte);
|
||||
const events = parser.parseEvents(uint8Bytes);
|
||||
|
||||
finalEvents.push(...events);
|
||||
}
|
||||
|
||||
// Verify the events match the expected events.
|
||||
expect(finalEvents).toEqual(parsed ?? []);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Tests that SSEEventParser clears its buffer when reset is called.
|
||||
*/
|
||||
const testSseEventParserClearsBufferOnReset = (): void => {
|
||||
// Create a new parser.
|
||||
const parser = new SSEEventParser();
|
||||
|
||||
// Parse the events in the buffer.
|
||||
parser.parseEvents(textEncoder.encode('data: stale'));
|
||||
|
||||
// Reset the parser.
|
||||
parser.reset();
|
||||
|
||||
// Parse the events in the buffer.
|
||||
const events = parser.parseEvents(textEncoder.encode('data: fresh\n\n'));
|
||||
|
||||
// Verify the events match the expected events.
|
||||
expect(events).toEqual([
|
||||
{
|
||||
data: 'fresh',
|
||||
},
|
||||
]);
|
||||
};
|
||||
|
||||
const runTests = async (): Promise<void> => {
|
||||
test('SSEEventParser: parses a simple data event', testSseEventParserParsesSimpleEvent);
|
||||
test('SSEEventParser: parses all fixture events', testSseEventParserParsesAllFixtures);
|
||||
test('SSEEventParser: handles multiple events in one chunk', testSseEventParserHandlesMultipleEventsInOneChunk);
|
||||
test('SSEEventParser: handles partial chunks', testSseEventParserHandlesPartialChunks);
|
||||
test('SSEEventParser: handles partial byte chunks', testSseEventParserHandlesPartialByteChunks);
|
||||
test('SSEEventParser: clears the buffer on reset', testSseEventParserClearsBufferOnReset);
|
||||
};
|
||||
|
||||
await runTests();
|
||||
Reference in New Issue
Block a user