Public Access
New page /audit/games: search every game and open the correction dialog without owning it. Time to beat as hours + minutes. Audit log game links open /audit/games?appid=. Menu entry next to the link queue.
92 lines
3.6 KiB
React
92 lines
3.6 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 GameCatalogPage from './GameCatalogPage.jsx';
|
|
import {PreferencesProvider} from '../context/PreferencesContext.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 hit = {appid: 10, name: 'Hades', imageUrl: null, platforms: ['PS5', 'Steam']};
|
|
const detail = {appid: 10, name: 'Hades', imageUrl: null, speedrunUrl: null, moods: [], endless: null, genres: [],
|
|
timeToBeat: null, corrections: []};
|
|
const catalog = (content, totalPages = 1) => json(200, {content, page: 0, size: 20, totalElements: content.length, totalPages});
|
|
|
|
const renderPage = (routes, url = '/audit/games') => {
|
|
fetchRoutes(routes);
|
|
render(<MemoryRouter initialEntries={[url]}><PreferencesProvider><GameCatalogPage/></PreferencesProvider></MemoryRouter>);
|
|
};
|
|
|
|
const urls = () => fetch.mock.calls.map(([url]) => url);
|
|
|
|
beforeEach(() => {
|
|
localStorage.setItem('tbp_session', '1');
|
|
});
|
|
|
|
afterEach(() => {
|
|
cleanup();
|
|
localStorage.clear();
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
describe('GameCatalogPage', () => {
|
|
it('listsHitsWithPlatformsAndKey', async () => {
|
|
renderPage({'GET /api/library/catalog': catalog([hit])});
|
|
|
|
expect(await screen.findByText('Hades')).toBeTruthy();
|
|
expect(screen.getByText(/PS5, Steam/)).toBeTruthy();
|
|
expect(screen.getByText(/CATALOG.KEY/)).toBeTruthy();
|
|
});
|
|
|
|
it('searchesWithTheTypedName', async () => {
|
|
renderPage({'GET /api/library/catalog': catalog([hit])});
|
|
await screen.findByText('Hades');
|
|
|
|
fireEvent.change(screen.getByLabelText('CATALOG.SEARCH'), {target: {value: ' had '}});
|
|
|
|
await waitFor(() => expect(urls().some((u) => u.includes('q=had'))).toBe(true));
|
|
});
|
|
|
|
it('opensTheCorrectionDialogForTheChosenGame', async () => {
|
|
renderPage({'GET /api/library/catalog': catalog([hit]), 'GET /api/library/catalog/10': json(200, detail)});
|
|
|
|
fireEvent.click(await screen.findByRole('button', {name: 'CATALOG.CORRECT'}));
|
|
|
|
expect(await screen.findByText('CORRECTION.TITLE')).toBeTruthy();
|
|
expect(urls().some((u) => u.endsWith('/api/library/catalog/10'))).toBe(true);
|
|
});
|
|
|
|
it('opensTheGameOfTheAppidInTheUrl', async () => {
|
|
renderPage({'GET /api/library/catalog': catalog([]), 'GET /api/library/catalog/10': json(200, detail)},
|
|
'/audit/games?appid=10');
|
|
|
|
expect(await screen.findByText('CORRECTION.TITLE')).toBeTruthy();
|
|
});
|
|
|
|
it('saysSoWhenTheGameIsGone', async () => {
|
|
const {toast} = await import('sonner');
|
|
renderPage({'GET /api/library/catalog': catalog([]), 'GET /api/library/catalog/10': json(404, {})},
|
|
'/audit/games?appid=10');
|
|
|
|
await waitFor(() => expect(toast.error).toHaveBeenCalledWith('CATALOG.GONE'));
|
|
expect(screen.queryByText('CORRECTION.TITLE')).toBeNull();
|
|
});
|
|
|
|
it('showsNoAccessOn403', async () => {
|
|
renderPage({'GET /api/library/catalog': json(403, {})});
|
|
|
|
expect(await screen.findByText('CATALOG.NO_ACCESS')).toBeTruthy();
|
|
});
|
|
|
|
it('pagesThroughTheCatalog', async () => {
|
|
renderPage({'GET /api/library/catalog': () => catalog([hit], 2)});
|
|
await screen.findByText('Hades');
|
|
|
|
fireEvent.click(screen.getByRole('button', {name: /ADMIN.NEXT/}));
|
|
|
|
await waitFor(() => expect(urls().at(-1)).toContain('page=1'));
|
|
});
|
|
});
|