feat(web): чат Фазы 2 — лента, композер, реакции, ответы, поиск и вложения
Полноценный текстовый чат в веб-клиенте:
- стор сообщений по комнатам (кэш 200, оптимистичная отправка с nonce,
применение всех событий Gateway, пагинация курсором, непрочитанные и
упоминания, сброс при логауте и INVALID_SESSION);
- лента: группировка подряд идущих сообщений одного автора, разделители дат,
разделитель «новые сообщения», подгрузка истории вверх, пустые состояния;
- разметка: жирный/курсив/код/блок кода/зачёркнутый/цитата/ссылки (только
http(s)) и упоминания <@id> — безопасный рендер React-узлами без
dangerouslySetInnerHTML;
- реакции чипами с подсветкой своих, быстрые эмодзи и пикер, панель действий и
контекстное меню (ответ, реакция, закрепление, правка, удаление, копирование);
- ответы с переходом к оригиналу, inline-правка, «печатает…» с POST /typing раз
в 3 с, пины в модалке, поиск по комнате с подсветкой и переходом;
- композер: автовысота, Enter/Shift+Enter, лимит 4000, drag&drop и скрепка
(POST /channels/{id}/files → attachment_ids), обработка 429 с таймером и
perm.denied с причиной, read-only без SEND_MESSAGES;
- бейджи непрочитанных и упоминаний в сайдбаре, авто-POST /ack при активном окне;
- 176 тестов Vitest (было 100), check/lint/test/build зелёные.
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
||||
json,
|
||||
makeReadySnapshot,
|
||||
makeUser,
|
||||
messagesRoutes,
|
||||
recordedRequests,
|
||||
renderApp,
|
||||
} from './helpers';
|
||||
@@ -90,6 +91,9 @@ describe('основной экран', () => {
|
||||
{ match: '/api/v1/users/@me', response: () => json({ user }) },
|
||||
{ match: '/api/v1/instance', response: () => json({ instance: { name: 'glchat-test' } }) },
|
||||
{ match: '/api/v1/users/@me/guilds', response: () => json({ guilds: [] }) },
|
||||
{ match: '/api/v1/guilds/g-1/members', response: () => json({ members: [] }) },
|
||||
{ match: '/api/v1/guilds/g-1/roles', response: () => json({ roles: [] }) },
|
||||
...messagesRoutes('c-general', []),
|
||||
]);
|
||||
const gateway = installGatewaySocket(snapshot);
|
||||
|
||||
@@ -118,8 +122,9 @@ describe('основной экран', () => {
|
||||
// Выход переехал во всплывающее меню (проверяется в tests/userMenu.test.tsx).
|
||||
expect(within(panel).getByLabelText('Открыть меню пользователя')).toBeVisible();
|
||||
|
||||
// Заглушка комнаты вместо чата Фазы 1: шапка комнаты + подсказка.
|
||||
expect(await screen.findByText('Чат появится в Фазе 2')).toBeVisible();
|
||||
// Фаза 2: вместо заглушки в области комнаты открывается чат.
|
||||
expect(await screen.findByTestId('composer')).toBeVisible();
|
||||
expect(await screen.findByTestId('chat-start')).toHaveTextContent('Это начало комнаты #общий');
|
||||
expect(screen.getByRole('heading', { name: 'общий' })).toBeVisible();
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user