feat(library): search IGDB and add games by hand
Build, Test & Push Frontend / quality-check (push) Successful in 13s
Build, Test & Push Frontend / docker (push) Successful in 23s

This commit is contained in:
lobo committed 2026-09-25 14:37:21 +02:00
1 parent d9a39dda22
commit 444b03acee
17 files changed
+699 -35

No files matched your search

+74 -3
View File
@@ -13,9 +13,12 @@ const game = {
rating: null, notes: null, priority: null, hasAchievements: false, statsVisible: false, achievements: [],
};
const renderDetail = () => render(
<MemoryRouter initialEntries={['/library/220']}><PreferencesProvider>
<Routes><Route path="/library/:appid" element={<GameDetail/>}/></Routes>
const renderDetail = (appid = 220) => render(
<MemoryRouter initialEntries={[`/library/${appid}`]}><PreferencesProvider>
<Routes>
<Route path="/library/:appid" element={<GameDetail/>}/>
<Route path="/library" element={<p>library page</p>}/>
</Routes>
</PreferencesProvider></MemoryRouter>,
);
@@ -81,3 +84,71 @@ describe('GameDetail', () => {
expect(JSON.parse(init.body)).toMatchObject({bannerAppid: 220, showBanner: true});
});
});
describe('GameDetail of a game added by hand', () => {
const manualGame = {
...game, appid: -1025, name: 'Zelda', source: 'MANUAL', platform: 'Nintendo Switch', playtimeMinutes: 90,
playtime2Weeks: 0, imageUrl: 'https://images.igdb.com/z.jpg',
};
beforeEach(() => {
globalThis.fetch = vi.fn(async (url, init) => (init?.method === 'PUT' || init?.method === 'DELETE')
? {ok: true, status: 204, json: async () => { throw new Error('204 has no body'); }}
: {ok: true, status: 200, json: async () => manualGame});
});
it('shows platform and IGDB picture, and offers no Steam actions', async () => {
const {container} = renderDetail(-1025);
expect(await screen.findByLabelText('MANUAL_GAME.PLATFORM')).toBeTruthy();
expect(screen.getAllByText('Nintendo Switch').length).toBeGreaterThan(0);
expect(container.querySelector('img[src="https://images.igdb.com/z.jpg"]')).toBeTruthy();
expect(screen.queryByRole('button', {name: 'GAME_DETAIL.SET_BACKGROUND'})).toBeNull();
expect(screen.queryByRole('button', {name: 'GAME_DETAIL.SET_BANNER'})).toBeNull();
expect(screen.queryByText('GAME_DETAIL.OPEN_IN_STEAM')).toBeNull();
expect(screen.getByText('MANUAL_GAME.NO_ACHIEVEMENTS')).toBeTruthy();
});
it('saves platform and hours', async () => {
renderDetail(-1025);
fireEvent.change(await screen.findByLabelText('MANUAL_GAME.HOURS'), {target: {value: '2.5'}});
fireEvent.change(screen.getByLabelText('MANUAL_GAME.PLATFORM'), {target: {value: ' PS5 '}});
const saveButtons = screen.getAllByRole('button', {name: 'BACKLOG.SAVE'});
fireEvent.click(saveButtons.at(-1));
await waitFor(() => expect(fetch.mock.calls.some(([, call]) => call?.method === 'PUT')).toBe(true));
const [url, init] = fetch.mock.calls.find(([, call]) => call?.method === 'PUT');
expect(url).toContain('/api/library/games/-1025/manual');
expect(JSON.parse(init.body)).toEqual({platform: 'PS5', playtimeMinutes: 150});
});
it('removes the game only after the confirm step and goes back to the library', async () => {
renderDetail(-1025);
fireEvent.click(await screen.findByRole('button', {name: 'MANUAL_GAME.REMOVE'}));
expect(fetch.mock.calls.some(([, call]) => call?.method === 'DELETE')).toBe(false);
fireEvent.click(screen.getByRole('button', {name: 'MANUAL_GAME.REMOVE_YES'}));
expect(await screen.findByText('library page')).toBeTruthy();
const [url] = fetch.mock.calls.find(([, call]) => call?.method === 'DELETE');
expect(url).toContain('/api/library/games/-1025');
});
it('keeps Save off for an unchanged game with 75 minutes', async () => {
globalThis.fetch = vi.fn(async () => ({ok: true, status: 200, json: async () => ({...manualGame, playtimeMinutes: 75})}));
renderDetail(-1025);
await screen.findByLabelText('MANUAL_GAME.HOURS');
expect(screen.getAllByRole('button', {name: 'BACKLOG.SAVE'}).at(-1).disabled).toBe(true);
});
it('shows no manual card for a Steam game', async () => {
globalThis.fetch = vi.fn(async () => ({ok: true, status: 200, json: async () => ({...game, source: 'STEAM'})}));
renderDetail();
expect(await screen.findByRole('button', {name: 'GAME_DETAIL.SET_BACKGROUND'})).toBeTruthy();
expect(screen.queryByText('MANUAL_GAME.TITLE')).toBeNull();
});
});