import { describe, test, expect } from '@jest/globals';
describe('Claude Code Cancellation Tests', () => {
test('should handle AbortSignal properly', () => {
// Create an AbortController
const controller = new AbortController();
const signal = controller.signal;
// Track if abort listener was called
let abortHandlerCalled = false;
signal.addEventListener('abort', () => {
abortHandlerCalled = true;
});
// Abort the signal
controller.abort();
expect(signal.aborted).toBe(true);
expect(abortHandlerCalled).toBe(true);
});
test('should propagate cancellation to Claude Code AbortController', () => {
// Simulate MCP abort signal
const mcpController = new AbortController();
const mcpSignal = mcpController.signal;
// Simulate Claude Code abort controller
const claudeController = new AbortController();
// Set up the listener (mimicking our implementation)
mcpSignal.addEventListener('abort', () => {
claudeController.abort();
});
// Initially, neither should be aborted
expect(mcpSignal.aborted).toBe(false);
expect(claudeController.signal.aborted).toBe(false);
// Abort MCP signal
mcpController.abort();
// Both should now be aborted
expect(mcpSignal.aborted).toBe(true);
expect(claudeController.signal.aborted).toBe(true);
});
test('should format cancellation result correctly', () => {
const cancelledResult = {
success: false,
summary: 'Query cancelled by user',
error: 'cancelled'
};
expect(cancelledResult.success).toBe(false);
expect(cancelledResult.error).toBe('cancelled');
expect(cancelledResult.summary).toContain('cancelled');
});
test('should identify AbortError correctly', () => {
// Create a mock AbortError
const abortError = new Error('The operation was aborted');
abortError.name = 'AbortError';
const isCancellation = abortError.name === 'AbortError';
expect(isCancellation).toBe(true);
// Regular error should not be identified as cancellation
const regularError = new Error('Something went wrong');
const isRegularCancellation = regularError.name === 'AbortError';
expect(isRegularCancellation).toBe(false);
});
test('should break loop on cancellation', async () => {
const messages = [];
const signal = { aborted: false };
// Simulate message processing
const mockMessages = ['msg1', 'msg2', 'msg3', 'msg4', 'msg5'];
for (const msg of mockMessages) {
// Simulate cancellation after 2 messages
if (messages.length === 2) {
signal.aborted = true;
}
if (signal.aborted) {
break;
}
messages.push(msg);
}
// Should only have processed 2 messages before cancellation
expect(messages).toHaveLength(2);
expect(messages).toEqual(['msg1', 'msg2']);
});
});