Merge branch 'feat/desktop-reader-brightness' into chore/reconcile-ui-review

This commit is contained in:
MechaCat02
2026-06-25 21:13:55 +02:00
2 changed files with 104 additions and 0 deletions

View File

@@ -66,6 +66,15 @@ async function mockReaderApis(page: Page) {
body: JSON.stringify({ error: { code: 'unauthenticated', message: '' } })
})
);
// Anonymous reader: read-progress reads/writes are unauthenticated. Without
// this the GET/PUT fall through to the (absent) backend and stall the load.
await page.route('**/api/v1/me/read-progress/**', (route) =>
route.fulfill({
status: 401,
contentType: 'application/json',
body: JSON.stringify({ error: { code: 'unauthenticated', message: '' } })
})
);
await page.route(`**/api/v1/mangas/${mangaId}`, (route) =>
route.fulfill({
status: 200,
@@ -126,6 +135,7 @@ test.beforeEach(async ({ context }) => {
try {
localStorage.removeItem('mangalord-reader-mode');
localStorage.removeItem('mangalord-reader-gap');
localStorage.removeItem('mangalord-reader-brightness');
} catch {
// ignore — about:blank doesn't expose localStorage yet.
}
@@ -181,6 +191,64 @@ test('gap select updates the inline gap on the continuous container', async ({ p
await expect(container).toHaveAttribute('style', /gap:\s*64px/);
});
test('desktop reader nav exposes a brightness control that dims and undims the reader', async ({
page
}) => {
// The brightness slider used to live only in the mobile settings sheet,
// so desktop users couldn't dim — and could be stuck dimmed by a value a
// phone had persisted. The desktop nav now carries its own slider.
await mockReaderApis(page);
await page.goto(`/manga/${mangaId}/chapter/${chapterId}`);
const slider = page.getByTestId('reader-brightness-desktop');
await expect(slider).toBeVisible();
const dim = () =>
page.evaluate(() =>
document.documentElement.style.getPropertyValue('--reader-dim')
);
// Default brightness is full → no dim overlay.
await expect.poll(async () => Number(await dim())).toBe(0);
// Dimming raises the overlay opacity…
await slider.fill('0.3');
await expect.poll(async () => Number(await dim())).toBeGreaterThan(0);
// …and restoring it clears the dim, so a desktop user is never stuck.
await slider.fill('1');
await expect.poll(async () => Number(await dim())).toBe(0);
});
test('a brightness value persisted by a phone is recoverable on desktop', async ({
page,
context
}) => {
// Seed a dimmed value as if set on mobile, then open the reader on a
// desktop viewport: the dim applies and the desktop control reflects it.
await context.addInitScript(() => {
try {
localStorage.setItem('mangalord-reader-brightness', '0.3');
} catch {
// about:blank — ignore
}
});
await mockReaderApis(page);
await page.goto(`/manga/${mangaId}/chapter/${chapterId}`);
const slider = page.getByTestId('reader-brightness-desktop');
await expect(slider).toHaveValue('0.3');
await expect
.poll(async () =>
Number(
await page.evaluate(() =>
document.documentElement.style.getPropertyValue('--reader-dim')
)
)
)
.toBeGreaterThan(0);
});
test('reader-mode preference set on one page is honored when the reader opens', async ({
page,
context