fix(frontend): E2E-Test-Suite vollständig grün machen
- Robuster gegen undefined API-Daten in Mail, ContactDetail, ContactsList, Settings, Sidebar - E2E-Mocks korrigiert für Kontakt-Detail, Mail-Liste/Folders und Plugin-Toggle - Auth-Store mit persist-Middleware für E2E-Login - test-results/ in .gitignore aufgenommen Playwright E2E: 34/34 passed
This commit is contained in:
+250
-306
@@ -66,37 +66,62 @@ export const MOCK_MAIL_ACCOUNTS = [
|
||||
smtp_host: 'smtp.test.test',
|
||||
smtp_port: 587,
|
||||
is_shared: false,
|
||||
is_active: true,
|
||||
},
|
||||
];
|
||||
|
||||
export const MOCK_MAIL_FOLDERS = [
|
||||
{ id: 'folder-001', name: 'INBOX', unread_count: 3, account_id: 'acc-001' },
|
||||
{ id: 'folder-002', name: 'Sent', unread_count: 0, account_id: 'acc-001' },
|
||||
{ id: 'folder-003', name: 'Drafts', unread_count: 0, account_id: 'acc-001' },
|
||||
{ id: 'folder-001', name: 'INBOX', imap_name: 'INBOX', parent_id: null, unread_count: 3, total_count: 2, account_id: 'acc-001' },
|
||||
{ id: 'folder-002', name: 'Sent', imap_name: 'Sent', parent_id: null, unread_count: 0, total_count: 0, account_id: 'acc-001' },
|
||||
{ id: 'folder-003', name: 'Drafts', imap_name: 'Drafts', parent_id: null, unread_count: 0, total_count: 0, account_id: 'acc-001' },
|
||||
];
|
||||
|
||||
export const MOCK_MAILS = [
|
||||
{
|
||||
id: 'mail-001',
|
||||
folder_id: 'folder-001',
|
||||
account_id: 'acc-001',
|
||||
subject: 'Welcome to LeoCRM',
|
||||
from: 'noreply@leocrm.test',
|
||||
to: 'test@leocrm.test',
|
||||
from_address: 'noreply@leocrm.test',
|
||||
from_name: 'LeoCRM',
|
||||
to_addresses: ['test@leocrm.test'],
|
||||
cc_addresses: [],
|
||||
bcc_addresses: [],
|
||||
date: '2026-07-23T10:00:00Z',
|
||||
body_text: 'Welcome to LeoCRM! Your account is ready.',
|
||||
is_read: false,
|
||||
flags: [],
|
||||
body_html: null,
|
||||
sanitized_html: null,
|
||||
is_seen: false,
|
||||
is_flagged: false,
|
||||
flag_type: null,
|
||||
is_draft: false,
|
||||
is_answered: false,
|
||||
has_attachments: false,
|
||||
attachments: [],
|
||||
labels: [],
|
||||
},
|
||||
{
|
||||
id: 'mail-002',
|
||||
folder_id: 'folder-001',
|
||||
account_id: 'acc-001',
|
||||
subject: 'Meeting Tomorrow',
|
||||
from: 'boss@leocrm.test',
|
||||
to: 'test@leocrm.test',
|
||||
from_address: 'boss@leocrm.test',
|
||||
from_name: 'Boss',
|
||||
to_addresses: ['test@leocrm.test'],
|
||||
cc_addresses: [],
|
||||
bcc_addresses: [],
|
||||
date: '2026-07-23T09:00:00Z',
|
||||
body_text: 'Don\'t forget the meeting tomorrow at 10 AM.',
|
||||
is_read: true,
|
||||
flags: [],
|
||||
body_html: null,
|
||||
sanitized_html: null,
|
||||
is_seen: true,
|
||||
is_flagged: false,
|
||||
flag_type: null,
|
||||
is_draft: false,
|
||||
is_answered: false,
|
||||
has_attachments: false,
|
||||
attachments: [],
|
||||
labels: [],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -188,13 +213,38 @@ export const MOCK_SEARCH_RESULTS = {
|
||||
* Call this in beforeEach to set up a fully mocked environment.
|
||||
*/
|
||||
export async function setupApiMocks(page: Page) {
|
||||
// Auth: login
|
||||
await page.route('**/api/v1/auth/login', (route) => {
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({
|
||||
user: {
|
||||
await page.route('**/api/v1/**', (route) => {
|
||||
const req = route.request();
|
||||
const url = new URL(req.url());
|
||||
const method = req.method();
|
||||
const pathname = url.pathname;
|
||||
|
||||
// Auth endpoints
|
||||
if (pathname === '/api/v1/auth/login') {
|
||||
return route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({
|
||||
user: {
|
||||
id: TEST_USER.id,
|
||||
email: TEST_USER.email,
|
||||
first_name: TEST_USER.firstName,
|
||||
last_name: TEST_USER.lastName,
|
||||
role: TEST_USER.role,
|
||||
tenants: [TEST_TENANT],
|
||||
permissions: ['*'],
|
||||
is_system_admin: true,
|
||||
},
|
||||
csrf_token: 'mock-csrf-token',
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
if (pathname === '/api/v1/auth/me') {
|
||||
return route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({
|
||||
id: TEST_USER.id,
|
||||
email: TEST_USER.email,
|
||||
first_name: TEST_USER.firstName,
|
||||
@@ -203,320 +253,214 @@ export async function setupApiMocks(page: Page) {
|
||||
tenants: [TEST_TENANT],
|
||||
permissions: ['*'],
|
||||
is_system_admin: true,
|
||||
},
|
||||
csrf_token: 'mock-csrf-token',
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
// Auth: me (current user)
|
||||
await page.route('**/api/v1/auth/me', (route) => {
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({
|
||||
id: TEST_USER.id,
|
||||
email: TEST_USER.email,
|
||||
first_name: TEST_USER.firstName,
|
||||
last_name: TEST_USER.lastName,
|
||||
role: TEST_USER.role,
|
||||
tenants: [TEST_TENANT],
|
||||
permissions: ['*'],
|
||||
is_system_admin: true,
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
// Auth: logout
|
||||
await page.route('**/api/v1/auth/logout', (route) => {
|
||||
route.fulfill({ status: 200, contentType: 'application/json', body: '{}' });
|
||||
});
|
||||
|
||||
// Contacts list
|
||||
await page.route('**/api/v1/contacts*', (route) => {
|
||||
const url = route.request().url();
|
||||
if (url.includes('/contact_persons')) {
|
||||
route.fulfill({ status: 200, contentType: 'application/json', body: '[]' });
|
||||
return;
|
||||
}
|
||||
if (route.request().method() === 'GET') {
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify(MOCK_CONTACTS),
|
||||
});
|
||||
} else if (route.request().method() === 'POST') {
|
||||
const body = route.request().postDataJSON();
|
||||
route.fulfill({
|
||||
status: 201,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({
|
||||
id: 'contact-new',
|
||||
contact_persons: [],
|
||||
displayname: body?.name || `${body?.firstname || ''} ${body?.surname || ''}`.trim(),
|
||||
...body,
|
||||
}),
|
||||
});
|
||||
} else {
|
||||
route.fulfill({ status: 200, contentType: 'application/json', body: '{}' });
|
||||
}
|
||||
});
|
||||
|
||||
// Contact detail
|
||||
await page.route('**/api/v1/contacts/*', (route) => {
|
||||
if (route.request().method() === 'GET') {
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify(MOCK_CONTACTS.items[0]),
|
||||
});
|
||||
} else if (route.request().method() === 'PUT') {
|
||||
const body = route.request().postDataJSON();
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({ ...MOCK_CONTACTS.items[0], ...body }),
|
||||
});
|
||||
} else if (route.request().method() === 'DELETE') {
|
||||
route.fulfill({ status: 204, body: '' });
|
||||
} else {
|
||||
route.continue();
|
||||
if (pathname === '/api/v1/auth/logout') {
|
||||
return route.fulfill({ status: 200, contentType: 'application/json', body: '{}' });
|
||||
}
|
||||
});
|
||||
|
||||
// Mail signatures
|
||||
await page.route('**/api/v1/mail/signatures*', (route) => {
|
||||
if (route.request().method() === 'GET') {
|
||||
route.fulfill({ status: 200, contentType: 'application/json', body: '[]' });
|
||||
} else {
|
||||
route.continue();
|
||||
// Contacts
|
||||
if (pathname.startsWith('/api/v1/contacts')) {
|
||||
if (pathname.includes('/contact_persons')) {
|
||||
return route.fulfill({ status: 200, contentType: 'application/json', body: '[]' });
|
||||
}
|
||||
// Contact detail: /api/v1/contacts/<id>
|
||||
const contactsDetailMatch = pathname.match(/^\/api\/v1\/contacts\/([^/]+)$/);
|
||||
if (contactsDetailMatch && method === 'GET') {
|
||||
return route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({ ...MOCK_CONTACTS.items[0], id: contactsDetailMatch[1], contact_persons: [] }),
|
||||
});
|
||||
}
|
||||
if (method === 'GET') {
|
||||
return route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify(MOCK_CONTACTS),
|
||||
});
|
||||
}
|
||||
if (method === 'POST') {
|
||||
const body = req.postDataJSON() || {};
|
||||
return route.fulfill({
|
||||
status: 201,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({
|
||||
id: 'contact-new',
|
||||
contact_persons: [],
|
||||
displayname: body.name || `${body.firstname || ''} ${body.surname || ''}`.trim(),
|
||||
...body,
|
||||
}),
|
||||
});
|
||||
}
|
||||
if (method === 'PUT') {
|
||||
const body = req.postDataJSON() || {};
|
||||
const id = pathname.split('/').pop() || 'contact-001';
|
||||
return route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({ ...MOCK_CONTACTS.items[0], id, ...body }),
|
||||
});
|
||||
}
|
||||
if (method === 'DELETE') {
|
||||
return route.fulfill({ status: 204, body: '' });
|
||||
}
|
||||
return route.fulfill({ status: 200, contentType: 'application/json', body: '{}' });
|
||||
}
|
||||
});
|
||||
|
||||
// Mail accounts
|
||||
await page.route('**/api/v1/mail/accounts*', (route) => {
|
||||
if (route.request().method() === 'GET') {
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify(MOCK_MAIL_ACCOUNTS),
|
||||
});
|
||||
} else if (route.request().method() === 'POST') {
|
||||
const body = route.request().postDataJSON();
|
||||
route.fulfill({
|
||||
// Mail
|
||||
if (pathname === '/api/v1/mail/accounts') {
|
||||
if (method === 'GET') {
|
||||
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(MOCK_MAIL_ACCOUNTS) });
|
||||
}
|
||||
const body = req.postDataJSON() || {};
|
||||
return route.fulfill({
|
||||
status: 201,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({ id: 'acc-new', display_name: body.display_name || body.email, ...body }),
|
||||
});
|
||||
}
|
||||
|
||||
if (pathname === '/api/v1/mail/folders') {
|
||||
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(MOCK_MAIL_FOLDERS) });
|
||||
}
|
||||
|
||||
if (pathname === '/api/v1/mail') {
|
||||
// fetchMails — /api/v1/mail?folder_id=...
|
||||
return route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({ mails: MOCK_MAILS, total: MOCK_MAILS.length, page: 1, page_size: 25 }),
|
||||
});
|
||||
}
|
||||
|
||||
if (pathname === '/api/v1/mail/search') {
|
||||
return route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({ mails: MOCK_MAILS, total: MOCK_MAILS.length, page: 1, page_size: 25 }),
|
||||
});
|
||||
}
|
||||
|
||||
if (pathname.startsWith('/api/v1/mail/signatures')) {
|
||||
return route.fulfill({ status: 200, contentType: 'application/json', body: '[]' });
|
||||
}
|
||||
|
||||
const singleMailMatch = pathname.match(/^\/api\/v1\/mail\/([^/]+)$/);
|
||||
if (singleMailMatch && method === 'GET') {
|
||||
const mailId = singleMailMatch[1];
|
||||
const mail = MOCK_MAILS.find((m) => m.id === mailId) || MOCK_MAILS[0];
|
||||
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(mail) });
|
||||
}
|
||||
|
||||
if (pathname.startsWith('/api/v1/mail/')) {
|
||||
return route.fulfill({ status: 200, contentType: 'application/json', body: '{}' });
|
||||
}
|
||||
|
||||
// DMS
|
||||
if (pathname === '/api/v1/dms/folders') {
|
||||
if (method === 'GET') {
|
||||
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(MOCK_DMS_FOLDERS) });
|
||||
}
|
||||
const body = req.postDataJSON() || {};
|
||||
return route.fulfill({
|
||||
status: 201,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({ id: 'folder-new', name: body.name, parent_id: body.parent_id ?? null }),
|
||||
});
|
||||
}
|
||||
|
||||
if (pathname === '/api/v1/dms/files') {
|
||||
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(MOCK_DMS_FILES) });
|
||||
}
|
||||
|
||||
if (pathname.startsWith('/api/v1/dms/')) {
|
||||
return route.fulfill({ status: 200, contentType: 'application/json', body: '[]' });
|
||||
}
|
||||
|
||||
// Calendar
|
||||
if (pathname === '/api/v1/calendars') {
|
||||
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(MOCK_CALENDARS) });
|
||||
}
|
||||
|
||||
if (pathname === '/api/v1/calendar/entries') {
|
||||
if (method === 'GET') {
|
||||
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(MOCK_CALENDAR_ENTRIES) });
|
||||
}
|
||||
const body = req.postDataJSON() || {};
|
||||
return route.fulfill({ status: 201, contentType: 'application/json', body: JSON.stringify({ id: 'entry-new', ...body }) });
|
||||
}
|
||||
|
||||
if (pathname === '/api/v1/calendar/kanban') {
|
||||
return route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({
|
||||
id: 'acc-new',
|
||||
display_name: body?.display_name || body?.email,
|
||||
...body,
|
||||
open: MOCK_CALENDAR_ENTRIES,
|
||||
in_progress: [],
|
||||
done: [],
|
||||
cancelled: [],
|
||||
}),
|
||||
});
|
||||
} else {
|
||||
route.continue();
|
||||
}
|
||||
});
|
||||
|
||||
// Mail folders (API calls /mail/folders?account_id=...)
|
||||
await page.route('**/api/v1/mail/folders*', (route) => {
|
||||
if (route.request().method() === 'GET') {
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify(MOCK_MAIL_FOLDERS),
|
||||
});
|
||||
} else {
|
||||
route.continue();
|
||||
// Plugins
|
||||
if (pathname === '/api/v1/plugins/active-manifests' || pathname === '/api/v1/plugins') {
|
||||
if (method === 'GET') {
|
||||
return route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({ plugins: MOCK_PLUGINS, total: MOCK_PLUGINS.length }),
|
||||
});
|
||||
}
|
||||
return route.fulfill({ status: 200, contentType: 'application/json', body: '{}' });
|
||||
}
|
||||
});
|
||||
|
||||
// Mail list (API calls /mail/mails?account_id=...&folder_id=...)
|
||||
await page.route('**/api/v1/mail/mails*', (route) => {
|
||||
if (route.request().method() === 'GET') {
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({ items: MOCK_MAILS, total: MOCK_MAILS.length }),
|
||||
});
|
||||
} else {
|
||||
route.continue();
|
||||
const pluginToggleMatch = pathname.match(/^\/api\/v1\/plugins\/([^/]+)\/(activate|deactivate)$/);
|
||||
if (pluginToggleMatch) {
|
||||
const [, slug, action] = pluginToggleMatch;
|
||||
const plugin = MOCK_PLUGINS.find((p) => p.name === slug);
|
||||
if (plugin) {
|
||||
plugin.active = action === 'activate';
|
||||
plugin.status = action === 'activate' ? 'active' : 'inactive';
|
||||
}
|
||||
return route.fulfill({ status: 200, contentType: 'application/json', body: '{}' });
|
||||
}
|
||||
});
|
||||
|
||||
// Mail detail
|
||||
await page.route('**/api/v1/mail/*', (route) => {
|
||||
if (route.request().method() === 'GET') {
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify(MOCK_MAILS[0]),
|
||||
});
|
||||
} else {
|
||||
route.continue();
|
||||
// Search
|
||||
if (pathname === '/api/v1/search') {
|
||||
if (method === 'POST') {
|
||||
return route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({
|
||||
results: [
|
||||
{ type: 'contact', id: 'contact-001', name: 'TechCorp GmbH', description: 'Company in Berlin', url: '/contacts/contact-001' },
|
||||
{ type: 'mail', id: 'mail-001', name: 'Welcome to LeoCRM', description: 'Welcome email', url: '/mail/mail-001' },
|
||||
],
|
||||
facets: {},
|
||||
summary: '2 results',
|
||||
}),
|
||||
});
|
||||
}
|
||||
return route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ results: [], facets: {}, summary: '' }) });
|
||||
}
|
||||
});
|
||||
|
||||
// DMS folders
|
||||
await page.route('**/api/v1/dms/folders*', (route) => {
|
||||
if (route.request().method() === 'GET') {
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify(MOCK_DMS_FOLDERS),
|
||||
});
|
||||
} else if (route.request().method() === 'POST') {
|
||||
const body = route.request().postDataJSON();
|
||||
route.fulfill({
|
||||
status: 201,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({ id: 'folder-new', name: body?.name, parent_id: body?.parent_id ?? null }),
|
||||
});
|
||||
} else {
|
||||
route.continue();
|
||||
// User preferences
|
||||
if (pathname.startsWith('/api/v1/user/preferences')) {
|
||||
return route.fulfill({ status: 200, contentType: 'application/json', body: '{}' });
|
||||
}
|
||||
});
|
||||
|
||||
// DMS files
|
||||
await page.route('**/api/v1/dms/files*', (route) => {
|
||||
if (route.request().method() === 'GET') {
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify(MOCK_DMS_FILES),
|
||||
});
|
||||
} else {
|
||||
route.continue();
|
||||
}
|
||||
});
|
||||
|
||||
// DMS shared files
|
||||
await page.route('**/api/v1/dms/shared*', (route) => {
|
||||
route.fulfill({ status: 200, contentType: 'application/json', body: '[]' });
|
||||
});
|
||||
|
||||
// Calendar list (API calls /calendars, not /calendar/calendars)
|
||||
await page.route('**/api/v1/calendars*', (route) => {
|
||||
if (route.request().method() === 'GET') {
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify(MOCK_CALENDARS),
|
||||
});
|
||||
} else {
|
||||
route.continue();
|
||||
}
|
||||
});
|
||||
|
||||
// Calendar entries
|
||||
await page.route('**/api/v1/calendar/entries*', (route) => {
|
||||
if (route.request().method() === 'GET') {
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify(MOCK_CALENDAR_ENTRIES),
|
||||
});
|
||||
} else if (route.request().method() === 'POST') {
|
||||
const body = route.request().postDataJSON();
|
||||
route.fulfill({
|
||||
status: 201,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({ id: 'entry-new', ...body }),
|
||||
});
|
||||
} else {
|
||||
route.continue();
|
||||
}
|
||||
});
|
||||
|
||||
// Calendar kanban
|
||||
await page.route('**/api/v1/calendar/kanban*', (route) => {
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({
|
||||
open: MOCK_CALENDAR_ENTRIES,
|
||||
in_progress: [],
|
||||
done: [],
|
||||
cancelled: [],
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
// Plugins
|
||||
await page.route('**/api/v1/plugins*', (route) => {
|
||||
const url = route.request().url();
|
||||
if (url.includes('/active-manifests')) {
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({ plugins: MOCK_PLUGINS, total: MOCK_PLUGINS.length }),
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (route.request().method() === 'GET') {
|
||||
// GET /plugins returns { plugins: Plugin[], total: number }
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({ plugins: MOCK_PLUGINS, total: MOCK_PLUGINS.length }),
|
||||
});
|
||||
} else if (route.request().method() === 'POST') {
|
||||
route.fulfill({ status: 200, contentType: 'application/json', body: '{}' });
|
||||
} else {
|
||||
route.continue();
|
||||
}
|
||||
});
|
||||
|
||||
// Plugin activate/deactivate
|
||||
await page.route('**/api/v1/plugins/*/activate', (route) => {
|
||||
route.fulfill({ status: 200, contentType: 'application/json', body: '{}' });
|
||||
});
|
||||
await page.route('**/api/v1/plugins/*/deactivate', (route) => {
|
||||
route.fulfill({ status: 200, contentType: 'application/json', body: '{}' });
|
||||
});
|
||||
|
||||
// Search (API uses POST to /search)
|
||||
await page.route('**/api/v1/search*', (route) => {
|
||||
if (route.request().method() === 'POST') {
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({ results: [
|
||||
{ type: 'contact', id: 'contact-001', name: 'TechCorp GmbH', description: 'Company in Berlin', url: '/contacts/contact-001' },
|
||||
{ type: 'mail', id: 'mail-001', name: 'Welcome to LeoCRM', description: 'Welcome email', url: '/mail/mail-001' },
|
||||
], facets: {}, summary: '2 results' }),
|
||||
});
|
||||
} else if (route.request().method() === 'GET') {
|
||||
route.fulfill({
|
||||
status: 200,
|
||||
contentType: 'application/json',
|
||||
body: JSON.stringify({ results: [], facets: {}, summary: '' }),
|
||||
});
|
||||
} else {
|
||||
route.continue();
|
||||
}
|
||||
});
|
||||
|
||||
// User preferences
|
||||
await page.route('**/api/v1/user/preferences*', (route) => {
|
||||
route.fulfill({ status: 200, contentType: 'application/json', body: '{}' });
|
||||
});
|
||||
|
||||
// Generic catch-all for other API endpoints
|
||||
await page.route('**/api/v1/**', (route) => {
|
||||
if (!route.request().url().includes('/auth/') &&
|
||||
!route.request().url().includes('/contacts') &&
|
||||
!route.request().url().includes('/mail/') &&
|
||||
!route.request().url().includes('/dms/') &&
|
||||
!route.request().url().includes('/calendar/') &&
|
||||
!route.request().url().includes('/plugins') &&
|
||||
!route.request().url().includes('/search')) {
|
||||
route.fulfill({ status: 200, contentType: 'application/json', body: '[]' });
|
||||
} else {
|
||||
route.continue();
|
||||
}
|
||||
// Fallback: empty array/object for any other API call
|
||||
return route.fulfill({ status: 200, contentType: 'application/json', body: '[]' });
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform login via the login form.}
|
||||
|
||||
/**
|
||||
* Perform login via the login form.
|
||||
* Assumes API mocks are already set up.
|
||||
|
||||
Reference in New Issue
Block a user