diff --git a/ts/session/messages/outgoing/content/data/ChatMessage.ts b/ts/session/messages/outgoing/content/data/ChatMessage.ts index aeb75e1ca..d75105903 100644 --- a/ts/session/messages/outgoing/content/data/ChatMessage.ts +++ b/ts/session/messages/outgoing/content/data/ChatMessage.ts @@ -3,7 +3,7 @@ import { SignalService } from '../../../../../protobuf'; import { MessageParams } from '../../Message'; import { LokiProfile } from '../../../../../types/Message'; -interface AttachmentPointer { +export interface AttachmentPointer { id?: number; contentType?: string; key?: Uint8Array; @@ -18,28 +18,27 @@ interface AttachmentPointer { url?: string; } -/** Properties of a Preview. */ -interface Preview { +export interface Preview { url?: string; title?: string; image?: AttachmentPointer; } -interface QuotedAttachment { +export interface QuotedAttachment { contentType?: string; fileName?: string; thumbnail?: AttachmentPointer; } -interface Quote { +export interface Quote { id?: number; author?: string; text?: string; attachments?: Array; } -interface ChatMessageParams extends MessageParams { - attachments: Array; +export interface ChatMessageParams extends MessageParams { + attachments?: Array; body?: string; quote?: Quote; expireTimer?: number; @@ -48,11 +47,11 @@ interface ChatMessageParams extends MessageParams { } -export abstract class ChatMessage extends DataMessage { - private readonly attachments: Array; +export class ChatMessage extends DataMessage { + private readonly attachments?: Array; private readonly body?: string; private readonly quote?: Quote; - private readonly expireTimer?: number | null; + private readonly expireTimer?: number; private readonly profileKey?: Uint8Array; private readonly displayName?: string; private readonly avatarPointer?: string; @@ -81,7 +80,7 @@ export abstract class ChatMessage extends DataMessage { dataMessage.body = this.body; } - dataMessage.attachments = this.attachments; + dataMessage.attachments = this.attachments || []; if (this.expireTimer) { diff --git a/ts/test/session/messages/ChatMessage_test.ts b/ts/test/session/messages/ChatMessage_test.ts new file mode 100644 index 000000000..01806d2e3 --- /dev/null +++ b/ts/test/session/messages/ChatMessage_test.ts @@ -0,0 +1,125 @@ +import { expect } from 'chai'; + +import { ChatMessage, Quote, Preview, AttachmentPointer } from '../../../session/messages/outgoing'; +import { SignalService } from '../../../protobuf'; +import { TextEncoder } from 'util'; + +describe('ChatMessage', () => { + it('can create empty message with just a timestamp', () => { + const message = new ChatMessage({ + timestamp: Date.now(), + }); + const plainText = message.plainTextBuffer(); + const decoded = SignalService.Content.toObject(SignalService.Content.decode(plainText)); + expect(decoded).to.have.deep.property('dataMessage', {}); + }); + + it('can create message with a body', () => { + const message = new ChatMessage({ + timestamp: Date.now(), + body: 'body', + }); + const plainText = message.plainTextBuffer(); + const decoded = SignalService.Content.toObject(SignalService.Content.decode(plainText)); + expect(decoded.dataMessage).to.have.deep.property('body', 'body'); + }); + + it('can create message with a expire timer', () => { + const message = new ChatMessage({ + timestamp: Date.now(), + expireTimer: 3600, + }); + const plainText = message.plainTextBuffer(); + const decoded = SignalService.Content.toObject(SignalService.Content.decode(plainText)); + expect(decoded.dataMessage).to.have.deep.property('expireTimer', 3600); + }); + + it('can create message with a full loki profile', () => { + const profileKey = new TextEncoder().encode('profileKey'); + + const lokiProfile = { + displayName: 'displayName', + avatarPointer: 'avatarPointer', + profileKey, + }; + const message = new ChatMessage({ + timestamp: Date.now(), + lokiProfile: lokiProfile, + }); + const plainText = message.plainTextBuffer(); + const decoded = SignalService.Content.toObject(SignalService.Content.decode(plainText)); + expect(decoded.dataMessage.profile).to.have.deep.property('displayName', 'displayName'); + expect(decoded.dataMessage.profile).to.have.deep.property('avatar', 'avatarPointer'); + expect(decoded.dataMessage).to.have.deep.property('profileKey', profileKey); + }); + + it('can create message with a quote without attachments', () => { + let quote: Quote; + + quote = { id: 1234, author: 'author', text: 'text' }; + const message = new ChatMessage({ + timestamp: Date.now(), + quote, + }); + const plainText = message.plainTextBuffer(); + const decoded = SignalService.Content.toObject(SignalService.Content.decode(plainText)); + const id = decoded.dataMessage.quote.id.toNumber(); + expect(id).to.be.deep.equal(1234); + expect(decoded.dataMessage.quote).to.have.deep.property('author', 'author'); + expect(decoded.dataMessage.quote).to.have.deep.property('text', 'text'); + }); + + it('can create message with a preview', () => { + let preview: Preview; + + preview = { url: 'url', title: 'title' }; + const previews = new Array(); + previews.push(preview); + + const message = new ChatMessage({ + timestamp: Date.now(), + preview: previews, + }); + const plainText = message.plainTextBuffer(); + const decoded = SignalService.Content.toObject(SignalService.Content.decode(plainText)); + expect(decoded.dataMessage.preview).to.have.lengthOf(1); + expect(decoded.dataMessage.preview[0]).to.have.deep.property('url', 'url'); + expect(decoded.dataMessage.preview[0]).to.have.deep.property('title', 'title'); + }); + + + it('can create message with an AttachmentPointer', () => { + let attachment: AttachmentPointer; + + attachment = { url: 'url', contentType: 'contentType', id: 1234 }; + const attachments = new Array(); + attachments.push(attachment); + + const message = new ChatMessage({ + timestamp: Date.now(), + attachments: attachments, + }); + const plainText = message.plainTextBuffer(); + const decoded = SignalService.Content.toObject(SignalService.Content.decode(plainText)); + expect(decoded.dataMessage.attachments).to.have.lengthOf(1); + expect(decoded.dataMessage.attachments[0]).to.have.deep.property('url', 'url'); + const id = decoded.dataMessage.attachments[0].id.toNumber(); + expect(id).to.be.equal(1234); + expect(decoded.dataMessage.attachments[0]).to.have.deep.property('contentType', 'contentType'); + }); + + it('ttl of 1 day', () => { + const message = new ChatMessage({ + timestamp: Date.now(), + }); + expect(message.ttl()).to.equal(24 * 60 * 60 * 1000); + }); + + it('has an identifier', () => { + const message = new ChatMessage({ + timestamp: Date.now(), + }); + expect(message.identifier).to.not.equal(null, 'identifier cannot be null'); + expect(message.identifier).to.not.equal(undefined, 'identifier cannot be undefined'); + }); +});