Page MenuHomePhorge

D14835.1765132210.diff
No OneTemporary

Size
13 KB
Referenced Files
None
Subscribers
None

D14835.1765132210.diff

diff --git a/web/shared-worker/queries/get-related-messages.test.js b/web/shared-worker/queries/get-related-messages.test.js
new file mode 100644
--- /dev/null
+++ b/web/shared-worker/queries/get-related-messages.test.js
@@ -0,0 +1,505 @@
+// @flow
+
+import { messageTypes } from 'lib/types/message-types-enum.js';
+
+import { getDatabaseModule } from '../db-module.js';
+import { clearSensitiveData } from '../utils/db-utils.js';
+
+const FILE_PATH = 'test.sqlite';
+
+describe('getRelatedMessages queries', () => {
+ let queryExecutor;
+ let dbModule;
+
+ beforeAll(async () => {
+ dbModule = getDatabaseModule();
+ });
+
+ beforeEach(() => {
+ if (!dbModule) {
+ throw new Error('Database module is missing');
+ }
+ queryExecutor = new dbModule.SQLiteQueryExecutor(FILE_PATH, false);
+ if (!queryExecutor) {
+ throw new Error('SQLiteQueryExecutor is missing');
+ }
+ });
+
+ afterEach(() => {
+ clearSensitiveData(dbModule, FILE_PATH, queryExecutor);
+ });
+
+ const createTestMessage = (
+ id: string,
+ type: number,
+ content?: ?string,
+ targetMessageID?: string,
+ time: number = 1000,
+ ): void => {
+ let messageContent = null;
+
+ if (content) {
+ messageContent = content;
+ } else if (!targetMessageID) {
+ messageContent = null;
+ } else if (type === messageTypes.REACTION) {
+ messageContent = JSON.stringify({
+ targetMessageID,
+ reaction: '👍',
+ action: 'add_reaction',
+ });
+ } else if (type === messageTypes.EDIT_MESSAGE) {
+ messageContent = JSON.stringify({
+ targetMessageID,
+ text: 'edited text',
+ });
+ } else if (type === messageTypes.DELETE_MESSAGE) {
+ messageContent = JSON.stringify({
+ targetMessageID,
+ });
+ } else if (type === messageTypes.TOGGLE_PIN) {
+ messageContent = JSON.stringify({
+ targetMessageID,
+ action: 'pin',
+ threadID: '1',
+ });
+ } else if (type === messageTypes.SIDEBAR_SOURCE) {
+ messageContent = JSON.stringify({
+ id: targetMessageID,
+ type: messageTypes.TEXT,
+ threadID: '1',
+ creatorID: '1',
+ time: 900,
+ content: 'original message text',
+ });
+ }
+
+ return queryExecutor.replaceMessage({
+ id,
+ localID: null,
+ thread: '1',
+ user: '1',
+ type,
+ futureType: null,
+ content: messageContent,
+ time: BigInt(time),
+ });
+ };
+
+ it('should handle non-existent message ID', () => {
+ const results = queryExecutor.getRelatedMessages('nonexistent');
+ expect(results.length).toBe(0);
+ });
+
+ it('should return the original message when queried', () => {
+ createTestMessage('original', messageTypes.TEXT, 'Hello world');
+
+ const results = queryExecutor.getRelatedMessages('original');
+ expect(results.length).toBe(1);
+ expect(results[0].message.id).toBe('original');
+ expect(results[0].message.content).toBe('Hello world');
+ });
+
+ it('should handle malformed JSON content gracefully', () => {
+ queryExecutor.replaceMessage({
+ id: 'malformed',
+ localID: null,
+ thread: '1',
+ user: '1',
+ type: messageTypes.REACTION,
+ futureType: null,
+ content: 'invalid json{',
+ time: BigInt(1000),
+ });
+
+ const results = queryExecutor.getRelatedMessages('malformed');
+ expect(results.length).toBe(1);
+ expect(results[0].message.id).toBe('malformed');
+ });
+
+ it('should handle null content', () => {
+ createTestMessage('nullcontent', messageTypes.TEXT, null);
+
+ const results = queryExecutor.getRelatedMessages('nullcontent');
+ expect(results.length).toBe(1);
+ expect(results[0].message.id).toBe('nullcontent');
+ });
+
+ it('should find reaction targeting a message', () => {
+ createTestMessage(
+ 'msg1',
+ messageTypes.TEXT,
+ 'Hello world',
+ undefined,
+ 1000,
+ );
+ createTestMessage(
+ 'reaction1',
+ messageTypes.REACTION,
+ undefined,
+ 'msg1',
+ 1100,
+ );
+
+ const results = queryExecutor.getRelatedMessages('msg1');
+ expect(results.length).toBe(2);
+
+ const messageIds = results.map(r => r.message.id).sort();
+ expect(messageIds).toEqual(['msg1', 'reaction1']);
+
+ const reaction = results.find(r => r.message.id === 'reaction1');
+ expect(reaction?.message.type).toBe(messageTypes.REACTION);
+ const reactionContent = JSON.parse(reaction?.message.content || '{}');
+ expect(reactionContent.targetMessageID).toBe('msg1');
+ expect(reactionContent.reaction).toBe('👍');
+ });
+
+ it('should find multiple reactions to same message', () => {
+ createTestMessage(
+ 'msg1',
+ messageTypes.TEXT,
+ 'Hello world',
+ undefined,
+ 1000,
+ );
+ createTestMessage(
+ 'reaction1',
+ messageTypes.REACTION,
+ undefined,
+ 'msg1',
+ 1100,
+ );
+ createTestMessage(
+ 'reaction2',
+ messageTypes.REACTION,
+ undefined,
+ 'msg1',
+ 1200,
+ );
+
+ const results = queryExecutor.getRelatedMessages('msg1');
+ expect(results.length).toBe(3);
+
+ const reactionIds = results
+ .filter(r => r.message.type === messageTypes.REACTION)
+ .map(r => r.message.id)
+ .sort();
+ expect(reactionIds).toEqual(['reaction1', 'reaction2']);
+ });
+
+ it('should find edit message targeting original', () => {
+ createTestMessage(
+ 'original',
+ messageTypes.TEXT,
+ 'Original text',
+ undefined,
+ 1000,
+ );
+ createTestMessage(
+ 'edit1',
+ messageTypes.EDIT_MESSAGE,
+ undefined,
+ 'original',
+ 1100,
+ );
+
+ const results = queryExecutor.getRelatedMessages('original');
+ expect(results.length).toBe(2);
+
+ const edit = results.find(r => r.message.id === 'edit1');
+ expect(edit?.message.type).toBe(messageTypes.EDIT_MESSAGE);
+ const editContent = JSON.parse(edit?.message.content || '{}');
+ expect(editContent.targetMessageID).toBe('original');
+ expect(editContent.text).toBe('edited text');
+ });
+
+ it('should find multiple edits to same message', () => {
+ createTestMessage(
+ 'original',
+ messageTypes.TEXT,
+ 'Original text',
+ undefined,
+ 1000,
+ );
+ createTestMessage(
+ 'edit1',
+ messageTypes.EDIT_MESSAGE,
+ undefined,
+ 'original',
+ 1100,
+ );
+ createTestMessage(
+ 'edit2',
+ messageTypes.EDIT_MESSAGE,
+ undefined,
+ 'original',
+ 1200,
+ );
+
+ const results = queryExecutor.getRelatedMessages('original');
+ expect(results.length).toBe(3);
+
+ const edits = results.filter(
+ r => r.message.type === messageTypes.EDIT_MESSAGE,
+ );
+ expect(edits.length).toBe(2);
+ });
+
+ it('should find delete message targeting original', () => {
+ createTestMessage(
+ 'original',
+ messageTypes.TEXT,
+ 'To be deleted',
+ undefined,
+ 1000,
+ );
+ createTestMessage(
+ 'delete1',
+ messageTypes.DELETE_MESSAGE,
+ undefined,
+ 'original',
+ 1100,
+ );
+
+ const results = queryExecutor.getRelatedMessages('original');
+ expect(results.length).toBe(2);
+
+ const deleteMsg = results.find(r => r.message.id === 'delete1');
+ expect(deleteMsg?.message.type).toBe(messageTypes.DELETE_MESSAGE);
+ const deleteContent = JSON.parse(deleteMsg?.message.content || '{}');
+ expect(deleteContent.targetMessageID).toBe('original');
+ });
+
+ it('should find pin/unpin messages targeting original', () => {
+ createTestMessage(
+ 'original',
+ messageTypes.TEXT,
+ 'Message to pin',
+ undefined,
+ 1000,
+ );
+ createTestMessage(
+ 'pin1',
+ messageTypes.TOGGLE_PIN,
+ undefined,
+ 'original',
+ 1100,
+ );
+
+ const results = queryExecutor.getRelatedMessages('original');
+ expect(results.length).toBe(2);
+
+ const pinMsg = results.find(r => r.message.id === 'pin1');
+ expect(pinMsg?.message.type).toBe(messageTypes.TOGGLE_PIN);
+ const pinContent = JSON.parse(pinMsg?.message.content || '{}');
+ expect(pinContent.targetMessageID).toBe('original');
+ expect(pinContent.action).toBe('pin');
+ });
+
+ it('should find messages related to sidebar source', () => {
+ createTestMessage(
+ 'original',
+ messageTypes.TEXT,
+ 'Message for sidebar',
+ undefined,
+ 1000,
+ );
+ createTestMessage(
+ 'sidebar1',
+ messageTypes.SIDEBAR_SOURCE,
+ undefined,
+ 'original',
+ 1000,
+ );
+
+ const results = queryExecutor.getRelatedMessages('original');
+ expect(results.length).toBe(2);
+
+ const sidebarMsg = results.find(r => r.message.id === 'sidebar1');
+ expect(sidebarMsg?.message.type).toBe(messageTypes.SIDEBAR_SOURCE);
+ const sidebarContent = JSON.parse(sidebarMsg?.message.content || '{}');
+ expect(sidebarContent.id).toBe('original');
+ });
+
+ it('should handle sidebar source special case', () => {
+ const sidebarContent = JSON.stringify({
+ id: 'source_msg_id',
+ type: messageTypes.TEXT,
+ threadID: '1',
+ creatorID: '1',
+ time: 900,
+ content: 'Source message for sidebar',
+ });
+
+ queryExecutor.replaceMessage({
+ id: 'sidebar1',
+ localID: null,
+ thread: '1',
+ user: '1',
+ type: messageTypes.SIDEBAR_SOURCE,
+ futureType: null,
+ content: sidebarContent,
+ time: BigInt(1000),
+ });
+
+ const results = queryExecutor.getRelatedMessages('source_msg_id');
+ expect(results.length).toBe(1);
+ expect(results[0].message.id).toBe('sidebar1');
+ expect(results[0].message.type).toBe(messageTypes.SIDEBAR_SOURCE);
+ });
+
+ it('should handle message with multiple types of relations', () => {
+ createTestMessage(
+ 'original',
+ messageTypes.TEXT,
+ 'Popular message',
+ undefined,
+ 1000,
+ );
+ createTestMessage(
+ 'reaction1',
+ messageTypes.REACTION,
+ undefined,
+ 'original',
+ 1100,
+ );
+ createTestMessage(
+ 'reaction2',
+ messageTypes.REACTION,
+ undefined,
+ 'original',
+ 1150,
+ );
+ createTestMessage(
+ 'edit1',
+ messageTypes.EDIT_MESSAGE,
+ undefined,
+ 'original',
+ 1200,
+ );
+ createTestMessage(
+ 'pin1',
+ messageTypes.TOGGLE_PIN,
+ undefined,
+ 'original',
+ 1300,
+ );
+
+ const results = queryExecutor.getRelatedMessages('original');
+ expect(results.length).toBe(5);
+
+ const types = results.map(r => r.message.type).sort();
+ expect(types).toEqual(
+ [
+ messageTypes.TEXT,
+ messageTypes.REACTION,
+ messageTypes.REACTION,
+ messageTypes.EDIT_MESSAGE,
+ messageTypes.TOGGLE_PIN,
+ ].sort(),
+ );
+ });
+
+ it('should not return unrelated messages', () => {
+ createTestMessage('msg1', messageTypes.TEXT, 'Message 1', undefined, 1000);
+ createTestMessage('msg2', messageTypes.TEXT, 'Message 2', undefined, 1100);
+ createTestMessage(
+ 'reaction1',
+ messageTypes.REACTION,
+ undefined,
+ 'msg1',
+ 1200,
+ );
+ createTestMessage(
+ 'edit1',
+ messageTypes.EDIT_MESSAGE,
+ undefined,
+ 'msg2',
+ 1300,
+ );
+
+ const results1 = queryExecutor.getRelatedMessages('msg1');
+ expect(results1.length).toBe(2);
+ const ids1 = results1.map(r => r.message.id).sort();
+ expect(ids1).toEqual(['msg1', 'reaction1']);
+
+ const results2 = queryExecutor.getRelatedMessages('msg2');
+ expect(results2.length).toBe(2);
+ const ids2 = results2.map(r => r.message.id).sort();
+ expect(ids2).toEqual(['edit1', 'msg2']);
+ });
+
+ it('should return messages ordered by time DESC', () => {
+ createTestMessage(
+ 'original',
+ messageTypes.TEXT,
+ 'Original',
+ undefined,
+ 1000,
+ );
+ createTestMessage(
+ 'reaction1',
+ messageTypes.REACTION,
+ undefined,
+ 'original',
+ 1500,
+ );
+ createTestMessage(
+ 'edit1',
+ messageTypes.EDIT_MESSAGE,
+ undefined,
+ 'original',
+ 1200,
+ );
+ createTestMessage(
+ 'reaction2',
+ messageTypes.REACTION,
+ undefined,
+ 'original',
+ 1800,
+ );
+
+ const results = queryExecutor.getRelatedMessages('original');
+ expect(results.length).toBe(4);
+
+ const times = results.map(r => Number(r.message.time));
+ expect(times).toEqual([1800, 1500, 1200, 1000]);
+
+ const ids = results.map(r => r.message.id);
+ expect(ids).toEqual(['reaction2', 'reaction1', 'edit1', 'original']);
+ });
+
+ it('should handle all message types that support targetMessageID', () => {
+ createTestMessage(
+ 'target',
+ messageTypes.TEXT,
+ 'Target message',
+ undefined,
+ 1000,
+ );
+
+ const targetingTypes = [
+ messageTypes.REACTION,
+ messageTypes.EDIT_MESSAGE,
+ messageTypes.DELETE_MESSAGE,
+ messageTypes.TOGGLE_PIN,
+ ];
+
+ targetingTypes.forEach((type, index) => {
+ createTestMessage(
+ `msg_${type}`,
+ type,
+ undefined,
+ 'target',
+ 1100 + index * 100,
+ );
+ });
+
+ const results = queryExecutor.getRelatedMessages('target');
+ expect(results.length).toBe(1 + targetingTypes.length);
+
+ const foundTypes = results.map(r => r.message.type).sort();
+ const expectedTypes = [messageTypes.TEXT, ...targetingTypes].sort();
+ expect(foundTypes).toEqual(expectedTypes);
+ });
+});

File Metadata

Mime Type
text/plain
Expires
Sun, Dec 7, 6:30 PM (20 h, 34 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5844370
Default Alt Text
D14835.1765132210.diff (13 KB)

Event Timeline