Public Access
98 lines
4.3 KiB
React
98 lines
4.3 KiB
React
// @vitest-environment jsdom
|
|
import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest';
|
|
import {cleanup, fireEvent, render, screen, waitFor} from '@testing-library/react';
|
|
import {MemoryRouter} from 'react-router-dom';
|
|
import {toast} from 'sonner';
|
|
import AdminUsersPage from './AdminUsersPage.jsx';
|
|
import {PreferencesProvider} from '../context/PreferencesContext.jsx';
|
|
|
|
vi.mock('react-i18next', () => import('../test/i18n-mock.js'));
|
|
vi.mock('sonner', () => ({toast: {success: vi.fn(), error: vi.fn()}}));
|
|
|
|
const PLAYER = {
|
|
id: 7, email: 'player@example.com', displayName: 'Player', role: 'USER', registrationDate: '2026-09-01T10:00:00',
|
|
lastLoginDate: null, steamLinked: true, blocked: false, deletedAt: null,
|
|
};
|
|
const ADMIN = {...PLAYER, id: 1, email: 'admin@example.com', role: 'PLATFORM_ADMIN', steamLinked: false};
|
|
|
|
const page = (content, totalPages = 1) => ({content, page: 0, size: 20, totalElements: content.length, totalPages});
|
|
const answer = (status, body) => ({ok: status < 300, status, headers: new Headers(), json: async () => body});
|
|
|
|
const renderPage = () => render(<MemoryRouter><PreferencesProvider><AdminUsersPage/></PreferencesProvider></MemoryRouter>);
|
|
const calls = (method) => fetch.mock.calls.filter(([, init]) => (init?.method ?? 'GET') === method);
|
|
|
|
describe('AdminUsersPage', () => {
|
|
beforeEach(() => {
|
|
localStorage.setItem('tbp_session', '1');
|
|
globalThis.fetch = vi.fn(async (url, init) => (init?.method ? answer(204) : answer(200, page([ADMIN, PLAYER]))));
|
|
});
|
|
|
|
afterEach(() => {
|
|
cleanup();
|
|
localStorage.clear();
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it('lists the users and offers no action on an admin', async () => {
|
|
renderPage();
|
|
|
|
expect(await screen.findByText('player@example.com')).toBeTruthy();
|
|
expect(screen.getByText('admin@example.com')).toBeTruthy();
|
|
expect(screen.getAllByRole('button', {name: 'ADMIN.BLOCK'})).toHaveLength(1);
|
|
expect(screen.getByText('ADMIN.STEAM')).toBeTruthy();
|
|
});
|
|
|
|
it('searches by the typed text from the first page', async () => {
|
|
renderPage();
|
|
await screen.findByText('player@example.com');
|
|
|
|
fireEvent.change(screen.getByPlaceholderText('ADMIN.SEARCH'), {target: {value: ' play '}});
|
|
fireEvent.submit(screen.getByPlaceholderText('ADMIN.SEARCH').closest('form'));
|
|
|
|
await waitFor(() => expect(calls('GET').at(-1)[0]).toContain('query=play&page=0'));
|
|
});
|
|
|
|
it('blocks a user after the confirm and loads the list again', async () => {
|
|
renderPage();
|
|
fireEvent.click(await screen.findByRole('button', {name: 'ADMIN.BLOCK'}));
|
|
|
|
fireEvent.click(screen.getAllByRole('button', {name: 'ADMIN.BLOCK'}).at(-1));
|
|
|
|
await waitFor(() => expect(toast.success).toHaveBeenCalledWith('ADMIN.DONE_BLOCK'));
|
|
const [url, init] = calls('PUT')[0];
|
|
expect(url).toMatch(/\/api\/admin\/users\/7\/blocked$/);
|
|
expect(JSON.parse(init.body)).toEqual({blocked: true});
|
|
expect(calls('GET')).toHaveLength(2);
|
|
});
|
|
|
|
it('deletes only after the email is typed', async () => {
|
|
renderPage();
|
|
fireEvent.click(await screen.findByRole('button', {name: 'ADMIN.DELETE'}));
|
|
const confirm = () => screen.getAllByRole('button', {name: 'ADMIN.DELETE'}).at(-1);
|
|
expect(confirm().disabled).toBe(true);
|
|
|
|
fireEvent.change(screen.getByLabelText('ADMIN.TYPE_EMAIL'), {target: {value: 'PLAYER@example.com'}});
|
|
fireEvent.click(confirm());
|
|
|
|
await waitFor(() => expect(calls('DELETE')[0][0]).toMatch(/\/api\/admin\/users\/7$/));
|
|
});
|
|
|
|
it('shows the reason when Auth refuses', async () => {
|
|
fetch.mockImplementation(async (url, init) => (init?.method
|
|
? answer(409, {code: 'TARGET_IS_ADMIN'}) : answer(200, page([PLAYER]))));
|
|
renderPage();
|
|
fireEvent.click(await screen.findByRole('button', {name: 'ADMIN.BLOCK'}));
|
|
|
|
fireEvent.click(screen.getAllByRole('button', {name: 'ADMIN.BLOCK'}).at(-1));
|
|
|
|
await waitFor(() => expect(toast.error).toHaveBeenCalledWith('ADMIN.ERROR_TARGET_IS_ADMIN'));
|
|
});
|
|
|
|
it('says no access to a user without the admin role', async () => {
|
|
fetch.mockResolvedValue(answer(403, {}));
|
|
renderPage();
|
|
|
|
expect(await screen.findByText('ADMIN.NO_ACCESS')).toBeTruthy();
|
|
});
|
|
});
|