Added missing 'success: true' property to all mock ContainerActionResponse
objects in the test file. These were causing TypeScript compilation errors
during the Next.js build process (tsc --noEmit), even though Jest tests
were passing.
The ContainerActionResponse interface requires the 'success' property,
but the mocks were only providing 'message'. This caused CI builds to fail
while local Jest tests passed because Jest's TypeScript handling is more
lenient than Next.js's build-time type checking.
Fixed:
- mockApiClient.startContainer responses (2 occurrences)
- mockApiClient.stopContainer response
- mockApiClient.restartContainer response
- mockApiClient.removeContainer response
Verified:
- npx tsc --noEmit: ✓ No TypeScript errors
- npm test: ✓ All tests pass
- npm run build: ✓ Build succeeds
https://claude.ai/code/session_7d4f1b7d-7a0d-44db-b437-c76b6b61dfb2
The previous change to use next/font/google caused build failures in CI
because Next.js tries to download fonts from Google Fonts during build time,
which fails with TLS/network errors in restricted environments.
Changes:
- Removed next/font/google dependency from app/layout.tsx
- Reverted to simpler approach without external font dependencies
- Added missing properties to CommandResponse interface:
- workdir: string (used by useSimpleTerminal)
- exit_code: number (used to determine output vs error type)
- Fixed TypeScript error in useSimpleTerminal.ts by ensuring content
is always a string with || '' fallback
Verified:
- npm run build: ✓ Builds successfully
- npm run lint: ✓ 0 errors, 0 warnings
- npm test: ✓ 282/282 unit tests passing
This fixes the CI build failures in:
- Build and Push to GHCR workflow
- Run Tests / frontend-tests workflow
https://claude.ai/code/session_7d4f1b7d-7a0d-44db-b437-c76b6b61dfb2
- Add jest.d.ts to include @testing-library/jest-dom types
- Fix dashboard test mock to include all required props (isAuthenticated, authLoading, isLoading, hasContainers)
- Fix authSlice test by properly typing the Redux store
- Fix useInteractiveTerminal test by adding type annotation to props parameter
- Update tsconfig.json to include jest.d.ts
All TypeScript errors are now resolved and the build passes successfully.
https://claude.ai/code/session_01KrwCxjP4joh9CFAtreiBFu
The terminal was rapidly connecting and disconnecting because handleFallback
in useTerminalModalState was not memoized, causing useInteractiveTerminal's
useEffect to re-run on every render. Added useCallback to all handlers and
created tests to catch handler stability regressions.
https://claude.ai/code/session_016MofX7DkHvBM43oTXB2D9y
Frontend improvements:
- Refactor useSimpleTerminal tests with it.each for empty/whitespace commands
- Add test for missing workdir in API response (100% branch coverage)
- Refactor DashboardHeader tests to parameterize container count variations
- Refactor LoginForm tests to parameterize input field changes
- Refactor ContainerCard tests to parameterize status border colors
- Add TerminalModal tests for FallbackNotification and isMobile dimensions
- Total: 254 passing tests, 76.94% coverage
Backend improvements:
- Refactor auth tests with pytest.parametrize for missing/empty fields
- Refactor container action tests with pytest.parametrize for start/stop/restart
- Maintains 100% backend coverage across all modules
- Total: 120 passing tests, 100% coverage
Benefits of parameterized tests:
- Reduced code duplication
- Easier to add new test cases
- Better test coverage with less code
- More maintainable test suite
https://claude.ai/code/session_mmQs0
- Improved useLoginForm tests to 100% coverage
- Added success path test (navigation to dashboard)
- Added failure path test (shake animation)
- Added tests for both success and failure branches
- Improved useTerminalModal tests to 100% coverage
- Added test for setTimeout behavior (300ms delay)
- Verified selectedContainer clears after close animation
- Enhanced LoginForm tests to 100% statements
- Added error state rendering test
- Added disabled button state test
Total: 235 passing tests (up from 229)
Coverage: 76.79% (up from 76.34%)
- useLoginForm.ts: 90.9% → 100%
- useTerminalModal.ts: 91.66% → 100%
https://claude.ai/code/session_mmQs0
This commit adds tests to catch the WebSocket transport misconfiguration
that caused "Invalid frame header" errors. The original test suite didn't
catch this because it was an infrastructure-level issue, not a code bug.
New Tests Added:
Frontend (frontend/lib/hooks/__tests__/useInteractiveTerminal.test.tsx):
- Verify Socket.IO client uses polling-only transport
- Ensure WebSocket is NOT in transports array
- Validate HTTP URL is used (not WebSocket URL)
- Confirm all event handlers are registered
- Test cleanup on unmount
Backend (backend/tests/test_websocket.py):
- TestSocketIOConfiguration class added
- Verify SocketIO async_mode, ping_timeout, ping_interval
- Confirm CORS is enabled
- Validate /terminal namespace registration
Documentation (TESTING.md):
- Explains why original tests didn't catch this issue
- Documents testing gaps (environment, mocking, integration)
- Provides recommendations for E2E, monitoring, error tracking
- Outlines testing strategy and coverage goals
Why Original Tests Missed This:
1. Environment Gap: Tests run locally where WebSocket works
2. Mock-Based: SocketIOTestClient doesn't simulate proxies/CDNs
3. No Infrastructure Tests: Didn't validate production-like setup
These new tests will catch configuration errors in code, but won't catch
infrastructure issues (Cloudflare blocking, proxy misconfig, etc.). For
those, we recommend E2E tests, synthetic monitoring, and error tracking
as documented in TESTING.md.
https://claude.ai/code/session_mmQs0
This change resolves the WebSocket connection error that occurs when Cloudflare
or other reverse proxies block WebSocket upgrade attempts.
Changes:
- Frontend: Configure Socket.IO client to use polling-only transport
- Backend: Add documentation comment about transport configuration
- Remove WebSocket URL conversion (no longer needed for polling)
The error occurred because:
1. Socket.IO started with HTTP polling (successful)
2. Attempted to upgrade to WebSocket (blocked by Cloudflare)
3. Browser received invalid/blocked frames causing "Invalid frame header"
4. Eventually fell back to polling (working)
With this fix:
- Socket.IO uses HTTP long-polling exclusively
- No WebSocket upgrade attempts
- No "Invalid frame header" errors
- Connection remains stable through Cloudflare
Polling transport provides equivalent functionality and reliability.
https://claude.ai/code/session_mmQs0
Changed interactive terminal from Ubuntu purple theme to authentic GNOME
Terminal color scheme for better Linux desktop terminal experience.
Changes:
- Background: #2E3436 (dark gray, GNOME Terminal default)
- Foreground: #D3D7CF (light gray text)
- Updated all 16 ANSI colors to match GNOME Terminal palette
- Added selection colors (#4A90D9 background)
- Updated container styling with darker borders
- Increased padding for better readability
The terminal now looks and feels like GNOME Terminal. Full interactive
functionality works with xterm.js when connected to running Docker
containers via WebSocket.
https://claude.ai/code/session_011PzvkCnVrsatoxbY3HbGXz
Added ref availability check with retry logic to ensure terminal DOM
element is ready before xterm initialization. This fixes the issue where
xterm.js would fail to render because terminalRef.current was null when
the useEffect ran.
Changes:
- Wait up to 1 second for terminalRef to become available
- Add mounted flag to prevent state updates after unmount
- Add console logging for better debugging
- Prevent fallback calls after component unmount
Tested with Playwright to verify xterm now initializes and renders correctly.
https://claude.ai/code/session_011PzvkCnVrsatoxbY3HbGXz
Changed Socket.IO transport order from ['websocket', 'polling'] to
['polling', 'websocket'] in the frontend terminal hook.
Why this fixes the issue:
- Cloudflare blocks direct WebSocket connections with 400 Bad Request
- HTTP polling works perfectly and bypasses Cloudflare's WebSocket protection
- Socket.IO now connects via polling first, then attempts upgrade to WebSocket
- If WebSocket upgrade fails (due to Cloudflare), connection stays on polling
- This ensures reliable connectivity without requiring Cloudflare config changes
Testing script included demonstrates:
✓ Polling transport: WORKS
✗ Direct WebSocket: BLOCKED by Cloudflare
✓ Auto-upgrade (polling→websocket): WORKS with graceful fallback
https://claude.ai/code/session_01SePwA78FSw4urCoyR2cqFh
Toolbar buttons were appearing greyed out due to MUI's default disabled
styling (0.38 opacity). Added custom disabled state styling with:
- 0.5 opacity for better visibility
- Muted background and border colors
- Clear visual distinction from enabled state
Also added hover effect with cyan glow to make enabled buttons more
interactive and easier to identify.
https://claude.ai/code/session_k071w
Install testing dependencies:
- Jest and jest-environment-jsdom for test runner
- React Testing Library for component testing
- @testing-library/user-event for user interaction simulation
- @types/jest for TypeScript support
Configure Jest:
- Next.js Jest configuration with jsdom environment
- Mock window.matchMedia, localStorage, and fetch
- Setup test paths and coverage collection
Add test coverage:
- Utility functions (terminal formatPrompt and highlightCommand)
- Redux store (authSlice async thunks and reducers)
- Custom hooks (useLoginForm, useAuthRedirect, useTerminalModal)
- React components (LoginForm, TerminalHeader, ContainerHeader, ContainerInfo, EmptyState)
Test results: 59 tests passing across 10 test suites
https://claude.ai/code/session_G4kZm
Move all TypeScript interfaces from component files to /lib/interfaces folder
Move terminal utility functions to /lib/utils folder
Update all component imports to use centralized interfaces and utilities
Fix JSX.Element type to React.ReactElement in terminal utils
This improves code organization and reduces duplication across components
https://claude.ai/code/session_G4kZm
- Extract login form logic into useLoginForm hook
- Create useAuthRedirect hook for auth-based navigation
- Refactor LoginForm component to use useLoginForm (147 -> 135 LOC)
- Refactor login page to use useAuthRedirect (23 -> 14 LOC)
- Update dashboard to use useAuthRedirect for cleaner code
- Improve code reusability and testability
https://claude.ai/code/session_01U3wVqokhrL3dTeq2dTq73n
- Memoize auth error callback with useCallback to prevent recreation
- Use useAppDispatch hook instead of direct store.dispatch
- Update initAuth to retrieve and persist username from localStorage
- Add getUsername/setUsername methods to API client
- Remove unused auth.tsx context file to avoid confusion
- Fix router dependency issue with proper memoization
Fixes all issues raised in PR #14 code review
https://claude.ai/code/session_01U3wVqokhrL3dTeq2dTq73n
- Install Redux Toolkit and React Redux
- Create Redux store with auth slice for centralized state management
- Implement global auth error handler to redirect to login on auth failures
- Update API client to trigger auth errors on 401 responses
- Replace React Context auth with Redux throughout the app
- Fix logout button to properly clear auth state and redirect
- Add automatic redirect to dashboard when already logged in on login page
- Add automatic redirect to login when not authenticated on dashboard
- Improve error handling for all container API methods
https://claude.ai/code/session_01U3wVqokhrL3dTeq2dTq73n
- Added backend API endpoints for start/stop/restart/remove container operations
- Updated frontend API client with new container control methods
- Added start/stop/restart/remove buttons to ContainerCard with status-based visibility
- Added confirmation dialog for container removal
- Improved AppBar responsiveness with icon-only buttons on mobile screens
- Enhanced TerminalModal responsiveness:
* Fullscreen mode on mobile devices
* Stacked input layout on small screens
* Icon-only send button on mobile
* Responsive font sizes and spacing
- Added responsive typography using clamp() for fluid scaling
- Improved spacing and layout for mobile devices:
* Reduced padding on small screens
* Responsive grid layout for container metadata
* Adaptive title sizes
- Added real-time notifications with Snackbar for operation feedback
https://claude.ai/code/session_01UFVy14uUD5Q7DjkUSgUFXC