diff --git a/web/src/components/ui/list/createChatRecord.test.ts b/web/src/components/ui/list/createChatRecord.test.ts index 21e1a51f8..dec00d9ad 100644 --- a/web/src/components/ui/list/createChatRecord.test.ts +++ b/web/src/components/ui/list/createChatRecord.test.ts @@ -1,155 +1,159 @@ import { createChatRecord } from './createChatRecord'; -import * as dateLib from '@/lib/date'; - -// Mock the date utilities to have consistent test results -jest.mock('@/lib/date'); - -interface MockDate { - subtract: jest.Mock; - startOf?: jest.Mock; -} +import dayjs from 'dayjs'; describe('createChatRecord', () => { - beforeEach(() => { - jest.clearAllMocks(); - }); + // Create test dates based on current time + const now = dayjs(); + const today = now.format(); + const yesterday = now.subtract(1, 'day').format(); + const threeDaysAgo = now.subtract(3, 'day').format(); + const tenDaysAgo = now.subtract(10, 'day').format(); - test('should categorize items by date', () => { - // Set up mocks for specific date conditions - const mockToday: MockDate = { - subtract: jest.fn(() => ({ - startOf: jest.fn().mockReturnThis(), - subtract: jest.fn() - })) - }; - - // Set up mock implementations - (dateLib.getNow as jest.Mock).mockReturnValue(mockToday); - - // Based on the debug output, we need to adjust our expectations - // "today" goes to TODAY, "last-week" goes to LAST_WEEK, everything else to ALL_OTHERS - (dateLib.isDateSame as jest.Mock).mockImplementation(({ date }) => { - return date === 'today'; - }); - - (dateLib.isDateAfter as jest.Mock).mockImplementation(({ date }) => { - return date === 'last-week'; - }); - - (dateLib.isDateBefore as jest.Mock).mockImplementation(({ date }) => { - return date === 'last-week'; - }); - - // Test data - const items = [ - { id: '1', last_edited: 'today' }, - { id: '2', last_edited: 'yesterday' }, - { id: '3', last_edited: 'last-week' }, - { id: '4', last_edited: 'old' } - ]; - - const result = createChatRecord(items); - - // Assertions based on the actual categorization behavior - expect(result.TODAY).toHaveLength(1); - expect(result.TODAY[0].id).toBe('1'); - - expect(result.YESTERDAY).toHaveLength(0); - - expect(result.LAST_WEEK).toHaveLength(1); - expect(result.LAST_WEEK[0].id).toBe('3'); - - expect(result.ALL_OTHERS).toHaveLength(2); - expect(result.ALL_OTHERS.map((i) => i.id).sort()).toEqual(['2', '4']); - }); - - test('should handle empty input array', () => { - // Mock minimal implementation needed for empty array test - (dateLib.getNow as jest.Mock).mockReturnValue({ - subtract: jest.fn().mockReturnValue({ - startOf: jest.fn().mockReturnThis() - }) - }); + // More precise yesterday times for edge case testing + const yesterdayStart = now.subtract(1, 'day').startOf('day').format(); + const yesterdayMiddle = now.subtract(1, 'day').hour(12).minute(0).second(0).format(); + const yesterdayEnd = now.subtract(1, 'day').endOf('day').format(); + test('should return empty buckets when input array is empty', () => { const result = createChatRecord([]); - expect(result.TODAY).toEqual([]); - expect(result.YESTERDAY).toEqual([]); - expect(result.LAST_WEEK).toEqual([]); - expect(result.ALL_OTHERS).toEqual([]); + expect(result).toEqual({ + TODAY: [], + YESTERDAY: [], + LAST_WEEK: [], + ALL_OTHERS: [] + }); }); - test('should handle all items in the same category', () => { - // Mock today's date - const mockToday: MockDate = { - subtract: jest.fn(() => ({ - startOf: jest.fn().mockReturnThis(), - subtract: jest.fn() - })) - }; - - // Set up mock implementations - (dateLib.getNow as jest.Mock).mockReturnValue(mockToday); - (dateLib.isDateSame as jest.Mock).mockImplementation(({ date }) => date === 'today'); - (dateLib.isDateAfter as jest.Mock).mockReturnValue(false); - (dateLib.isDateBefore as jest.Mock).mockReturnValue(false); - - const items = [ - { id: '1', last_edited: 'today' }, - { id: '2', last_edited: 'today' }, - { id: '3', last_edited: 'today' } + test('should categorize items into correct buckets', () => { + const mockData = [ + { id: '1', last_edited: today }, + { id: '2', last_edited: yesterday }, + { id: '3', last_edited: threeDaysAgo }, + { id: '4', last_edited: tenDaysAgo } ]; - const result = createChatRecord(items); + const result = createChatRecord(mockData); - expect(result.TODAY).toHaveLength(3); + // Check TODAY bucket + expect(result.TODAY.length).toBe(1); + expect(result.TODAY[0].id).toBe('1'); + + // Check YESTERDAY bucket + expect(result.YESTERDAY.length).toBe(1); + expect(result.YESTERDAY[0].id).toBe('2'); + + // Check LAST_WEEK bucket + expect(result.LAST_WEEK.length).toBe(1); + expect(result.LAST_WEEK[0].id).toBe('3'); + + // Check ALL_OTHERS bucket + expect(result.ALL_OTHERS.length).toBe(1); + expect(result.ALL_OTHERS[0].id).toBe('4'); + }); + + test('should place all items in ALL_OTHERS when all are older than a week', () => { + const mockData = [ + { id: '1', last_edited: tenDaysAgo }, + { id: '2', last_edited: now.subtract(15, 'day').format() }, + { id: '3', last_edited: now.subtract(30, 'day').format() } + ]; + + const result = createChatRecord(mockData); + + expect(result.TODAY).toHaveLength(0); expect(result.YESTERDAY).toHaveLength(0); expect(result.LAST_WEEK).toHaveLength(0); - expect(result.ALL_OTHERS).toHaveLength(0); + expect(result.ALL_OTHERS).toHaveLength(3); + expect(result.ALL_OTHERS.map((item) => item.id)).toEqual(['1', '2', '3']); }); test('should handle items with extended properties', () => { - // Mock today's date - const mockToday: MockDate = { - subtract: jest.fn(() => ({ - startOf: jest.fn().mockReturnThis(), - subtract: jest.fn() - })) + // Create an item with additional properties beyond the required id and last_edited + const extendedItem = { + id: '1', + last_edited: today, + name: 'Test Item', + created_by: 'user-123', + updated_at: '2025-04-22T20:40:31.672893+00:00', + extra_field: 'some value' }; - // Set up mock implementations - (dateLib.getNow as jest.Mock).mockReturnValue(mockToday); + const result = createChatRecord([extendedItem]); - // Based on the debug output, adjust expectations for the test case - (dateLib.isDateSame as jest.Mock).mockImplementation(({ date }) => { - if (date.includes('today')) return true; - return false; - }); + // Verify the item is placed in TODAY bucket and preserves all properties + expect(result.TODAY).toHaveLength(1); + expect(result.TODAY[0]).toEqual(extendedItem); + expect(result.TODAY[0].name).toBe('Test Item'); + expect(result.TODAY[0].extra_field).toBe('some value'); + }); - (dateLib.isDateAfter as jest.Mock).mockReturnValue(false); - (dateLib.isDateBefore as jest.Mock).mockReturnValue(false); - - type ExtendedItem = { - id: string; - last_edited: string; - name: string; - count: number; - }; - - const items: ExtendedItem[] = [ - { id: '1', last_edited: 'today', name: 'Item 1', count: 5 }, - { id: '2', last_edited: 'yesterday', name: 'Item 2', count: 10 } + test('should place multiple items from yesterday in the YESTERDAY bucket', () => { + const mockData = [ + { id: 'y1', last_edited: yesterday }, + { id: 'y2', last_edited: yesterdayStart }, + { id: 'y3', last_edited: yesterdayMiddle }, + { id: 'y4', last_edited: yesterdayEnd } ]; - const result = createChatRecord(items); + const result = createChatRecord(mockData); + + expect(result.TODAY).toHaveLength(0); + expect(result.YESTERDAY).toHaveLength(4); + expect(result.LAST_WEEK).toHaveLength(0); + expect(result.ALL_OTHERS).toHaveLength(0); + + // Verify all IDs are in the YESTERDAY bucket + const yesterdayIds = result.YESTERDAY.map((item) => item.id); + expect(yesterdayIds).toContain('y1'); + expect(yesterdayIds).toContain('y2'); + expect(yesterdayIds).toContain('y3'); + expect(yesterdayIds).toContain('y4'); + }); + + test('should handle boundary cases for yesterday time', () => { + // Create dates right at the boundary of yesterday/today + const almostToday = now.startOf('day').subtract(1, 'millisecond').format(); + const barelyToday = now.startOf('day').format(); + + const mockData = [ + { id: 'still-yesterday', last_edited: almostToday }, + { id: 'barely-today', last_edited: barelyToday } + ]; + + const result = createChatRecord(mockData); + + expect(result.YESTERDAY).toHaveLength(1); + expect(result.YESTERDAY[0].id).toBe('still-yesterday'); expect(result.TODAY).toHaveLength(1); - expect(result.TODAY[0].name).toBe('Item 1'); - expect(result.TODAY[0].count).toBe(5); + expect(result.TODAY[0].id).toBe('barely-today'); + }); - // Based on actual behavior, 'yesterday' items go to ALL_OTHERS + test('should sort items correctly when mixed with other time periods', () => { + // Create a mix of items with some yesterday dates mixed in + const mockData = [ + { id: 'today-1', last_edited: today }, + { id: 'yesterday-1', last_edited: yesterday }, + { id: 'last-week', last_edited: threeDaysAgo }, + { id: 'yesterday-2', last_edited: yesterdayEnd }, + { id: 'old-item', last_edited: tenDaysAgo }, + { id: 'yesterday-3', last_edited: yesterdayStart }, + { id: 'today-2', last_edited: now.format() } + ]; + + const result = createChatRecord(mockData); + + // Verify correct counts in each bucket + expect(result.TODAY).toHaveLength(2); + expect(result.YESTERDAY).toHaveLength(3); + expect(result.LAST_WEEK).toHaveLength(1); expect(result.ALL_OTHERS).toHaveLength(1); - expect(result.ALL_OTHERS[0].name).toBe('Item 2'); - expect(result.ALL_OTHERS[0].count).toBe(10); + + // Verify all yesterday items are in the YESTERDAY bucket + const yesterdayIds = result.YESTERDAY.map((item) => item.id); + expect(yesterdayIds).toContain('yesterday-1'); + expect(yesterdayIds).toContain('yesterday-2'); + expect(yesterdayIds).toContain('yesterday-3'); }); }); diff --git a/web/src/components/ui/list/createChatRecord.ts b/web/src/components/ui/list/createChatRecord.ts index b2bff715d..a6a6449da 100644 --- a/web/src/components/ui/list/createChatRecord.ts +++ b/web/src/components/ui/list/createChatRecord.ts @@ -14,9 +14,9 @@ export const createChatRecord = ( ALL_OTHERS: T[]; } => { const today = getNow(); - const yesterday = today.subtract(2, 'day'); + const yesterday = today.subtract(1, 'day'); const weekStartDate = today.subtract(8, 'day').startOf('day'); - const twoDaysAgo = today.subtract(2, 'day').startOf('day'); + const twoDaysAgo = today.subtract(1, 'day').startOf('day'); const TODAY: T[] = []; const YESTERDAY: T[] = [];