import { fireEvent, render, screen } from '@testing-library/react'; import { describe, expect, it, vi } from 'vitest'; import { computeFreshness } from '../../lib/memory/memoryFreshness'; import type { GraphRelation } from '../../utils/tauriCommands/memory'; import MemoryFreshnessPanel from './MemoryFreshnessPanel'; const NOW = 1_700_000_000; const DAY = 86400; function rel(subject: string, object: string, agoDays: number): GraphRelation { return { namespace: 'n', subject, predicate: 'likes', object, attrs: {}, updatedAt: NOW - agoDays * DAY, evidenceCount: 1, orderIndex: null, documentIds: [], chunkIds: [], }; } const report = computeFreshness( [rel('You', 'Berlin', 0), rel('You', 'coffee', 30), rel('You', 'guitar', 90)], NOW ); describe('', () => { it('renders the loading skeleton', () => { render(); expect(screen.getByTestId('memory-freshness-loading')).toBeInTheDocument(); }); it('renders the empty state when there are no facts', () => { render(); expect(screen.getByText('No knowledge graph yet.')).toBeInTheDocument(); }); it('renders an error with a working retry button', () => { const onRetry = vi.fn(); render(); expect(screen.getByRole('alert').textContent).toMatch(/graph unavailable/); fireEvent.click(screen.getByRole('button', { name: 'Retry' })); expect(onRetry).toHaveBeenCalledTimes(1); }); it('renders status tiles and the re-confirm queue (non-fresh facts only)', () => { render(); expect(screen.getByText('Fresh')).toBeInTheDocument(); expect(screen.getByText('Fading')).toBeInTheDocument(); expect(screen.getByText('Stale')).toBeInTheDocument(); expect(screen.getByText('Re-confirm queue')).toBeInTheDocument(); // The stale 'guitar' fact and fading 'coffee' fact are in the queue... expect(screen.getByText(/guitar/)).toBeInTheDocument(); expect(screen.getByText(/coffee/)).toBeInTheDocument(); // ...but the fresh 'Berlin' fact is not. expect(screen.queryByText(/Berlin/)).not.toBeInTheDocument(); }); it('shows the all-fresh message when nothing needs re-confirming', () => { const allFresh = computeFreshness([rel('You', 'Berlin', 0)], NOW); render(); expect( screen.getByText('Every fact is still fresh — nothing to re-confirm.') ).toBeInTheDocument(); }); it('notes when the re-confirm queue is truncated past the row cap', () => { // 60 stale facts -> the queue is capped at 50 and a "showing 50 of 60" note appears. const many = Array.from({ length: 60 }, (_, i) => rel('You', `fact${i}`, 365)); render(); expect(screen.getByText('Showing 50 of 60 — address these first.')).toBeInTheDocument(); }); });