2176f8ecce
- Spalte DomainsConfig.defaultNameServers per Migration 20261008160000 entfernt - Feld in Einstellungen/Status (API, DTO, Typen) und Karte im Web entfernt - Anleitungen und CHANGELOG: Nameserver kommen aus AutoDNS Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
551 lines
22 KiB
TypeScript
551 lines
22 KiB
TypeScript
import {
|
||
cleanup,
|
||
fireEvent,
|
||
render as rtlRender,
|
||
screen,
|
||
waitFor,
|
||
within,
|
||
} from '@testing-library/react';
|
||
import { NextIntlClientProvider } from 'next-intl';
|
||
import type { ReactElement } from 'react';
|
||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
||
import type {
|
||
DomainsContactList,
|
||
DomainsCustomer,
|
||
DomainsDomainList,
|
||
DomainsSettings,
|
||
DomainsStatus,
|
||
} from '@/lib/domains-api';
|
||
import de from '@/messages/de.json';
|
||
import DomainsPage from './page';
|
||
|
||
function render(ui: ReactElement) {
|
||
return rtlRender(
|
||
<NextIntlClientProvider locale="de" messages={de} timeZone="Europe/Berlin">
|
||
{ui}
|
||
</NextIntlClientProvider>,
|
||
);
|
||
}
|
||
|
||
const mockGetStatus = vi.fn();
|
||
const mockGetSettings = vi.fn();
|
||
const mockSaveSettings = vi.fn();
|
||
const mockTestConnection = vi.fn();
|
||
const mockListCustomers = vi.fn();
|
||
const mockListContacts = vi.fn();
|
||
const mockListDomains = vi.fn();
|
||
const mockAssignContacts = vi.fn();
|
||
const mockCreateCustomer = vi.fn();
|
||
const mockDeleteCustomer = vi.fn();
|
||
const mockListOrders = vi.fn();
|
||
const mockRefreshOrders = vi.fn();
|
||
|
||
vi.mock('@/lib/domains-api', async (importOriginal) => {
|
||
const actual = await importOriginal<typeof import('@/lib/domains-api')>();
|
||
return {
|
||
...actual,
|
||
getDomainsStatus: (...args: unknown[]) => mockGetStatus(...args),
|
||
getDomainsSettings: (...args: unknown[]) => mockGetSettings(...args),
|
||
saveDomainsSettings: (...args: unknown[]) => mockSaveSettings(...args),
|
||
testDomainsConnection: (...args: unknown[]) => mockTestConnection(...args),
|
||
listCustomers: (...args: unknown[]) => mockListCustomers(...args),
|
||
listContacts: (...args: unknown[]) => mockListContacts(...args),
|
||
listDomains: (...args: unknown[]) => mockListDomains(...args),
|
||
assignContacts: (...args: unknown[]) => mockAssignContacts(...args),
|
||
createCustomer: (...args: unknown[]) => mockCreateCustomer(...args),
|
||
deleteCustomer: (...args: unknown[]) => mockDeleteCustomer(...args),
|
||
listOrders: (...args: unknown[]) => mockListOrders(...args),
|
||
refreshOrders: (...args: unknown[]) => mockRefreshOrders(...args),
|
||
};
|
||
});
|
||
|
||
let mockCanManage: boolean | null = true;
|
||
vi.mock('@/lib/use-module-capability', () => ({
|
||
useCanManageModule: () => mockCanManage,
|
||
}));
|
||
|
||
function status(over: Partial<DomainsStatus> = {}): DomainsStatus {
|
||
return {
|
||
environment: 'DEMO',
|
||
configured: true,
|
||
demoConfigured: true,
|
||
liveConfigured: false,
|
||
...over,
|
||
};
|
||
}
|
||
|
||
function settings(over: Partial<DomainsSettings> = {}): DomainsSettings {
|
||
return {
|
||
environment: 'DEMO',
|
||
demo: { user: 'api-user', hasPassword: true, context: 1 },
|
||
live: { user: null, hasPassword: false, context: null },
|
||
configured: { demo: true, live: false },
|
||
...over,
|
||
};
|
||
}
|
||
|
||
const CUSTOMERS: DomainsCustomer[] = [
|
||
{ id: 'c-own', name: 'Unsere Firma', isOwnCompany: true, contactCount: 1 },
|
||
{ id: 'c-a', name: 'Alpha GmbH', isOwnCompany: false, contactCount: 2 },
|
||
];
|
||
|
||
function domainList(): DomainsDomainList {
|
||
return {
|
||
environment: 'DEMO',
|
||
truncated: false,
|
||
fetchedAt: '2026-10-08T10:00:00.000Z',
|
||
domains: [
|
||
{
|
||
name: 'frei.de',
|
||
expire: '2027-03-01T12:00:00.000Z',
|
||
status: 'ACTIVE',
|
||
cancelationPending: false,
|
||
ownerContactId: 5,
|
||
ownerName: 'Niemand',
|
||
customerId: null,
|
||
customerName: null,
|
||
},
|
||
{
|
||
name: 'alpha.de',
|
||
expire: '2027-07-15T12:00:00.000Z',
|
||
status: 'LOCK',
|
||
cancelationPending: true,
|
||
ownerContactId: 6,
|
||
ownerName: 'Alpha GmbH',
|
||
customerId: 'c-a',
|
||
customerName: 'Alpha GmbH',
|
||
},
|
||
{
|
||
name: 'eigen.de',
|
||
expire: null,
|
||
status: 'SONDERWERT',
|
||
cancelationPending: false,
|
||
ownerContactId: 7,
|
||
ownerName: 'Unsere Firma',
|
||
customerId: 'c-own',
|
||
customerName: 'Unsere Firma',
|
||
},
|
||
],
|
||
};
|
||
}
|
||
|
||
function contactList(): DomainsContactList {
|
||
return {
|
||
environment: 'DEMO',
|
||
truncated: false,
|
||
fetchedAt: '2026-10-08T10:00:00.000Z',
|
||
contacts: [
|
||
{
|
||
id: 6,
|
||
type: 'ORG',
|
||
displayName: 'Alpha GmbH',
|
||
fname: 'Anna',
|
||
lname: 'Alpha',
|
||
organization: 'Alpha GmbH',
|
||
address: ['Weg 1'],
|
||
pcode: '10115',
|
||
city: 'Berlin',
|
||
country: 'DE',
|
||
email: 'anna@alpha.example',
|
||
phone: '+49 30 1',
|
||
alias: null,
|
||
customerId: 'c-a',
|
||
customerName: 'Alpha GmbH',
|
||
},
|
||
{
|
||
id: 5,
|
||
type: 'PERSON',
|
||
displayName: 'Bert Beta',
|
||
fname: 'Bert',
|
||
lname: 'Beta',
|
||
organization: null,
|
||
address: [],
|
||
pcode: null,
|
||
city: 'Hamburg',
|
||
country: 'DE',
|
||
email: 'bert@beta.example',
|
||
phone: null,
|
||
alias: null,
|
||
customerId: null,
|
||
customerName: null,
|
||
},
|
||
],
|
||
};
|
||
}
|
||
|
||
/** Oeffnet den Reiter Einstellungen (Standardreiter ist Domains). */
|
||
async function renderSettings() {
|
||
render(<DomainsPage />);
|
||
fireEvent.click(await screen.findByRole('button', { name: 'Einstellungen' }));
|
||
}
|
||
|
||
beforeEach(() => {
|
||
mockCanManage = true;
|
||
mockListCustomers.mockReset().mockResolvedValue(CUSTOMERS);
|
||
mockListDomains.mockReset().mockResolvedValue(domainList());
|
||
mockListContacts.mockReset().mockResolvedValue(contactList());
|
||
mockAssignContacts.mockReset().mockResolvedValue({ assigned: 1, removed: 0 });
|
||
mockCreateCustomer.mockReset().mockResolvedValue(CUSTOMERS[1]);
|
||
mockDeleteCustomer.mockReset().mockResolvedValue({ deleted: true });
|
||
mockListOrders.mockReset().mockResolvedValue([]);
|
||
mockRefreshOrders.mockReset().mockResolvedValue([]);
|
||
mockGetStatus.mockReset().mockResolvedValue(status());
|
||
mockGetSettings.mockReset().mockResolvedValue(settings());
|
||
mockSaveSettings.mockReset().mockImplementation(async () => settings());
|
||
mockTestConnection
|
||
.mockReset()
|
||
.mockResolvedValue({ ok: true, message: 'Verbindung erfolgreich.' });
|
||
});
|
||
|
||
afterEach(() => {
|
||
cleanup();
|
||
});
|
||
|
||
describe('Domains-Seite — Kopf und Reiter', () => {
|
||
it('Verwalter sieht den Reiter Einstellungen und die Demo-Kennzeichnung', async () => {
|
||
render(<DomainsPage />);
|
||
expect(await screen.findByRole('button', { name: 'Einstellungen' })).toBeTruthy();
|
||
expect(screen.getByRole('button', { name: 'Domains' })).toBeTruthy();
|
||
expect(screen.getByRole('button', { name: 'Kontakte' })).toBeTruthy();
|
||
expect(screen.getByRole('button', { name: 'Kunden' })).toBeTruthy();
|
||
expect((await screen.findByTestId('domains-environment-badge')).textContent).toBe(
|
||
'Demo-System (Testbetrieb)',
|
||
);
|
||
});
|
||
|
||
it('Live-System zeigt die Kostenwarnung', async () => {
|
||
mockGetStatus.mockResolvedValue(status({ environment: 'LIVE', liveConfigured: true }));
|
||
render(<DomainsPage />);
|
||
await waitFor(() =>
|
||
expect(screen.getByTestId('domains-environment-badge').textContent).toBe(
|
||
'Live-System – Registrierungen kosten Geld',
|
||
),
|
||
);
|
||
});
|
||
|
||
it('nicht eingerichtet: Kennzeichnung und Hinweis', async () => {
|
||
mockGetStatus.mockResolvedValue(status({ configured: false, demoConfigured: false }));
|
||
render(<DomainsPage />);
|
||
await waitFor(() =>
|
||
expect(screen.getByTestId('domains-environment-badge').textContent).toBe(
|
||
'AutoDNS nicht eingerichtet',
|
||
),
|
||
);
|
||
expect(screen.getByText('AutoDNS ist noch nicht eingerichtet.')).toBeTruthy();
|
||
expect(screen.getByRole('button', { name: 'Zu den Einstellungen' })).toBeTruthy();
|
||
});
|
||
|
||
it('nicht eingerichtet, ohne Verwalten: Hinweis auf einen Administrator, kein Einstellungen-Reiter', async () => {
|
||
mockCanManage = false;
|
||
mockGetStatus.mockResolvedValue(status({ configured: false, demoConfigured: false }));
|
||
render(<DomainsPage />);
|
||
expect(await screen.findByText(/Bitte wenden Sie sich an einen Administrator/)).toBeTruthy();
|
||
expect(screen.queryByRole('button', { name: 'Zu den Einstellungen' })).toBeNull();
|
||
expect(screen.queryByRole('button', { name: 'Einstellungen' })).toBeNull();
|
||
});
|
||
|
||
it('Benutzer ohne Verwalten sieht den Reiter Einstellungen nicht', async () => {
|
||
mockCanManage = false;
|
||
render(<DomainsPage />);
|
||
await screen.findByTestId('domains-environment-badge');
|
||
expect(screen.queryByRole('button', { name: 'Einstellungen' })).toBeNull();
|
||
expect(mockGetSettings).not.toHaveBeenCalled();
|
||
});
|
||
});
|
||
|
||
describe('Einstellungen', () => {
|
||
it('Passwortfelder beginnen leer, mit Hinweis auf das gespeicherte Passwort', async () => {
|
||
await renderSettings();
|
||
const demoPassword = (await screen.findByLabelText('Passwort', {
|
||
selector: '#domains-demo-password',
|
||
})) as HTMLInputElement;
|
||
expect(demoPassword.value).toBe('');
|
||
expect(demoPassword.placeholder).toBe('Gespeichert – leer lassen, um es beizubehalten');
|
||
const livePassword = document.getElementById('domains-live-password') as HTMLInputElement;
|
||
expect(livePassword.placeholder).toBe('');
|
||
});
|
||
|
||
it('der Live-Kontext ist mit 4 vorbelegt, der Demo-Kontext zeigt den gespeicherten Wert', async () => {
|
||
await renderSettings();
|
||
await screen.findByLabelText('Passwort', { selector: '#domains-demo-password' });
|
||
expect((document.getElementById('domains-live-context') as HTMLInputElement).value).toBe('4');
|
||
expect((document.getElementById('domains-demo-context') as HTMLInputElement).value).toBe('1');
|
||
});
|
||
|
||
it('Wechsel auf Live verlangt Bestaetigung; erst die bestaetigte Speicherung sendet confirmLive', async () => {
|
||
mockSaveSettings.mockResolvedValue(settings({ environment: 'LIVE' }));
|
||
await renderSettings();
|
||
const liveRadio = await screen.findByRole('radio', { name: /Live-System \(kostenpflichtig\)/ });
|
||
fireEvent.click(liveRadio);
|
||
|
||
const dialog = await screen.findByRole('alertdialog');
|
||
expect(within(dialog).getByText(/kosten Geld/)).toBeTruthy();
|
||
expect(mockSaveSettings).not.toHaveBeenCalled();
|
||
|
||
// Abbrechen sendet nichts und stellt die Auswahl zurueck.
|
||
fireEvent.click(within(dialog).getByRole('button', { name: 'Abbrechen' }));
|
||
expect(mockSaveSettings).not.toHaveBeenCalled();
|
||
expect(screen.queryByRole('alertdialog')).toBeNull();
|
||
expect(
|
||
(screen.getByRole('radio', { name: /Demo-System \(Testbetrieb\)/ }) as HTMLInputElement)
|
||
.checked,
|
||
).toBe(true);
|
||
|
||
fireEvent.click(screen.getByRole('radio', { name: /Live-System \(kostenpflichtig\)/ }));
|
||
fireEvent.click(
|
||
within(await screen.findByRole('alertdialog')).getByRole('button', {
|
||
name: 'Live-System verwenden',
|
||
}),
|
||
);
|
||
await waitFor(() => expect(mockSaveSettings).toHaveBeenCalledTimes(1));
|
||
expect(mockSaveSettings).toHaveBeenCalledWith({ environment: 'LIVE', confirmLive: true });
|
||
});
|
||
|
||
it('Speichern des Zugangs sendet nur die eigenen Felder; ohne Eingabe kein Passwort', async () => {
|
||
await renderSettings();
|
||
const user = (await screen.findByLabelText('Benutzername', {
|
||
selector: '#domains-demo-user',
|
||
})) as HTMLInputElement;
|
||
fireEvent.change(user, { target: { value: 'neuer-user' } });
|
||
const demoCard = document.getElementById('domains-demo') as HTMLElement;
|
||
fireEvent.click(within(demoCard).getByRole('button', { name: 'Speichern' }));
|
||
await waitFor(() => expect(mockSaveSettings).toHaveBeenCalledTimes(1));
|
||
expect(mockSaveSettings).toHaveBeenCalledWith({ demoUser: 'neuer-user', demoContext: 1 });
|
||
});
|
||
|
||
it('Verbindung testen: ein Aufruf je Klick, gesperrt waehrend des Laufs, zeigt das Ergebnis', async () => {
|
||
let resolveTest: (v: { ok: boolean; message: string }) => void = () => undefined;
|
||
mockTestConnection.mockImplementation(
|
||
() =>
|
||
new Promise((resolve) => {
|
||
resolveTest = resolve;
|
||
}),
|
||
);
|
||
await renderSettings();
|
||
await screen.findByLabelText('Passwort', { selector: '#domains-demo-password' });
|
||
const demoCard = document.getElementById('domains-demo') as HTMLElement;
|
||
const button = within(demoCard).getByRole('button', { name: 'Verbindung testen' });
|
||
|
||
fireEvent.click(button);
|
||
await waitFor(() => expect(mockTestConnection).toHaveBeenCalledTimes(1));
|
||
expect(mockTestConnection).toHaveBeenCalledWith('DEMO');
|
||
const running = within(demoCard).getByRole('button', { name: 'Verbindung wird getestet …' });
|
||
expect((running as HTMLButtonElement).disabled).toBe(true);
|
||
fireEvent.click(running);
|
||
expect(mockTestConnection).toHaveBeenCalledTimes(1);
|
||
|
||
resolveTest({ ok: false, message: 'Anmeldung bei AutoDNS fehlgeschlagen.' });
|
||
expect(await within(demoCard).findByText('Anmeldung bei AutoDNS fehlgeschlagen.')).toBeTruthy();
|
||
});
|
||
|
||
it('der Verbindungstest ist bei ungespeicherten Aenderungen gesperrt', async () => {
|
||
await renderSettings();
|
||
const password = (await screen.findByLabelText('Passwort', {
|
||
selector: '#domains-demo-password',
|
||
})) as HTMLInputElement;
|
||
fireEvent.change(password, { target: { value: 'neu' } });
|
||
const demoCard = document.getElementById('domains-demo') as HTMLElement;
|
||
expect(
|
||
(within(demoCard).getByRole('button', { name: 'Verbindung testen' }) as HTMLButtonElement)
|
||
.disabled,
|
||
).toBe(true);
|
||
expect(within(demoCard).getByText('Bitte zuerst speichern')).toBeTruthy();
|
||
});
|
||
|
||
it('Einstellungen zeigen keine Karte "Standard-Nameserver" mehr (h3t)', async () => {
|
||
await renderSettings();
|
||
await screen.findByRole('radio', { name: /Live-System \(kostenpflichtig\)/ });
|
||
expect(screen.queryByText('Standard-Nameserver')).toBeNull();
|
||
expect(document.getElementById('domains-nameservers')).toBeNull();
|
||
});
|
||
});
|
||
|
||
describe('Reiter Domains, Kontakte und Kunden', () => {
|
||
it('Benutzen-Benutzer sieht Domains, Kontakte, Kunden, aber weder Einstellungen noch Schreibknoepfe', async () => {
|
||
mockCanManage = false;
|
||
render(<DomainsPage />);
|
||
expect(await screen.findByRole('button', { name: 'Domains' })).toBeTruthy();
|
||
expect(screen.getByRole('button', { name: 'Kontakte' })).toBeTruthy();
|
||
expect(screen.getByRole('button', { name: 'Kunden' })).toBeTruthy();
|
||
expect(screen.queryByRole('button', { name: 'Einstellungen' })).toBeNull();
|
||
|
||
fireEvent.click(screen.getByRole('button', { name: 'Kontakte' }));
|
||
await screen.findByText('Bert Beta');
|
||
expect(screen.queryByRole('button', { name: 'Neuer Kontakt' })).toBeNull();
|
||
expect(screen.queryByRole('button', { name: 'Zuordnen' })).toBeNull();
|
||
expect(screen.queryByRole('checkbox', { name: /auswählen/ })).toBeNull();
|
||
// Der Neuabruf bei AutoDNS ist Verwaltern vorbehalten (der Server ignoriert ihn sonst).
|
||
expect(screen.queryByRole('button', { name: 'Aus AutoDNS neu einlesen' })).toBeNull();
|
||
|
||
fireEvent.click(screen.getByRole('button', { name: 'Kunden' }));
|
||
await screen.findByText('Alpha GmbH');
|
||
expect(screen.queryByRole('button', { name: 'Kunde anlegen' })).toBeNull();
|
||
expect(screen.queryByRole('button', { name: 'Bearbeiten' })).toBeNull();
|
||
expect(screen.queryByRole('button', { name: 'Löschen' })).toBeNull();
|
||
});
|
||
|
||
it('Verwalter sieht die Schreibknoepfe', async () => {
|
||
render(<DomainsPage />);
|
||
fireEvent.click(await screen.findByRole('button', { name: 'Kontakte' }));
|
||
expect(await screen.findByRole('button', { name: 'Neuer Kontakt' })).toBeTruthy();
|
||
expect(screen.getByRole('button', { name: 'Zuordnen' })).toBeTruthy();
|
||
|
||
fireEvent.click(screen.getByRole('button', { name: 'Kunden' }));
|
||
expect(await screen.findByRole('button', { name: 'Kunde anlegen' })).toBeTruthy();
|
||
expect(screen.getAllByRole('button', { name: 'Bearbeiten' })).toHaveLength(2);
|
||
});
|
||
|
||
it('Domainliste: Gruppen je Kunde, "Nicht zugeordnet" zuletzt, Datum und Statusbeschriftung', async () => {
|
||
render(<DomainsPage />);
|
||
await screen.findByText('alpha.de');
|
||
const titles = Array.from(document.querySelectorAll('.cc-section-title')).map(
|
||
(h) => h.textContent,
|
||
);
|
||
expect(titles).toEqual(['Unsere Firma', 'Alpha GmbH', 'Nicht zugeordnet']);
|
||
|
||
const row = screen.getByText('alpha.de').closest('tr') as HTMLElement;
|
||
expect(within(row).getByText('15.07.2027')).toBeTruthy();
|
||
expect(within(row).getByText(/Gesperrt/)).toBeTruthy();
|
||
expect(within(row).getByText('Kündigung vorgemerkt')).toBeTruthy();
|
||
|
||
const frei = screen.getByText('frei.de').closest('tr') as HTMLElement;
|
||
expect(within(frei).getByText('01.03.2027')).toBeTruthy();
|
||
expect(within(frei).getByText('Aktiv')).toBeTruthy();
|
||
|
||
// Unbekannter Status: Rohwert als Rueckfall, fehlendes Datum als Strich.
|
||
const eigen = screen.getByText('eigen.de').closest('tr') as HTMLElement;
|
||
expect(within(eigen).getByText('SONDERWERT')).toBeTruthy();
|
||
});
|
||
|
||
it('Kundenfilter blendet die anderen Gruppen aus', async () => {
|
||
render(<DomainsPage />);
|
||
await screen.findByText('alpha.de');
|
||
fireEvent.change(document.getElementById('domains-filter') as HTMLSelectElement, {
|
||
target: { value: 'c-a' },
|
||
});
|
||
expect(screen.getByText('alpha.de')).toBeTruthy();
|
||
expect(screen.queryByText('frei.de')).toBeNull();
|
||
expect(screen.queryByText('eigen.de')).toBeNull();
|
||
|
||
fireEvent.change(document.getElementById('domains-filter') as HTMLSelectElement, {
|
||
target: { value: 'unassigned' },
|
||
});
|
||
expect(screen.getByText('frei.de')).toBeTruthy();
|
||
expect(screen.queryByText('alpha.de')).toBeNull();
|
||
});
|
||
|
||
it('Textsuche und "Aus AutoDNS neu laden"', async () => {
|
||
render(<DomainsPage />);
|
||
await screen.findByText('alpha.de');
|
||
fireEvent.change(document.getElementById('domains-search') as HTMLInputElement, {
|
||
target: { value: 'FREI' },
|
||
});
|
||
expect(screen.queryByText('alpha.de')).toBeNull();
|
||
expect(screen.getByText('frei.de')).toBeTruthy();
|
||
|
||
fireEvent.click(screen.getByRole('button', { name: 'Aus AutoDNS neu laden' }));
|
||
await waitFor(() => expect(mockListDomains).toHaveBeenLastCalledWith({ refresh: true }));
|
||
});
|
||
|
||
it('zeigt den Hinweis bei abgeschnittener Liste und die Fehlermeldung der API', async () => {
|
||
mockListDomains.mockResolvedValueOnce({ ...domainList(), truncated: true });
|
||
render(<DomainsPage />);
|
||
expect(await screen.findByText('Es werden die ersten 2000 Einträge angezeigt.')).toBeTruthy();
|
||
});
|
||
|
||
it('Kontakte zuordnen: ausgewaehlte Kontakte gehen an den gewaehlten Kunden', async () => {
|
||
render(<DomainsPage />);
|
||
fireEvent.click(await screen.findByRole('button', { name: 'Kontakte' }));
|
||
await screen.findByText('Bert Beta');
|
||
fireEvent.click(screen.getByRole('checkbox', { name: 'Kontakt Bert Beta auswählen' }));
|
||
fireEvent.change(document.getElementById('contacts-assign-target') as HTMLSelectElement, {
|
||
target: { value: 'c-a' },
|
||
});
|
||
fireEvent.click(screen.getByRole('button', { name: 'Zuordnen' }));
|
||
await waitFor(() => expect(mockAssignContacts).toHaveBeenCalledTimes(1));
|
||
expect(mockAssignContacts).toHaveBeenCalledWith([5], 'c-a');
|
||
});
|
||
|
||
it('Zuordnung entfernen sendet null', async () => {
|
||
render(<DomainsPage />);
|
||
fireEvent.click(await screen.findByRole('button', { name: 'Kontakte' }));
|
||
await screen.findByText('Bert Beta');
|
||
fireEvent.click(screen.getByRole('checkbox', { name: 'Kontakt Alpha GmbH auswählen' }));
|
||
fireEvent.change(document.getElementById('contacts-assign-target') as HTMLSelectElement, {
|
||
target: { value: '__remove__' },
|
||
});
|
||
fireEvent.click(screen.getByRole('button', { name: 'Zuordnen' }));
|
||
await waitFor(() => expect(mockAssignContacts).toHaveBeenCalledWith([6], null));
|
||
});
|
||
|
||
it('Kunden: Loeschen verlangt eine Bestaetigung und zeigt den 409-Text der API', async () => {
|
||
const { DomainsRequestError } = await import('@/lib/domains-api');
|
||
mockDeleteCustomer.mockRejectedValueOnce(
|
||
new DomainsRequestError(409, 'customerInUse', 'Diesem Kunden sind noch Kontakte zugeordnet.'),
|
||
);
|
||
render(<DomainsPage />);
|
||
fireEvent.click(await screen.findByRole('button', { name: 'Kunden' }));
|
||
const buttons = await screen.findAllByRole('button', { name: 'Löschen' });
|
||
fireEvent.click(buttons[1]);
|
||
const dialog = await screen.findByRole('alertdialog');
|
||
expect(mockDeleteCustomer).not.toHaveBeenCalled();
|
||
fireEvent.click(within(dialog).getByRole('button', { name: 'Endgültig löschen' }));
|
||
await waitFor(() => expect(mockDeleteCustomer).toHaveBeenCalledWith('c-a'));
|
||
expect(await screen.findByText('Diesem Kunden sind noch Kontakte zugeordnet.')).toBeTruthy();
|
||
});
|
||
|
||
it('Kunden: neuer Kunde mit Markierung eigene Firma', async () => {
|
||
render(<DomainsPage />);
|
||
fireEvent.click(await screen.findByRole('button', { name: 'Kunden' }));
|
||
fireEvent.change(await screen.findByLabelText('Name', { selector: '#customer-new-name' }), {
|
||
target: { value: ' Neu AG ' },
|
||
});
|
||
fireEvent.click(screen.getByRole('checkbox', { name: 'Das ist unsere eigene Firma' }));
|
||
fireEvent.click(screen.getByRole('button', { name: 'Kunde anlegen' }));
|
||
await waitFor(() => expect(mockCreateCustomer).toHaveBeenCalledTimes(1));
|
||
expect(mockCreateCustomer).toHaveBeenCalledWith({ name: 'Neu AG', isOwnCompany: true });
|
||
});
|
||
|
||
it('nicht eingerichtet: keine Liste, nur der Hinweis', async () => {
|
||
mockGetStatus.mockResolvedValue(status({ configured: false, demoConfigured: false }));
|
||
render(<DomainsPage />);
|
||
await screen.findByText('AutoDNS ist noch nicht eingerichtet.');
|
||
expect(mockListDomains).not.toHaveBeenCalled();
|
||
});
|
||
});
|
||
|
||
describe('Reiter Registrieren und Aufträge', () => {
|
||
it('Verwalter sieht beide Reiter in der festen Reihenfolge', async () => {
|
||
render(<DomainsPage />);
|
||
await screen.findByRole('button', { name: 'Einstellungen' });
|
||
const wanted = ['Domains', 'Kontakte', 'Kunden', 'Registrieren', 'Aufträge', 'Einstellungen'];
|
||
const names = screen
|
||
.getAllByRole('button')
|
||
.map((b) => b.textContent ?? '')
|
||
.filter((x) => wanted.includes(x));
|
||
expect(names).toEqual(wanted);
|
||
});
|
||
|
||
it('Benutzer ohne Verwalten sieht Aufträge, aber weder Registrieren noch Einstellungen', async () => {
|
||
mockCanManage = false;
|
||
render(<DomainsPage />);
|
||
await screen.findByTestId('domains-environment-badge');
|
||
expect(screen.getByRole('button', { name: 'Aufträge' })).toBeTruthy();
|
||
expect(screen.queryByRole('button', { name: 'Registrieren' })).toBeNull();
|
||
expect(screen.queryByRole('button', { name: 'Einstellungen' })).toBeNull();
|
||
});
|
||
|
||
it('der Reiter Aufträge gleicht beim Öffnen mit AutoDNS ab', async () => {
|
||
mockCanManage = false;
|
||
render(<DomainsPage />);
|
||
fireEvent.click(await screen.findByRole('button', { name: 'Aufträge' }));
|
||
await waitFor(() => expect(mockRefreshOrders).toHaveBeenCalledTimes(1));
|
||
});
|
||
|
||
it('der Reiter Registrieren zeigt die Domain-Eingabe', async () => {
|
||
render(<DomainsPage />);
|
||
fireEvent.click(await screen.findByRole('button', { name: 'Registrieren' }));
|
||
expect(await screen.findByRole('button', { name: 'Verfügbarkeit prüfen' })).toBeTruthy();
|
||
});
|
||
});
|