feat(bug-reports): Herkunft der Fehlermeldung im Betreff-Kuerzel und als Zeile Herkunft ausweisen

WebView2 (Windows) sieht im User-Agent aus wie Edge, WebKitGTK (Linux) wie
Safari — im Postfach war eine Client-Meldung von einer Browser-Meldung
nicht zu unterscheiden. Neuer reiner Helfer origin.ts leitet aus vier
optionalen DTO-Feldern (Desktop-App) bzw. dem User-Agent (Browser) ein
Betreff-Kuerzel und eine Zeile "Herkunft: ..." ab; rein informativ,
laengenbegrenzt, nichts wird gespeichert (T-GZA-01). Browser-Pfad ist
damit Ende-zu-Ende fertig.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016g2npLxzH5gZpg8s2S6vKh
This commit is contained in:
2026-09-18 12:32:29 +02:00
parent ab99a9ab5d
commit 716947228e
6 changed files with 411 additions and 6 deletions
+130
View File
@@ -0,0 +1,130 @@
import { describe, expect, it } from 'vitest';
import { describeOrigin, parseUserAgent } from './origin';
/**
* origin.spec.ts — NEU (quick-260918-gza, Herkunft einer Fehlermeldung).
*
* Zehn Tests fuer die beiden reinen Funktionen aus origin.ts:
* 1-5 `parseUserAgent` fuer Desktop- und Mobil-Browser (Reihenfolge der
* Muster: Edge/Opera vor Chrome, Safari nur ohne Chrome-Token,
* Android/iOS vor Linux/macOS);
* 6-8 `describeOrigin` im Desktop-Fall (mit/ohne Commit, ganz ohne
* Details — alter Client);
* 9 Rueckfall auf den Browser-Pfad, wenn alle vier Client-Felder
* fehlen (alter Web-Bau);
* 10 Bereinigung: kein Zeilenumbruch, kein Markup, hoechstens 40
* Zeichen je Wert (T-GZA-01).
*/
const EDGE_WINDOWS_UA =
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.2792.52';
const CHROME_WINDOWS_UA =
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36';
const FIREFOX_LINUX_UA = 'Mozilla/5.0 (X11; Linux x86_64; rv:130.0) Gecko/20100101 Firefox/130.0';
const SAFARI_MACOS_UA =
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15';
const ANDROID_CHROME_UA =
'Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Mobile Safari/537.36';
const IPAD_SAFARI_UA =
'Mozilla/5.0 (iPad; CPU OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Mobile/15E148 Safari/604.1';
const OPERA_UA =
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 OPR/114.0.0.0';
const WEBKITGTK_LINUX_UA =
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15';
describe('origin (quick-260918-gza)', () => {
it('Test 1: Edge auf Windows — Edge gewinnt vor Chrome', () => {
expect(parseUserAgent(EDGE_WINDOWS_UA)).toEqual({ browser: 'Edge 129', os: 'Windows' });
expect(describeOrigin({ clientKind: 'browser', userAgent: EDGE_WINDOWS_UA })).toEqual({
tag: '[Browser]',
line: 'Browser — Edge 129 auf Windows',
});
});
it('Test 2: derselbe UA ohne Edg/ — Chrome auf Windows', () => {
expect(parseUserAgent(CHROME_WINDOWS_UA)).toEqual({ browser: 'Chrome 129', os: 'Windows' });
});
it('Test 3: Firefox auf Linux', () => {
expect(parseUserAgent(FIREFOX_LINUX_UA)).toEqual({ browser: 'Firefox 130', os: 'Linux' });
expect(describeOrigin({ userAgent: FIREFOX_LINUX_UA }).line).toBe('Browser — Firefox 130 auf Linux');
});
it('Test 4: Safari auf macOS — Version aus Version/, nur ohne Chrome-Token', () => {
expect(parseUserAgent(SAFARI_MACOS_UA)).toEqual({ browser: 'Safari 17', os: 'macOS' });
});
it('Test 5: Mobil — Android statt Linux, iOS statt macOS, Opera erkannt', () => {
expect(parseUserAgent(ANDROID_CHROME_UA).os).toBe('Android');
const ipad = parseUserAgent(IPAD_SAFARI_UA);
expect(ipad.os).toBe('iOS');
expect(ipad.browser).toBe('Safari 17');
expect(parseUserAgent(OPERA_UA).browser).toBe('Opera 114');
});
it('Test 6: WebKitGTK-Client als Desktop — der User-Agent spielt keine Rolle', () => {
expect(
describeOrigin({
userAgent: WEBKITGTK_LINUX_UA,
clientKind: 'desktop',
clientOs: 'linux',
clientVersion: '1.2.0',
clientCommit: 'a6d1a64',
}),
).toEqual({
tag: '[Desktop/Linux]',
line: 'Desktop-App (Linux), Tessera-App 1.2.0 · Stand a6d1a64',
});
});
it('Test 7: Desktop ohne Commit — kein "· Stand"; Leerraum wird wie ein leerer Commit behandelt', () => {
expect(
describeOrigin({ clientKind: 'desktop', clientOs: 'windows', clientVersion: '1.2.0', clientCommit: '' }),
).toEqual({ tag: '[Desktop/Windows]', line: 'Desktop-App (Windows), Tessera-App 1.2.0' });
expect(
describeOrigin({ clientKind: 'desktop', clientOs: 'windows', clientVersion: '1.2.0', clientCommit: ' ' }),
).toEqual({ tag: '[Desktop/Windows]', line: 'Desktop-App (Windows), Tessera-App 1.2.0' });
});
it('Test 8: Desktop ohne Details (alter Client, Cookie fehlt) — unbekanntes Betriebssystem ebenfalls', () => {
expect(
describeOrigin({ clientKind: 'desktop', clientOs: '', clientVersion: '', clientCommit: '' }),
).toEqual({ tag: '[Desktop]', line: 'Desktop-App (unbekannt)' });
expect(
describeOrigin({ clientKind: 'desktop', clientOs: 'freebsd', clientVersion: '', clientCommit: '' }),
).toEqual({ tag: '[Desktop]', line: 'Desktop-App (unbekannt)' });
});
it('Test 9: Rueckfall auf den Browser-Pfad, wenn alle vier Client-Felder fehlen (alter Web-Bau)', () => {
expect(describeOrigin({ userAgent: 'UA' })).toEqual({
tag: '[Browser]',
line: 'Browser — unbekannt auf unbekannt',
});
expect(describeOrigin({ clientKind: 'browser', userAgent: '' })).toEqual({
tag: '[Browser]',
line: 'Browser — unbekannt auf unbekannt',
});
});
it('Test 10: Bereinigung — kein Zeilenumbruch, kein Markup, hoechstens 40 Zeichen je Wert (T-GZA-01)', () => {
const origin = describeOrigin({
clientKind: 'desktop',
clientOs: 'windows',
clientVersion: '1.2.0\nBenutzer: admin',
clientCommit: 'a6d1a64<b>',
});
expect(origin.line).not.toMatch(/[\n\r<>]/);
expect(origin.line).toBe('Desktop-App (Windows), Tessera-App 1.2.0Benutzeradmin · Stand a6d1a64b');
const longValue = 'x'.repeat(60);
const truncated = describeOrigin({
clientKind: 'desktop',
clientOs: 'linux',
clientVersion: longValue,
clientCommit: longValue,
});
expect(truncated.line).toBe(`Desktop-App (Linux), Tessera-App ${'x'.repeat(40)} · Stand ${'x'.repeat(40)}`);
});
});