diff --git a/app/src/components/settings/workspace/AppearanceSettings.test.tsx b/app/src/components/settings/workspace/AppearanceSettings.test.tsx new file mode 100644 index 0000000..adf30af --- /dev/null +++ b/app/src/components/settings/workspace/AppearanceSettings.test.tsx @@ -0,0 +1,80 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { render as rtlRender, screen, fireEvent } from '@testing-library/react'; +import React from 'react'; +import { MantineProvider } from '@mantine/core'; +import AppearanceSettings from './AppearanceSettings'; +import { Theme } from '@/types/models'; + +const mockUpdateColorScheme = vi.fn(); + +vi.mock('../../../contexts/ThemeContext', () => ({ + useTheme: vi.fn(), +})); + +const TestWrapper = ({ children }: { children: React.ReactNode }) => ( + {children} +); + +const render = (ui: React.ReactElement) => { + return rtlRender(ui, { wrapper: TestWrapper }); +}; + +describe('AppearanceSettings', () => { + const mockOnThemeChange = vi.fn(); + + beforeEach(async () => { + vi.clearAllMocks(); + const { useTheme } = await import('../../../contexts/ThemeContext'); + vi.mocked(useTheme).mockReturnValue({ + colorScheme: 'light', + updateColorScheme: mockUpdateColorScheme, + }); + }); + + it('renders dark mode toggle with correct state', () => { + render(); + + expect(screen.getByText('Dark Mode')).toBeInTheDocument(); + const toggle = screen.getByRole('switch'); + expect(toggle).not.toBeChecked(); + }); + + it('shows toggle as checked when in dark mode', async () => { + const { useTheme } = await import('../../../contexts/ThemeContext'); + vi.mocked(useTheme).mockReturnValue({ + colorScheme: 'dark', + updateColorScheme: mockUpdateColorScheme, + }); + + render(); + + const toggle = screen.getByRole('switch'); + expect(toggle).toBeChecked(); + }); + + it('toggles theme from light to dark', () => { + render(); + + const toggle = screen.getByRole('switch'); + fireEvent.click(toggle); + + expect(mockUpdateColorScheme).toHaveBeenCalledWith(Theme.Dark); + expect(mockOnThemeChange).toHaveBeenCalledWith(Theme.Dark); + }); + + it('toggles theme from dark to light', async () => { + const { useTheme } = await import('../../../contexts/ThemeContext'); + vi.mocked(useTheme).mockReturnValue({ + colorScheme: 'dark', + updateColorScheme: mockUpdateColorScheme, + }); + + render(); + + const toggle = screen.getByRole('switch'); + fireEvent.click(toggle); + + expect(mockUpdateColorScheme).toHaveBeenCalledWith(Theme.Light); + expect(mockOnThemeChange).toHaveBeenCalledWith(Theme.Light); + }); +}); diff --git a/app/src/components/settings/workspace/DangerZoneSettings.test.tsx b/app/src/components/settings/workspace/DangerZoneSettings.test.tsx new file mode 100644 index 0000000..6439d61 --- /dev/null +++ b/app/src/components/settings/workspace/DangerZoneSettings.test.tsx @@ -0,0 +1,283 @@ +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 DangerZoneSettings from './DangerZoneSettings'; +import { Theme } from '@/types/models'; + +const mockDeleteCurrentWorkspace = vi.fn(); + +vi.mock('../../../hooks/useWorkspace', () => ({ + useWorkspace: vi.fn(), +})); + +const mockSetSettingsModalVisible = vi.fn(); +vi.mock('../../../contexts/ModalContext', () => ({ + useModalContext: () => ({ + setSettingsModalVisible: mockSetSettingsModalVisible, + }), +})); + +vi.mock('../../modals/workspace/DeleteWorkspaceModal', () => ({ + default: ({ + opened, + onClose, + onConfirm, + workspaceName, + }: { + opened: boolean; + onClose: () => void; + onConfirm: () => Promise; + workspaceName: string | undefined; + }) => + opened ? ( +
+ {workspaceName} + + +
+ ) : null, +})); + +// 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('DangerZoneSettings (Workspace)', () => { + beforeEach(async () => { + vi.clearAllMocks(); + mockDeleteCurrentWorkspace.mockResolvedValue(undefined); + + const { useWorkspace } = await import('../../../hooks/useWorkspace'); + vi.mocked(useWorkspace).mockReturnValue({ + currentWorkspace: { + id: 1, + userId: 1, + 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: [ + { + id: 1, + userId: 1, + name: 'Workspace 1', + createdAt: '2024-01-01T00:00:00Z', + theme: Theme.Light, + autoSave: false, + showHiddenFiles: false, + gitEnabled: false, + gitUrl: '', + gitUser: '', + gitToken: '', + gitAutoCommit: false, + gitCommitMsgTemplate: '', + gitCommitName: '', + gitCommitEmail: '', + }, + { + id: 2, + userId: 1, + name: 'Workspace 2', + createdAt: '2024-01-01T00:00:00Z', + theme: Theme.Light, + autoSave: false, + showHiddenFiles: false, + gitEnabled: false, + gitUrl: '', + gitUser: '', + gitToken: '', + gitAutoCommit: false, + gitCommitMsgTemplate: '', + gitCommitName: '', + gitCommitEmail: '', + }, + ], + settings: { + id: 1, + userId: 1, + 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: '', + }, + updateSettings: vi.fn(), + loading: false, + colorScheme: 'light', + updateColorScheme: vi.fn(), + switchWorkspace: vi.fn(), + deleteCurrentWorkspace: mockDeleteCurrentWorkspace, + }); + }); + + it('renders delete button when multiple workspaces exist', () => { + render(); + + const deleteButton = screen.getByRole('button', { + name: 'Delete Workspace', + }); + expect(deleteButton).toBeInTheDocument(); + expect(deleteButton).not.toBeDisabled(); + }); + + it('disables delete button when only one workspace exists', async () => { + const { useWorkspace } = await import('../../../hooks/useWorkspace'); + vi.mocked(useWorkspace).mockReturnValue({ + currentWorkspace: { + id: 1, + userId: 1, + name: 'Last 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: [ + { + id: 1, + userId: 1, + name: 'Last Workspace', + createdAt: '2024-01-01T00:00:00Z', + theme: Theme.Light, + autoSave: false, + showHiddenFiles: false, + gitEnabled: false, + gitUrl: '', + gitUser: '', + gitToken: '', + gitAutoCommit: false, + gitCommitMsgTemplate: '', + gitCommitName: '', + gitCommitEmail: '', + }, + ], + settings: { + id: 1, + userId: 1, + name: 'Last Workspace', + createdAt: '2024-01-01T00:00:00Z', + theme: Theme.Light, + autoSave: false, + showHiddenFiles: false, + gitEnabled: false, + gitUrl: '', + gitUser: '', + gitToken: '', + gitAutoCommit: false, + gitCommitMsgTemplate: '', + gitCommitName: '', + gitCommitEmail: '', + }, + updateSettings: vi.fn(), + loading: false, + colorScheme: 'light', + updateColorScheme: vi.fn(), + switchWorkspace: vi.fn(), + deleteCurrentWorkspace: mockDeleteCurrentWorkspace, + }); + + render(); + + const deleteButton = screen.getByRole('button', { + name: 'Delete Workspace', + }); + expect(deleteButton).toBeDisabled(); + expect(deleteButton).toHaveAttribute( + 'title', + 'Cannot delete the last workspace' + ); + }); + + it('opens and closes delete modal', () => { + render(); + + const deleteButton = screen.getByRole('button', { + name: 'Delete Workspace', + }); + fireEvent.click(deleteButton); + + expect(screen.getByTestId('delete-workspace-modal')).toBeInTheDocument(); + expect(screen.getByTestId('workspace-name')).toHaveTextContent( + 'Test Workspace' + ); + + fireEvent.click(screen.getByTestId('modal-close')); + expect( + screen.queryByTestId('delete-workspace-modal') + ).not.toBeInTheDocument(); + }); + + it('completes workspace deletion flow', async () => { + render(); + + fireEvent.click(screen.getByRole('button', { name: 'Delete Workspace' })); + fireEvent.click(screen.getByTestId('modal-confirm')); + + await waitFor(() => { + expect(mockDeleteCurrentWorkspace).toHaveBeenCalled(); + }); + + await waitFor(() => { + expect(mockSetSettingsModalVisible).toHaveBeenCalledWith(false); + }); + + expect( + screen.queryByTestId('delete-workspace-modal') + ).not.toBeInTheDocument(); + }); + + it('allows cancellation of deletion process', () => { + render(); + + fireEvent.click(screen.getByRole('button', { name: 'Delete Workspace' })); + fireEvent.click(screen.getByTestId('modal-close')); + + expect( + screen.queryByTestId('delete-workspace-modal') + ).not.toBeInTheDocument(); + expect(mockDeleteCurrentWorkspace).not.toHaveBeenCalled(); + expect(mockSetSettingsModalVisible).not.toHaveBeenCalled(); + }); +}); diff --git a/app/src/components/settings/workspace/EditorSettings.test.tsx b/app/src/components/settings/workspace/EditorSettings.test.tsx new file mode 100644 index 0000000..3dc1d40 --- /dev/null +++ b/app/src/components/settings/workspace/EditorSettings.test.tsx @@ -0,0 +1,78 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { render as rtlRender, screen, fireEvent } from '@testing-library/react'; +import React from 'react'; +import { MantineProvider } from '@mantine/core'; +import EditorSettings from './EditorSettings'; + +// 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('EditorSettings', () => { + const mockOnAutoSaveChange = vi.fn(); + const mockOnShowHiddenFilesChange = vi.fn(); + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('renders both toggle switches with labels', () => { + render( + + ); + + expect(screen.getByText('Auto Save')).toBeInTheDocument(); + expect(screen.getByText('Show Hidden Files')).toBeInTheDocument(); + }); + + it('shows correct toggle states', () => { + render( + + ); + + const toggles = screen.getAllByRole('switch'); + const autoSaveToggle = toggles[0]; + const hiddenFilesToggle = toggles[1]; + + expect(autoSaveToggle).toBeChecked(); + expect(hiddenFilesToggle).not.toBeChecked(); + }); + + it('calls onShowHiddenFilesChange when toggle is clicked', () => { + render( + + ); + + // Get the show hidden files toggle by finding the one that's not disabled + const toggles = screen.getAllByRole('switch'); + const hiddenFilesToggle = toggles.find( + (toggle) => !toggle.hasAttribute('disabled') + ); + + expect(hiddenFilesToggle).toBeDefined(); + fireEvent.click(hiddenFilesToggle!); + + expect(mockOnShowHiddenFilesChange).toHaveBeenCalledWith(true); + }); +}); diff --git a/app/src/components/settings/workspace/GeneralSettings.test.tsx b/app/src/components/settings/workspace/GeneralSettings.test.tsx new file mode 100644 index 0000000..0db590e --- /dev/null +++ b/app/src/components/settings/workspace/GeneralSettings.test.tsx @@ -0,0 +1,61 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { render as rtlRender, screen, fireEvent } from '@testing-library/react'; +import React from 'react'; +import { MantineProvider } from '@mantine/core'; +import GeneralSettings from './GeneralSettings'; + +// 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('GeneralSettings', () => { + const mockOnInputChange = vi.fn(); + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('renders workspace name input with current value', () => { + render( + + ); + + const nameInput = screen.getByDisplayValue('My Workspace'); + expect(nameInput).toBeInTheDocument(); + expect(screen.getByText('Workspace Name')).toBeInTheDocument(); + }); + + it('renders with empty name', () => { + render(); + + const nameInput = screen.getByPlaceholderText('Enter workspace name'); + expect(nameInput).toHaveValue(''); + }); + + it('calls onInputChange when name is modified', () => { + render( + + ); + + const nameInput = screen.getByDisplayValue('Old Name'); + fireEvent.change(nameInput, { target: { value: 'New Workspace Name' } }); + + expect(mockOnInputChange).toHaveBeenCalledWith( + 'name', + 'New Workspace Name' + ); + }); + + it('has required attribute on input', () => { + render(); + + const nameInput = screen.getByDisplayValue('Test'); + expect(nameInput).toHaveAttribute('required'); + }); +}); diff --git a/app/src/components/settings/workspace/GitSettings.test.tsx b/app/src/components/settings/workspace/GitSettings.test.tsx new file mode 100644 index 0000000..3439917 --- /dev/null +++ b/app/src/components/settings/workspace/GitSettings.test.tsx @@ -0,0 +1,134 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { render as rtlRender, screen, fireEvent } from '@testing-library/react'; +import React from 'react'; +import { MantineProvider } from '@mantine/core'; +import GitSettings from './GitSettings'; + +// 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('GitSettings', () => { + const mockOnInputChange = vi.fn(); + + const defaultProps = { + gitEnabled: false, + gitUrl: '', + gitUser: '', + gitToken: '', + gitAutoCommit: false, + gitCommitMsgTemplate: '', + gitCommitName: '', + gitCommitEmail: '', + onInputChange: mockOnInputChange, + }; + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('renders all git settings fields', () => { + render(); + + expect(screen.getByText('Enable Git Repository')).toBeInTheDocument(); + expect(screen.getByText('Git URL')).toBeInTheDocument(); + expect(screen.getByText('Username')).toBeInTheDocument(); + expect(screen.getByText('Access Token')).toBeInTheDocument(); + expect(screen.getByText('Commit on Save')).toBeInTheDocument(); + expect(screen.getByText('Commit Message Template')).toBeInTheDocument(); + expect(screen.getByText('Commit Author')).toBeInTheDocument(); + expect(screen.getByText('Commit Author Email')).toBeInTheDocument(); + }); + + it('disables all inputs when git is not enabled', () => { + render(); + + expect(screen.getByPlaceholderText('Enter Git URL')).toBeDisabled(); + expect(screen.getByPlaceholderText('Enter Git username')).toBeDisabled(); + expect(screen.getByPlaceholderText('Enter Git token')).toBeDisabled(); + + const switches = screen.getAllByRole('switch'); + const commitOnSaveSwitch = switches[1]; // Second switch is commit on save + expect(commitOnSaveSwitch).toBeDisabled(); + }); + + it('enables all inputs when git is enabled', () => { + render(); + + expect(screen.getByPlaceholderText('Enter Git URL')).not.toBeDisabled(); + expect( + screen.getByPlaceholderText('Enter Git username') + ).not.toBeDisabled(); + expect(screen.getByPlaceholderText('Enter Git token')).not.toBeDisabled(); + + const switches = screen.getAllByRole('switch'); + const commitOnSaveSwitch = switches[1]; + expect(commitOnSaveSwitch).not.toBeDisabled(); + }); + + it('calls onInputChange when git enabled toggle is changed', () => { + render(); + + const switches = screen.getAllByRole('switch'); + const gitEnabledSwitch = switches[0]; + expect(gitEnabledSwitch).toBeDefined(); + + fireEvent.click(gitEnabledSwitch!); + + expect(mockOnInputChange).toHaveBeenCalledWith('gitEnabled', true); + }); + + it('calls onInputChange when git URL is changed', () => { + render(); + + const urlInput = screen.getByPlaceholderText('Enter Git URL'); + fireEvent.change(urlInput, { + target: { value: 'https://github.com/user/repo.git' }, + }); + + expect(mockOnInputChange).toHaveBeenCalledWith( + 'gitUrl', + 'https://github.com/user/repo.git' + ); + }); + + it('calls onInputChange when commit template is changed', () => { + render(); + + const templateInput = screen.getByPlaceholderText( + 'Enter commit message template' + ); + fireEvent.change(templateInput, { + target: { value: '${action}: ${filename}' }, + }); + + expect(mockOnInputChange).toHaveBeenCalledWith( + 'gitCommitMsgTemplate', + '${action}: ${filename}' + ); + }); + + it('shows current values in form fields', () => { + const propsWithValues = { + ...defaultProps, + gitEnabled: true, + gitUrl: 'https://github.com/test/repo.git', + gitUser: 'testuser', + gitCommitMsgTemplate: 'Update ${filename}', + }; + + render(); + + expect( + screen.getByDisplayValue('https://github.com/test/repo.git') + ).toBeInTheDocument(); + expect(screen.getByDisplayValue('testuser')).toBeInTheDocument(); + expect(screen.getByDisplayValue('Update ${filename}')).toBeInTheDocument(); + }); +}); diff --git a/app/src/components/settings/workspace/WorkspaceSettings.test.tsx b/app/src/components/settings/workspace/WorkspaceSettings.test.tsx new file mode 100644 index 0000000..a9603db --- /dev/null +++ b/app/src/components/settings/workspace/WorkspaceSettings.test.tsx @@ -0,0 +1,212 @@ +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: [], + settings: { + id: 1, + userId: 1, + 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: '', + }, + 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(); + }); +}); diff --git a/app/src/components/settings/workspace/WorkspaceSettings.tsx b/app/src/components/settings/workspace/WorkspaceSettings.tsx index f20b01c..109f999 100644 --- a/app/src/components/settings/workspace/WorkspaceSettings.tsx +++ b/app/src/components/settings/workspace/WorkspaceSettings.tsx @@ -235,7 +235,7 @@ const WorkspaceSettings: React.FC = () => { - +