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