feat(ui): keep the active operations tab across page refreshes (#27)
CI / build + unit + e2e (pull_request) Successful in 2m15s

Persist the selected tab ID to localStorage (sw-active-tab) on every change
and restore it on mount when it matches one of the seven valid tab IDs. The
Radix Tabs become controlled for this; SSR and first client render still agree
on the default, so there is no hydration mismatch.
This commit is contained in:
2026-09-29 09:42:18 +00:00
parent 4b030716f7
commit f4690bc1a2
4 changed files with 38 additions and 2 deletions
+12
View File
@@ -70,6 +70,18 @@ test('tabs switch panels client-side (event log terminal)', async ({ page }) =>
await expect(page.getByText(/T\d+ \/\/ /).first()).toBeVisible();
});
test('active tab survives a page reload (#27)', async ({ page }) => {
await page.goto('/');
// Fresh context → nothing stored yet, so CREW starts unselected (the default is WORLD MAP).
await expect(page.getByRole('tab', { name: 'CREW' })).toHaveAttribute('aria-selected', 'false');
await page.getByRole('tab', { name: 'CREW' }).click();
await expect(page.getByRole('tab', { name: 'CREW' })).toHaveAttribute('aria-selected', 'true');
await page.reload();
// The tab is restored from localStorage on mount — no API state involved, so this holds across retries.
await expect(page.getByRole('tab', { name: 'CREW' })).toHaveAttribute('aria-selected', 'true');
});
test('world map shows the generated starting system and its neighbours', async ({ page }) => {
const world = (await (await page.request.get('/api/world')).json()) as WorldState;