import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import '@testing-library/jest-dom/vitest'; import { IGitUserInfos } from '@services/git/interface'; import { SupportedStorageServices } from '@services/types'; import { IWorkspace } from '@services/workspaces/interface'; import { NewWikiForm } from '../NewWikiForm'; import { IErrorInWhichComponent, IWikiWorkspaceForm } from '../useForm'; // Mock form data helper const createMockForm = (overrides: Partial = {}): IWikiWorkspaceForm => ({ storageProvider: SupportedStorageServices.local, storageProviderSetter: vi.fn(), wikiPort: 5212, wikiPortSetter: vi.fn(), parentFolderLocation: '/test/parent', parentFolderLocationSetter: vi.fn(), wikiFolderName: 'test-wiki', wikiFolderNameSetter: vi.fn(), wikiFolderLocation: '/test/parent/test-wiki', mainWikiToLink: { wikiFolderLocation: '/main/wiki', id: 'main-wiki-id', port: 5212, }, mainWikiToLinkSetter: vi.fn(), mainWikiToLinkIndex: 0, mainWorkspaceList: [ { id: 'main-wiki-id', name: 'Main Wiki', wikiFolderLocation: '/main/wiki', port: 5212, gitUrl: 'https://example.com/git', homeUrl: 'http://localhost:5212', metadata: {}, } as unknown as IWorkspace, { id: 'second-wiki-id', name: 'Second Wiki', wikiFolderLocation: '/second/wiki', port: 5213, gitUrl: 'https://example.com/git2', homeUrl: 'http://localhost:5213', metadata: {}, } as unknown as IWorkspace, ], tagName: '', tagNameSetter: vi.fn(), gitRepoUrl: '', gitRepoUrlSetter: vi.fn(), gitUserInfo: undefined as IGitUserInfos | undefined, workspaceList: [] as IWorkspace[], wikiHtmlPath: '', wikiHtmlPathSetter: vi.fn(), ...overrides, }); const createMockProps = (overrides: Partial<{ form: IWikiWorkspaceForm; isCreateMainWorkspace: boolean; isCreateSyncedWorkspace: boolean; errorInWhichComponent: IErrorInWhichComponent; errorInWhichComponentSetter: ReturnType; }> = {}) => ({ form: createMockForm(), isCreateMainWorkspace: true, isCreateSyncedWorkspace: false, errorInWhichComponent: {}, errorInWhichComponentSetter: vi.fn(), ...overrides, }); describe('NewWikiForm Component', () => { beforeEach(() => { vi.clearAllMocks(); }); // Helper function to render component with default props // This async version waits for useAvailableTags hook to complete its async operations const renderNewWikiForm = async (overrides = {}) => { const props = createMockProps(overrides); const result = render(); // Wait for any async state updates to complete await waitFor(() => { // The component is considered stable when it's fully rendered // We don't need to wait for any specific element, just let React settle // This empty waitFor will ensure all effects are processed, to remove `act(...)` warnings }); return result; }; describe('Basic Rendering Tests', () => { it('should render main workspace form with basic fields', async () => { await renderNewWikiForm({ isCreateMainWorkspace: true, }); // Should render parent folder input expect(screen.getAllByRole('textbox', { name: 'AddWorkspace.WorkspaceParentFolder' })[0]).toBeInTheDocument(); // Should render wiki folder name input expect(screen.getAllByRole('textbox', { name: 'AddWorkspace.WorkspaceFolderNameToCreate' })[0]).toBeInTheDocument(); // Should render choose folder button expect(screen.getAllByRole('button', { name: 'AddWorkspace.Choose' })[0]).toBeInTheDocument(); // Main workspace should not show sub workspace fields expect(screen.queryAllByRole('combobox', { name: 'AddWorkspace.MainWorkspaceLocation' }).length).toBe(0); expect(screen.queryAllByRole('combobox', { name: 'AddWorkspace.TagName' }).length).toBe(0); }); it('should render sub workspace form with all fields', async () => { await renderNewWikiForm({ isCreateMainWorkspace: false, }); // Should render basic fields expect(screen.getAllByRole('textbox', { name: 'AddWorkspace.WorkspaceParentFolder' })[0]).toBeInTheDocument(); expect(screen.getAllByRole('textbox', { name: 'AddWorkspace.WorkspaceFolderNameToCreate' })[0]).toBeInTheDocument(); // Should render sub workspace specific fields expect(screen.getAllByRole('combobox', { name: 'AddWorkspace.MainWorkspaceLocation' })[0]).toBeInTheDocument(); expect(screen.getAllByRole('combobox', { name: 'AddWorkspace.TagName' })[0]).toBeInTheDocument(); }); it('should display correct initial values', async () => { const form = createMockForm({ parentFolderLocation: '/custom/path', wikiFolderName: 'my-wiki', }); await renderNewWikiForm({ form, isCreateMainWorkspace: false, }); expect(screen.getByDisplayValue('/custom/path')).toBeInTheDocument(); expect(screen.getByDisplayValue('my-wiki')).toBeInTheDocument(); }); }); describe('User Interaction Tests', () => { it('should handle parent folder path input change', async () => { const user = userEvent.setup(); const mockSetter = vi.fn(); const form = createMockForm({ parentFolderLocationSetter: mockSetter, }); await renderNewWikiForm({ form }); const input = screen.getAllByRole('textbox', { name: 'AddWorkspace.WorkspaceParentFolder' })[0]; await user.clear(input); await user.type(input, '/new/path'); // Should call setter for each character expect(mockSetter).toHaveBeenCalled(); expect(mockSetter.mock.calls.length).toBeGreaterThan(0); }); it('should handle wiki folder name input change', async () => { const user = userEvent.setup(); const mockSetter = vi.fn(); const form = createMockForm({ wikiFolderNameSetter: mockSetter, }); await renderNewWikiForm({ form }); const input = screen.getAllByRole('textbox', { name: 'AddWorkspace.WorkspaceFolderNameToCreate' })[0]; await user.clear(input); await user.type(input, 'new-wiki-name'); // Should call setter for each character expect(mockSetter).toHaveBeenCalled(); expect(mockSetter.mock.calls.length).toBeGreaterThan(0); }); it('should handle directory picker button click', async () => { const user = userEvent.setup(); const mockSetter = vi.fn(); const form = createMockForm({ parentFolderLocationSetter: mockSetter, }); await renderNewWikiForm({ form }); const button = screen.getAllByRole('button', { name: 'AddWorkspace.Choose' })[0]; await user.click(button); // Should call the setter with empty string first, then with selected path expect(mockSetter).toHaveBeenCalledWith(''); expect(mockSetter).toHaveBeenCalledWith('/test/selected/path'); }); it('should handle tag name input for sub workspace', async () => { const user = userEvent.setup(); const mockSetter = vi.fn(); const form = createMockForm({ tagNameSetter: mockSetter, }); await renderNewWikiForm({ form, isCreateMainWorkspace: false, }); // Simulate user typing in autocomplete and pressing enter const tagInput = screen.getByTestId('tagname-autocomplete-input'); await user.type(tagInput, 'MyTag'); await user.keyboard('{enter}'); expect(mockSetter).toHaveBeenCalledWith('MyTag'); }); }); describe('Error State Tests', () => { it('should display errors on form fields when provided', async () => { await renderNewWikiForm({ errorInWhichComponent: { parentFolderLocation: true, wikiFolderName: true, }, }); // Should show error state on input fields const parentInputs = screen.getAllByRole('textbox', { name: 'AddWorkspace.WorkspaceParentFolder' }); const wikiNameInputs = screen.getAllByRole('textbox', { name: 'AddWorkspace.WorkspaceFolderNameToCreate' }); expect(parentInputs.some(input => input.getAttribute('aria-invalid') === 'true')).toBe(true); expect(wikiNameInputs.some(input => input.getAttribute('aria-invalid') === 'true')).toBe(true); }); it('should display errors on sub workspace fields when provided', async () => { await renderNewWikiForm({ isCreateMainWorkspace: false, errorInWhichComponent: { mainWikiToLink: true, tagName: true, }, }); // Should show error state on sub workspace fields const mainWikiSelects = screen.getAllByRole('combobox', { name: 'AddWorkspace.MainWorkspaceLocation' }); const tagInputs = screen.getAllByRole('combobox', { name: 'AddWorkspace.TagName' }); expect(mainWikiSelects.some(select => select.getAttribute('aria-invalid') === 'true')).toBe(true); expect(tagInputs.some(input => input.getAttribute('aria-invalid') === 'true')).toBe(true); }); }); describe('Props and State Tests', () => { it('should render without errors when required props are provided', async () => { // Just render successfully without throwing await renderNewWikiForm(); // If we got here without errors, the test passes expect(screen.getAllByRole('textbox').length).toBeGreaterThan(0); }); it('should show helper text for wiki folder location', async () => { const form = createMockForm({ wikiFolderLocation: '/test/parent/my-wiki', }); await renderNewWikiForm({ form }); expect(screen.getByText('AddWorkspace.CreateWiki/test/parent/my-wiki')).toBeInTheDocument(); }); it('should show helper text for sub workspace linking', async () => { const form = createMockForm({ wikiFolderName: 'sub-wiki', mainWikiToLink: { wikiFolderLocation: '/main/wiki', id: 'main-id', port: 5212, }, }); await renderNewWikiForm({ form, isCreateMainWorkspace: false, }); // Because the text is rendered with a template literal and newlines, we need to use a regex expect(screen.getByText((content, _element) => { // The actual text might have whitespace and newlines const normalized = content.replace(/\s+/g, ' ').trim(); return normalized === 'AddWorkspace.SubWorkspaceWillLinkTo /main/wiki/tiddlers/subwiki/sub-wiki'; })).toBeInTheDocument(); }); }); });