import { describe, it, expect, vi, beforeEach } from 'vitest';
import {
render as rtlRender,
screen,
fireEvent,
waitFor,
} from '@testing-library/react';
import React from 'react';
import { MantineProvider } from '@mantine/core';
import WorkspaceSettings from './WorkspaceSettings';
import { Theme } from '@/types/models';
const mockUpdateSettings = vi.fn();
vi.mock('../../../hooks/useWorkspace', () => ({
useWorkspace: vi.fn(),
}));
const mockSetSettingsModalVisible = vi.fn();
vi.mock('../../../contexts/ModalContext', () => ({
useModalContext: () => ({
settingsModalVisible: true,
setSettingsModalVisible: mockSetSettingsModalVisible,
}),
}));
vi.mock('@mantine/notifications', () => ({
notifications: {
show: vi.fn(),
},
}));
vi.mock('./GeneralSettings', () => ({
default: ({
name,
onInputChange,
}: {
name: string;
onInputChange: (key: string, value: string) => void;
}) => (
onInputChange('name', e.target.value)}
/>
),
}));
vi.mock('./AppearanceSettings', () => ({
default: ({ onThemeChange }: { onThemeChange: (theme: string) => void }) => (
),
}));
vi.mock('./EditorSettings', () => ({
default: () => Editor Settings
,
}));
vi.mock('./GitSettings', () => ({
default: () => Git Settings
,
}));
vi.mock('./DangerZoneSettings', () => ({
default: () => Danger Zone
,
}));
// Helper wrapper component for testing
const TestWrapper = ({ children }: { children: React.ReactNode }) => (
{children}
);
// Custom render function
const render = (ui: React.ReactElement) => {
return rtlRender(ui, { wrapper: TestWrapper });
};
describe('WorkspaceSettings', () => {
beforeEach(async () => {
vi.clearAllMocks();
mockUpdateSettings.mockResolvedValue(undefined);
const { useWorkspace } = await import('../../../hooks/useWorkspace');
vi.mocked(useWorkspace).mockReturnValue({
currentWorkspace: {
name: 'Test Workspace',
createdAt: '2024-01-01T00:00:00Z',
theme: Theme.Light,
autoSave: false,
showHiddenFiles: false,
gitEnabled: false,
gitUrl: '',
gitUser: '',
gitToken: '',
gitAutoCommit: false,
gitCommitMsgTemplate: '',
gitCommitName: '',
gitCommitEmail: '',
},
workspaces: [],
updateSettings: mockUpdateSettings,
loading: false,
colorScheme: 'light',
updateColorScheme: vi.fn(),
switchWorkspace: vi.fn(),
deleteCurrentWorkspace: vi.fn(),
});
});
it('renders modal with all setting sections', () => {
render();
expect(screen.getByText('Workspace Settings')).toBeInTheDocument();
expect(screen.getByTestId('general-settings')).toBeInTheDocument();
expect(screen.getByTestId('appearance-settings')).toBeInTheDocument();
expect(screen.getByTestId('editor-settings')).toBeInTheDocument();
expect(screen.getByTestId('git-settings')).toBeInTheDocument();
expect(screen.getByTestId('danger-zone-settings')).toBeInTheDocument();
});
it('shows unsaved changes badge when settings are modified', () => {
render();
const nameInput = screen.getByTestId('workspace-name-input');
fireEvent.change(nameInput, { target: { value: 'Updated Workspace' } });
expect(screen.getByText('Unsaved Changes')).toBeInTheDocument();
});
it('saves settings successfully', async () => {
render();
const nameInput = screen.getByTestId('workspace-name-input');
fireEvent.change(nameInput, { target: { value: 'Updated Workspace' } });
const saveButton = screen.getByRole('button', { name: 'Save Changes' });
expect(saveButton).toBeDefined();
fireEvent.click(saveButton);
await waitFor(() => {
expect(mockUpdateSettings).toHaveBeenCalledWith(
expect.objectContaining({ name: 'Updated Workspace' })
);
});
await waitFor(() => {
expect(mockSetSettingsModalVisible).toHaveBeenCalledWith(false);
});
});
it('handles theme changes', () => {
render();
const themeToggle = screen.getByTestId('theme-toggle');
fireEvent.click(themeToggle);
expect(screen.getByText('Unsaved Changes')).toBeInTheDocument();
});
it('closes modal when cancel is clicked', () => {
render();
const cancelButton = screen.getByRole('button', { name: 'Cancel' });
fireEvent.click(cancelButton);
expect(mockSetSettingsModalVisible).toHaveBeenCalledWith(false);
});
it('prevents saving with empty workspace name', async () => {
const { notifications } = await import('@mantine/notifications');
render();
const nameInput = screen.getByTestId('workspace-name-input');
fireEvent.change(nameInput, { target: { value: ' ' } }); // Empty/whitespace
const saveButton = screen.getByRole('button', { name: 'Save Changes' });
fireEvent.click(saveButton);
await waitFor(() => {
expect(notifications.show).toHaveBeenCalledWith(
expect.objectContaining({
message: 'Workspace name cannot be empty',
color: 'red',
})
);
});
expect(mockUpdateSettings).not.toHaveBeenCalled();
});
});