// @vitest-environment jsdom import React from 'react'; import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, screen, fireEvent, waitFor } from '@testing-library/react'; const h = vi.hoisted(() => ({ active: null as string | null, list: [] as Array<{ project: { id: string; orgId: string; name: string; slug: string }; role: string }>, setSpy: vi.fn(), })); vi.mock('../../api/projects', () => ({ getProjects: () => Promise.resolve(h.list), getActiveProjectId: () => h.active, setActiveProjectId: (id: string | null) => { h.active = id; h.setSpy(id); }, })); import { ProjectSwitcher } from '../ProjectSwitcher'; const P = (id: string, name: string) => ({ project: { id, orgId: 'o', name, slug: id }, role: 'member' }); beforeEach(() => { h.active = null; h.list = []; h.setSpy.mockClear(); Object.defineProperty(window, 'location', { configurable: true, writable: true, value: { reload: vi.fn() } }); }); describe('ProjectSwitcher (#244)', () => { it('defaults to the first project and hides when only one is accessible', async () => { h.list = [P('a', 'Alpha')]; const { container } = render(); await waitFor(() => expect(h.setSpy).toHaveBeenCalledWith('a')); expect(container.querySelector('button')).toBeNull(); // nothing to switch }); it('shows the active project, lists all on open, and persists + reloads on select', async () => { h.active = 'a'; h.list = [P('a', 'Alpha'), P('b', 'Beta')]; render(); fireEvent.click(await screen.findByRole('button', { name: /Alpha/ })); expect(screen.getByRole('menuitemradio', { name: 'Beta' })).toBeInTheDocument(); fireEvent.click(screen.getByRole('menuitemradio', { name: 'Beta' })); expect(h.setSpy).toHaveBeenCalledWith('b'); expect(window.location.reload).toHaveBeenCalled(); }); it('recovers to the first accessible project (and reloads) when the active one is revoked', async () => { h.active = 'gone'; h.list = [P('a', 'Alpha'), P('b', 'Beta')]; render(); await waitFor(() => expect(h.setSpy).toHaveBeenCalledWith('a')); expect(window.location.reload).toHaveBeenCalled(); }); it('closes the menu on Escape', async () => { h.active = 'a'; h.list = [P('a', 'Alpha'), P('b', 'Beta')]; render(); fireEvent.click(await screen.findByRole('button', { name: /Alpha/ })); expect(screen.getByRole('menu')).toBeInTheDocument(); fireEvent.keyDown(document, { key: 'Escape' }); expect(screen.queryByRole('menu')).not.toBeInTheDocument(); }); });