WIP: A simple cli for daily tangled use cases and AI integration. This is for my personal use right now, but happy if others get mileage from it! :)
at main 146 lines 5.5 kB view raw
1import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; 2import { formatDate, outputJson } from '../../src/utils/formatting.js'; 3 4describe('formatDate', () => { 5 beforeEach(() => { 6 // Mock current date to 2024-06-15 12:00:00 UTC for consistent testing 7 vi.useFakeTimers(); 8 vi.setSystemTime(new Date('2024-06-15T12:00:00.000Z')); 9 }); 10 11 afterEach(() => { 12 vi.useRealTimers(); 13 }); 14 15 it('should return "today" for current day', () => { 16 const today = new Date('2024-06-15T10:00:00.000Z').toISOString(); 17 expect(formatDate(today)).toBe('today'); 18 }); 19 20 it('should return "yesterday" for previous day', () => { 21 const yesterday = new Date('2024-06-14T10:00:00.000Z').toISOString(); 22 expect(formatDate(yesterday)).toBe('yesterday'); 23 }); 24 25 it('should return days ago for 2-6 days', () => { 26 const twoDaysAgo = new Date('2024-06-13T10:00:00.000Z').toISOString(); 27 expect(formatDate(twoDaysAgo)).toBe('2 days ago'); 28 29 const threeDaysAgo = new Date('2024-06-12T10:00:00.000Z').toISOString(); 30 expect(formatDate(threeDaysAgo)).toBe('3 days ago'); 31 32 const sixDaysAgo = new Date('2024-06-09T10:00:00.000Z').toISOString(); 33 expect(formatDate(sixDaysAgo)).toBe('6 days ago'); 34 }); 35 36 it('should return weeks ago for 7-29 days', () => { 37 const oneWeekAgo = new Date('2024-06-08T10:00:00.000Z').toISOString(); 38 expect(formatDate(oneWeekAgo)).toBe('1 weeks ago'); 39 40 const twoWeeksAgo = new Date('2024-06-01T10:00:00.000Z').toISOString(); 41 expect(formatDate(twoWeeksAgo)).toBe('2 weeks ago'); 42 43 const threeWeeksAgo = new Date('2024-05-25T10:00:00.000Z').toISOString(); 44 expect(formatDate(threeWeeksAgo)).toBe('3 weeks ago'); 45 }); 46 47 it('should return months ago for 30-364 days', () => { 48 const oneMonthAgo = new Date('2024-05-16T10:00:00.000Z').toISOString(); 49 expect(formatDate(oneMonthAgo)).toBe('1 months ago'); 50 51 const threeMonthsAgo = new Date('2024-03-16T10:00:00.000Z').toISOString(); 52 expect(formatDate(threeMonthsAgo)).toBe('3 months ago'); 53 54 const sixMonthsAgo = new Date('2023-12-16T10:00:00.000Z').toISOString(); 55 expect(formatDate(sixMonthsAgo)).toBe('6 months ago'); 56 }); 57 58 it('should return locale date string for 365+ days', () => { 59 const oneYearAgo = new Date('2023-06-15T10:00:00.000Z').toISOString(); 60 const formatted = formatDate(oneYearAgo); 61 62 // The exact format depends on locale, but it should be a date string 63 expect(formatted).toMatch(/\d{1,2}\/\d{1,2}\/\d{4}/); 64 }); 65 66 it('should handle edge case at exactly 7 days', () => { 67 const sevenDaysAgo = new Date('2024-06-08T12:00:00.000Z').toISOString(); 68 expect(formatDate(sevenDaysAgo)).toBe('1 weeks ago'); 69 }); 70 71 it('should handle edge case at exactly 30 days', () => { 72 const thirtyDaysAgo = new Date('2024-05-16T12:00:00.000Z').toISOString(); 73 expect(formatDate(thirtyDaysAgo)).toBe('1 months ago'); 74 }); 75 76 it('should handle edge case at exactly 365 days', () => { 77 const oneYearAgo = new Date('2023-06-15T12:00:00.000Z').toISOString(); 78 const formatted = formatDate(oneYearAgo); 79 80 // Should use locale date string 81 expect(formatted).toMatch(/\d{1,2}\/\d{1,2}\/\d{4}/); 82 }); 83}); 84 85describe('outputJson', () => { 86 let consoleLogSpy: ReturnType<typeof vi.spyOn>; 87 88 beforeEach(() => { 89 consoleLogSpy = vi.spyOn(console, 'log').mockImplementation(() => {}); 90 }); 91 92 afterEach(() => { 93 vi.restoreAllMocks(); 94 }); 95 96 it('should output all fields of an object when no fields specified', () => { 97 const data = { title: 'Test', state: 'open', author: 'did:plc:abc' }; 98 outputJson(data); 99 expect(consoleLogSpy).toHaveBeenCalledWith(JSON.stringify(data, null, 2)); 100 }); 101 102 it('should output only specified fields of an object', () => { 103 const data = { title: 'Test', state: 'open', author: 'did:plc:abc', cid: 'bafyrei1' }; 104 outputJson(data, 'title,state'); 105 const output = JSON.parse(consoleLogSpy.mock.calls[0][0] as string); 106 expect(output).toEqual({ title: 'Test', state: 'open' }); 107 expect(output).not.toHaveProperty('author'); 108 expect(output).not.toHaveProperty('cid'); 109 }); 110 111 it('should output all fields of an array when no fields specified', () => { 112 const data = [ 113 { title: 'First', state: 'open' }, 114 { title: 'Second', state: 'closed' }, 115 ]; 116 outputJson(data); 117 expect(consoleLogSpy).toHaveBeenCalledWith(JSON.stringify(data, null, 2)); 118 }); 119 120 it('should output only specified fields of an array', () => { 121 const data = [ 122 { title: 'First', state: 'open', author: 'did:plc:abc' }, 123 { title: 'Second', state: 'closed', author: 'did:plc:xyz' }, 124 ]; 125 outputJson(data, 'title,state'); 126 const output = JSON.parse(consoleLogSpy.mock.calls[0][0] as string); 127 expect(output).toEqual([ 128 { title: 'First', state: 'open' }, 129 { title: 'Second', state: 'closed' }, 130 ]); 131 }); 132 133 it('should silently omit fields not present in the object', () => { 134 const data = { title: 'Test', state: 'open' }; 135 outputJson(data, 'title,nonexistent'); 136 const output = JSON.parse(consoleLogSpy.mock.calls[0][0] as string); 137 expect(output).toEqual({ title: 'Test' }); 138 }); 139 140 it('should trim whitespace from field names', () => { 141 const data = { title: 'Test', state: 'open' }; 142 outputJson(data, ' title , state '); 143 const output = JSON.parse(consoleLogSpy.mock.calls[0][0] as string); 144 expect(output).toEqual({ title: 'Test', state: 'open' }); 145 }); 146});