Fix Home dashboard integration findings (Feature 21)
CI / ci (push) Successful in 8m57s
CI / ci (pull_request) Successful in 8m27s

- F21-01: plan_ready and list_ready links carry their week
  (/plan?week=, /plan/shopping?week=), and the Plan opens on ?week=
  and keeps it on the week shown, so an older update opens its week.
- F21-02: a failed refresh of the Rotation check shows its ErrorBanner
  beside the cached pending card instead of replacing it.
- F21-03: Home carries the household's timezone and is read again at
  its next local midnight.
- F21-04: Home counts pending Side quests through a read-only query
  (suggest.PendingCount), so reading Home never writes batches.

Task: ac3dddf0-a05f-4e43-a5ad-3105fe6bdd95

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-10 18:03:52 -04:00
co-authored by Claude Opus 5.5
parent 62f4f9eece
commit 0a69efea5c
22 changed files with 312 additions and 60 deletions
+27 -1
View File
@@ -1,4 +1,4 @@
import { fireEvent, render, screen, within } from '@testing-library/react'
import { act, fireEvent, render, screen, within } from '@testing-library/react'
import { createMemoryRouter, RouterProvider, useLocation } from 'react-router'
import { afterEach, describe, expect, it, vi } from 'vitest'
import { ApiProviders, HOME } from '../test/ApiProviders.tsx'
@@ -20,6 +20,7 @@ const NOTHING_YET = {
}
afterEach(() => {
vi.useRealTimers()
vi.unstubAllGlobals()
})
@@ -72,6 +73,31 @@ describe('HomePage', () => {
expect(screen.queryByRole('heading', { name: 'No quest planned tonight' })).not.toBeInTheDocument()
})
it("reads Home again at the household's next local midnight, so a Home left open moves to the new day", async () => {
// setTimeout moves with real time, and the test jumps to midnight.
vi.useFakeTimers({ toFake: ['Date', 'setTimeout', 'clearTimeout'], shouldAdvanceTime: true })
// 23:58 on Friday Oct 2 in New York, the household's zone.
vi.setSystemTime(new Date('2026-10-03T03:58:00Z'))
const days = [HOME, { ...HOME, dateLabel: 'Saturday, Oct 3', tonight: null }]
let reads = 0
stubFetchByPath({
[HOME_PATH]: () => jsonResponse(200, days[Math.min(reads++, 1)]),
[ROTATION_REVIEWS_PATH]: () => jsonResponse(200, { reviews: [] }),
})
renderRouter()
expect(await screen.findByText('Friday, Oct 2')).toBeInTheDocument()
expect(reads).toBe(1)
// A minute before midnight Home is not read again.
await act(() => vi.advanceTimersByTimeAsync(60_000))
expect(reads).toBe(1)
// At midnight it is, and shows the new day.
await act(() => vi.advanceTimersByTimeAsync(60_000))
expect(await screen.findByText('Saturday, Oct 3')).toBeInTheDocument()
expect(reads).toBe(2)
expect(screen.getByRole('heading', { name: 'No quest planned tonight' })).toBeInTheDocument()
})
it('shows the grape unread dot on the bell when there are unread updates', async () => {
renderHome(HOME)