import { screen, waitFor } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { http, HttpResponse } from 'msw' import { beforeEach, describe, expect, it, vi } from 'vitest' import { MenuBar } from '@/components/MenuBar' import { getGetConfigQueryKey, getGetSceneJsonQueryKey } from '@/lib/api/default/default' import { queryClient } from '@/lib/queryClient' import { renderWithQuery } from '../helpers' import { server } from '../msw/server' vi.mock('@/lib/io/openFiles', () => ({ openImageFiles: vi.fn().mockResolvedValue([]), openImageFolder: vi.fn().mockResolvedValue([]), openKhrFile: vi.fn().mockResolvedValue(null), })) beforeEach(() => { // Default: config + scene exist so the menu enables scene-dependent items. server.use( http.get('/api/v1/scene.json', () => HttpResponse.json({ epoch: 0, scene: { pages: {}, project: { name: 'P' } as never }, }), ), http.get('/api/v1/config', () => HttpResponse.json({})), ) queryClient.setQueryData(getGetSceneJsonQueryKey(), { epoch: 0, scene: { pages: {}, project: { name: 'P' } }, }) queryClient.setQueryData(getGetConfigQueryKey(), {}) }) describe('MenuBar', () => { it('renders File / View / Process / Help triggers', async () => { renderWithQuery() expect(screen.getByTestId('menu-file-trigger')).toBeInTheDocument() expect(screen.getByTestId('menu-process-trigger')).toBeInTheDocument() }) it('Close Project calls DELETE /projects/current and invalidates scene', async () => { let deleted = 0 server.use( http.delete('/api/v1/projects/current', () => { deleted += 1 return new HttpResponse(null, { status: 204 }) }), ) const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries') renderWithQuery() await userEvent.click(screen.getByTestId('menu-file-trigger')) const close = await screen.findByTestId('menu-file-close-project') await userEvent.click(close) await waitFor(() => expect(deleted).toBe(1)) await waitFor(() => { const invalidatedKeys = invalidateSpy.mock.calls.map((c) => c[0]?.queryKey) expect(invalidatedKeys).toContainEqual(getGetSceneJsonQueryKey()) }) }) it('Close Project is disabled when no project is open', async () => { // Clear seeded cache + point /scene.json at the 400 response so useScene // resolves to null. queryClient.clear() server.use( http.get('/api/v1/scene.json', () => HttpResponse.json({ message: 'no project' }, { status: 400 }), ), ) renderWithQuery() await waitFor(() => expect(queryClient.isFetching()).toBe(0)) await userEvent.click(screen.getByTestId('menu-file-trigger')) const close = await screen.findByTestId('menu-file-close-project') expect(close).toHaveAttribute('data-disabled') }) })