fix(web): раздел «Эмодзи» обновляется событием, а не перезапросом

`GUILD_EMOJIS_UPDATE` несёт набор эмодзи целиком, но раздел настроек читает
REST-кэш, а клиент на событие запрос инвалидировал. Под нагрузкой повторный
`GET /guilds/{id}/emojis` попадает под лимит частоты (429), а запрос списка идёт
с `retry: 0` — список оставался старым до перезахода. Тот же дефект, что у
раздела «Звуки» (коммит 4175b14), и та же правка: событие кладёт набор в кэш
запроса через `setQueryData`, а ошибка перезапроса больше не прячет уже
полученный список.

Регрессионный тест `web/tests/guildEmojisSettings.test.tsx` («показывает эмодзи
из GUILD_EMOJIS_UPDATE, даже если список по REST не отдался») падает на старом
коде.
This commit is contained in:
2026-09-26 16:16:16 +03:00
parent 324d2aac72
commit 6afbdf621b
3 changed files with 51 additions and 13 deletions
+32 -2
View File
@@ -6,7 +6,9 @@ import {
apiError,
findRequest,
installFetch,
installGatewaySocket,
json,
makeReadySnapshot,
makeUser,
recordedRequests,
renderApp,
@@ -18,8 +20,9 @@ import {
/**
* Секция «Эмодзи» в настройках сервера (AGENT.md 7.12): список загруженных
* эмодзи со счётчиком, загрузка с клиентскими проверками, переименование и
* удаление. Лента и пикер видят изменения сразу — запросы эмодзи
* инвалидируются, а снапшот обновляет событие `GUILD_EMOJIS_UPDATE`.
* удаление. Лента и пикер видят изменения сразу: событие `GUILD_EMOJIS_UPDATE`
* несёт набор целиком и попадает прямо в кэш запроса, а свои операции
* инвалидируют список.
*/
const user = makeUser();
@@ -351,4 +354,31 @@ describe('настройки сервера: секция «Эмодзи»', ()
expect(findRequest(fetchMock, { url: '/emojis/e-1', method: 'DELETE' })).toBeDefined();
});
});
it('показывает эмодзи из GUILD_EMOJIS_UPDATE, даже если список по REST не отдался', async () => {
// Под нагрузкой ручка списка отвечает 429 (AGENT.md 8.6), а раздел должен
// обновляться снапшотом из события шлюза, а не повтором запроса (7.12).
const gateway = installGatewaySocket(
makeReadySnapshot([{ id: 'g-1', name: 'Сервер', my_permissions: ['MANAGE_EMOJIS'] }]),
);
installFetch(
routes({
extra: [
{
match: '/api/v1/guilds/g-1/emojis',
method: 'GET',
response: () => apiError('ratelimit.hit', 429),
},
],
}),
);
renderApp('/settings/servers/g-1');
const dialog = await screen.findByRole('dialog', { name: 'Настройки' });
await gateway.greet();
const fresh = { id: 'e-9', name: 'fresh', file_id: '920', animated: false, url: '/files/920' };
gateway.dispatch('GUILD_EMOJIS_UPDATE', { guild_id: 'g-1', emojis: [pepe, fresh] });
expect(await within(dialog).findByTestId('guild-emoji-e-1')).toHaveTextContent(':pepe:');
expect(within(dialog).getByTestId('guild-emoji-e-9')).toHaveTextContent(':fresh:');
});
});