From 31fa8908fca25360216df058fab1920e558b0ab3 Mon Sep 17 00:00:00 2001 From: Maurice Date: Wed, 2 Sep 2026 19:01:17 +0200 Subject: [PATCH] fix(weather): one failed fetch no longer parks the badge on the dash (#2167) failed was set once and never cleared, so a single hiccup kept the badge on its error dash while later fetches quietly delivered data. It resets with every new anchor. --- .../components/Weather/WeatherWidget.test.tsx | 41 +++++++++++++++++++ .../src/components/Weather/WeatherWidget.tsx | 4 ++ 2 files changed, 45 insertions(+) diff --git a/client/src/components/Weather/WeatherWidget.test.tsx b/client/src/components/Weather/WeatherWidget.test.tsx index db6811c64..b3e5c8c8f 100644 --- a/client/src/components/Weather/WeatherWidget.test.tsx +++ b/client/src/components/Weather/WeatherWidget.test.tsx @@ -208,4 +208,45 @@ describe('WeatherWidget', () => { expect(weatherApi.get).toHaveBeenCalledWith(48.86, 2.35, '2025-06-01', 'de') expect(sessionStorage.getItem('weather_48.86_2.35_2025-06-01_de')).not.toBeNull() }) + + // The day-local anchor (#2167) moves whenever the day is edited, so a single + // failed lookup must not keep the badge on the dash for the widget's lifetime. + it('FE-COMP-WEATHERWIDGET-016: clears the error dash once a new anchor resolves', async () => { + vi.mocked(weatherApi.get).mockRejectedValueOnce(new Error('Network error')) + vi.mocked(weatherApi.get).mockResolvedValue(buildWeather({ temp: 21 })) + useSettingsStore.setState({ settings: { ...useSettingsStore.getState().settings, temperature_unit: 'celsius' } }) + + const { rerender } = render() + await waitFor(() => { + expect(screen.getByText('—')).toBeInTheDocument() + }) + + rerender() + + await waitFor(() => { + expect(screen.getByText('21°C')).toBeInTheDocument() + }) + expect(screen.queryByText('—')).not.toBeInTheDocument() + }) + + it('FE-COMP-WEATHERWIDGET-017: clears the error dash when the new anchor comes from cache', async () => { + vi.mocked(weatherApi.get).mockRejectedValue(new Error('Network error')) + sessionStorage.setItem( + 'weather_41.9_12.5_2025-06-01_en', + JSON.stringify({ data: buildWeather({ temp: 24 }), fetchedAt: Date.now() }), + ) + useSettingsStore.setState({ settings: { ...useSettingsStore.getState().settings, temperature_unit: 'celsius' } }) + + const { rerender } = render() + await waitFor(() => { + expect(screen.getByText('—')).toBeInTheDocument() + }) + + rerender() + + await waitFor(() => { + expect(screen.getByText('24°C')).toBeInTheDocument() + }) + expect(weatherApi.get).toHaveBeenCalledTimes(1) + }) }) diff --git a/client/src/components/Weather/WeatherWidget.tsx b/client/src/components/Weather/WeatherWidget.tsx index d56753d68..4ee413196 100644 --- a/client/src/components/Weather/WeatherWidget.tsx +++ b/client/src/components/Weather/WeatherWidget.tsx @@ -63,6 +63,10 @@ export default function WeatherWidget({ lat, lng, date, compact = false, stacked useEffect(() => { if (!lat || !lng || !date) return let cancelled = false + // Every anchor, date or language change is a fresh attempt, so a failure from + // the previous one must not outlive it. Since #2167 the anchor is day-local and + // moves with each edit, which would otherwise pin the badge on the error dash. + setFailed(false) const rLat = Math.round(lat * 100) / 100 const rLng = Math.round(lng * 100) / 100 // The language is part of the key: descriptions come back localized, and the