feat(ui): add follow button, follows card, and inbox page
Build, Test & Push Frontend / quality-check (push) Successful in 34s
Build, Test & Push Frontend / docker (push) Successful in 23s

This commit is contained in:
lobo committed 2026-10-06 16:22:22 +02:00
1 parent 3aed243e35
commit 43c4862606
23 files changed
+603 -2

No files matched your search

+58
View File
@@ -0,0 +1,58 @@
// @vitest-environment jsdom
import {afterEach, describe, expect, it, vi} from 'vitest';
import {cleanup, fireEvent, screen, waitFor} from '@testing-library/react';
import FollowsCard from './FollowsCard.jsx';
import {fetchRoutes, json} from '../test/fetchRoutes.js';
import {renderWithProviders} from '../test/renderWithProviders.jsx';
vi.mock('react-i18next', () => import('../test/i18n-mock.js'));
vi.mock('sonner', () => ({toast: {success: vi.fn(), error: vi.fn()}}));
afterEach(() => {
cleanup();
vi.clearAllMocks();
});
const follows = {following: [{id: 5, displayName: 'Lobo'}], followers: [{id: 6, displayName: 'Wolf'}, {id: 7, displayName: null}]};
describe('FollowsCard', () => {
it('listsBothSidesWithLinksAndPrivateFollowersWithoutAName', async () => {
fetchRoutes({'GET /api/follows': json(200, follows)});
renderWithProviders(<FollowsCard/>);
expect((await screen.findByRole('link', {name: 'Lobo'})).getAttribute('href')).toBe('/u/Lobo');
expect(screen.getByRole('link', {name: 'Wolf'}).getAttribute('href')).toBe('/u/Wolf');
expect(screen.getByText('FOLLOW.PRIVATE_USER')).toBeTruthy();
});
it('unfollowsByRowIdAndLoadsTheListAgain', async () => {
let answered = follows;
fetchRoutes({'GET /api/follows': () => json(200, answered),
'DELETE /api/follows/5': () => {
answered = {...follows, following: []};
return json(204);
}});
renderWithProviders(<FollowsCard/>);
fireEvent.click(await screen.findByRole('button', {name: 'FOLLOW.UNFOLLOW'}));
await waitFor(() => expect(screen.queryByRole('link', {name: 'Lobo'})).toBeNull());
expect(screen.getByText('FOLLOW.NO_FOLLOWING')).toBeTruthy();
});
it('removesAFollowerByRowId', async () => {
fetchRoutes({'GET /api/follows': json(200, follows), 'DELETE /api/follows/7': json(204)});
renderWithProviders(<FollowsCard/>);
fireEvent.click((await screen.findAllByRole('button', {name: 'FOLLOW.REMOVE'}))[1]);
await waitFor(() => expect(fetch.mock.calls.filter(([, init]) => init?.method === 'DELETE')).toHaveLength(1));
});
it('saysSoWhenTheListDoesNotLoad', async () => {
fetchRoutes({'GET /api/follows': json(500, {})});
renderWithProviders(<FollowsCard/>);
expect(await screen.findByText('FOLLOW.LOAD_ERROR')).toBeTruthy();
});
});