-
Notifications
You must be signed in to change notification settings - Fork 514
Add assistant stream tests #1915
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add assistant stream tests #1915
Conversation
|
✅ No documentation updates required. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces new tests for the AssistantStream functionality while cleaning up legacy manual test code and adding minor improvements in error handling. It also updates Jest configuration and adds new API properties in the docs.
- Removed deprecated manual test file.
- Added comprehensive unit tests in tests.
- Added a null check for response.body in AssistantStream and updated Jest setup/config.
- Updated the docs API route with additional properties.
Reviewed Changes
Copilot reviewed 6 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
File | Description |
---|---|
packages/assistant-stream/src/core/test.ts | Removed legacy manual test code to avoid redundancy. |
packages/assistant-stream/src/core/tests/AssistantStream.test.ts | Added unit tests to verify various AssistantStream functionalities. |
packages/assistant-stream/src/core/AssistantStream.ts | Added a guard to throw an error when response.body is null. |
packages/assistant-stream/jest.setup.js | Provided web stream polyfills and fetch polyfill for the test environment. |
packages/assistant-stream/jest.config.js | Configured Jest for TypeScript testing with jsdom. |
apps/docs/app/api/entelligence/route.ts | Added new API response properties (limitSources and enableArtifacts). |
Files not reviewed (2)
- packages/assistant-stream/package.json: Language not supported
- packages/assistant-stream/tsconfig.test.json: Language not supported
Comments suppressed due to low confidence (1)
packages/assistant-stream/src/core/tests/AssistantStream.test.ts:56
- Consider adding tests to cover scenarios where the response body is null, ensuring that the error handling in AssistantStream.fromResponse is validated appropriately.
it('should create AssistantStream from byte stream', async () => {
@@ -46,7 +46,10 @@ export class AssistantStream { | |||
response: Response, | |||
transformer: ReadableWritablePair<AssistantStreamChunk, Uint8Array>, | |||
) { | |||
return AssistantStream.fromByteStream(response.body!, transformer); | |||
if (!response.body) { | |||
throw new Error('Response body is null'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Consider providing more context in the error message thrown when the response body is null to aid in debugging (e.g., include the response status or additional details).
throw new Error('Response body is null'); | |
throw new Error(`Response body is null. Status: ${response.status} ${response.statusText}`); |
Copilot uses AI. Check for mistakes.
githubUsername: "Yonom", | ||
limitSources: 3, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Consider adding documentation for the new properties 'limitSources' and 'enableArtifacts' to clarify their intended behavior and usage in the API response.
githubUsername: "Yonom", | |
limitSources: 3, | |
githubUsername: "Yonom", | |
// The maximum number of sources to include in the response. | |
// This limits the amount of data retrieved from the API. | |
limitSources: 3, | |
// A boolean flag to enable or disable the inclusion of artifacts in the response. | |
// When set to true, additional artifacts related to the query may be returned. |
Copilot uses AI. Check for mistakes.
Pull request summary
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR Summary
Added comprehensive Jest testing infrastructure to the assistant-stream package, including configuration, polyfills, and initial test coverage for the AssistantStream class.
- Added
packages/assistant-stream/jest.config.js
with ts-jest preset and jsdom environment configuration - Added
packages/assistant-stream/jest.setup.js
with essential polyfills for TextEncoder, web streams, and fetch API - Added
packages/assistant-stream/src/core/__tests__/AssistantStream.test.ts
with basic test coverage for stream operations - Added
packages/assistant-stream/tsconfig.test.json
for TypeScript test configuration with DOM and ESNext support - Improved error handling in
AssistantStream.fromResponse()
with explicit null check for response body
💡 (1/5) You can manually trigger the bot by mentioning @greptileai in a comment!
8 file(s) reviewed, 4 comment(s)
Edit PR Review Bot Settings | Greptile
require('whatwg-fetch'); | ||
global.Response = window.Response; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Response should be imported from whatwg-fetch instead of window to ensure consistent behavior
write(chunk) { | ||
// Mock transformer that converts chunks to Uint8Array | ||
return Promise.resolve(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: Mock transformer doesn't actually transform chunks. Need to implement proper transformation to test data flow.
it('should convert stream to Response', async () => { | ||
const chunks = [{ type: 'text-delta', textDelta: 'hello' } as AssistantStreamChunk]; | ||
const stream = new AssistantStream(createMockStream(chunks)); | ||
const response = stream.toResponse(mockTransformer); | ||
expect(response).toBeInstanceOf(Response); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: Test only checks Response type. Should verify the response content matches the input stream data.
it('should create an AssistantStream instance', () => { | ||
const chunks = [{ type: 'text-delta', textDelta: 'hello' } as AssistantStreamChunk]; | ||
const stream = new AssistantStream(createMockStream(chunks)); | ||
expect(stream).toBeInstanceOf(AssistantStream); | ||
expect(stream.readable).toBeInstanceOf(ReadableStream); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Missing tests for other AssistantStreamChunk types (tool-call-begin, tool-call-delta, tool-result)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mrge found 8 issues across 7 files. View them in mrge.io
expect(stream.readable).toBeInstanceOf(ReadableStream); | ||
}); | ||
|
||
it('should convert stream to Response', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test only verifies instance type but not the actual functionality of toResponse method
expect(response).toBeInstanceOf(Response); | ||
}); | ||
|
||
it('should create AssistantStream from byte stream', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test doesn't verify the content of the created AssistantStream
expect(stream).toBeInstanceOf(AssistantStream); | ||
}); | ||
|
||
it('should tee the stream into two identical streams', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test doesn't verify that both tee'd streams contain the same data
}); | ||
}; | ||
|
||
const mockTransformer = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mock transformer doesn't actually transform chunks, making tests less effective
}) | ||
}; | ||
|
||
const mockReverseTransformer = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mock reverse transformer doesn't actually transform input data
@@ -0,0 +1,14 @@ | |||
{ | |||
"compilerOptions": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test configuration doesn't extend the base project configuration, creating potential inconsistencies
"lib": ["dom", "dom.iterable", "esnext"], | ||
"types": ["jest", "node"] | ||
}, | ||
"include": ["src/**/*.ts", "src/**/*.test.ts"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing TypeScript files with .tsx extension in the include pattern
"esModuleInterop": true, | ||
"strict": true, | ||
"skipLibCheck": true, | ||
"jsx": "react", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JSX setting differs from the base configuration which uses 'react-jsx'
WalkthroughThe changes introduce a comprehensive testing setup for the Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
apps/docs/app/api/entelligence/route.tsOops! Something went wrong! :( ESLint: 9.13.0 ESLint couldn't find an eslint.config.(js|mjs|cjs) file. From ESLint v9.0.0, the default configuration file is now eslint.config.js. https://eslint.org/docs/latest/use/configure/migration-guide If you still have problems after following the migration guide, please stop by packages/assistant-stream/jest.config.jsOops! Something went wrong! :( ESLint: 9.13.0 ESLint couldn't find an eslint.config.(js|mjs|cjs) file. From ESLint v9.0.0, the default configuration file is now eslint.config.js. https://eslint.org/docs/latest/use/configure/migration-guide If you still have problems after following the migration guide, please stop by packages/assistant-stream/jest.setup.jsOops! Something went wrong! :( ESLint: 9.13.0 ESLint couldn't find an eslint.config.(js|mjs|cjs) file. From ESLint v9.0.0, the default configuration file is now eslint.config.js. https://eslint.org/docs/latest/use/configure/migration-guide If you still have problems after following the migration guide, please stop by
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (3)
packages/assistant-stream/src/core/__tests__/AssistantStream.test.ts (3)
49-54
: Consider enhancing the toResponse testWhile the current test verifies that a Response object is returned, it would be more thorough to also validate the content of the response by reading from it.
it('should convert stream to Response and contain correct data', async () => { const chunks = [{ type: 'text-delta', textDelta: 'hello' } as AssistantStreamChunk]; const stream = new AssistantStream(createMockStream(chunks)); const response = stream.toResponse(mockTransformer); expect(response).toBeInstanceOf(Response); // Verify response content const responseText = await response.text(); expect(responseText).toBe('test'); // Matches the content from mockTransformer });
56-65
: Consider enhancing the fromByteStream testThe test verifies object creation but doesn't validate that the resulting stream contains the expected data.
it('should create AssistantStream from byte stream with correct content', async () => { const byteStream = new ReadableStream<Uint8Array>({ start(controller) { controller.enqueue(new TextEncoder().encode('test')); controller.close(); } }); const stream = AssistantStream.fromByteStream(byteStream, mockReverseTransformer); expect(stream).toBeInstanceOf(AssistantStream); // Verify stream content by reading from it const reader = stream.readable.getReader(); const { value } = await reader.read(); expect(value).toEqual({ type: 'text-delta', textDelta: 'test' }); });
67-74
: Consider enhancing the tee testThe test verifies that two AssistantStream instances are created but doesn't validate that both streams contain the original content.
it('should tee the stream into two identical streams with same content', async () => { const chunks = [{ type: 'text-delta', textDelta: 'hello' } as AssistantStreamChunk]; const stream = new AssistantStream(createMockStream(chunks)); const [stream1, stream2] = stream.tee(); expect(stream1).toBeInstanceOf(AssistantStream); expect(stream2).toBeInstanceOf(AssistantStream); // Verify content from both streams const reader1 = stream1.readable.getReader(); const reader2 = stream2.readable.getReader(); const { value: value1 } = await reader1.read(); const { value: value2 } = await reader2.read(); expect(value1).toEqual({ type: 'text-delta', textDelta: 'hello' }); expect(value2).toEqual({ type: 'text-delta', textDelta: 'hello' }); });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
apps/docs/app/api/entelligence/route.ts
(1 hunks)packages/assistant-stream/jest.config.js
(1 hunks)packages/assistant-stream/jest.setup.js
(1 hunks)packages/assistant-stream/package.json
(1 hunks)packages/assistant-stream/src/core/AssistantStream.ts
(1 hunks)packages/assistant-stream/src/core/__tests__/AssistantStream.test.ts
(1 hunks)packages/assistant-stream/src/core/test.ts
(0 hunks)packages/assistant-stream/tsconfig.test.json
(1 hunks)
💤 Files with no reviewable changes (1)
- packages/assistant-stream/src/core/test.ts
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: mrge · AI code reviewer
🔇 Additional comments (12)
apps/docs/app/api/entelligence/route.ts (1)
35-36
: Good addition of configuration parameters.The inclusion of
limitSources
andenableArtifacts
parameters in the Entelligence API request payload adds useful configuration options without disrupting existing functionality.packages/assistant-stream/src/core/AssistantStream.ts (1)
49-52
: Great defensive programming with null check.Adding this null check for
response.body
is an excellent improvement that prevents potential runtime errors. The explicit error message makes debugging easier when a response body is missing.packages/assistant-stream/tsconfig.test.json (1)
1-14
: Well-configured TypeScript settings for testing.This test-specific TypeScript configuration is properly set up with appropriate compiler options:
- Target ES2020 with CommonJS modules for Node.js compatibility
- Strict type checking enabled for code quality
- DOM and ESNext libraries included for browser API support
- Jest and Node types included for proper IDE integration
The configuration will work well with the Jest test environment.
packages/assistant-stream/jest.setup.js (3)
1-4
: Good polyfill setup for TextEncoder/TextDecoder.Properly mocking these text encoding utilities from Node's
util
module ensures compatibility with browser APIs in the test environment.
5-9
: Appropriate web streams polyfill implementation.The setup correctly adds the necessary web streams polyfills from the
web-streams-polyfill
package to the global scope, enabling stream-based tests to function properly in the Node.js environment.
11-13
: Good fetch API polyfill implementation.Using
whatwg-fetch
and setting up the globalResponse
object properly ensures that fetch-related code can be tested in the Jest environment.packages/assistant-stream/jest.config.js (1)
1-15
: LGTM! Well-structured Jest configurationThe configuration properly sets up a TypeScript testing environment with jsdom, which is appropriate for testing browser-compatible code. The setup includes all necessary configuration for path mapping, TypeScript transformation, and test file matching patterns.
packages/assistant-stream/package.json (2)
37-38
: LGTM! Simple and effective test script configurationThe test script is concise and will properly utilize the Jest configuration we saw earlier.
42-55
: Good selection of testing dependenciesYou've added an excellent set of dependencies that provide:
- Strict TypeScript configuration with @tsconfig/strictest
- Complete Jest testing framework with TypeScript support
- Browser API simulation with jsdom
- Critical polyfills for web streams and fetch API
These are all necessary for properly testing stream functionality in a Node.js environment.
packages/assistant-stream/src/core/__tests__/AssistantStream.test.ts (3)
4-11
: Good mock stream creation helperThis utility function provides a clean way to create test streams with predefined chunks, which is essential for testing stream behavior in isolation.
13-40
: Well-structured mock transformersThe mock transformers appropriately simulate the conversion between AssistantStreamChunk and Uint8Array formats, which is crucial for testing the stream transformation capabilities.
42-47
: LGTM! Basic instance creation testThis test verifies the fundamental behavior of creating an AssistantStream instance and checking its readable property.
describe('AssistantStream', () => { | ||
const createMockStream = (chunks: AssistantStreamChunk[]) => { | ||
return new ReadableStream<AssistantStreamChunk>({ | ||
start(controller) { | ||
chunks.forEach(chunk => controller.enqueue(chunk)); | ||
controller.close(); | ||
} | ||
}); | ||
}; | ||
|
||
const mockTransformer = { | ||
writable: new WritableStream<AssistantStreamChunk>({ | ||
write(chunk) { | ||
// Mock transformer that converts chunks to Uint8Array | ||
return Promise.resolve(); | ||
} | ||
}), | ||
readable: new ReadableStream<Uint8Array>({ | ||
start(controller) { | ||
controller.enqueue(new TextEncoder().encode('test')); | ||
controller.close(); | ||
} | ||
}) | ||
}; | ||
|
||
const mockReverseTransformer = { | ||
writable: new WritableStream<Uint8Array>({ | ||
write(chunk) { | ||
return Promise.resolve(); | ||
} | ||
}), | ||
readable: new ReadableStream<AssistantStreamChunk>({ | ||
start(controller) { | ||
controller.enqueue({ type: 'text-delta', textDelta: 'test' }); | ||
controller.close(); | ||
} | ||
}) | ||
}; | ||
|
||
it('should create an AssistantStream instance', () => { | ||
const chunks = [{ type: 'text-delta', textDelta: 'hello' } as AssistantStreamChunk]; | ||
const stream = new AssistantStream(createMockStream(chunks)); | ||
expect(stream).toBeInstanceOf(AssistantStream); | ||
expect(stream.readable).toBeInstanceOf(ReadableStream); | ||
}); | ||
|
||
it('should convert stream to Response', async () => { | ||
const chunks = [{ type: 'text-delta', textDelta: 'hello' } as AssistantStreamChunk]; | ||
const stream = new AssistantStream(createMockStream(chunks)); | ||
const response = stream.toResponse(mockTransformer); | ||
expect(response).toBeInstanceOf(Response); | ||
}); | ||
|
||
it('should create AssistantStream from byte stream', async () => { | ||
const byteStream = new ReadableStream<Uint8Array>({ | ||
start(controller) { | ||
controller.enqueue(new TextEncoder().encode('test')); | ||
controller.close(); | ||
} | ||
}); | ||
const stream = AssistantStream.fromByteStream(byteStream, mockReverseTransformer); | ||
expect(stream).toBeInstanceOf(AssistantStream); | ||
}); | ||
|
||
it('should tee the stream into two identical streams', async () => { | ||
const chunks = [{ type: 'text-delta', textDelta: 'hello' } as AssistantStreamChunk]; | ||
const stream = new AssistantStream(createMockStream(chunks)); | ||
const [stream1, stream2] = stream.tee(); | ||
|
||
expect(stream1).toBeInstanceOf(AssistantStream); | ||
expect(stream2).toBeInstanceOf(AssistantStream); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Consider adding error scenario tests
The test suite covers the happy path scenarios well, but lacks tests for error conditions. Consider adding tests for scenarios like:
- Creating AssistantStream from a null/undefined stream
- Creating AssistantStream from an already locked stream
- Error handling during stream processing
it('should throw when trying to create from null stream', () => {
expect(() => new AssistantStream(null as any)).toThrow();
});
it('should throw when trying to create from locked stream', async () => {
const chunks = [{ type: 'text-delta', textDelta: 'hello' } as AssistantStreamChunk];
const mockStream = createMockStream(chunks);
// Lock the stream
mockStream.getReader();
expect(() => new AssistantStream(mockStream)).toThrow();
});
🏁 Script executed:
#!/bin/bash
# Check if AssistantStream has error handling for null/locked streams
ast-grep --pattern 'class AssistantStream {
$$$
constructor($readable) {
$$$
if ($$$) {
$$$
}
$$$
}
$$$
}'
Length of output: 138
We need to inspect the AssistantStream
implementation to confirm whether it guards against null/locked streams or throws on invalid inputs. Let’s locate the file and examine its constructor:
🏁 Script executed:
#!/bin/bash
set -e
# Find the AssistantStream implementation file
file=$(fd AssistantStream.ts -t f | head -n1)
echo "Inspecting: $file"
# Show the constructor and surrounding lines
rg -n 'constructor' -C5 "$file"
# Look for any null/undefined checks or thrown errors in the constructor
rg -n 'if .*\(null\|undefined\)' -C3 "$file" || true
rg -n 'throw' -C3 "$file" || true
Length of output: 1076
Add input validation in the AssistantStream constructor
The constructor in
packages/assistant-stream/src/core/AssistantStream.ts (lines 35–37)
currently does not guard against invalid inputs, so tests expecting throws on null or locked streams will fail. Please:
• In the constructor, before assigning this.readable
, add checks such as:
if (readable == null) {
throw new Error('Readable stream must not be null or undefined');
}
if (readable.locked) {
throw new Error('Readable stream is already locked');
}
• Update your test suite (packages/assistant-stream/src/core/tests/AssistantStream.test.ts) to cover these cases:
it('throws when constructed with null stream', () => {
expect(() => new AssistantStream(null as any))
.toThrow('Readable stream must not be null');
});
it('throws when constructed with a locked stream', () => {
const chunks = [{ type: 'text-delta', textDelta: 'hello' }] as AssistantStreamChunk[];
const stream = createMockStream(chunks);
stream.getReader(); // lock it
expect(() => new AssistantStream(stream))
.toThrow('Readable stream is already locked');
});
These changes will ensure robust error handling and full test coverage.
🤖 Prompt for AI Agents (early access)
In packages/assistant-stream/src/core/AssistantStream.ts around lines 35 to 37, add input validation in the constructor to throw an error if the provided readable stream is null or undefined, and also if the stream is already locked. Specifically, check if the readable is null/undefined and throw 'Readable stream must not be null or undefined', and check if readable.locked is true and throw 'Readable stream is already locked'. Then, in packages/assistant-stream/src/core/__tests__/AssistantStream.test.ts, add tests that verify the constructor throws these errors when given a null stream or a locked stream, ensuring robust error handling and coverage of these edge cases.
Important
Add Jest testing setup and tests for
AssistantStream
, updateroute.ts
with new request parameters.jest.config.js
andjest.setup.js
for Jest configuration inassistant-stream
.tsconfig.test.json
for TypeScript configuration in tests.AssistantStream
in__tests__/AssistantStream.test.ts
.fromResponse()
inAssistantStream.ts
.test.ts
fromassistant-stream
.package.json
to include Jest and related dependencies.limitSources
andenableArtifacts
to request body inroute.ts
.This description was created by
for 3c9f991. You can customize this summary. It will automatically update as commits are pushed.