test(e2e): realign mocks + assertions with the current API and OCR-era UI

The route-mocked E2E specs had drifted from the app they exercise, so
each rendered an empty/500 page and timed out on missing elements:

- Manga detail + reader loads now also fetch read-progress/{id} and
  /similar; several specs never mocked them, so the load's Promise.all
  rejected. Add the mocks and fill the manga fixtures out to a real
  MangaDetail (status/alt_titles/authors/genres/tags/... ) so the
  components stop throwing mid-render.
- back-nav + library: widen `read-progress*`/`page-tags` globs — `*`
  doesn't cross `/`, so `/me/read-progress/{id}` fell through to the
  proxy and 500'd; mock the library page-tags pair too.
- manga-list search: wait for the initial load to settle before
  searching so the search fetch can't race the mount-time load.
- reader-chapter-select: assert the shared `chapterLabel` output.
- admin-analysis: the active OCR backend extracts text only, so the
  detail modal shows OCR (no tags/NSFW) and metrics shows tiles +
  trend charts (no by-model) — assert what the OCR-era UI renders.
- profile: assert the wrong-password 401 stays inline (guards the
  fix in the preceding commit) and mock the guest bookmark/collection
  fetches the /profile load maps to the sign-in prompt.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-07-01 20:11:23 +02:00
parent 0865659ab3
commit 4d02b56b77
8 changed files with 206 additions and 22 deletions

View File

@@ -123,12 +123,20 @@ test('wrong current password surfaces the 401 envelope inline', async ({ page })
);
await page.goto('/profile/account');
// Wait for the session to hydrate before submitting: a wrong current
// password must be surfaced inline, which the form distinguishes from a
// genuinely-signed-out state via session.user — so the user must be
// known-authenticated first (as they always are on a real page load).
await expect(page.getByText('Signed in as')).toBeVisible();
await page.getByTestId('current-password').fill('definitelyNotIt');
await page.getByTestId('new-password').fill('freshpassfreshpass');
await page.getByTestId('confirm-password').fill('freshpassfreshpass');
await page.getByTestId('password-submit').click();
await expect(page.getByTestId('password-error')).toBeVisible();
// Stays on the account page — a wrong current password is an inline
// error, not a session expiry, so it must not bounce to /login.
await expect(page).toHaveURL(/\/profile\/account$/);
});
test('mismatched new + confirm disables the submit button', async ({ page }) => {
@@ -153,6 +161,24 @@ test('anonymous user sees a profile sign-in prompt', async ({ page }) => {
})
})
);
// The /profile load pair-fetches these; a real backend returns 401 for a
// guest, which the load maps to `authenticated: false`. Without the mock
// the calls fall through to the dead proxy and 500, and the load rethrows
// (only 401 is handled) → error page instead of the sign-in prompt.
await page.route('**/api/v1/me/bookmarks?*', (route) =>
route.fulfill({
status: 401,
contentType: 'application/json',
body: JSON.stringify({ error: { code: 'unauthenticated', message: 'unauthenticated' } })
})
);
await page.route('**/api/v1/me/collections?*', (route) =>
route.fulfill({
status: 401,
contentType: 'application/json',
body: JSON.stringify({ error: { code: 'unauthenticated', message: 'unauthenticated' } })
})
);
await page.goto('/profile');
await expect(page.getByTestId('profile-signin')).toBeVisible();