af1878d5ee
- Verwaltungs-Endpunkte nur fuer Administratoren, statische Routen vor :key - Loeschen verschiebt alle Eintraege inkl. persoenlicher eigener Module in einer Transaktion, ohne Ziel 409 - /modules, /modules/catalog und /module-grants/matrix liefern wirksame Kategorie und Reihenfolge - eigene Module pruefen die Kategorie gegen die Organisation (400 bei unbekannter) - Zugriffsinventar nachgezogen Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
88 lines
3.2 KiB
TypeScript
88 lines
3.2 KiB
TypeScript
import 'reflect-metadata';
|
|
import { plainToInstance } from 'class-transformer';
|
|
import { validate } from 'class-validator';
|
|
import { describe, expect, it } from 'vitest';
|
|
import { CreateCustomModuleDto, UpdateCustomModuleDto } from './custom-module.dto';
|
|
|
|
async function errorsFor<T extends object>(cls: new () => T, plain: Record<string, unknown>) {
|
|
const dto = plainToInstance(cls, plain);
|
|
const errors = await validate(dto as object);
|
|
return errors.map((e) => e.property);
|
|
}
|
|
|
|
const valid = { name: 'Wiki', url: 'https://example.com', category: 'infrastructure' };
|
|
|
|
describe('CreateCustomModuleDto', () => {
|
|
it('nimmt einen gueltigen Eintrag an', async () => {
|
|
expect(await errorsFor(CreateCustomModuleDto, valid)).toEqual([]);
|
|
});
|
|
|
|
it.each([
|
|
'http://example.com',
|
|
'javascript:alert(1)',
|
|
'data:text/html,x',
|
|
'ftp://x',
|
|
'kaputt',
|
|
'https://user:pw@example.com',
|
|
'https://user@example.com',
|
|
])('lehnt die Adresse %s ab', async (url) => {
|
|
expect(await errorsFor(CreateCustomModuleDto, { ...valid, url })).toContain('url');
|
|
});
|
|
|
|
// quick-261003-387: das DTO prueft nur das Format der Kennung; ob die
|
|
// Organisation sie fuehrt, entscheidet der Dienst (400, siehe Dienst-Spec).
|
|
it.each(['', 'Gross', 'mit leerzeichen', '-fuehrend', 'x'.repeat(61)])(
|
|
'lehnt die Kategorie-Kennung %j ab',
|
|
async (category) => {
|
|
expect(await errorsFor(CreateCustomModuleDto, { ...valid, category })).toContain('category');
|
|
},
|
|
);
|
|
|
|
it.each(['fleet', 'custom-modules', 'werkzeuge-tools'])(
|
|
'akzeptiert die Kategorie-Kennung %s',
|
|
async (category) => {
|
|
expect(await errorsFor(CreateCustomModuleDto, { ...valid, category })).not.toContain(
|
|
'category',
|
|
);
|
|
},
|
|
);
|
|
|
|
it.each(['', ' '])('lehnt den Namen %j ab', async (name) => {
|
|
expect(await errorsFor(CreateCustomModuleDto, { ...valid, name })).toContain('name');
|
|
});
|
|
|
|
it('trimmt den Namen', () => {
|
|
const dto = plainToInstance(CreateCustomModuleDto, { ...valid, name: ' Wiki ' });
|
|
expect(dto.name).toBe('Wiki');
|
|
});
|
|
|
|
it('lehnt zu lange Namen und Adressen ab', async () => {
|
|
expect(await errorsFor(CreateCustomModuleDto, { ...valid, name: 'a'.repeat(101) })).toContain(
|
|
'name',
|
|
);
|
|
const longUrl = `https://example.com/${'a'.repeat(2048)}`;
|
|
expect(await errorsFor(CreateCustomModuleDto, { ...valid, url: longUrl })).toContain('url');
|
|
});
|
|
});
|
|
|
|
describe('UpdateCustomModuleDto', () => {
|
|
it('akzeptiert Teilmengen', async () => {
|
|
expect(await errorsFor(UpdateCustomModuleDto, { name: 'Neu' })).toEqual([]);
|
|
expect(await errorsFor(UpdateCustomModuleDto, {})).toEqual([]);
|
|
});
|
|
|
|
it('prueft jedes gesetzte Feld gleich', async () => {
|
|
expect(await errorsFor(UpdateCustomModuleDto, { url: 'http://example.com' })).toContain('url');
|
|
expect(await errorsFor(UpdateCustomModuleDto, { category: 'Nicht Gueltig' })).toContain('category');
|
|
expect(await errorsFor(UpdateCustomModuleDto, { name: ' ' })).toContain('name');
|
|
});
|
|
|
|
it.each([
|
|
'name',
|
|
'url',
|
|
'category',
|
|
])('lehnt %s: null ab statt es durchzulassen', async (field) => {
|
|
expect(await errorsFor(UpdateCustomModuleDto, { [field]: null })).toContain(field);
|
|
});
|
|
});
|