Public Access
test: data router, one render helper, fetchRoutes in every test
This commit is contained in:
1 parent
d0ea9e900d
commit
2a22789435
37 files changed
+454
-425
No files matched your search
@@ -1,9 +1,10 @@
|
||||
// @vitest-environment jsdom
|
||||
import {afterEach, beforeEach, describe, expect, it, vi} from 'vitest';
|
||||
import {act, cleanup, fireEvent, render, screen, waitFor} from '@testing-library/react';
|
||||
import {MemoryRouter, Route, Routes, useLocation, useNavigate} from 'react-router-dom';
|
||||
import {createMemoryRouter, RouterProvider, useLocation, useNavigate} from 'react-router-dom';
|
||||
import GameLibrary from './GameLibrary.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('../hooks/useLibrarySync.js', () => ({default: () => ({status: 'OK', lastSyncedAt: null, isRunning: false})}));
|
||||
@@ -12,9 +13,14 @@ vi.mock('../hooks/useForceSync.js', () => ({default: () => ({trigger: vi.fn(), b
|
||||
const DEBOUNCE_WAIT_MS = 700;
|
||||
const page = {content: [{appid: 220, name: 'Half-Life 2', playtimeMinutes: 0, status: 'BACKLOG'}], page: 0, size: 20, totalElements: 1, totalPages: 1};
|
||||
|
||||
const answer = (games = page.content, hasSteamId = true) => fetchRoutes({
|
||||
'GET /api/library/games': json(200, {...page, content: games, totalElements: games.length, totalPages: games.length ? 1 : 0}),
|
||||
'GET /api/library/games-count': json(200, {count: games.length, hasSteamId}),
|
||||
});
|
||||
|
||||
const wait = (ms) => act(() => new Promise((resolve) => setTimeout(resolve, ms)));
|
||||
|
||||
// MemoryRouter, not createMemoryRouter: it pushes like the BrowserRouter in main.jsx, also for an unchanged URL.
|
||||
// A data router like main.jsx: a navigation to the same URL replaces the entry.
|
||||
function renderLibrary(initialEntry = '/library') {
|
||||
const lib = {navigations: 0, location: null, navigate: null};
|
||||
function Spy() {
|
||||
@@ -26,11 +32,11 @@ function renderLibrary(initialEntry = '/library') {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
render(
|
||||
<MemoryRouter initialEntries={[initialEntry]}><PreferencesProvider>
|
||||
<Routes><Route path="/library" element={<><GameLibrary/><Spy/></>}/></Routes>
|
||||
</PreferencesProvider></MemoryRouter>,
|
||||
);
|
||||
const router = createMemoryRouter([{
|
||||
path: '/library',
|
||||
element: <PreferencesProvider><GameLibrary/><Spy/></PreferencesProvider>,
|
||||
}], {initialEntries: [initialEntry]});
|
||||
render(<RouterProvider router={router}/>);
|
||||
return {
|
||||
navigations: () => lib.navigations,
|
||||
params: () => new URLSearchParams(lib.location.search),
|
||||
@@ -42,7 +48,7 @@ const typeInto = (value) => fireEvent.change(screen.getByRole('searchbox'), {tar
|
||||
|
||||
beforeEach(() => {
|
||||
localStorage.setItem('tbp_session', '1');
|
||||
globalThis.fetch = vi.fn(async () => ({ok: true, status: 200, json: async () => page}));
|
||||
answer();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
@@ -52,10 +58,10 @@ afterEach(() => {
|
||||
|
||||
describe('GameLibrary search', () => {
|
||||
it('shows the achievement progress of a game when it is known', async () => {
|
||||
globalThis.fetch = vi.fn(async () => ({ok: true, status: 200, json: async () => ({...page, content: [
|
||||
answer([
|
||||
{...page.content[0], achievementsUnlocked: 3, achievementsTotal: 4},
|
||||
{appid: 620, name: 'Portal 2', playtimeMinutes: 0, status: 'BACKLOG', achievementsUnlocked: null, achievementsTotal: 5},
|
||||
]})}));
|
||||
]);
|
||||
renderLibrary();
|
||||
|
||||
expect(await screen.findByText('3/4')).toBeTruthy();
|
||||
@@ -100,7 +106,7 @@ describe('GameLibrary search', () => {
|
||||
typeInto('half');
|
||||
await waitFor(() => expect(lib.params().get('q')).toBe('half'));
|
||||
|
||||
act(() => lib.back());
|
||||
await act(async () => lib.back());
|
||||
|
||||
await waitFor(() => expect(screen.getByRole('searchbox').value).toBe(''));
|
||||
});
|
||||
@@ -161,7 +167,7 @@ describe('GameLibrary short games', () => {
|
||||
});
|
||||
|
||||
it('says so when no game is hidden', async () => {
|
||||
globalThis.fetch = vi.fn(async () => ({ok: true, status: 200, json: async () => ({...page, content: [], totalElements: 0, totalPages: 0})}));
|
||||
answer([]);
|
||||
renderLibrary('/library?hidden=true');
|
||||
|
||||
expect(await screen.findByText('LIBRARY.NO_HIDDEN')).toBeTruthy();
|
||||
@@ -169,15 +175,11 @@ describe('GameLibrary short games', () => {
|
||||
});
|
||||
|
||||
describe('GameLibrary with games added by hand', () => {
|
||||
const answer = (games, hasSteamId) => vi.fn(async (url) => ({
|
||||
ok: true, status: 200,
|
||||
json: async () => (String(url).includes('/games-count') ? {count: games.length, hasSteamId} : {...page, content: games}),
|
||||
}));
|
||||
const zelda = {appid: -1025, name: 'Zelda', playtimeMinutes: 90, status: 'BACKLOG', source: 'MANUAL',
|
||||
platform: 'Nintendo Switch', imageUrl: 'https://images.igdb.com/z.jpg'};
|
||||
|
||||
it('shows the platform and the IGDB picture of a manual game', async () => {
|
||||
globalThis.fetch = answer([zelda], true);
|
||||
answer([zelda], true);
|
||||
renderLibrary();
|
||||
|
||||
expect(await screen.findByText('Nintendo Switch')).toBeTruthy();
|
||||
@@ -185,7 +187,7 @@ describe('GameLibrary with games added by hand', () => {
|
||||
});
|
||||
|
||||
it('shows Steam as the platform of a Steam game, and links the import', async () => {
|
||||
globalThis.fetch = answer([{appid: 220, name: 'Half-Life 2', playtimeMinutes: 0, status: 'BACKLOG', source: 'STEAM',
|
||||
answer([{appid: 220, name: 'Half-Life 2', playtimeMinutes: 0, status: 'BACKLOG', source: 'STEAM',
|
||||
platform: null}], true);
|
||||
renderLibrary();
|
||||
|
||||
@@ -194,7 +196,7 @@ describe('GameLibrary with games added by hand', () => {
|
||||
});
|
||||
|
||||
it('hides the Steam sync for a user without a Steam ID but still offers adding a game', async () => {
|
||||
globalThis.fetch = answer([zelda], false);
|
||||
answer([zelda], false);
|
||||
renderLibrary();
|
||||
|
||||
await screen.findByText('Zelda');
|
||||
@@ -203,7 +205,7 @@ describe('GameLibrary with games added by hand', () => {
|
||||
});
|
||||
|
||||
it('opens the add panel', async () => {
|
||||
globalThis.fetch = answer([zelda], true);
|
||||
answer([zelda], true);
|
||||
renderLibrary();
|
||||
|
||||
fireEvent.click(await screen.findByRole('button', {name: 'MANUAL_GAME.ADD_BUTTON'}));
|
||||
|
||||
Reference in new issue
Block a user