veza/apps/web/src/features/settings/services/settingsService.test.ts

329 lines
8.6 KiB
TypeScript
Raw Normal View History

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { AxiosError } from 'axios';
import { getSettings, getDefaultSettings, updateSettings } from './settingsService';
import { apiClient } from '@/services/api/client';
import { UserSettings, UpdateSettingsRequest } from '../types/settings';
// Mock apiClient
vi.mock('@/services/api/client', () => ({
apiClient: {
get: vi.fn(),
put: vi.fn(),
},
}));
describe('settingsService', () => {
const mockSettings: UserSettings = {
notifications: {
email_notifications: true,
push_notifications: true,
browser_notifications: true,
email_on_follow: true,
email_on_like: true,
email_on_comment: true,
email_on_message: true,
email_on_mention: true,
email_marketing: false,
},
privacy: {
allow_search_indexing: true,
show_activity: true,
},
content: {
explicit_content: false,
autoplay: true,
},
preferences: {
language: 'en',
timezone: 'UTC',
theme: 'auto',
},
};
beforeEach(() => {
vi.clearAllMocks();
});
describe('getSettings', () => {
it('should return settings successfully', async () => {
vi.mocked(apiClient.get).mockResolvedValue({
data: mockSettings,
status: 200,
statusText: 'OK',
headers: {},
config: {} as any,
});
const result = await getSettings(1);
expect(result).toEqual(mockSettings);
expect(apiClient.get).toHaveBeenCalledWith('/users/1/settings');
});
it('should throw error on 401 Unauthorized', async () => {
const error = new AxiosError('Unauthorized');
error.response = {
status: 401,
data: {},
statusText: 'Unauthorized',
headers: {},
config: {} as any,
};
vi.mocked(apiClient.get).mockRejectedValue(error);
2025-12-13 02:34:34 +00:00
await expect(getSettings(1)).rejects.toThrow(
'Unauthorized: Please log in to access settings',
);
});
it('should throw error on 403 Forbidden', async () => {
const error = new AxiosError('Forbidden');
error.response = {
status: 403,
data: {},
statusText: 'Forbidden',
headers: {},
config: {} as any,
};
vi.mocked(apiClient.get).mockRejectedValue(error);
2025-12-13 02:34:34 +00:00
await expect(getSettings(1)).rejects.toThrow(
'Forbidden: You cannot access these settings',
);
});
it('should return default settings on 404 Not Found', async () => {
const error = new AxiosError('Not Found');
error.response = {
status: 404,
data: {},
statusText: 'Not Found',
headers: {},
config: {} as any,
};
vi.mocked(apiClient.get).mockRejectedValue(error);
const result = await getSettings('1');
const defaults = getDefaultSettings();
expect(result.preferences.language).toBe(defaults.preferences.language);
expect(result.preferences.theme).toBe(defaults.preferences.theme);
expect(result.notifications).toEqual(defaults.notifications);
expect(result.privacy).toEqual(defaults.privacy);
expect(result.content).toEqual(defaults.content);
});
it('should throw error with custom message from response', async () => {
const error = new AxiosError('Error');
error.response = {
status: 500,
data: { error: 'Internal server error' },
statusText: 'Internal Server Error',
headers: {},
config: {} as any,
};
vi.mocked(apiClient.get).mockRejectedValue(error);
await expect(getSettings(1)).rejects.toThrow('Internal server error');
});
it('should throw generic error on unknown error', async () => {
const error = new Error('Network error');
vi.mocked(apiClient.get).mockRejectedValue(error);
await expect(getSettings(1)).rejects.toThrow(error);
});
});
describe('updateSettings', () => {
const updateRequest: UpdateSettingsRequest = {
preferences: {
language: 'fr',
timezone: 'Europe/Paris',
theme: 'dark',
},
};
it('should update settings successfully', async () => {
vi.mocked(apiClient.put).mockResolvedValue({
data: {},
status: 200,
statusText: 'OK',
headers: {},
config: {} as any,
});
await updateSettings(1, updateRequest);
2025-12-13 02:34:34 +00:00
expect(apiClient.put).toHaveBeenCalledWith(
'/users/settings',
2025-12-13 02:34:34 +00:00
updateRequest,
);
});
it('should throw error on 400 Bad Request', async () => {
const error = new AxiosError('Bad Request');
error.response = {
status: 400,
data: { error: 'Invalid settings data' },
statusText: 'Bad Request',
headers: {},
config: {} as any,
};
vi.mocked(apiClient.put).mockRejectedValue(error);
2025-12-13 02:34:34 +00:00
await expect(updateSettings(1, updateRequest)).rejects.toThrow(
'Invalid settings data',
);
});
it('should throw error on 401 Unauthorized', async () => {
const error = new AxiosError('Unauthorized');
error.response = {
status: 401,
data: {},
statusText: 'Unauthorized',
headers: {},
config: {} as any,
};
vi.mocked(apiClient.put).mockRejectedValue(error);
2025-12-13 02:34:34 +00:00
await expect(updateSettings(1, updateRequest)).rejects.toThrow(
'Unauthorized: Please log in to update settings',
);
});
it('should throw error on 403 Forbidden', async () => {
const error = new AxiosError('Forbidden');
error.response = {
status: 403,
data: {},
statusText: 'Forbidden',
headers: {},
config: {} as any,
};
vi.mocked(apiClient.put).mockRejectedValue(error);
2025-12-13 02:34:34 +00:00
await expect(updateSettings(1, updateRequest)).rejects.toThrow(
'Forbidden: You cannot update these settings',
);
});
it('should throw error on 404 Not Found', async () => {
const error = new AxiosError('Not Found');
error.response = {
status: 404,
data: {},
statusText: 'Not Found',
headers: {},
config: {} as any,
};
vi.mocked(apiClient.put).mockRejectedValue(error);
2025-12-13 02:34:34 +00:00
await expect(updateSettings(1, updateRequest)).rejects.toThrow(
'Settings not found',
);
});
it('should throw error with custom message from response', async () => {
const error = new AxiosError('Error');
error.response = {
status: 500,
data: { error: 'Internal server error' },
statusText: 'Internal Server Error',
headers: {},
config: {} as any,
};
vi.mocked(apiClient.put).mockRejectedValue(error);
2025-12-13 02:34:34 +00:00
await expect(updateSettings(1, updateRequest)).rejects.toThrow(
'Internal server error',
);
});
it('should throw generic error on unknown error', async () => {
const error = new Error('Network error');
vi.mocked(apiClient.put).mockRejectedValue(error);
await expect(updateSettings(1, updateRequest)).rejects.toThrow(error);
});
it('should update only notifications', async () => {
const notificationsOnly: UpdateSettingsRequest = {
notifications: {
email_notifications: false,
},
};
vi.mocked(apiClient.put).mockResolvedValue({
data: {},
status: 200,
statusText: 'OK',
headers: {},
config: {} as any,
});
await updateSettings(1, notificationsOnly);
2025-12-13 02:34:34 +00:00
expect(apiClient.put).toHaveBeenCalledWith(
'/users/settings',
2025-12-13 02:34:34 +00:00
notificationsOnly,
);
});
it('should update only privacy', async () => {
const privacyOnly: UpdateSettingsRequest = {
privacy: {
allow_search_indexing: false,
},
};
vi.mocked(apiClient.put).mockResolvedValue({
data: {},
status: 200,
statusText: 'OK',
headers: {},
config: {} as any,
});
await updateSettings(1, privacyOnly);
2025-12-13 02:34:34 +00:00
expect(apiClient.put).toHaveBeenCalledWith(
'/users/settings',
2025-12-13 02:34:34 +00:00
privacyOnly,
);
});
it('should update only content', async () => {
const contentOnly: UpdateSettingsRequest = {
content: {
explicit_content: true,
},
};
vi.mocked(apiClient.put).mockResolvedValue({
data: {},
status: 200,
statusText: 'OK',
headers: {},
config: {} as any,
});
await updateSettings(1, contentOnly);
2025-12-13 02:34:34 +00:00
expect(apiClient.put).toHaveBeenCalledWith(
'/users/settings',
2025-12-13 02:34:34 +00:00
contentOnly,
);
});
});
});