// @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();
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();
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();
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();
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();
await waitFor(() => expect(fetch).toHaveBeenCalled());
expect(screen.queryByRole('button')).toBeNull();
});
});