Merge branch 'refactor/desktop-sort-options' into chore/reconcile-ui-review

This commit is contained in:
MechaCat02
2026-06-25 21:12:18 +02:00
2 changed files with 35 additions and 4 deletions

View File

@@ -1,4 +1,5 @@
import { test, expect, type Page } from '@playwright/test';
import { SORT_FIELD_LABELS } from '../src/lib/mangaSort';
// These E2E tests run against the SvelteKit dev server, which proxies /api
// to the backend. Playwright starts vite via `webServer` (see
@@ -44,6 +45,35 @@ test('home page renders the Mangalord heading and search input', async ({ page }
await expect(page.getByTestId('empty')).toContainText('No mangas yet');
});
// Anti-drift guard: the desktop sort <select> and the mobile sort sheet must
// both enumerate exactly SORT_FIELD_LABELS, in the same order. The desktop
// select used to hard-code its <option>s, so a label rename in mangaSort.ts
// would silently diverge the two surfaces. Comparing the rendered options to
// the single source of truth makes that divergence fail loudly.
test('desktop sort options stay in sync with SORT_FIELD_LABELS', async ({ page }) => {
await mockAnonymous(page);
await page.route('**/api/v1/mangas*', async (route) => {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(emptyPage)
});
});
await page.goto('/');
const select = page.getByTestId('sort-select');
await expect(select).toBeVisible();
const options = select.locator('option');
const labels = (await options.allTextContents()).map((s) => s.trim());
const values = await options.evaluateAll((opts) =>
opts.map((o) => (o as HTMLOptionElement).value)
);
expect(values).toEqual(Object.keys(SORT_FIELD_LABELS));
expect(labels).toEqual(Object.values(SORT_FIELD_LABELS));
});
test('search updates the manga list', async ({ page }) => {
await mockAnonymous(page);
let lastSearch: string | null = null;

View File

@@ -538,10 +538,11 @@
<label class="sort">
<span>Sort</span>
<select bind:value={sort} onchange={onSortChange} data-testid="sort-select">
<option value="updated">Last updated</option>
<option value="created">Date added</option>
<option value="title">Title</option>
<option value="author">Author</option>
<!-- Options derive from SORT_FIELD_LABELS — the same source the
mobile sort sheet uses — so the two surfaces can't drift. -->
{#each Object.entries(SORT_FIELD_LABELS) as [value, label] (value)}
<option {value}>{label}</option>
{/each}
</select>
</label>
<div class="sort">