Add global navigation search, cancellation policies, and UI improvements
- Add global search in top bar for navigating to dashboard pages - Add cancellation policy settings (window hours, late fee, deposit refund) - Display booking policies on customer confirmation page - Filter API tokens by sandbox/live mode - Widen settings layout and full-width site builder - Add help documentation search with OpenAI integration - Add blocked time ranges API for calendar visualization - Update business hours settings with holiday management 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
611
frontend/src/api/__tests__/staffEmail.test.ts
Normal file
611
frontend/src/api/__tests__/staffEmail.test.ts
Normal file
@@ -0,0 +1,611 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import apiClient from '../client';
|
||||
import * as staffEmailApi from '../staffEmail';
|
||||
|
||||
vi.mock('../client');
|
||||
|
||||
describe('staffEmail API', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('Folder Operations', () => {
|
||||
const mockFolderResponse = {
|
||||
id: 1,
|
||||
owner: 1,
|
||||
name: 'Inbox',
|
||||
folder_type: 'inbox',
|
||||
email_count: 10,
|
||||
unread_count: 3,
|
||||
created_at: '2024-01-01T00:00:00Z',
|
||||
updated_at: '2024-01-01T00:00:00Z',
|
||||
};
|
||||
|
||||
describe('getFolders', () => {
|
||||
it('fetches all folders', async () => {
|
||||
vi.mocked(apiClient.get).mockResolvedValueOnce({ data: [mockFolderResponse] });
|
||||
|
||||
const result = await staffEmailApi.getFolders();
|
||||
|
||||
expect(apiClient.get).toHaveBeenCalledWith('/staff-email/folders/');
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].folderType).toBe('inbox');
|
||||
expect(result[0].emailCount).toBe(10);
|
||||
});
|
||||
|
||||
it('transforms snake_case to camelCase', async () => {
|
||||
vi.mocked(apiClient.get).mockResolvedValueOnce({ data: [mockFolderResponse] });
|
||||
|
||||
const result = await staffEmailApi.getFolders();
|
||||
|
||||
expect(result[0].createdAt).toBe('2024-01-01T00:00:00Z');
|
||||
expect(result[0].updatedAt).toBe('2024-01-01T00:00:00Z');
|
||||
});
|
||||
});
|
||||
|
||||
describe('createFolder', () => {
|
||||
it('creates a new folder', async () => {
|
||||
vi.mocked(apiClient.post).mockResolvedValueOnce({
|
||||
data: { ...mockFolderResponse, id: 2, name: 'Custom' },
|
||||
});
|
||||
|
||||
const result = await staffEmailApi.createFolder('Custom');
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/staff-email/folders/', { name: 'Custom' });
|
||||
expect(result.name).toBe('Custom');
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateFolder', () => {
|
||||
it('updates a folder name', async () => {
|
||||
vi.mocked(apiClient.patch).mockResolvedValueOnce({
|
||||
data: { ...mockFolderResponse, name: 'Updated' },
|
||||
});
|
||||
|
||||
const result = await staffEmailApi.updateFolder(1, 'Updated');
|
||||
|
||||
expect(apiClient.patch).toHaveBeenCalledWith('/staff-email/folders/1/', { name: 'Updated' });
|
||||
expect(result.name).toBe('Updated');
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteFolder', () => {
|
||||
it('deletes a folder', async () => {
|
||||
vi.mocked(apiClient.delete).mockResolvedValueOnce({});
|
||||
|
||||
await staffEmailApi.deleteFolder(1);
|
||||
|
||||
expect(apiClient.delete).toHaveBeenCalledWith('/staff-email/folders/1/');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Email Operations', () => {
|
||||
const mockEmailResponse = {
|
||||
id: 1,
|
||||
folder: 1,
|
||||
from_address: 'sender@example.com',
|
||||
from_name: 'Sender',
|
||||
to_addresses: [{ email: 'recipient@example.com', name: 'Recipient' }],
|
||||
subject: 'Test Email',
|
||||
snippet: 'This is a test...',
|
||||
status: 'received',
|
||||
is_read: false,
|
||||
is_starred: false,
|
||||
is_important: false,
|
||||
has_attachments: false,
|
||||
attachment_count: 0,
|
||||
thread_id: 'thread-1',
|
||||
email_date: '2024-01-01T12:00:00Z',
|
||||
created_at: '2024-01-01T12:00:00Z',
|
||||
labels: [],
|
||||
};
|
||||
|
||||
describe('getEmails', () => {
|
||||
it('fetches emails with filters', async () => {
|
||||
vi.mocked(apiClient.get).mockResolvedValueOnce({
|
||||
data: {
|
||||
count: 1,
|
||||
next: null,
|
||||
previous: null,
|
||||
results: [mockEmailResponse],
|
||||
},
|
||||
});
|
||||
|
||||
const result = await staffEmailApi.getEmails({ folderId: 1 }, 1, 50);
|
||||
|
||||
expect(apiClient.get).toHaveBeenCalledWith(
|
||||
expect.stringContaining('/staff-email/messages/')
|
||||
);
|
||||
expect(result.count).toBe(1);
|
||||
expect(result.results).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('handles legacy array response', async () => {
|
||||
vi.mocked(apiClient.get).mockResolvedValueOnce({
|
||||
data: [mockEmailResponse],
|
||||
});
|
||||
|
||||
const result = await staffEmailApi.getEmails({}, 1, 50);
|
||||
|
||||
expect(result.count).toBe(1);
|
||||
expect(result.results).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('applies all filter parameters', async () => {
|
||||
vi.mocked(apiClient.get).mockResolvedValueOnce({
|
||||
data: { count: 0, next: null, previous: null, results: [] },
|
||||
});
|
||||
|
||||
await staffEmailApi.getEmails({
|
||||
folderId: 1,
|
||||
emailAddressId: 2,
|
||||
isRead: true,
|
||||
isStarred: false,
|
||||
search: 'test',
|
||||
fromDate: '2024-01-01',
|
||||
toDate: '2024-01-31',
|
||||
});
|
||||
|
||||
const callUrl = vi.mocked(apiClient.get).mock.calls[0][0] as string;
|
||||
expect(callUrl).toContain('folder=1');
|
||||
expect(callUrl).toContain('email_address=2');
|
||||
expect(callUrl).toContain('is_read=true');
|
||||
expect(callUrl).toContain('is_starred=false');
|
||||
expect(callUrl).toContain('search=test');
|
||||
expect(callUrl).toContain('from_date=2024-01-01');
|
||||
expect(callUrl).toContain('to_date=2024-01-31');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getEmail', () => {
|
||||
it('fetches a single email by id', async () => {
|
||||
vi.mocked(apiClient.get).mockResolvedValueOnce({ data: mockEmailResponse });
|
||||
|
||||
const result = await staffEmailApi.getEmail(1);
|
||||
|
||||
expect(apiClient.get).toHaveBeenCalledWith('/staff-email/messages/1/');
|
||||
expect(result.fromAddress).toBe('sender@example.com');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getEmailThread', () => {
|
||||
it('fetches emails in a thread', async () => {
|
||||
vi.mocked(apiClient.get).mockResolvedValueOnce({
|
||||
data: { results: [mockEmailResponse] },
|
||||
});
|
||||
|
||||
const result = await staffEmailApi.getEmailThread('thread-1');
|
||||
|
||||
expect(apiClient.get).toHaveBeenCalledWith('/staff-email/messages/', {
|
||||
params: { thread_id: 'thread-1' },
|
||||
});
|
||||
expect(result).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Draft Operations', () => {
|
||||
describe('createDraft', () => {
|
||||
it('creates a draft with formatted addresses', async () => {
|
||||
vi.mocked(apiClient.post).mockResolvedValueOnce({
|
||||
data: {
|
||||
id: 1,
|
||||
folder: 1,
|
||||
subject: 'New Draft',
|
||||
from_address: 'sender@example.com',
|
||||
to_addresses: [{ email: 'recipient@example.com', name: '' }],
|
||||
},
|
||||
});
|
||||
|
||||
await staffEmailApi.createDraft({
|
||||
emailAddressId: 1,
|
||||
toAddresses: ['recipient@example.com'],
|
||||
subject: 'New Draft',
|
||||
bodyText: 'Body text',
|
||||
});
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/staff-email/messages/', expect.objectContaining({
|
||||
email_address: 1,
|
||||
to_addresses: [{ email: 'recipient@example.com', name: '' }],
|
||||
subject: 'New Draft',
|
||||
}));
|
||||
});
|
||||
|
||||
it('handles "Name <email>" format', async () => {
|
||||
vi.mocked(apiClient.post).mockResolvedValueOnce({
|
||||
data: { id: 1 },
|
||||
});
|
||||
|
||||
await staffEmailApi.createDraft({
|
||||
emailAddressId: 1,
|
||||
toAddresses: ['John Doe <john@example.com>'],
|
||||
subject: 'Test',
|
||||
});
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/staff-email/messages/', expect.objectContaining({
|
||||
to_addresses: [{ email: 'john@example.com', name: 'John Doe' }],
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateDraft', () => {
|
||||
it('updates draft subject', async () => {
|
||||
vi.mocked(apiClient.patch).mockResolvedValueOnce({
|
||||
data: { id: 1, subject: 'Updated Subject' },
|
||||
});
|
||||
|
||||
await staffEmailApi.updateDraft(1, { subject: 'Updated Subject' });
|
||||
|
||||
expect(apiClient.patch).toHaveBeenCalledWith('/staff-email/messages/1/', {
|
||||
subject: 'Updated Subject',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteDraft', () => {
|
||||
it('deletes a draft', async () => {
|
||||
vi.mocked(apiClient.delete).mockResolvedValueOnce({});
|
||||
|
||||
await staffEmailApi.deleteDraft(1);
|
||||
|
||||
expect(apiClient.delete).toHaveBeenCalledWith('/staff-email/messages/1/');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Send/Reply/Forward', () => {
|
||||
describe('sendEmail', () => {
|
||||
it('sends a draft', async () => {
|
||||
vi.mocked(apiClient.post).mockResolvedValueOnce({
|
||||
data: { id: 1, status: 'sent' },
|
||||
});
|
||||
|
||||
await staffEmailApi.sendEmail(1);
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/staff-email/messages/1/send/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('replyToEmail', () => {
|
||||
it('replies to an email', async () => {
|
||||
vi.mocked(apiClient.post).mockResolvedValueOnce({
|
||||
data: { id: 2, in_reply_to: 1 },
|
||||
});
|
||||
|
||||
await staffEmailApi.replyToEmail(1, {
|
||||
bodyText: 'Reply body',
|
||||
replyAll: false,
|
||||
});
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/staff-email/messages/1/reply/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('forwardEmail', () => {
|
||||
it('forwards an email', async () => {
|
||||
vi.mocked(apiClient.post).mockResolvedValueOnce({
|
||||
data: { id: 3 },
|
||||
});
|
||||
|
||||
await staffEmailApi.forwardEmail(1, {
|
||||
toAddresses: ['forward@example.com'],
|
||||
bodyText: 'FW: Original message',
|
||||
});
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/staff-email/messages/1/forward/', expect.objectContaining({
|
||||
to_addresses: [{ email: 'forward@example.com', name: '' }],
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Email Actions', () => {
|
||||
describe('markAsRead', () => {
|
||||
it('marks email as read', async () => {
|
||||
vi.mocked(apiClient.post).mockResolvedValueOnce({});
|
||||
|
||||
await staffEmailApi.markAsRead(1);
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/staff-email/messages/1/mark_read/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('markAsUnread', () => {
|
||||
it('marks email as unread', async () => {
|
||||
vi.mocked(apiClient.post).mockResolvedValueOnce({});
|
||||
|
||||
await staffEmailApi.markAsUnread(1);
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/staff-email/messages/1/mark_unread/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('starEmail', () => {
|
||||
it('stars an email', async () => {
|
||||
vi.mocked(apiClient.post).mockResolvedValueOnce({});
|
||||
|
||||
await staffEmailApi.starEmail(1);
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/staff-email/messages/1/star/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('unstarEmail', () => {
|
||||
it('unstars an email', async () => {
|
||||
vi.mocked(apiClient.post).mockResolvedValueOnce({});
|
||||
|
||||
await staffEmailApi.unstarEmail(1);
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/staff-email/messages/1/unstar/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('archiveEmail', () => {
|
||||
it('archives an email', async () => {
|
||||
vi.mocked(apiClient.post).mockResolvedValueOnce({});
|
||||
|
||||
await staffEmailApi.archiveEmail(1);
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/staff-email/messages/1/archive/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('trashEmail', () => {
|
||||
it('moves email to trash', async () => {
|
||||
vi.mocked(apiClient.post).mockResolvedValueOnce({});
|
||||
|
||||
await staffEmailApi.trashEmail(1);
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/staff-email/messages/1/trash/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('restoreEmail', () => {
|
||||
it('restores email from trash', async () => {
|
||||
vi.mocked(apiClient.post).mockResolvedValueOnce({});
|
||||
|
||||
await staffEmailApi.restoreEmail(1);
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/staff-email/messages/1/restore/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('permanentlyDeleteEmail', () => {
|
||||
it('permanently deletes an email', async () => {
|
||||
vi.mocked(apiClient.delete).mockResolvedValueOnce({});
|
||||
|
||||
await staffEmailApi.permanentlyDeleteEmail(1);
|
||||
|
||||
expect(apiClient.delete).toHaveBeenCalledWith('/staff-email/messages/1/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('moveEmails', () => {
|
||||
it('moves emails to a folder', async () => {
|
||||
vi.mocked(apiClient.post).mockResolvedValueOnce({});
|
||||
|
||||
await staffEmailApi.moveEmails({ emailIds: [1, 2, 3], folderId: 2 });
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/staff-email/messages/move/', {
|
||||
email_ids: [1, 2, 3],
|
||||
folder_id: 2,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('bulkAction', () => {
|
||||
it('performs bulk action on emails', async () => {
|
||||
vi.mocked(apiClient.post).mockResolvedValueOnce({});
|
||||
|
||||
await staffEmailApi.bulkAction({ emailIds: [1, 2], action: 'mark_read' });
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/staff-email/messages/bulk_action/', {
|
||||
email_ids: [1, 2],
|
||||
action: 'mark_read',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Labels', () => {
|
||||
const mockLabelResponse = {
|
||||
id: 1,
|
||||
owner: 1,
|
||||
name: 'Important',
|
||||
color: '#ef4444',
|
||||
created_at: '2024-01-01T00:00:00Z',
|
||||
};
|
||||
|
||||
describe('getLabels', () => {
|
||||
it('fetches all labels', async () => {
|
||||
vi.mocked(apiClient.get).mockResolvedValueOnce({ data: [mockLabelResponse] });
|
||||
|
||||
const result = await staffEmailApi.getLabels();
|
||||
|
||||
expect(apiClient.get).toHaveBeenCalledWith('/staff-email/labels/');
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].name).toBe('Important');
|
||||
});
|
||||
});
|
||||
|
||||
describe('createLabel', () => {
|
||||
it('creates a new label', async () => {
|
||||
vi.mocked(apiClient.post).mockResolvedValueOnce({
|
||||
data: { ...mockLabelResponse, id: 2, name: 'Work', color: '#10b981' },
|
||||
});
|
||||
|
||||
const result = await staffEmailApi.createLabel('Work', '#10b981');
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/staff-email/labels/', { name: 'Work', color: '#10b981' });
|
||||
expect(result.name).toBe('Work');
|
||||
});
|
||||
});
|
||||
|
||||
describe('updateLabel', () => {
|
||||
it('updates a label', async () => {
|
||||
vi.mocked(apiClient.patch).mockResolvedValueOnce({
|
||||
data: { ...mockLabelResponse, name: 'Updated' },
|
||||
});
|
||||
|
||||
const result = await staffEmailApi.updateLabel(1, { name: 'Updated' });
|
||||
|
||||
expect(apiClient.patch).toHaveBeenCalledWith('/staff-email/labels/1/', { name: 'Updated' });
|
||||
expect(result.name).toBe('Updated');
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteLabel', () => {
|
||||
it('deletes a label', async () => {
|
||||
vi.mocked(apiClient.delete).mockResolvedValueOnce({});
|
||||
|
||||
await staffEmailApi.deleteLabel(1);
|
||||
|
||||
expect(apiClient.delete).toHaveBeenCalledWith('/staff-email/labels/1/');
|
||||
});
|
||||
});
|
||||
|
||||
describe('addLabelToEmail', () => {
|
||||
it('adds label to email', async () => {
|
||||
vi.mocked(apiClient.post).mockResolvedValueOnce({});
|
||||
|
||||
await staffEmailApi.addLabelToEmail(1, 2);
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/staff-email/messages/1/add_label/', { label_id: 2 });
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeLabelFromEmail', () => {
|
||||
it('removes label from email', async () => {
|
||||
vi.mocked(apiClient.post).mockResolvedValueOnce({});
|
||||
|
||||
await staffEmailApi.removeLabelFromEmail(1, 2);
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/staff-email/messages/1/remove_label/', { label_id: 2 });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Contacts', () => {
|
||||
describe('searchContacts', () => {
|
||||
it('searches contacts', async () => {
|
||||
const mockContacts = [
|
||||
{ id: 1, owner: 1, email: 'test@example.com', name: 'Test', use_count: 5, last_used_at: '2024-01-01' },
|
||||
];
|
||||
vi.mocked(apiClient.get).mockResolvedValueOnce({ data: mockContacts });
|
||||
|
||||
const result = await staffEmailApi.searchContacts('test');
|
||||
|
||||
expect(apiClient.get).toHaveBeenCalledWith('/staff-email/contacts/', {
|
||||
params: { search: 'test' },
|
||||
});
|
||||
expect(result[0].email).toBe('test@example.com');
|
||||
expect(result[0].useCount).toBe(5);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Attachments', () => {
|
||||
describe('uploadAttachment', () => {
|
||||
it('uploads a file attachment', async () => {
|
||||
const mockResponse = {
|
||||
id: 1,
|
||||
filename: 'test.pdf',
|
||||
content_type: 'application/pdf',
|
||||
size: 1024,
|
||||
url: 'https://example.com/test.pdf',
|
||||
created_at: '2024-01-01T00:00:00Z',
|
||||
};
|
||||
vi.mocked(apiClient.post).mockResolvedValueOnce({ data: mockResponse });
|
||||
|
||||
const file = new File(['content'], 'test.pdf', { type: 'application/pdf' });
|
||||
const result = await staffEmailApi.uploadAttachment(file, 1);
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith(
|
||||
'/staff-email/attachments/',
|
||||
expect.any(FormData),
|
||||
{ headers: { 'Content-Type': 'multipart/form-data' } }
|
||||
);
|
||||
expect(result.filename).toBe('test.pdf');
|
||||
});
|
||||
|
||||
it('uploads attachment without email id', async () => {
|
||||
vi.mocked(apiClient.post).mockResolvedValueOnce({
|
||||
data: { id: 1, filename: 'test.pdf' },
|
||||
});
|
||||
|
||||
const file = new File(['content'], 'test.pdf', { type: 'application/pdf' });
|
||||
await staffEmailApi.uploadAttachment(file);
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteAttachment', () => {
|
||||
it('deletes an attachment', async () => {
|
||||
vi.mocked(apiClient.delete).mockResolvedValueOnce({});
|
||||
|
||||
await staffEmailApi.deleteAttachment(1);
|
||||
|
||||
expect(apiClient.delete).toHaveBeenCalledWith('/staff-email/attachments/1/');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Sync', () => {
|
||||
describe('syncEmails', () => {
|
||||
it('triggers email sync', async () => {
|
||||
vi.mocked(apiClient.post).mockResolvedValueOnce({
|
||||
data: { success: true, message: 'Synced' },
|
||||
});
|
||||
|
||||
const result = await staffEmailApi.syncEmails();
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/staff-email/messages/sync/');
|
||||
expect(result.success).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('fullSyncEmails', () => {
|
||||
it('triggers full email sync', async () => {
|
||||
vi.mocked(apiClient.post).mockResolvedValueOnce({
|
||||
data: {
|
||||
status: 'started',
|
||||
tasks: [{ email_address: 'user@example.com', task_id: 'task-1' }],
|
||||
},
|
||||
});
|
||||
|
||||
const result = await staffEmailApi.fullSyncEmails();
|
||||
|
||||
expect(apiClient.post).toHaveBeenCalledWith('/staff-email/messages/full_sync/');
|
||||
expect(result.status).toBe('started');
|
||||
expect(result.tasks).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('User Email Addresses', () => {
|
||||
describe('getUserEmailAddresses', () => {
|
||||
it('fetches user email addresses', async () => {
|
||||
const mockAddresses = [
|
||||
{
|
||||
id: 1,
|
||||
email_address: 'user@example.com',
|
||||
display_name: 'User',
|
||||
color: '#3b82f6',
|
||||
is_default: true,
|
||||
last_check_at: '2024-01-01T00:00:00Z',
|
||||
emails_processed_count: 100,
|
||||
},
|
||||
];
|
||||
vi.mocked(apiClient.get).mockResolvedValueOnce({ data: mockAddresses });
|
||||
|
||||
const result = await staffEmailApi.getUserEmailAddresses();
|
||||
|
||||
expect(apiClient.get).toHaveBeenCalledWith('/staff-email/messages/email_addresses/');
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].email_address).toBe('user@example.com');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user