diff --git a/web/src/lib/components/AdminSidebar.svelte b/web/src/lib/components/AdminSidebar.svelte deleted file mode 100644 index 99114878..00000000 --- a/web/src/lib/components/AdminSidebar.svelte +++ /dev/null @@ -1,59 +0,0 @@ - - - diff --git a/web/src/lib/components/AdminSidebar.test.ts b/web/src/lib/components/AdminSidebar.test.ts deleted file mode 100644 index 8e73d0ab..00000000 --- a/web/src/lib/components/AdminSidebar.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { describe, expect, test, vi } from 'vitest'; -import { render, screen } from '@testing-library/svelte'; - -const state = vi.hoisted(() => ({ - pageUrl: new URL('http://localhost/admin') -})); - -vi.mock('$app/state', () => ({ - page: { get url() { return state.pageUrl; } } -})); - -import AdminSidebar from './AdminSidebar.svelte'; - -describe('AdminSidebar', () => { - test('Overview link is active when on /admin', () => { - state.pageUrl = new URL('http://localhost/admin'); - render(AdminSidebar); - const overview = screen.getByRole('link', { name: /overview/i }); - expect(overview).toHaveAttribute('aria-current', 'page'); - }); - - test('Integrations link is active when on /admin/integrations', () => { - state.pageUrl = new URL('http://localhost/admin/integrations'); - render(AdminSidebar); - expect(screen.getByRole('link', { name: /integrations/i })).toHaveAttribute( - 'aria-current', - 'page' - ); - expect(screen.getByRole('link', { name: /overview/i })).not.toHaveAttribute('aria-current'); - }); - - test('Requests link is active when on /admin/requests', () => { - state.pageUrl = new URL('http://localhost/admin/requests'); - render(AdminSidebar); - expect(screen.getByRole('link', { name: /requests/i })).toHaveAttribute( - 'aria-current', - 'page' - ); - }); - - test('Quarantine link is active when on /admin/quarantine', () => { - state.pageUrl = new URL('http://localhost/admin/quarantine'); - render(AdminSidebar); - expect(screen.getByRole('link', { name: /quarantine/i })).toHaveAttribute( - 'aria-current', - 'page' - ); - }); - - test('Quarantine renders as a real link', () => { - state.pageUrl = new URL('http://localhost/admin'); - render(AdminSidebar); - const link = screen.getByRole('link', { name: /quarantine/i }); - expect(link).toHaveAttribute('href', '/admin/quarantine'); - }); - - test('placeholder items render as non-links with aria-disabled', () => { - state.pageUrl = new URL('http://localhost/admin'); - render(AdminSidebar); - // Users + Library are still placeholders today. - expect(screen.queryByRole('link', { name: /^users$/i })).not.toBeInTheDocument(); - expect(screen.queryByRole('link', { name: /^library$/i })).not.toBeInTheDocument(); - const users = screen.getByText(/^users$/i); - expect(users.closest('[aria-disabled="true"]')).toBeInTheDocument(); - }); -}); diff --git a/web/src/lib/components/AdminTabs.svelte b/web/src/lib/components/AdminTabs.svelte new file mode 100644 index 00000000..618ea22c --- /dev/null +++ b/web/src/lib/components/AdminTabs.svelte @@ -0,0 +1,38 @@ + + + diff --git a/web/src/lib/components/AdminTabs.test.ts b/web/src/lib/components/AdminTabs.test.ts new file mode 100644 index 00000000..cbdb6efe --- /dev/null +++ b/web/src/lib/components/AdminTabs.test.ts @@ -0,0 +1,58 @@ +import { describe, expect, test, vi } from 'vitest'; +import { render, screen } from '@testing-library/svelte'; + +const state = vi.hoisted(() => ({ + pageUrl: new URL('http://localhost/admin') +})); + +vi.mock('$app/state', () => ({ + page: { get url() { return state.pageUrl; } } +})); + +import AdminTabs from './AdminTabs.svelte'; + +describe('AdminTabs', () => { + test('Overview tab is current when on /admin', () => { + state.pageUrl = new URL('http://localhost/admin'); + render(AdminTabs); + const overview = screen.getByRole('link', { name: /overview/i }); + expect(overview).toHaveAttribute('aria-current', 'page'); + }); + + test('Integrations tab is current when on /admin/integrations', () => { + state.pageUrl = new URL('http://localhost/admin/integrations'); + render(AdminTabs); + expect(screen.getByRole('link', { name: /integrations/i })).toHaveAttribute( + 'aria-current', + 'page' + ); + expect(screen.getByRole('link', { name: /overview/i })).not.toHaveAttribute('aria-current'); + }); + + test('Requests tab is current when on /admin/requests', () => { + state.pageUrl = new URL('http://localhost/admin/requests'); + render(AdminTabs); + expect(screen.getByRole('link', { name: /requests/i })).toHaveAttribute('aria-current', 'page'); + }); + + test('Quarantine tab is current when on /admin/quarantine', () => { + state.pageUrl = new URL('http://localhost/admin/quarantine'); + render(AdminTabs); + expect(screen.getByRole('link', { name: /quarantine/i })).toHaveAttribute( + 'aria-current', + 'page' + ); + }); + + test('renders exactly four tabs (Users + Library deferred until built)', () => { + state.pageUrl = new URL('http://localhost/admin'); + render(AdminTabs); + const links = screen.getAllByRole('link'); + expect(links.map((l) => l.textContent?.trim())).toEqual([ + 'Overview', + 'Integrations', + 'Requests', + 'Quarantine' + ]); + }); +}); diff --git a/web/src/routes/admin/+layout.svelte b/web/src/routes/admin/+layout.svelte index 072dd601..83eec272 100644 --- a/web/src/routes/admin/+layout.svelte +++ b/web/src/routes/admin/+layout.svelte @@ -1,19 +1,10 @@ -