Files
hikari-desktop/src/lib/components/SystemClock.test.ts
T
hikari f173892aaa
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 1m2s
CI / Build Linux (push) Has been cancelled
CI / Build Windows (cross-compile) (push) Has been cancelled
CI / Lint & Test (push) Has been cancelled
feat: major feature additions and improvements (#135)
## Summary

This PR includes major feature additions, bug fixes, comprehensive testing improvements, and responsive design enhancements!

## New Features โœจ

### Plugin & MCP Management (#133, #134)
- **Plugin Management Panel**: Install, uninstall, enable/disable, and update plugins
- **MCP Server Management Panel**: Add/remove MCP servers, view detailed configuration
- **Marketplace Management**: Add/remove plugin marketplaces from GitHub
- Backend commands for full CLI integration (`list_plugins`, `install_plugin`, `add_mcp_server`, etc.)
- Beautiful UI with proper loading states, error handling, and theme support

### Visual Todo List Panel (#132)
- Real-time todo list display when Hikari uses the `TodoWrite` tool
- Shows pending/in-progress/completed status with visual indicators
- Progress bar and completion count
- Automatically clears on disconnect
- Theme-aware styling

### Clear Session History Button (#130)
- "Clear All Sessions" button in Session History panel
- Confirmation dialog with session count
- Keyboard support and accessibility features
- Gives users control over disk usage

### CLI Version Display (#131)
- Displays Claude CLI version in status bar
- Auto-polls every 30 seconds for updates
- Useful for debugging and feature compatibility

## Bug Fixes ๐Ÿ›

### Stats Panel Scrolling (#136)
- **Fixed stats panel overflow**: Added scrollable container with `max-height` constraint
- Stats panel now scrolls when content (Tools Used, Historical Costs, Budget sections) gets too long
- Prevents content from overflowing off screen

### Agent Monitor Fixes (#122)
- **Fixed agents stuck in "running" state**: Added `SubagentStop` hook parsing
- **Fixed agents persisting after disconnect**: Call `clearConversation()` on disconnect
- **Fixed "Kill All" button**: Now properly marks all agents as errored
- **Fixed badge persisting after tab close**: Cleanup agents when conversation is deleted
- Comprehensive tests for agent lifecycle management

### Discord RPC Cleanup (#129)
- Removed file-based logging for Discord RPC
- Replaced with proper `tracing` framework usage
- Reduces disk usage and eliminates maintenance burden

### Close Modal Bug Fix (#128)
- Fixed close confirmation modal not triggering after Discord RPC refactor
- Removed frontend calls to deleted `log_discord_rpc` command
- Modal now works correctly after all operations

### Responsive Design Fixes (#118)
- Fixed top navigation icons getting cut off at small screen widths
- Fixed Connect button disappearing on narrow screens
- Fixed bottom status info (clock, CLI version) getting cut off
- Added flex-wrap and mobile-optimised layouts
- Icons-only mode on screens < 640px
- Vertical stacking on screens < 768px

## Testing Improvements ๐Ÿงช

### Comprehensive Test Coverage (#114)
- **417 backend tests** (up from 408)
- **387 frontend tests** (up from 363)
- **61%+ backend code coverage**
- Added E2E integration tests for cross-platform notification commands
- New test files: `agents.test.ts`, comprehensive CLI parsing tests
- Tests for `debug_logger.rs`, `bridge_manager.rs`, `notifications.rs`
- Console mocking for cleaner test output
- Fixed flaky frontend tests

### Testing Documentation
- Updated CLAUDE.md with comprehensive testing guidelines
- Documented mocking approaches (console mocking, E2E command structure testing)
- Added step-by-step guide for adding tests to new features
- Goal to maintain ~100% test coverage documented

## Closes

Closes #114
Closes #118
Closes #122
Closes #128
Closes #129
Closes #130
Closes #131
Closes #132
Closes #133
Closes #134
Closes #136

## Technical Details

- All new backend commands properly registered in `lib.rs`
- CLI output parsing with comprehensive test coverage
- Cross-platform compatibility verified through E2E tests (Linux CI can test Windows commands)
- Theme-aware UI components using CSS variables throughout
- Proper TypeScript types for all new stores and components
- ESLint and Prettier compliant
- All Clippy warnings addressed

โœจ This PR was created with help from Hikari~ ๐ŸŒธ

Reviewed-on: #135
Co-authored-by: Hikari <hikari@nhcarrigan.com>
Co-committed-by: Hikari <hikari@nhcarrigan.com>
2026-02-07 21:15:41 -08:00

150 lines
4.6 KiB
TypeScript

/**
* SystemClock Component Tests
*
* Note: This file tests the time formatting logic used by the SystemClock component.
* Full component rendering tests are challenging with Svelte 5 + @testing-library/svelte
* due to SSR/CSR compatibility issues. The component itself is simple and visually
* testable - it displays the current date and time, updating every second.
*
* What this component does:
* - Displays date in British format: "7 February 2026"
* - Displays time in 24-hour format: "14:35:42"
* - Updates every second via setInterval
* - Cleans up interval on unmount via $effect
*
* Manual testing checklist:
* - [ ] Clock appears above the Send button
* - [ ] Time updates every second
* - [ ] Date format is "DD Month YYYY"
* - [ ] Time format is "HH:MM:SS" (24-hour)
* - [ ] Hover effect works (border turns accent colour)
*/
import { describe, it, expect } from "vitest";
// Helper function that mirrors the component's formatting logic
function formatDateTime(date: Date): string {
const day = date.getDate();
const month = date.toLocaleString("en-GB", { month: "long" });
const year = date.getFullYear();
const hours = String(date.getHours()).padStart(2, "0");
const minutes = String(date.getMinutes()).padStart(2, "0");
const seconds = String(date.getSeconds()).padStart(2, "0");
return `${day} ${month} ${year}, ${hours}:${minutes}:${seconds}`;
}
describe("SystemClock date/time formatting", () => {
it("formats date in British format (DD Month YYYY)", () => {
// Use local timezone (not UTC) since the component uses local time
const date = new Date(2026, 1, 7, 14, 35, 42); // Feb 7, 2026 14:35:42 local
const formatted = formatDateTime(date);
expect(formatted).toContain("7 February 2026");
});
it("formats time in 24-hour format (HH:MM:SS)", () => {
const date = new Date(2026, 1, 7, 14, 35, 42);
const formatted = formatDateTime(date);
// Should have the pattern HH:MM:SS
expect(formatted).toMatch(/\d{2}:\d{2}:\d{2}/);
expect(formatted).toContain("14:35:42");
});
it("combines date and time with comma separator", () => {
const date = new Date(2026, 1, 7, 14, 35, 42);
const formatted = formatDateTime(date);
expect(formatted).toBe("7 February 2026, 14:35:42");
});
it("pads single-digit hours, minutes, and seconds with zeros", () => {
const date = new Date(2026, 1, 7, 3, 5, 8);
const formatted = formatDateTime(date);
// Should have leading zeros: 03:05:08, not 3:5:8
expect(formatted).toContain("03:05:08");
});
it("handles different months correctly", () => {
const date = new Date(2026, 11, 25, 12, 0, 0); // December is month 11
const formatted = formatDateTime(date);
expect(formatted).toContain("25 December 2026");
});
it("handles year changes correctly", () => {
const date = new Date(2027, 0, 1, 0, 0, 0); // January is month 0
const formatted = formatDateTime(date);
expect(formatted).toContain("1 January 2027");
expect(formatted).toContain("00:00:00");
});
it("handles midnight correctly", () => {
const date = new Date(2026, 1, 7, 0, 0, 0);
const formatted = formatDateTime(date);
expect(formatted).toContain("00:00:00");
});
it("handles noon correctly", () => {
const date = new Date(2026, 1, 7, 12, 0, 0);
const formatted = formatDateTime(date);
// 24-hour format, so noon is 12:00:00, not 00:00:00
expect(formatted).toContain("12:00:00");
});
it("handles end of day correctly", () => {
const date = new Date(2026, 1, 7, 23, 59, 59);
const formatted = formatDateTime(date);
expect(formatted).toContain("23:59:59");
});
it("handles month boundaries correctly", () => {
// Last day of January
const jan31 = new Date(2026, 0, 31, 23, 59, 59);
expect(formatDateTime(jan31)).toContain("31 January 2026");
// First day of February
const feb1 = new Date(2026, 1, 1, 0, 0, 0);
expect(formatDateTime(feb1)).toContain("1 February 2026");
});
it("handles leap year February correctly", () => {
// 2024 is a leap year
const feb29 = new Date(2024, 1, 29, 12, 0, 0);
const formatted = formatDateTime(feb29);
expect(formatted).toContain("29 February 2024");
});
it("handles all 12 months correctly", () => {
const months = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
];
months.forEach((month, index) => {
const date = new Date(2026, index, 15, 12, 0, 0);
const formatted = formatDateTime(date);
expect(formatted).toContain(month);
});
});
});