diff --git a/web/shared-worker/queries/entry-queries.test.js b/web/shared-worker/queries/entry-queries.test.js --- a/web/shared-worker/queries/entry-queries.test.js +++ b/web/shared-worker/queries/entry-queries.test.js @@ -53,6 +53,7 @@ if (!queryExecutor) { throw new Error('SQLiteQueryExecutor is missing'); } + // Add regular entries queryExecutor?.replaceEntry( convertEntryInfoIntoClientDBEntryInfo({ id: '0', @@ -69,6 +70,33 @@ }), false, ); + // Add backup entries + queryExecutor?.replaceEntry( + convertEntryInfoIntoClientDBEntryInfo({ + id: 'backup1', + entry: { + ...TEST_ENTRY_1, + id: 'backup1', + text: 'backup_entry_1', + threadID: '2', + }, + isBackedUp: true, + }), + true, + ); + queryExecutor?.replaceEntry( + convertEntryInfoIntoClientDBEntryInfo({ + id: 'backup2', + entry: { + ...TEST_ENTRY_2, + id: 'backup2', + text: 'backup_entry_2', + threadID: '3', + }, + isBackedUp: false, + }), + true, + ); }); afterEach(() => { @@ -78,17 +106,84 @@ clearSensitiveData(dbModule, FILE_PATH, queryExecutor); }); - it('should return all entries', () => { + it('should return all entries from both regular and backup tables', () => { const entries = queryExecutor?.getAllEntries(); - expect(entries?.length).toBe(2); + expect(entries?.length).toBe(4); // 2 regular + 2 backup + + // Check regular entries exist + const regularEntries = entries?.filter(e => ['0', '1'].includes(e.id)); + expect(regularEntries?.length).toBe(2); + + // Check backup entries exist + const backupEntries = entries?.filter(e => + ['backup1', 'backup2'].includes(e.id), + ); + expect(backupEntries?.length).toBe(2); + + const backup1 = backupEntries?.find(e => e.id === 'backup1'); + expect(backup1?.entry).toContain('backup_entry_1'); }); - it('should remove all entries', () => { + it('should remove all entries from both tables', () => { queryExecutor?.removeAllEntries(); const entries = queryExecutor?.getAllEntries(); expect(entries?.length).toBe(0); }); + it('should remove subset of entries from both tables', () => { + queryExecutor?.removeEntries(['1', 'backup1']); + const entries = queryExecutor?.getAllEntries(); + expect(entries?.length).toBe(2); // 4 - 2 = 2 + + // Verify correct entries removed + const remainingIds = entries?.map(e => e.id); + expect(remainingIds).toContain('0'); + expect(remainingIds).toContain('backup2'); + expect(remainingIds).not.toContain('1'); + expect(remainingIds).not.toContain('backup1'); + }); + + it('should target correct table when replacing based on backupItem parameter', () => { + // Add new entry to regular table + queryExecutor?.replaceEntry( + convertEntryInfoIntoClientDBEntryInfo({ + id: 'new_regular', + entry: { + ...TEST_ENTRY_1, + id: 'new_regular', + text: 'new_regular_entry', + threadID: '5', + }, + isBackedUp: false, + }), + false, + ); + + // Add new entry to backup table + queryExecutor?.replaceEntry( + convertEntryInfoIntoClientDBEntryInfo({ + id: 'new_backup', + entry: { + ...TEST_ENTRY_2, + id: 'new_backup', + text: 'new_backup_entry', + threadID: '6', + }, + isBackedUp: true, + }), + true, + ); + + const entries = queryExecutor?.getAllEntries(); + expect(entries?.length).toBe(6); // 4 + 2 = 6 + + const newRegular = entries?.find(e => e.id === 'new_regular'); + const newBackup = entries?.find(e => e.id === 'new_backup'); + + expect(newRegular?.entry).toContain('new_regular_entry'); + expect(newBackup?.entry).toContain('new_backup_entry'); + }); + it('should update text property', () => { const updatedText = 'updated_test_entry_text'; const updatedTestEntry = { @@ -114,15 +209,4 @@ expect(entries['1'].creatorID).toBe('1'); expect(entries['1'].text).toBe(updatedText); }); - - it('should remove entry', () => { - queryExecutor?.removeEntries(['1']); - - const entries = queryExecutor?.getAllEntries(); - if (!entries) { - throw new Error('entries not defined'); - } - expect(entries.length).toBe(1); - expect(entries[0].id).toBe('0'); - }); }); diff --git a/web/shared-worker/queries/message-store-local-queries.test.js b/web/shared-worker/queries/message-store-local-queries.test.js --- a/web/shared-worker/queries/message-store-local-queries.test.js +++ b/web/shared-worker/queries/message-store-local-queries.test.js @@ -21,6 +21,7 @@ if (!queryExecutor) { throw new Error('SQLiteQueryExecutor is missing'); } + // Add regular message store local infos queryExecutor.replaceMessageStoreLocalMessageInfo( { id: '1', @@ -49,26 +50,102 @@ }, false, ); + // Add backup message store local infos + queryExecutor.replaceMessageStoreLocalMessageInfo( + { + id: 'backup1', + localMessageInfo: JSON.stringify({ + sendFailed: '0', + customProp: 'backup1', + }), + }, + true, + ); + queryExecutor.replaceMessageStoreLocalMessageInfo( + { + id: 'backup2', + localMessageInfo: JSON.stringify({ + sendFailed: '1', + customProp: 'backup2', + }), + }, + true, + ); }); afterEach(() => { clearSensitiveData(dbModule, FILE_PATH, queryExecutor); }); - it('should return all message store local message infos', () => { + it('should return all message store local message infos from both regular and backup tables', () => { const local = queryExecutor.getAllMessageStoreLocalMessageInfos(); - expect(local.length).toBe(4); + expect(local.length).toBe(6); // 4 regular + 2 backup + + // Check regular infos exist + const regularInfos = local.filter(l => ['1', '2', '3', '4'].includes(l.id)); + expect(regularInfos.length).toBe(4); + + // Check backup infos exist + const backupInfos = local.filter(l => + ['backup1', 'backup2'].includes(l.id), + ); + expect(backupInfos.length).toBe(2); + + const backup1 = backupInfos.find(l => l.id === 'backup1'); + const backup1Data = JSON.parse(backup1?.localMessageInfo || '{}'); + expect(backup1Data.customProp).toBe('backup1'); }); - it('should remove all message store local message infos', () => { + it('should remove all message store local message infos from both tables', () => { queryExecutor.removeAllMessageStoreLocalMessageInfos(); const local = queryExecutor.getAllMessageStoreLocalMessageInfos(); expect(local.length).toBe(0); }); - it('should remove a subset of message store local message infos', () => { - queryExecutor.removeMessageStoreLocalMessageInfos(['2', '3']); + it('should remove subset of message store local message infos from both tables', () => { + queryExecutor.removeMessageStoreLocalMessageInfos(['2', 'backup1']); + const local = queryExecutor.getAllMessageStoreLocalMessageInfos(); + expect(local.length).toBe(4); // 6 - 2 = 4 + + // Verify correct infos removed + const remainingIds = local.map(l => l.id); + expect(remainingIds).toContain('1'); + expect(remainingIds).toContain('3'); + expect(remainingIds).toContain('4'); + expect(remainingIds).toContain('backup2'); + expect(remainingIds).not.toContain('2'); + expect(remainingIds).not.toContain('backup1'); + }); + + it('should target correct table when replacing based on backupItem parameter', () => { + // Add new info to regular table + queryExecutor.replaceMessageStoreLocalMessageInfo( + { + id: 'new_regular', + localMessageInfo: JSON.stringify({ sendFailed: '0', type: 'regular' }), + }, + false, + ); + + // Add new info to backup table + queryExecutor.replaceMessageStoreLocalMessageInfo( + { + id: 'new_backup', + localMessageInfo: JSON.stringify({ sendFailed: '1', type: 'backup' }), + }, + true, + ); + const local = queryExecutor.getAllMessageStoreLocalMessageInfos(); - expect(local.length).toBe(2); + expect(local.length).toBe(8); // 6 + 2 = 8 + + const newRegular = local.find(l => l.id === 'new_regular'); + const newBackup = local.find(l => l.id === 'new_backup'); + + const regularData = JSON.parse(newRegular?.localMessageInfo || '{}'); + const backupData = JSON.parse(newBackup?.localMessageInfo || '{}'); + + expect(regularData.type).toBe('regular'); + expect(backupData.type).toBe('backup'); }); }); diff --git a/web/shared-worker/queries/message-store-threads-queries.test.js b/web/shared-worker/queries/message-store-threads-queries.test.js --- a/web/shared-worker/queries/message-store-threads-queries.test.js +++ b/web/shared-worker/queries/message-store-threads-queries.test.js @@ -21,6 +21,7 @@ if (!queryExecutor) { throw new Error('SQLiteQueryExecutor is missing'); } + // Add regular message store threads queryExecutor.replaceMessageStoreThreads( [ { id: '1', startReached: 0 }, @@ -30,26 +31,81 @@ ], false, ); + // Add backup message store threads + queryExecutor.replaceMessageStoreThreads( + [ + { id: 'backup1', startReached: 1 }, + { id: 'backup2', startReached: 1 }, + ], + true, + ); }); afterEach(() => { clearSensitiveData(dbModule, FILE_PATH, queryExecutor); }); - it('should return all message store threads', () => { + it('should return all message store threads from both regular and backup tables', () => { const threads = queryExecutor.getAllMessageStoreThreads(); - expect(threads.length).toBe(4); + expect(threads.length).toBe(6); // 4 regular + 2 backup + + // Check regular threads exist + const regularThreads = threads.filter(t => + ['1', '2', '3', '4'].includes(t.id), + ); + expect(regularThreads.length).toBe(4); + + // Check backup threads exist + const backupThreads = threads.filter(t => + ['backup1', 'backup2'].includes(t.id), + ); + expect(backupThreads.length).toBe(2); + + const backup1 = backupThreads.find(t => t.id === 'backup1'); + expect(backup1?.startReached).toBe(1); }); - it('should remove all message store threads', () => { + it('should remove all message store threads from both tables', () => { queryExecutor.removeAllMessageStoreThreads(); const threads = queryExecutor.getAllMessageStoreThreads(); expect(threads.length).toBe(0); }); - it('should remove a subset of message store threads', () => { - queryExecutor.removeMessageStoreThreads(['2', '3']); + it('should remove subset of message store threads from both tables', () => { + queryExecutor.removeMessageStoreThreads(['2', 'backup1']); + const threads = queryExecutor.getAllMessageStoreThreads(); + expect(threads.length).toBe(4); // 6 - 2 = 4 + + // Verify correct threads removed + const remainingIds = threads.map(t => t.id); + expect(remainingIds).toContain('1'); + expect(remainingIds).toContain('3'); + expect(remainingIds).toContain('4'); + expect(remainingIds).toContain('backup2'); + expect(remainingIds).not.toContain('2'); + expect(remainingIds).not.toContain('backup1'); + }); + + it('should target correct table when replacing based on backupItem parameter', () => { + // Add new threads to regular table + queryExecutor.replaceMessageStoreThreads( + [{ id: 'new_regular', startReached: 0 }], + false, + ); + + // Add new threads to backup table + queryExecutor.replaceMessageStoreThreads( + [{ id: 'new_backup', startReached: 1 }], + true, + ); + const threads = queryExecutor.getAllMessageStoreThreads(); - expect(threads.length).toBe(2); + expect(threads.length).toBe(8); // 6 + 2 = 8 + + const newRegular = threads.find(t => t.id === 'new_regular'); + const newBackup = threads.find(t => t.id === 'new_backup'); + + expect(newRegular?.startReached).toBe(0); + expect(newBackup?.startReached).toBe(1); }); }); diff --git a/web/shared-worker/queries/thread-activity-queries.test.js b/web/shared-worker/queries/thread-activity-queries.test.js --- a/web/shared-worker/queries/thread-activity-queries.test.js +++ b/web/shared-worker/queries/thread-activity-queries.test.js @@ -25,6 +25,7 @@ if (!queryExecutor) { throw new Error('SQLiteQueryExecutor is missing'); } + // Add backup thread activities queryExecutor?.replaceThreadActivityEntry( { id: 'test_id_1', @@ -55,6 +56,27 @@ }, false, ); + // Add backup thread activities + queryExecutor?.replaceThreadActivityEntry( + { + id: 'backup_activity_1', + threadActivityStoreEntry: JSON.stringify({ + lastNavigatedTo: 10, + lastPruned: 11, + }), + }, + true, + ); + queryExecutor?.replaceThreadActivityEntry( + { + id: 'backup_activity_2', + threadActivityStoreEntry: JSON.stringify({ + lastNavigatedTo: 12, + lastPruned: 13, + }), + }, + true, + ); }); afterEach(() => { @@ -65,19 +87,96 @@ clearSensitiveData(dbModule, FILE_PATH, queryExecutor); }); - it('should return all thread activity entries', () => { + it('should return all thread activity entries from both regular and backup tables', () => { const threadActivityEntries = queryExecutor?.getAllThreadActivityEntries(); - expect(threadActivityEntries).toHaveLength(3); + expect(threadActivityEntries).toHaveLength(5); // 3 regular + 2 backup + + // Check regular entries exist + const regularEntries = threadActivityEntries?.filter(e => + ['test_id_1', 'test_id_2', 'test_id_3'].includes(e.id), + ); + expect(regularEntries?.length).toBe(3); + + // Check backup entries exist + const backupEntries = threadActivityEntries?.filter(e => + ['backup_activity_1', 'backup_activity_2'].includes(e.id), + ); + expect(backupEntries?.length).toBe(2); + + const backup1 = backupEntries?.find(e => e.id === 'backup_activity_1'); + const backup1Data = JSON.parse(backup1?.threadActivityStoreEntry || '{}'); + expect(backup1Data.lastNavigatedTo).toBe(10); }); - it('should remove all thread activity entries', () => { + it('should remove all thread activity entries from both tables', () => { queryExecutor?.removeAllThreadActivityEntries(); const threadActivityEntries = queryExecutor?.getAllThreadActivityEntries(); expect(threadActivityEntries).toHaveLength(0); }); + it('should remove subset of thread activity entries from both tables', () => { + queryExecutor?.removeThreadActivityEntries([ + 'test_id_2', + 'backup_activity_1', + ]); + const threadActivityEntries = queryExecutor?.getAllThreadActivityEntries(); + expect(threadActivityEntries?.length).toBe(3); // 5 - 2 = 3 + + // Verify correct entries removed + const remainingIds = threadActivityEntries?.map(e => e.id); + expect(remainingIds).toContain('test_id_1'); + expect(remainingIds).toContain('test_id_3'); + expect(remainingIds).toContain('backup_activity_2'); + expect(remainingIds).not.toContain('test_id_2'); + expect(remainingIds).not.toContain('backup_activity_1'); + }); + + it('should target correct table when replacing based on backupItem parameter', () => { + // Add new activity to regular table + queryExecutor?.replaceThreadActivityEntry( + { + id: 'new_regular_activity', + threadActivityStoreEntry: JSON.stringify({ + lastNavigatedTo: 20, + lastPruned: 21, + }), + }, + false, + ); + + // Add new activity to backup table + queryExecutor?.replaceThreadActivityEntry( + { + id: 'new_backup_activity', + threadActivityStoreEntry: JSON.stringify({ + lastNavigatedTo: 22, + lastPruned: 23, + }), + }, + true, + ); + + const threadActivityEntries = queryExecutor?.getAllThreadActivityEntries(); + expect(threadActivityEntries?.length).toBe(7); // 5 + 2 = 7 + + const newRegular = threadActivityEntries?.find( + e => e.id === 'new_regular_activity', + ); + const newBackup = threadActivityEntries?.find( + e => e.id === 'new_backup_activity', + ); + + const regularData = JSON.parse( + newRegular?.threadActivityStoreEntry || '{}', + ); + const backupData = JSON.parse(newBackup?.threadActivityStoreEntry || '{}'); + + expect(regularData.lastNavigatedTo).toBe(20); + expect(backupData.lastNavigatedTo).toBe(22); + }); + it('should update thread activity entry test_id_2', () => { queryExecutor?.replaceThreadActivityEntry( { @@ -95,7 +194,7 @@ throw new Error('thread activity entries not defined'); } - expect(threadActivityEntries).toHaveLength(3); + expect(threadActivityEntries).toHaveLength(5); const threadActivityEntriesFromDB = threadActivityStoreOpsHandlers.translateClientDBData( @@ -117,7 +216,7 @@ throw new Error('thread activity entries not defined'); } - expect(threadActivityEntries.length).toBe(1); + expect(threadActivityEntries.length).toBe(3); const threadActivityEntriesFromDB = threadActivityStoreOpsHandlers.translateClientDBData( diff --git a/web/shared-worker/queries/threads-queries.test.js b/web/shared-worker/queries/threads-queries.test.js --- a/web/shared-worker/queries/threads-queries.test.js +++ b/web/shared-worker/queries/threads-queries.test.js @@ -21,6 +21,7 @@ if (!queryExecutor) { throw new Error('SQLiteQueryExecutor is missing'); } + // Add backup threads queryExecutor.replaceThread( { id: '1', @@ -87,26 +88,151 @@ }, false, ); + // Add backup threads + queryExecutor.replaceThread( + { + id: 'backup1', + type: 1, + name: 'Backup Thread 1', + avatar: null, + description: null, + color: 'ff0000', + creationTime: BigInt(2000), + parentThreadID: null, + containingThreadID: null, + community: null, + members: '2', + roles: '2', + currentUser: '2', + sourceMessageID: null, + repliesCount: 2, + pinnedCount: 1, + timestamps: null, + }, + true, + ); + queryExecutor.replaceThread( + { + id: 'backup2', + type: 1, + name: 'Backup Thread 2', + avatar: null, + description: null, + color: '00ff00', + creationTime: BigInt(3000), + parentThreadID: null, + containingThreadID: null, + community: null, + members: '3', + roles: '3', + currentUser: '3', + sourceMessageID: null, + repliesCount: 3, + pinnedCount: 2, + timestamps: null, + }, + true, + ); }); afterEach(() => { clearSensitiveData(dbModule, FILE_PATH, queryExecutor); }); - it('should return all threads', () => { + it('should return all threads from both regular and backup tables', () => { const threads = queryExecutor.getAllThreads(); - expect(threads.length).toBe(3); + expect(threads.length).toBe(5); // 3 regular + 2 backup + + // Check regular threads exist + const regularThreads = threads.filter(t => ['1', '2', '3'].includes(t.id)); + expect(regularThreads.length).toBe(3); + + // Check backup threads exist + const backupThreads = threads.filter(t => + ['backup1', 'backup2'].includes(t.id), + ); + expect(backupThreads.length).toBe(2); + + const backup1 = backupThreads.find(t => t.id === 'backup1'); + expect(backup1?.name).toBe('Backup Thread 1'); }); - it('should remove all threads', () => { + it('should remove all threads from both tables', () => { queryExecutor.removeAllThreads(); const threads = queryExecutor.getAllThreads(); expect(threads.length).toBe(0); }); - it('should remove subset of threads', () => { - queryExecutor.removeThreads(['2']); + it('should remove subset of threads from both tables', () => { + queryExecutor.removeThreads(['2', 'backup1']); + const threads = queryExecutor.getAllThreads(); + expect(threads.length).toBe(3); // 5 - 2 = 3 + + // Verify correct threads removed + const remainingIds = threads.map(t => t.id); + expect(remainingIds).toContain('1'); + expect(remainingIds).toContain('3'); + expect(remainingIds).toContain('backup2'); + expect(remainingIds).not.toContain('2'); + expect(remainingIds).not.toContain('backup1'); + }); + + it('should target correct table when replacing based on backupItem parameter', () => { + // Add new thread to regular table + queryExecutor.replaceThread( + { + id: 'new_regular', + type: 1, + name: 'New Regular Thread', + avatar: null, + description: null, + color: 'ff00ff', + creationTime: BigInt(4000), + parentThreadID: null, + containingThreadID: null, + community: null, + members: '4', + roles: '4', + currentUser: '4', + sourceMessageID: null, + repliesCount: 4, + pinnedCount: 0, + timestamps: null, + }, + false, + ); + + // Add new thread to backup table + queryExecutor.replaceThread( + { + id: 'new_backup', + type: 1, + name: 'New Backup Thread', + avatar: null, + description: null, + color: '00ffff', + creationTime: BigInt(5000), + parentThreadID: null, + containingThreadID: null, + community: null, + members: '5', + roles: '5', + currentUser: '5', + sourceMessageID: null, + repliesCount: 5, + pinnedCount: 3, + timestamps: null, + }, + true, + ); + const threads = queryExecutor.getAllThreads(); - expect(threads.length).toBe(2); + expect(threads.length).toBe(7); // 5 + 2 = 7 + + const newRegular = threads.find(t => t.id === 'new_regular'); + const newBackup = threads.find(t => t.id === 'new_backup'); + + expect(newRegular?.name).toBe('New Regular Thread'); + expect(newBackup?.name).toBe('New Backup Thread'); }); });