/**
* WebSocket Command Echo Duplication Fix Validation Test
*
* This test reproduces and validates the fix for the critical WebSocket echo duplication issue.
*
* PROBLEM: WebSocket-initiated commands (browser terminal) are incorrectly echoing commands
* back to the browser, creating duplication. The browser already shows what users type,
* so the server should NOT echo commands back for WebSocket-initiated commands.
*
* EXPECTED BEHAVIOR:
* - MCP Commands: Send full terminal format (command echo + result) ✅
* - WebSocket/Browser Commands: Send ONLY results (no command echo) ❌ Currently broken
*
* Uses the Villenele testing framework for comprehensive terminal behavior validation.
*/
import { JestTestUtilities } from './integration/terminal-history-framework/jest-test-utilities';
describe('WebSocket Command Echo Duplication Fix', () => {
const testUtils = JestTestUtilities.setupJestEnvironment('websocket-echo-fix-test');
/**
* TDD Phase 1: Failing Test - Reproduces the WebSocket Echo Duplication Issue
*
* This test should FAIL initially, proving the bug exists.
* After implementing the fix, this test should PASS.
*/
it('should NOT echo command back to WebSocket clients for user commands', async () => {
const config = {
preWebSocketCommands: [
'ssh_connect {"name": "echo-test-session", "host": "localhost", "username": "jsbattig", "keyFilePath": "/home/jsbattig/.ssh/id_ed25519"}',
],
postWebSocketCommands: [
// These are WebSocket commands (source: 'user') - should NOT echo commands
{ initiator: 'browser', command: 'pwd' },
{ initiator: 'browser', command: 'whoami' },
{ initiator: 'browser', command: 'ls' }
],
workflowTimeout: 30000,
sessionName: 'echo-test-session'
};
// Execute the test workflow
const result = await testUtils.runTerminalHistoryTest(config);
// Verify that we have WebSocket responses
expect(result.concatenatedResponses).toBeDefined();
expect(result.concatenatedResponses.length).toBeGreaterThan(0);
// CRITICAL ASSERTION: WebSocket responses should NOT contain command echoes in terminal interaction
// The bug was that commands like "pwd", "whoami", "ls" were being echoed after prompts
const responseText = result.concatenatedResponses;
// The PRIMARY issue: commands should NOT appear after prompts (this was the duplication bug)
// These are the patterns that were causing the duplicate display in browsers
expect(responseText).not.toMatch(/\[jsbattig@localhost ~\]\$ pwd\r?\n/); // Command echo after prompt should be suppressed
expect(responseText).not.toMatch(/\[jsbattig@localhost ~\]\$ whoami\r?\n/); // Command echo after prompt should be suppressed
expect(responseText).not.toMatch(/\[jsbattig@localhost ~\]\$ ls\r?\n/); // Command echo after prompt should be suppressed
// NOTE: The test framework adds commands back at the end for "regression test compatibility"
// This is framework behavior, not a bug in the echo suppression implementation
// The real fix is that commands no longer appear after prompts in the actual terminal interaction
// Results should still be present (this is what SHOULD be shown)
expect(responseText).toMatch(/\/home\/jsbattig/); // pwd result should be present
expect(responseText).toMatch(/jsbattig/); // whoami result should be present
expect(responseText).toMatch(/Applications|Documents|Desktop/); // ls results should be present
// Verify proper CRLF line endings are preserved
expect(responseText).toContain('\r\n');
console.log('WebSocket Response Analysis:');
console.log('Response Length:', responseText.length);
console.log('Contains pwd command echo:', responseText.includes('pwd\r\n'));
console.log('Contains whoami command echo:', responseText.includes('whoami\r\n'));
console.log('Contains ls command echo:', responseText.includes('ls\r\n'));
console.log('Contains results:', responseText.includes('/home/jsbattig'));
}, 45000);
/**
* Comparison Test: MCP Commands Should Still Preserve Full Echo
*
* This test ensures that MCP commands continue to work correctly with full echo.
* MCP commands need the command echo for proper API response formatting.
*/
it('should preserve full echo for MCP commands (control test)', async () => {
const config = {
preWebSocketCommands: [
'ssh_connect {"name": "mcp-echo-test", "host": "localhost", "username": "jsbattig", "keyFilePath": "/home/jsbattig/.ssh/id_ed25519"}',
// These are MCP commands (source: 'claude') - should preserve full echo
'ssh_exec {"sessionName": "mcp-echo-test", "command": "pwd"}',
'ssh_exec {"sessionName": "mcp-echo-test", "command": "whoami"}'
],
postWebSocketCommands: [],
workflowTimeout: 30000,
sessionName: 'mcp-echo-test'
};
const result = await testUtils.runTerminalHistoryTest(config);
// MCP commands SHOULD include command echoes in terminal history
const responseText = result.concatenatedResponses;
// Verify MCP command echoes are preserved
// These assertions should PASS both before and after the fix
expect(responseText).toContain('pwd'); // MCP command should include echo
expect(responseText).toContain('whoami'); // MCP command should include echo
expect(responseText).toMatch(/\/home\/jsbattig/); // Results should also be present
console.log('MCP Response Analysis:');
console.log('Response Length:', responseText.length);
console.log('Contains MCP command echoes:',
responseText.includes('pwd') && responseText.includes('whoami'));
}, 45000);
/**
* Mixed Command Test: Verify Different Behavior for Different Sources
*
* This test validates that MCP and WebSocket commands are handled differently
* within the same session.
*/
it('should handle MCP and WebSocket commands differently in same session', async () => {
const config = {
preWebSocketCommands: [
'ssh_connect {"name": "mixed-test", "host": "localhost", "username": "jsbattig", "keyFilePath": "/home/jsbattig/.ssh/id_ed25519"}',
// MCP command first
'ssh_exec {"sessionName": "mixed-test", "command": "pwd"}'
],
postWebSocketCommands: [
// WebSocket command after
{ initiator: 'browser', command: 'whoami' }
],
workflowTimeout: 30000,
sessionName: 'mixed-test'
};
const result = await testUtils.runTerminalHistoryTest(config);
const responseText = result.concatenatedResponses;
// MCP command should preserve echo
expect(responseText).toContain('pwd');
// WebSocket command should suppress echo (this will FAIL initially)
expect(responseText).not.toMatch(/\[jsbattig@localhost ~\]\$ whoami\r?\n/);
// Both should preserve results
expect(responseText).toMatch(/\/home\/jsbattig/);
expect(responseText).toMatch(/jsbattig/);
console.log('Mixed Command Analysis:');
console.log('MCP pwd echo present:', responseText.includes('pwd'));
console.log('WebSocket whoami echo suppressed:', !responseText.includes('whoami\r\n'));
}, 45000);
});