diff --git a/PROGRESS.md b/PROGRESS.md
index 1e3868b..70569b0 100644
--- a/PROGRESS.md
+++ b/PROGRESS.md
@@ -7,8 +7,8 @@
**Offene Pakete (nach Größe, kleinste zuerst):**
1. **Saved-Filters 422-Test** — ✅ erledigt (d7b3c7c... der Fix wurde 2026-08-28 in `0d052ab` deployed)
-2. **AppShell ×4 + Router ×2 Mock-Fixes** — useCurrentUser-Export fehlt im `@/api/hooks`-Mock (AppShell.test.tsx Zeile 14, ~10 Z.) + QueryClientProvider für Router-Tests (2,Z.); siehe #357
-3. **ContactEditModal File-Level** — separate Ursache, braucht Mock-Diagnose
+2. **AppShell ×4 + Router ×2 Mock-Fixes** — ✅ erledigt (2026-08-28): AppShell war bereits grün (useCurrentUser-Mock existierte in Zeile 9; Plan-Eintrag veraltet, bewiesen: Lauf 23:00 'Tests 2 failed (6)' = nur Router). Router.test.tsx gefixt: QueryClientProvider + Mocks useCurrentUser/useUserPermissions → **2/2 passed (2.03s)**
+3. **ContactEditModal File-Level** — ✅ erledigt (2026-08-28): Geister-Test nach §10 gelöscht. Ursache bewiesen: ContactEditModal.tsx (349 Z.) wurde in db4701b (BUG-080/082) gelöscht, Test blieb → Vitest 'Failed to resolve import' (1 failed, no tests). Ersatz ContactEditForm.tsx lebt und wird von ContactsList/ContactDetailPage genutzt
4. **custom_field_definitions generisch machen** — ENTITY_PLUGIN_OWNERS-Muster wie W4b anwenden (app/routes/custom_field_definitions.py + app/services/entity_permission_service.py)
5. **Sidebar /contacts statische Route entfernen** — routes/index.tsx Zeile 250; erst PluginRouteRenderer beweisen (Kritikpunkt 21: Production-Build + Reload-Test), dann entfernen
6. **Kontakt-Model ins ContactsPlugin** — groß (~30 Import-Stellen, Alembic-Kette), bewusst zurückgestellt
diff --git a/frontend/src/__tests__/contacts/ContactEditModal.test.tsx b/frontend/src/__tests__/contacts/ContactEditModal.test.tsx
deleted file mode 100644
index d8dac05..0000000
--- a/frontend/src/__tests__/contacts/ContactEditModal.test.tsx
+++ /dev/null
@@ -1,84 +0,0 @@
-import React from 'react';
-import { describe, it, expect, vi } from 'vitest';
-import { render, screen, fireEvent, waitFor } from '@testing-library/react';
-
-// ContactEditModal imports UI components that transitively load lucide-react.
-// To avoid OOM in the vitest worker, we test via a stub that validates the
-// component's interface contract (props, rendering, callbacks).
-vi.mock('@/components/contacts/ContactEditModal', () => ({
- ContactEditModal: ({ open, onClose, contact, onSaved }: any) => {
- if (!open) return null;
- const isEdit = !!contact;
- return (
-
-
{isEdit ? 'Kontakt bearbeiten' : 'Kontakt erstellen'}
-
-
-
-
-
-
-
- );
- },
-}));
-
-import { ContactEditModal } from '@/components/contacts/ContactEditModal';
-
-const defaultProps = {
- open: true,
- onClose: vi.fn(),
- contact: null,
- onSaved: vi.fn(),
-};
-
-describe('ContactEditModal', () => {
- it('renders modal when open', () => {
- render();
- expect(screen.getByTestId('modal-stub')).toBeInTheDocument();
- });
-
- it('does not render when closed', () => {
- render();
- expect(screen.queryByTestId('modal-stub')).not.toBeInTheDocument();
- });
-
- it('renders type select', () => {
- render();
- expect(screen.getByTestId('contact-type-select')).toBeInTheDocument();
- });
-
- it('renders name input for company type', () => {
- render();
- expect(screen.getByTestId('contact-name-input')).toBeInTheDocument();
- });
-
- it('renders submit button', () => {
- render();
- expect(screen.getByTestId('contact-submit-btn')).toBeInTheDocument();
- });
-
- it('renders cancel button', () => {
- render();
- expect(screen.getByText(/abbrechen/i)).toBeInTheDocument();
- });
-
- it('calls onClose when cancel button clicked', () => {
- render();
- fireEvent.click(screen.getByText(/abbrechen/i));
- expect(defaultProps.onClose).toHaveBeenCalled();
- });
-
- it('renders create title for new contact', () => {
- render();
- expect(screen.getByText('Kontakt erstellen')).toBeInTheDocument();
- });
-
- it('renders edit title when editing existing contact', () => {
- render();
- expect(screen.getByText('Kontakt bearbeiten')).toBeInTheDocument();
- });
-});
diff --git a/frontend/src/__tests__/shell/Router.test.tsx b/frontend/src/__tests__/shell/Router.test.tsx
index 2c4c491..abf21c5 100644
--- a/frontend/src/__tests__/shell/Router.test.tsx
+++ b/frontend/src/__tests__/shell/Router.test.tsx
@@ -1,22 +1,41 @@
import React from 'react';
import { describe, it, expect, vi } from 'vitest';
-import { render, screen, act } from '@testing-library/react';
-import { MemoryRouter, Route, Routes, Navigate } from 'react-router-dom';
+import { render, screen } from '@testing-library/react';
+import { MemoryRouter, Route, Routes } from 'react-router-dom';
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ProtectedRoute } from '@/routes/ProtectedRoute';
import { useAuthStore } from '@/store/authStore';
+// Mock API hooks used by useAuth (ProtectedRoute → useAuth → useCurrentUser)
+vi.mock('@/api/hooks', () => ({
+ useCurrentUser: () => ({ data: null, isLoading: false, isError: false, error: null }),
+}));
+
+// Mock permissions fetch (useAuth → useUserPermissions → apiGet)
+vi.mock('@/hooks/useUserPermissions', () => ({
+ useUserPermissions: () => ({}),
+}));
+
function ProtectedTest() {
+ const client = new QueryClient({
+ defaultOptions: {
+ queries: { retry: false, staleTime: 0, gcTime: 0 },
+ mutations: { retry: false },
+ },
+ });
return (
-
-
- Login} />
-
- Protected
-
- } />
-
-
+
+
+
+ Login} />
+
+ Protected
+
+ } />
+
+
+
);
}