Files

154 lines
5.6 KiB
TypeScript
Raw Permalink Normal View History

import { beforeEach, describe, expect, it } from 'vitest';
import { screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import {
findRequest,
installFetch,
installFailingFetch,
json,
makeUser,
renderApp,
resetStores,
type FetchRoute,
} from './helpers';
/**
* Страница приглашения `/invite/{code}` (AGENT.md 7.9): splash сервера или
* переопределение приглашения, карточка сервера, пригласивший и присоединение.
*/
const user = makeUser();
function guildPreview(overrides: Record<string, unknown> = {}) {
return {
id: 'g-9',
name: 'Сообщество',
icon_file_id: 'icon-9',
splash_file_id: 'splash-9',
description: 'Обсуждаем всё подряд',
member_count: 12,
is_member: false,
inviter: { id: 'user-2', username: 'bob', display_name: 'Боб', avatar_file_id: 'av-2' },
...overrides,
};
}
function routes(
options: { guild?: Record<string, unknown>; background?: string } = {},
): FetchRoute[] {
return [
{
match: '/api/v1/invites/abc123',
method: 'POST',
response: () => json({ guild_id: 'g-9' }),
},
{
match: '/api/v1/invites/abc123',
response: () =>
json({
invite: {
code: 'abc123',
guild_id: 'g-9',
...(options.background === undefined ? {} : { background_file_id: options.background }),
},
guild: options.guild ?? guildPreview(),
}),
},
{ 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-9/channels', response: () => json({ channels: [] }) },
{
match: '/api/v1/guilds/g-9',
response: () => json({ guild: { id: 'g-9', name: 'Сообщество' } }),
},
];
}
beforeEach(() => {
resetStores();
});
describe('страница приглашения', () => {
it('показывает splash сервера, карточку и пригласившего', async () => {
installFetch(routes());
renderApp('/invite/abc123');
const page = await screen.findByTestId('invite-page');
expect(await screen.findByTestId('invite-guild-name')).toHaveTextContent('Сообщество');
expect(screen.getByText('Обсуждаем всё подряд')).toBeVisible();
expect(screen.getByText('Участников: 12')).toBeVisible();
expect(screen.getByTestId('invite-inviter')).toHaveTextContent('Боб');
// Splash сервера становится фоном страницы.
const background = screen.getByTestId('invite-background').parentElement;
expect(background?.querySelector('img')?.getAttribute('src')).toBe('/files/splash-9');
expect(page).toBeInTheDocument();
});
it('переопределение приглашения важнее splash сервера', async () => {
installFetch(routes({ background: 'invite-bg' }));
renderApp('/invite/abc123');
await screen.findByTestId('invite-page');
const background = await screen.findByTestId('invite-background');
expect(background.parentElement?.querySelector('img')?.getAttribute('src')).toBe(
'/files/invite-bg',
);
});
it('присоединяет по кнопке и открывает сервер', async () => {
const fetchMock = installFetch(routes());
const { router } = renderApp('/invite/abc123');
await userEvent.click(await screen.findByTestId('invite-accept'));
await waitFor(() => {
expect(findRequest(fetchMock, { url: '/invites/abc123', method: 'POST' })).toBeDefined();
});
await waitFor(() => {
expect(router.state.location.pathname).toBe('/app/g-9');
});
});
it('для участника показывает «Открыть сервер» вместо присоединения', async () => {
installFetch(routes({ guild: guildPreview({ is_member: true }) }));
renderApp('/invite/abc123');
expect(await screen.findByTestId('invite-open')).toBeVisible();
expect(screen.queryByTestId('invite-accept')).toBeNull();
});
it('недействительное приглашение объясняет ошибку', async () => {
installFailingFetch();
renderApp('/invite/broken');
expect(await screen.findByTestId('invite-page')).toBeInTheDocument();
expect(await screen.findByText('Приглашение не работает')).toBeVisible();
});
});
describe('страница приглашения для гостя', () => {
it('показывает карточку и ведёт на вход с возвратом', async () => {
installFetch([
{
match: '/api/v1/invites/abc123',
response: () =>
json({
invite: { code: 'abc123', guild_id: 'g-9' },
guild: guildPreview({ is_member: false }),
}),
},
{
match: '/api/v1/users/@me',
response: () => json({ error: { code: 'auth.session_expired', message: 'no' } }, 401),
},
{ match: '/api/v1/instance', response: () => json({ instance: { name: 'glchat-test' } }) },
]);
renderApp('/invite/abc123');
expect(await screen.findByTestId('invite-guild-name')).toHaveTextContent('Сообщество');
await userEvent.click(screen.getByTestId('invite-login'));
expect(await screen.findByLabelText('Почта', { exact: true })).toBeVisible();
});
});