Files
tessera-ctl/apps/api/src/custom-modules/dto/custom-module.dto.spec.ts
T
schalli be1e0035e0 fix(custom-modules): null beim Aendern ablehnen, Ladefehler statt 404, Fehlertexte, Seitenleiste eingeklappt
- PATCH mit null fuer name/url/category ergibt 400 statt 500
- Modulansicht unterscheidet Ladefehler von "nicht gefunden"
- Formular/Loeschdialog nennen 403 und 400 eigens
- eingeklappte Seitenleiste folgt der Gruppenreihenfolge der ausgeklappten
- neue Eintraege sind mit "Eigene Module" vorbelegt
- Verwaltung zeigt bei Ladefehler nicht zusaetzlich "keine Eintraege"

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 03:20:16 +02:00

76 lines
2.7 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');
});
it('lehnt eine unbekannte Kategorie ab', async () => {
expect(await errorsFor(CreateCustomModuleDto, { ...valid, category: 'other' })).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: 'other' })).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);
});
});