diff --git a/backend/Cargo.lock b/backend/Cargo.lock index ac52fa1..b7f8097 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -1558,7 +1558,7 @@ checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" [[package]] name = "mangalord" -version = "0.112.0" +version = "0.113.0" dependencies = [ "anyhow", "argon2", diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 6b96dc3..f57864d 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mangalord" -version = "0.112.0" +version = "0.113.0" edition = "2021" default-run = "mangalord" diff --git a/frontend/e2e/manga-list.spec.ts b/frontend/e2e/manga-list.spec.ts index 70d2493..5847f06 100644 --- a/frontend/e2e/manga-list.spec.ts +++ b/frontend/e2e/manga-list.spec.ts @@ -63,6 +63,51 @@ test('home page renders the Mangalord heading and search input', async ({ page } await expect(page.getByTestId('empty')).toContainText('No mangas yet'); }); +test('shows a skeleton grid while the catalog is loading, then the real grid', async ({ page }) => { + await mockAnonymous(page); + + // Hold the catalog fetch open so the loading state is observable. + let release: () => void = () => {}; + const gate = new Promise((resolve) => { + release = resolve; + }); + await page.route('**/api/v1/mangas*', async (route) => { + await gate; + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ + items: [ + { + id: 'm1', + title: 'Berserk', + status: 'ongoing', + alt_titles: [], + description: null, + cover_image_path: null, + created_at: '2026-01-01T00:00:00Z', + updated_at: '2026-01-01T00:00:00Z', + authors: [], + genres: [] + } + ], + page: { limit: 50, offset: 0, total: 1 } + }) + }); + }); + + await page.goto('/'); + + // Skeleton stands in for the grid while the fetch is pending. + await expect(page.getByTestId('manga-grid-skeleton')).toBeVisible(); + await expect(page.getByTestId('manga-list')).toHaveCount(0); + + // Once data lands, the real grid replaces the skeleton. + release(); + await expect(page.getByTestId('manga-list')).toContainText('Berserk'); + await expect(page.getByTestId('manga-grid-skeleton')).toHaveCount(0); +}); + // Anti-drift guard: the desktop sort