import { test } from 'node:test'; import assert from 'node:assert/strict'; import { IContent } from 'matrix-js-sdk'; import { mergeScheduledBody } from './ScheduleMessageModal'; // [Gitea #36] Pure merge of the modal textarea back into the composer-built // content: verbatim when unedited, body-only replacement (rich HTML dropped, // mentions + relation kept) when edited. const richContent: IContent = { msgtype: 'm.text', body: 'hello **bold** @alice', format: 'org.matrix.custom.html', formatted_body: 'hello bold alice', 'm.mentions': { user_ids: ['@alice:x'] }, 'm.relates_to': { 'm.in_reply_to': { event_id: '$reply' }, rel_type: 'm.thread', event_id: '$root', is_falling_back: false, }, }; test('mergeScheduledBody returns the content verbatim when the body is unedited', () => { assert.equal(mergeScheduledBody(richContent, richContent.body), richContent); // Whitespace-only differences (the textarea value is trimmed) still count as unedited. assert.equal(mergeScheduledBody(richContent, ` ${richContent.body}\n`), richContent); }); test('mergeScheduledBody drops stale formatting but keeps mentions and relation on edit', () => { const merged = mergeScheduledBody(richContent, 'edited text '); assert.deepEqual(merged, { msgtype: 'm.text', body: 'edited text', 'm.mentions': { user_ids: ['@alice:x'] }, 'm.relates_to': richContent['m.relates_to'], }); assert.equal('format' in merged, false); assert.equal('formatted_body' in merged, false); // Input is not mutated. assert.equal(richContent.formatted_body !== undefined, true); }); test('mergeScheduledBody builds a bare text content when opened blank', () => { assert.deepEqual(mergeScheduledBody(null, ' hi '), { body: 'hi', msgtype: 'm.text' }); assert.deepEqual(mergeScheduledBody(undefined, 'hi'), { body: 'hi', msgtype: 'm.text' }); }); test('mergeScheduledBody preserves a non-text msgtype on edit', () => { const merged = mergeScheduledBody({ msgtype: 'm.emote', body: 'waves' }, 'nods'); assert.deepEqual(merged, { msgtype: 'm.emote', body: 'nods' }); });