Skip to main content
Glama
extra-crlf-after-completion-bug.test.ts6.17 kB
/** * Extra CRLF After Command Completion Bug Test * * This test reproduces the specific bug where an extra blank line appears * after command completion in browser terminals. * * BUG DESCRIPTION: * After commands complete, there's an extra blank line appearing: * ``` * [jsbattig@localhost ~]$ pwd * /home/jsbattig * [jsbattig@localhost ~]$ * * ``` * * EXPECTED: Final prompt should end immediately after `[jsbattig@localhost ~]$ ` * without the extra CRLF. * * FAILING TEST: This test should fail until the bug is fixed. */ import { JestTestUtilities } from './integration/terminal-history-framework/jest-test-utilities'; describe('Extra CRLF After Command Completion Bug - TDD', () => { const testUtils = JestTestUtilities.setupJestEnvironment('extra-crlf-bug-test'); it('should NOT have extra CRLF after command completion (TDD fix verification)', async () => { // ARRANGE - Simple test to verify fix for the extra CRLF bug const config = { preWebSocketCommands: [ 'ssh_connect {"name": "extra-crlf-test", "host": "localhost", "username": "jsbattig", "keyFilePath": "~/.ssh/id_ed25519"}', 'ssh_exec {"sessionName": "extra-crlf-test", "command": "pwd"}' ], postWebSocketCommands: [], workflowTimeout: 15000, sessionName: 'extra-crlf-test' }; console.log('🐛 Testing for extra CRLF after command completion (fix verification)...'); try { // ACT - Run the terminal history test const result = await testUtils.runTerminalHistoryTest(config); // ASSERT - Check for the specific extra CRLF bug expect(result).toBeDefined(); if (result.success && result.concatenatedResponses.length > 0) { const terminalOutput = result.concatenatedResponses; console.log('📄 Terminal output for extra CRLF analysis:'); console.log('Raw output:', JSON.stringify(terminalOutput)); // Print last 20 characters with their codes to debug console.log('📄 Last 20 characters with codes:'); const start = Math.max(0, terminalOutput.length - 20); for (let i = start; i < terminalOutput.length; i++) { const char = terminalOutput[i]; const code = char.charCodeAt(0); console.log(`[${i}]: "${char}" (${code}) ${code === 13 ? '<CR>' : code === 10 ? '<LF>' : ''}`); } // CRITICAL TEST: Ensure final prompt does NOT have trailing CRLF const finalPromptPattern = /\[jsbattig@localhost ~\]\$ $/; expect(terminalOutput).toMatch(finalPromptPattern); console.log('✅ Final prompt ends correctly without extra CRLF'); // NEGATIVE TEST: Should NOT have extra CRLF pattern const extraCRLFPattern = /\[jsbattig@localhost ~\]\$ \r\n$/; expect(terminalOutput).not.toMatch(extraCRLFPattern); console.log('✅ No extra CRLF pattern detected after final prompt'); // Validate that command results still have proper CRLF const commandResultPattern = /\/home\/jsbattig\r\n/; expect(terminalOutput).toMatch(commandResultPattern); console.log('✅ Command results still have proper CRLF formatting'); } else { console.log('❌ Test failed or no output captured'); console.log('📋 Test result:', result); if (result.error) { throw new Error(`Test execution failed: ${result.error}`); } else { throw new Error('No terminal output captured for extra CRLF validation'); } } } catch (error) { console.log('❌ Extra CRLF test encountered error:', error); if (error instanceof Error) { console.log('🔍 Error details:', error.message); console.log('📍 Stack trace:', error.stack); } throw error; } }, 20000); it('should show exact character sequence after command completion for debugging', async () => { // DEBUGGING TEST: Show the exact character sequence to understand the bug const config = { preWebSocketCommands: [ 'ssh_connect {"name": "debug-crlf-test", "host": "localhost", "username": "jsbattig", "keyFilePath": "~/.ssh/id_ed25519"}', 'ssh_exec {"sessionName": "debug-crlf-test", "command": "echo test"}' ], postWebSocketCommands: [], workflowTimeout: 15000, sessionName: 'debug-crlf-test' }; console.log('🔬 Debugging exact character sequence after command completion...'); try { const result = await testUtils.runTerminalHistoryTest(config); if (result.success && result.concatenatedResponses.length > 0) { const terminalOutput = result.concatenatedResponses; // Show every character with its code console.log('📄 Character-by-character analysis:'); for (let i = 0; i < Math.min(terminalOutput.length, 200); i++) { const char = terminalOutput[i]; const code = char.charCodeAt(0); console.log(`[${i}]: "${char}" (${code}) ${code === 13 ? '<CR>' : code === 10 ? '<LF>' : ''}`); } // Show the last 50 characters with codes console.log('📄 Last 50 characters analysis:'); const start = Math.max(0, terminalOutput.length - 50); for (let i = start; i < terminalOutput.length; i++) { const char = terminalOutput[i]; const code = char.charCodeAt(0); console.log(`[${i}]: "${char}" (${code}) ${code === 13 ? '<CR>' : code === 10 ? '<LF>' : ''}`); } // Count CRLF sequences const crlfCount = (terminalOutput.match(/\r\n/g) || []).length; const crCount = (terminalOutput.match(/\r/g) || []).length; const lfCount = (terminalOutput.match(/\n/g) || []).length; console.log(`📊 CRLF Statistics:`); console.log(` CRLF sequences (\\r\\n): ${crlfCount}`); console.log(` CR characters (\\r): ${crCount}`); console.log(` LF characters (\\n): ${lfCount}`); } else { throw new Error('Failed to capture terminal output for debugging'); } } catch (error) { console.log('❌ Debug test failed:', error); throw error; } }, 20000); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/LightspeedDMS/ssh-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server