Files
ToBePlayed-Frontend/src/components/people/FollowButton.test.jsx
T
lobo 43c4862606
Build, Test & Push Frontend / quality-check (push) Successful in 34s
Build, Test & Push Frontend / docker (push) Successful in 23s
feat(ui): add follow button, follows card, and inbox page
2026-10-06 16:22:22 +02:00

71 lines
3.0 KiB
React

// @vitest-environment jsdom
import {afterEach, describe, expect, it, vi} from 'vitest';
import {cleanup, fireEvent, render, screen, waitFor} from '@testing-library/react';
import {toast} from 'sonner';
import FollowButton from './FollowButton.jsx';
import {fetchRoutes, json} from '../../test/fetchRoutes.js';
vi.mock('react-i18next', () => import('../../test/i18n-mock.js'));
vi.mock('sonner', () => ({toast: {success: vi.fn(), error: vi.fn()}}));
const noFollows = {following: [], followers: []};
const callsOf = (method) => fetch.mock.calls.filter(([, init]) => init?.method === method);
afterEach(() => {
cleanup();
vi.clearAllMocks();
});
describe('FollowButton', () => {
it('offersFollowAndFollowsByNameThenOffersUnfollow', async () => {
fetchRoutes({'GET /api/follows': json(200, noFollows), 'PUT /api/follows/by-name/Lobo%20Wolf': json(204)});
render(<FollowButton displayName="Lobo Wolf"/>);
fireEvent.click(await screen.findByRole('button', {name: 'FOLLOW.FOLLOW'}));
expect(await screen.findByRole('button', {name: 'FOLLOW.UNFOLLOW'})).toBeTruthy();
expect(callsOf('PUT')).toHaveLength(1);
});
it('offersUnfollowForANameAlreadyFollowedIgnoringCase', async () => {
fetchRoutes({'GET /api/follows': json(200, {following: [{id: 1, displayName: 'lobo'}], followers: []}),
'DELETE /api/follows/by-name/Lobo': json(204)});
render(<FollowButton displayName="Lobo"/>);
fireEvent.click(await screen.findByRole('button', {name: 'FOLLOW.UNFOLLOW'}));
expect(await screen.findByRole('button', {name: 'FOLLOW.FOLLOW'})).toBeTruthy();
expect(callsOf('DELETE')).toHaveLength(1);
});
it('saysSoWhenTheProfileCannotBeFollowed', async () => {
fetchRoutes({'GET /api/follows': json(200, noFollows),
'PUT /api/follows/by-name/Lobo': json(404, {code: 'PROFILE_NOT_FOUND'})});
render(<FollowButton displayName="Lobo"/>);
fireEvent.click(await screen.findByRole('button', {name: 'FOLLOW.FOLLOW'}));
expect(await screen.findByText('FOLLOW.NOT_FOLLOWABLE')).toBeTruthy();
expect(screen.queryByRole('button')).toBeNull();
});
it('toastsOnAnOtherErrorAndKeepsTheButton', async () => {
fetchRoutes({'GET /api/follows': json(200, noFollows),
'PUT /api/follows/by-name/Lobo': json(400, {code: 'FOLLOW_LIMIT'})});
render(<FollowButton displayName="Lobo"/>);
fireEvent.click(await screen.findByRole('button', {name: 'FOLLOW.FOLLOW'}));
await waitFor(() => expect(toast.error).toHaveBeenCalledWith('FOLLOW.LIMIT'));
expect(screen.getByRole('button', {name: 'FOLLOW.FOLLOW'})).toBeTruthy();
});
it('showsNoButtonWhenTheListDoesNotLoad', async () => {
fetchRoutes({'GET /api/follows': json(500, {})});
render(<FollowButton displayName="Lobo"/>);
await waitFor(() => expect(fetch).toHaveBeenCalled());
expect(screen.queryByRole('button')).toBeNull();
});
});