// @vitest-environment jsdom import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react'; import { renderToStaticMarkup } from 'react-dom/server'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { isOpenDesignHostAvailable, pickHostWorkingDir } from '@open-design/host'; import { buildDesignSystemCreateSelection, defaultDesignSystemSelection, NewProjectPanel, } from '../../src/components/NewProjectPanel'; import { openFolderDialog } from '../../src/providers/registry'; import type { DesignSystemSummary, ProjectTemplate, SkillSummary } from '../../src/types'; vi.mock('@open-design/host', async () => { const actual = await vi.importActual('@open-design/host'); return { ...actual, isOpenDesignHostAvailable: vi.fn(), pickHostWorkingDir: vi.fn(), }; }); vi.mock('../../src/providers/registry', async () => { const actual = await vi.importActual( '../../src/providers/registry', ); return { ...actual, openFolderDialog: vi.fn(), }; }); const mockedIsHostAvailable = vi.mocked(isOpenDesignHostAvailable); const mockedPickHostWorkingDir = vi.mocked(pickHostWorkingDir); const mockedOpenFolderDialog = vi.mocked(openFolderDialog); const skills: SkillSummary[] = [ { id: 'prototype-skill', name: 'Prototype', description: 'Build prototypes', mode: 'prototype', surface: 'web', previewType: 'html', designSystemRequired: true, defaultFor: ['prototype'], triggers: [], upstream: null, hasBody: true, examplePrompt: 'Build a prototype.', aggregatesExamples: false, }, ]; const designSystems: DesignSystemSummary[] = [ { id: 'clay', title: 'Clay', summary: 'Friendly tactile product UI.', category: 'Product', swatches: ['#f4efe7', '#25211d'], source: 'built-in', status: 'published', }, { id: 'noir', title: 'Editorial Noir', summary: 'High-contrast editorial system.', category: 'Editorial', swatches: ['#111111', '#f7f0e8'], source: 'built-in', status: 'published', }, { id: 'user:draft-system', title: 'Draft Personal DS', summary: 'Should not be selectable for project creation.', category: 'Personal', swatches: ['#663399', '#faf7ff'], source: 'user', isEditable: true, status: 'draft', }, ]; const templates: ProjectTemplate[] = [ { id: 'tmpl-landing', name: 'Landing Page', description: 'A saved landing page starter.', files: [{ name: 'prototype/App.jsx', path: 'prototype/App.jsx' }], createdAt: '2026-05-07T00:00:00.000Z', }, ]; afterEach(() => { cleanup(); globalThis.ResizeObserver = originalResizeObserver; Element.prototype.scrollIntoView = originalScrollIntoView; vi.unstubAllGlobals(); }); const originalResizeObserver = globalThis.ResizeObserver; const originalScrollIntoView = Element.prototype.scrollIntoView; class ResizeObserverMock { observe() {} disconnect() {} unobserve() {} } beforeEach(() => { globalThis.ResizeObserver = ResizeObserverMock as typeof ResizeObserver; Element.prototype.scrollIntoView = vi.fn(); vi.clearAllMocks(); mockedIsHostAvailable.mockReturnValue(false); mockedOpenFolderDialog.mockResolvedValue(null); }); describe('NewProjectPanel design system defaults', () => { it('uses the configured default design system when it exists in the catalog', () => { expect(defaultDesignSystemSelection('clay', designSystems)).toEqual(['clay']); expect(defaultDesignSystemSelection('missing', designSystems)).toEqual([]); expect(defaultDesignSystemSelection(null, designSystems)).toEqual([]); }); it('shows the configured default design system as the active project selection', () => { const markup = renderToStaticMarkup( , ); expect(markup).toContain('Clay'); expect(markup).toContain('Default'); expect(markup).not.toContain('Freeform'); }); it('filters draft personal design systems out of the new project picker', () => { render( , ); fireEvent.click(screen.getByTestId('design-system-trigger')); expect(screen.queryByRole('option', { name: /Draft Personal DS/i })).toBeNull(); expect(screen.getByRole('option', { name: /Clay/i })).toBeTruthy(); expect(screen.getByRole('option', { name: /Editorial Noir/i })).toBeTruthy(); }); it('keeps media project creation from inheriting a hidden design system pick', () => { expect(buildDesignSystemCreateSelection(true, ['clay', 'bmw'])).toEqual({ primary: 'clay', inspirations: ['bmw'], }); expect(buildDesignSystemCreateSelection(false, ['clay', 'bmw'])).toEqual({ primary: null, inspirations: [], }); }); it('preserves prototype fidelity across tab switches and saves it into the create payload', () => { const onCreate = vi.fn(); render( , ); fireEvent.change(screen.getByTestId('new-project-name'), { target: { value: 'Wireframe fidelity payload' }, }); fireEvent.click(screen.getByRole('button', { name: 'Wireframe' })); expect(screen.getByRole('button', { name: 'Wireframe' }).getAttribute('aria-pressed')).toBe('true'); fireEvent.click(screen.getByRole('tab', { name: 'Slide deck' })); fireEvent.click(screen.getByRole('tab', { name: 'Prototype' })); expect(screen.getByRole('button', { name: 'Wireframe' }).getAttribute('aria-pressed')).toBe('true'); fireEvent.click(screen.getByTestId('create-project')); expect(onCreate).toHaveBeenCalledWith( expect.objectContaining({ name: 'Wireframe fidelity payload', designSystemId: 'clay', metadata: expect.objectContaining({ kind: 'prototype', fidelity: 'wireframe', }), }), ); }); it('does not persist OS widgets metadata for web-only platform targets', () => { const onCreate = vi.fn(); render( , ); fireEvent.change(screen.getByTestId('new-project-name'), { target: { value: 'Responsive web payload' }, }); // CompactToggle renders as a `