perf(dashboard): load core data in parallel with /me
Build, Test & Push Frontend / quality-check (push) Successful in 36s
Build, Test & Push Frontend / docker (push) Successful in 22s

The dashboard no longer waits for /me before it calls the library.
History loads when games-count says canSync or fails. Refs #40.
This commit is contained in:
lobo committed 2026-10-11 11:05:18 +02:00
1 parent 84b16a2ca8
commit 4b25e7f5fe
3 files changed
+40 -15

No files matched your search

+27 -3
View File
@@ -32,7 +32,7 @@ const dashboardRoutes = (settings) => ({
'GET /api/library/steam-profile': json(200, {personaName: 'Lobo', avatarUrl: avatar}),
'GET /api/library/activity': json(200, {totalMinutes: 90, days: [{day: '2026-09-23', minutes: 0}, {day: '2026-09-24', minutes: 90}], recentGames: [
{appid: 1086940, name: "Baldur's Gate 3", playtimeMinutes: 900, playtime2Weeks: 90, status: 'PLAYING'}]}),
'GET /api/library/games-count': json(200, {count: 1, hasSteamId: true}),
'GET /api/library/games-count': json(200, {count: 1, hasSteamId: true, canSync: true}),
'GET /api/library/backlog': json(200, {games: [{appid: 7, name: 'Hades'}]}),
'GET /api/library/achievements/summary': json(200, {unlocked: 24, startedGames: 4, perfectGames: 2,
averageCompletion: 71.3, pendingGames: 0, hiddenGames: 0, closest: []}),
@@ -81,6 +81,22 @@ describe('Dashboard', () => {
});
const order = (container) => [...container.querySelectorAll('[data-tile]')].map((el) => el.dataset.tile);
const asked = (path) => fetch.mock.calls.some(([url]) => url.includes(path));
it('asks for the library before /me answers', async () => {
let answerMe;
const meAnswer = new Promise((resolve) => { answerMe = resolve; });
const routes = dashboardRoutes();
const me = routes['GET /api/users/me'];
fetchRoutes({...routes, 'GET /api/users/me': () => meAnswer});
const container = renderDashboard().container;
await waitFor(() => expect(asked('/api/library/games')).toBe(true));
expect(asked('/api/library/summary')).toBe(true);
answerMe(me);
await waitFor(() => expect(container.querySelector(`img[src="${avatar}"]`)).not.toBeNull());
});
it('shows today\'s tiles without a saved layout', async () => {
const container = mockDashboard();
@@ -227,20 +243,28 @@ describe('Dashboard', () => {
it('watches the sync the server started for this visit', async () => {
fetchRoutes({
...dashboardRoutes(),
'GET /api/library/games-count': json(200, {count: 1, hasSteamId: true, syncStarted: true}),
'GET /api/library/games-count': json(200, {count: 1, hasSteamId: true, canSync: true, syncStarted: true}),
});
renderDashboard();
await waitFor(() => expect(watchSync).toHaveBeenCalledTimes(1));
});
it('loads the activity and the achievements of a Steam user when games-count fails', async () => {
fetchRoutes({...dashboardRoutes(), 'GET /api/library/games-count': json(500, {})});
renderDashboard();
expect(await screen.findByText(/DASHBOARD.HELLO/)).toBeTruthy();
await waitFor(() => expect(asked('/api/library/activity')).toBe(true));
await waitFor(() => expect(asked('/api/library/achievements/summary')).toBe(true));
});
describe('of a user with a PlayStation link and no Steam ID', () => {
const psnOnlyRoutes = (canSync) => ({
...dashboardRoutes(),
'GET /api/users/me': json(200, {email: 'a@b.de', displayName: 'Lobo', settings: {}}),
'GET /api/library/games-count': json(200, {count: 1, hasSteamId: false, canSync}),
});
const asked = (path) => fetch.mock.calls.some(([url]) => url.includes(path));
it('loads the activity, the achievements and the sync result, but no Steam profile', async () => {
fetchRoutes(psnOnlyRoutes(true));