feat(social): add friends, private chats, inbox and music sharing
ci / module boundaries / boundaries (push) Successful in 7s
ci / api / api (push) Successful in 1m9s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m8s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m23s
ci / db / db (push) Successful in 2m29s
ci / ts / ts (packages + web) (push) Successful in 2m55s
ci / module boundaries / boundaries (push) Successful in 7s
ci / api / api (push) Successful in 1m9s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m8s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m23s
ci / db / db (push) Successful in 2m29s
ci / ts / ts (packages + web) (push) Successful in 2m55s
This commit is contained in:
1 parent
f1528de948
commit
0a05bfe2cd
43 files changed
+2828
-389
No files matched your search
@@ -14,6 +14,49 @@ import { albumTracks, fakeApi, makeUser, type FakeUser } from './test/fakeApi';
|
||||
|
||||
afterEach(cleanup);
|
||||
|
||||
describe('social', () => {
|
||||
it('shows persistent notifications and acknowledges only the chosen event', async () => {
|
||||
const alice = makeUser('alice', 'user');
|
||||
const bob = makeUser('bob', 'user');
|
||||
const { api, user, queryClient } = await renderApp([alice, bob], '/friends', { signedInAs: alice });
|
||||
await screen.findByRole('heading', { name: 'Друзья и общение' });
|
||||
api.notifications.push({ id: crypto.randomUUID(), recipient: alice.id, actor_id: bob.id, actor_name: 'bob', kind: 'friend_request', created_at: new Date().toISOString(), read: false });
|
||||
await queryClient.invalidateQueries({ queryKey: ['social'] });
|
||||
await user.click(await screen.findByRole('button', { name: 'Уведомления 1' }));
|
||||
await screen.findByText('Хочет добавить вас в друзья');
|
||||
await user.click(screen.getByRole('button', { name: 'Прочитано' }));
|
||||
await waitFor(() => expect(screen.queryByRole('button', { name: 'Прочитано' })).not.toBeInTheDocument());
|
||||
expect(api.notifications[0]?.read).toBe(true);
|
||||
expect(api.calls.filter(c => c.path.endsWith('/actions')).at(-1)?.body).toMatchObject({ action: 'read_notification', target_id: api.notifications[0]!.id });
|
||||
});
|
||||
it('searches, requests, cancels, accepts and exchanges messages and music', async () => {
|
||||
const alice = makeUser('alice', 'user');
|
||||
const bob = makeUser('bob', 'user', { display_name: 'Борис' });
|
||||
const { api, router, user, queryClient } = await renderApp([alice, bob], '/friends', { signedInAs: alice });
|
||||
await user.type(await screen.findByLabelText('Найти по имени или логину'), 'bob');
|
||||
await user.click(await screen.findByRole('button', { name: 'В друзья' }));
|
||||
await screen.findByRole('button', { name: 'Отменить заявку' });
|
||||
await user.click(screen.getByRole('button', { name: 'Отменить заявку' }));
|
||||
await screen.findByRole('button', { name: 'В друзья' });
|
||||
api.friendships.set([alice.id, bob.id].sort().join(':'), { sender: bob.id, accepted: false });
|
||||
await queryClient.invalidateQueries({ queryKey: ['social'] });
|
||||
await user.click(await screen.findByRole('button', { name: 'Принять' }));
|
||||
await user.click(await screen.findByRole('button', { name: 'Написать' }));
|
||||
await user.type(await screen.findByLabelText('Сообщение', { exact: true }), 'Привет, послушай это');
|
||||
await user.click(screen.getByRole('button', { name: 'Отправить' }));
|
||||
expect(await screen.findByText('Привет, послушай это')).toBeInTheDocument();
|
||||
expect(api.messages).toHaveLength(1);
|
||||
await router.navigate({ to: '/track/$id', params: { id: albumTracks[0]!.id } });
|
||||
await user.click(await screen.findByRole('button', { name: 'Слушать' }));
|
||||
const player = screen.getByRole('contentinfo', { name: 'Плеер' });
|
||||
await user.click(within(player).getByRole('button', { name: 'Поделиться треком' }));
|
||||
await user.click(await screen.findByRole('button', { name: 'Борис · Отправить' }));
|
||||
await screen.findByRole('button', { name: 'Борис · Отправлено' });
|
||||
expect(api.messages.at(-1)).toMatchObject({ attachment_kind: 'track', attachment_id: albumTracks[0]!.id, recipient: bob.id });
|
||||
expect(screen.getByRole('button', { name: 'Борис · Отправлено' })).toBeDisabled();
|
||||
});
|
||||
});
|
||||
|
||||
async function renderApp(users: FakeUser[], path = '/', opts: { signedInAs?: FakeUser } = {}) {
|
||||
const api = fakeApi(users);
|
||||
const i18n = await createI18n('ru');
|
||||
@@ -27,7 +70,7 @@ async function renderApp(users: FakeUser[], path = '/', opts: { signedInAs?: Fak
|
||||
<App session={session} router={router} queryClient={queryClient} />
|
||||
</I18nextProvider>,
|
||||
);
|
||||
return { api, router, session, i18n, user: userEvent.setup() };
|
||||
return { api, router, session, i18n, queryClient, user: userEvent.setup() };
|
||||
}
|
||||
|
||||
describe('sign-in', () => {
|
||||
@@ -294,7 +337,8 @@ describe('player', () => {
|
||||
await user.click(screen.getByRole('button', { name: 'Слушать' }));
|
||||
const bar = screen.getByRole('contentinfo', { name: 'Плеер' });
|
||||
await user.click(within(bar).getByRole('button', { name: 'Поделиться треком' }));
|
||||
expect(await within(bar).findByRole('status')).toHaveTextContent('Ссылка на трек скопирована');
|
||||
await user.click(await screen.findByRole('button', { name: 'Скопировать ссылку' }));
|
||||
await screen.findByRole('button', { name: 'Ссылка скопирована' });
|
||||
expect(await navigator.clipboard.readText()).toBe(`${window.location.origin}${path}`);
|
||||
});
|
||||
|
||||
@@ -517,7 +561,9 @@ describe('playlist sharing', () => {
|
||||
await router.navigate({ to: '/playlist/$id', params: { id: playlist.id } });
|
||||
await screen.findByRole('heading', { name: 'Общий микс' });
|
||||
await user.click(screen.getByRole('button', { name: 'Поделиться плейлистом' }));
|
||||
expect(await screen.findByRole('status')).toHaveTextContent('Ссылка на плейлист скопирована');
|
||||
await user.click(await screen.findByRole('button', { name: 'Скопировать ссылку' }));
|
||||
await screen.findByRole('button', { name: 'Ссылка скопирована' });
|
||||
await user.click(within(screen.getByRole('dialog')).getByRole('button', { name: 'Закрыть' }));
|
||||
const shareId = api.playlists.get(playlist.id)!.share_id!;
|
||||
expect(await navigator.clipboard.readText()).toBe(`${window.location.origin}/shared/playlist/${shareId}`);
|
||||
await user.click(screen.getByRole('button', { name: 'Поделиться плейлистом' }));
|
||||
|
||||
Reference in new issue
Block a user