import { ICommentSource, buildCommentText, hasAttachments, toChatMessages } from './chatMessages'; const ME = 'ivan@tnsu.kz'; function comment(over: Partial): ICommentSource { return { id: '1', text: 'Сообщение', createdDate: '2026-08-21T09:00:00Z', author: { name: 'Иванов Иван', email: ME }, ...over }; } describe('toChatMessages', () => { it('сортирует от старых к новым — свежие в чате внизу', () => { const messages = toChatMessages( [ comment({ id: '2', createdDate: '2026-08-21T10:00:00Z', text: 'второе' }), comment({ id: '1', createdDate: '2026-08-21T09:00:00Z', text: 'первое' }) ], ME ); expect(messages.map((m) => m.text)).toEqual(['первое', 'второе']); }); it('свои сообщения помечаются по email автора, регистр не важен', () => { const messages = toChatMessages( [ comment({ id: '1', author: { name: 'Иванов Иван', email: 'IVAN@TNSU.KZ' } }), comment({ id: '2', author: { name: 'Петров Пётр', email: 'petr@tnsu.kz' } }) ], ME ); expect(messages[0].isOwn).toBe(true); expect(messages[1].isOwn).toBe(false); }); it('без текущего пользователя своих сообщений нет (а не все свои)', () => { const messages = toChatMessages([comment({})], ''); expect(messages[0].isOwn).toBe(false); }); it('пустые комментарии отбрасываются — пустой «пузырь» показывать нечего', () => { const messages = toChatMessages( [comment({ id: '1', text: '' }), comment({ id: '2', text: ' ' }), comment({ id: '3' })], ME ); expect(messages).toHaveLength(1); expect(messages[0].id).toBe('3'); }); it('дата без часового пояса читается как UTC, а не как местное время', () => { const withZone = toChatMessages([comment({ createdDate: '2026-08-21T09:00:00Z' })], ME); const withoutZone = toChatMessages([comment({ createdDate: '2026-08-21T09:00:00' })], ME); expect(withoutZone[0].createdAt.getTime()).toBe(withZone[0].createdAt.getTime()); }); it('автор без ФИО подписывается email, без email — заглушкой', () => { const messages = toChatMessages( [ comment({ id: '1', author: { email: 'petr@tnsu.kz' } }), comment({ id: '2', author: undefined }) ], ME ); expect(messages[0].authorName).toBe('petr@tnsu.kz'); expect(messages[1].authorName).toBe('Неизвестный автор'); }); }); describe('файлы в сообщении', () => { const FOLDER = '/sites/requests/Файлы чата/hr-vacation-12'; const FILE = '20260824-153012-1__акт.pdf'; const SECOND_FILE = '20260824-153012-2__скан.jpg'; it('пометка о файлах не показывается в тексте сообщения', () => { const messages = toChatMessages( [comment({ text: `Посмотрите акт\n[rp-files]${FILE}` })], ME, FOLDER ); expect(messages[0].text).toBe('Посмотрите акт'); }); it('файл получает исходное имя и ссылку в папке заявки', () => { const messages = toChatMessages( [comment({ text: `[rp-files]${FILE}|${SECOND_FILE}` })], ME, FOLDER ); expect(messages[0].text).toBe(''); expect(messages[0].attachments).toEqual([ { fileName: 'акт.pdf', url: `${FOLDER}/${FILE}` }, { fileName: 'скан.jpg', url: `${FOLDER}/${SECOND_FILE}` } ]); }); it('сообщение из одних файлов не отбрасывается как пустое', () => { const messages = toChatMessages([comment({ text: `[rp-files]${FILE}` })], ME, FOLDER); expect(messages).toHaveLength(1); }); it('пометка переживает перевод строки в формате Windows', () => { const messages = toChatMessages([comment({ text: `Текст\r\n[rp-files]${FILE}` })], ME, FOLDER); expect(messages[0].text).toBe('Текст'); expect(messages[0].attachments).toHaveLength(1); }); it('обычное сообщение остаётся без вложений', () => { const messages = toChatMessages([comment({ text: 'Просто текст' })], ME); expect(messages[0].attachments).toEqual([]); }); it('hasAttachments отличает переписку с файлами от переписки без них', () => { expect(hasAttachments([comment({ text: 'Просто текст' })])).toBe(false); expect(hasAttachments([comment({ text: `[rp-files]${FILE}` })])).toBe(true); }); }); describe('buildCommentText', () => { it('без файлов отдаёт очищенный текст', () => { expect(buildCommentText(' Привет ', [])).toBe('Привет'); }); it('с файлами дописывает пометку отдельной строкой', () => { expect(buildCommentText('Смотрите', ['a__акт.pdf', 'b__скан.jpg'])).toBe( 'Смотрите\n[rp-files]a__акт.pdf|b__скан.jpg' ); }); it('без текста остаётся одна пометка — отправка «только файл»', () => { expect(buildCommentText('', ['a__акт.pdf'])).toBe('[rp-files]a__акт.pdf'); }); it('собранный текст читается обратно без потерь', () => { const raw = buildCommentText('Смотрите акт', ['20260824-153012-1__акт.pdf']); const messages = toChatMessages([comment({ text: raw })], ME, '/f'); expect(messages[0].text).toBe('Смотрите акт'); expect(messages[0].attachments[0].fileName).toBe('акт.pdf'); }); });