feat(dashboard): playtime chart, recently played and a playing hint

The dashboard shows the playtime of the last 30 days and Steam's recently
played games. The detail page offers to set a backlog game to Playing when
Steam reports recent playtime; unsaved edits in the backlog card stay.
This commit is contained in:
lobo committed 2026-09-24 13:41:37 +02:00
1 parent d4c0f8d8f3
commit 89c5ba5253
11 files changed
+334 -15

No files matched your search

+44
View File
@@ -0,0 +1,44 @@
// @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 PlayingHint from './PlayingHint.jsx';
vi.mock('react-i18next', () => import('../test/i18n-mock.js'));
vi.mock('sonner', () => ({toast: {success: vi.fn(), error: vi.fn()}}));
const game = {appid: 220, status: 'BACKLOG', rating: 3, notes: 'keep', priority: 'HIGH', playtime2Weeks: 90};
const renderHint = (props) => render(<MemoryRouter><PlayingHint game={game} onChanged={() => {}} {...props}/></MemoryRouter>);
describe('PlayingHint', () => {
beforeEach(() => {
localStorage.setItem('tbp_jwt', 'token');
globalThis.fetch = vi.fn(async (url, init) => ({ok: true, status: 200, json: async () => JSON.parse(init.body)}));
});
afterEach(() => {
cleanup();
localStorage.clear();
});
it.each([
['a game that is not in the backlog', {...game, status: 'PLAYING'}],
['a backlog game without recent playtime', {...game, playtime2Weeks: 0}],
])('is hidden for %s', (_, other) => {
renderHint({game: other});
expect(screen.queryByRole('button')).toBeNull();
});
it('sets the game to PLAYING and keeps the other fields', async () => {
const onChanged = vi.fn();
renderHint({onChanged});
fireEvent.click(screen.getByRole('button', {name: 'GAME_DETAIL.SET_PLAYING'}));
await waitFor(() => expect(onChanged).toHaveBeenCalledWith({status: 'PLAYING', rating: 3, notes: 'keep', priority: 'HIGH'}));
const [url, init] = fetch.mock.calls[0];
expect(url).toMatch(/\/api\/library\/games\/220\/backlog$/);
expect(JSON.parse(init.body)).toEqual({status: 'PLAYING', rating: 3, notes: 'keep', priority: 'HIGH'});
});
});