feat(domains): Modul Domains mit AutoDNS-Zugang, Verbindungstest und Einstellungen
- Migration mit vier Tabellen (Einstellungen, Kunden, Kontaktzuordnung, Bestellungen), Zeilenschutz je Organisation - AutoDNS-Client mit festen Demo-/Live-Adressen, Takt-Begrenzer, 20 s Zeitlimit, ohne Wiederholung - Zugang je System verschluesselt gespeichert, Live-Wechsel nur mit Bestaetigung, Verbindungstest - Modulseite mit Systemkennzeichnung und Reiter Einstellungen (nur Verwalten) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
import 'reflect-metadata';
|
||||
import { ForbiddenException } from '@nestjs/common';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { ROLES_KEY } from '../auth/decorators/roles.decorator';
|
||||
import { MODULE_MANAGE_KEY, MODULE_SLUG_KEY } from '../module-registry/module.guard';
|
||||
import { DomainsController } from './domains.controller';
|
||||
|
||||
const proto = DomainsController.prototype as any;
|
||||
const req = (tenantId?: string) => ({ tenantId }) as any;
|
||||
|
||||
function makeSettings() {
|
||||
return {
|
||||
getStatus: vi.fn(async (..._a: unknown[]) => ({})),
|
||||
getSettings: vi.fn(async (..._a: unknown[]) => ({})),
|
||||
saveSettings: vi.fn(async (..._a: unknown[]) => ({})),
|
||||
testConnection: vi.fn(async (..._a: unknown[]) => ({})),
|
||||
};
|
||||
}
|
||||
|
||||
describe('DomainsController — Metadaten', () => {
|
||||
it('haengt an modules/domains und traegt @UseModule(domains)', () => {
|
||||
expect(Reflect.getMetadata('path', DomainsController)).toBe('modules/domains');
|
||||
expect(Reflect.getMetadata(MODULE_SLUG_KEY, DomainsController)).toBe('domains');
|
||||
});
|
||||
|
||||
it('Einstellungen und Verbindungstest verlangen Verwalten, ohne Rollen-Decorator', () => {
|
||||
for (const name of ['getSettings', 'saveSettings', 'testConnection']) {
|
||||
expect(Reflect.getMetadata(MODULE_MANAGE_KEY, proto[name]), name).toBe(true);
|
||||
expect(Reflect.getMetadata(ROLES_KEY, proto[name]), name).toBeUndefined();
|
||||
}
|
||||
});
|
||||
|
||||
it('getStatus steht auf Benutzen-Ebene', () => {
|
||||
expect(Reflect.getMetadata(MODULE_MANAGE_KEY, proto.getStatus)).toBeUndefined();
|
||||
expect(Reflect.getMetadata(ROLES_KEY, proto.getStatus)).toBeUndefined();
|
||||
});
|
||||
|
||||
it('Pfade und Methoden', () => {
|
||||
const route = (name: string) => [
|
||||
Reflect.getMetadata('method', proto[name]),
|
||||
Reflect.getMetadata('path', proto[name]),
|
||||
];
|
||||
// RequestMethod: GET 0, POST 1, PUT 2, DELETE 3
|
||||
expect(route('getStatus')).toEqual([0, 'status']);
|
||||
expect(route('getSettings')).toEqual([0, 'settings']);
|
||||
expect(route('saveSettings')).toEqual([2, 'settings']);
|
||||
expect(route('testConnection')).toEqual([1, 'connection-test']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DomainsController — Routen-Reihenfolge (statisch vor :id)', () => {
|
||||
it('deklariert jeden Handler mit :id-Pfad nach allen statischen Handlern', () => {
|
||||
const names = Object.getOwnPropertyNames(DomainsController.prototype).filter(
|
||||
(n) => n !== 'constructor' && typeof proto[n] === 'function' && n !== 'requireTenantId',
|
||||
);
|
||||
const isIdRoute = (n: string) => String(Reflect.getMetadata('path', proto[n])).includes(':id');
|
||||
const firstId = names.findIndex(isIdRoute);
|
||||
if (firstId === -1) return;
|
||||
names.slice(firstId).forEach((n) => {
|
||||
expect(isIdRoute(n), `${n} steht nach einer :id-Route, ist aber statisch`).toBe(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('DomainsController — Verhalten', () => {
|
||||
it('reicht req.tenantId weiter', async () => {
|
||||
const settings = makeSettings();
|
||||
const c = new DomainsController(settings as any);
|
||||
await c.getStatus(req('t1'));
|
||||
await c.getSettings(req('t1'));
|
||||
await c.saveSettings(req('t1'), { demoUser: 'x' } as any);
|
||||
await c.testConnection(req('t1'), { environment: 'DEMO' });
|
||||
expect(settings.getStatus).toHaveBeenCalledWith('t1');
|
||||
expect(settings.getSettings).toHaveBeenCalledWith('t1');
|
||||
expect(settings.saveSettings).toHaveBeenCalledWith('t1', { demoUser: 'x' });
|
||||
expect(settings.testConnection).toHaveBeenCalledWith('t1', 'DEMO');
|
||||
});
|
||||
|
||||
it('ohne Mandantenkontext 403', async () => {
|
||||
const c = new DomainsController(makeSettings() as any);
|
||||
await expect(c.getStatus(req(undefined))).rejects.toBeInstanceOf(ForbiddenException);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user