Fix the open bugs: read state, Unread tab, feed errors, theme button, log button, relative images
- Opening an item stays read: a list refresh that crossed with the write no longer puts the unread dot back (#16). - On the Unread tab the item you were reading goes when you move to the next (#17). - Feed errors mark the feed with a red ! instead of a toast per failure (#20). - The theme is chosen in Settings only (#15). - The server leaves the Log button out of a non-admin's page, so it no longer flashes (#29). - Relative images and links in a post resolve against the post's link (#28). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -20,27 +20,6 @@ test('the page loads and lists the configured feeds', async ({ page }) => {
|
||||
expect(errors, 'the page script must not throw at load').toEqual([]);
|
||||
});
|
||||
|
||||
test('the theme toggle actually changes the theme', async ({ page }) => {
|
||||
// Regression: this button was wired after a line that threw, so it did nothing.
|
||||
const before = await page.evaluate(() => document.documentElement.dataset.theme || 'system');
|
||||
await page.locator('#theme').click();
|
||||
await expect
|
||||
.poll(() => page.evaluate(() => document.documentElement.dataset.theme))
|
||||
.not.toBe(before);
|
||||
});
|
||||
|
||||
test('the theme button steps through dark, light and classic, and remembers', async ({ page }) => {
|
||||
const theme = () => page.evaluate(() => document.documentElement.dataset.theme);
|
||||
for (let i = 0; i < 3 && (await theme()) !== 'classic'; i++) await page.locator('#theme').click();
|
||||
expect(await theme()).toBe('classic');
|
||||
await expect(page.locator('#theme')).toHaveAttribute('title', /Classic.*Click for Auto/);
|
||||
|
||||
await page.reload();
|
||||
await expect.poll(theme).toBe('classic');
|
||||
// The 2004 Mac app set its type in Lucida Grande.
|
||||
expect(await page.evaluate(() => getComputedStyle(document.body).fontFamily)).toContain('Lucida Grande');
|
||||
});
|
||||
|
||||
test('the theme dropdown in Settings jumps straight to a theme, including Auto', async ({ page }) => {
|
||||
const theme = () => page.evaluate(() => document.documentElement.dataset.theme);
|
||||
await page.locator('#prefs').click();
|
||||
@@ -57,10 +36,12 @@ test('the theme dropdown in Settings jumps straight to a theme, including Auto',
|
||||
await expect.poll(() => page.evaluate(() => getComputedStyle(document.body).backgroundColor))
|
||||
.toBe('rgb(14, 19, 27)'); // the bare :root is already dark; Auto adds nothing here
|
||||
|
||||
// The header button and the dropdown are the same one setting, not two.
|
||||
await page.locator('#modalCard .cardacts .btn').first().click(); // Cancel, closing the modal
|
||||
await page.locator('#theme').click();
|
||||
expect(await theme()).toBe('dark');
|
||||
await page.locator('#stheme').selectOption('classic');
|
||||
await page.reload();
|
||||
await expect.poll(theme).toBe('classic');
|
||||
// The 2004 Mac app set its type in Lucida Grande.
|
||||
expect(await page.evaluate(() => getComputedStyle(document.body).fontFamily)).toContain('Lucida Grande');
|
||||
expect(await page.locator('#theme').count(), 'the theme lives in Settings only').toBe(0);
|
||||
});
|
||||
|
||||
test('settings opens and saves the global schedule', async ({ page }) => {
|
||||
@@ -233,6 +214,32 @@ test('the filter tabs change what is listed', async ({ page }) => {
|
||||
await expect(page.locator('#count')).toContainText('0 items');
|
||||
});
|
||||
|
||||
test('on the Unread tab an item stays while you read it and goes when you move on', async ({ page }) => {
|
||||
await page.locator('.feed', { hasText: 'Test Show' }).click();
|
||||
await page.locator('.tabs button', { hasText: 'All' }).first().click();
|
||||
await expect(page.locator('.ep').nth(1)).toBeVisible({ timeout: 20_000 });
|
||||
// Earlier tests read things; make the first two unread with their own dots.
|
||||
for (const i of [0, 1]) {
|
||||
const row = page.locator('.ep').nth(i);
|
||||
if (await row.evaluate(r => r.classList.contains('read'))) {
|
||||
await row.locator('[data-a="read"]').click();
|
||||
await expect(page.locator('.ep').nth(i)).not.toHaveClass(/\bread\b/);
|
||||
}
|
||||
}
|
||||
await page.locator('.tabs button', { hasText: 'Unread' }).first().click();
|
||||
const first = page.locator('.ep').first();
|
||||
const guid = await first.getAttribute('data-guid');
|
||||
await first.click();
|
||||
const it = page.locator(`.ep[data-guid="${guid}"]`);
|
||||
await expect(it).toHaveClass(/\bread\b/);
|
||||
await page.waitForTimeout(1500); // past the SSE refresh debounce and loadFeeds
|
||||
await expect(it).toBeVisible();
|
||||
|
||||
await page.locator('.ep').nth(1).click();
|
||||
await expect(it).toHaveCount(0);
|
||||
await page.locator('.tabs button', { hasText: 'All' }).first().click();
|
||||
});
|
||||
|
||||
test('a feed URL is editable and has a copy button', async ({ page }) => {
|
||||
await page.locator('.feed', { hasText: 'Test Show' }).click();
|
||||
await page.locator('#content .acts [data-a="settings"]').click();
|
||||
|
||||
Reference in New Issue
Block a user