Files
Portfolio/src/app/shared/terminal/terminal-commands.spec.ts
Antonio Ledebuhr 55d012cc10 Open the systems-map gist dialog and turn the dock into a default-open TTY.
Plain node activation no longer navigates, case cards stay quiet evidence rows, and the terminal keeps one top-to-bottom scrollport.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-27 00:41:20 +02:00

107 lines
3.8 KiB
TypeScript

import {
applyCompletion,
isUnsafeNavigateTarget,
navigateTargetKeys,
parseCommand,
suggestCompletions,
} from './terminal-commands';
describe('terminal command grammar', () => {
it('parses help, history, clear, brew and rev', () => {
expect(parseCommand('help')).toEqual({ kind: 'help' });
expect(parseCommand('history')).toEqual({ kind: 'history' });
expect(parseCommand('clear')).toEqual({ kind: 'clear' });
expect(parseCommand('brew')).toEqual({ kind: 'brew' });
expect(parseCommand('rev')).toEqual({ kind: 'rev' });
expect(parseCommand(' Hilfe ')).toEqual({ kind: 'help' });
expect(parseCommand('')).toEqual({ kind: 'empty' });
});
it('resolves navigate targets including the four service fragments', () => {
expect(parseCommand('navigate home')).toEqual({
kind: 'navigate',
resolution: { kind: 'route', routeId: 'home' },
targetKey: 'home',
});
expect(parseCommand('navigate pitch')).toEqual({
kind: 'navigate',
resolution: { kind: 'route', routeId: 'pitch' },
targetKey: 'pitch',
});
expect(parseCommand('navigate services')).toEqual({
kind: 'navigate',
resolution: { kind: 'route', routeId: 'services' },
targetKey: 'services',
});
expect(parseCommand('navigate services ai')).toEqual({
kind: 'navigate',
resolution: { kind: 'route', routeId: 'services', fragment: 'ai-workflows' },
targetKey: 'services ai',
});
expect(parseCommand('navigate leistungen software')).toEqual({
kind: 'navigate',
resolution: { kind: 'route', routeId: 'services', fragment: 'software-data' },
targetKey: 'services software',
});
expect(parseCommand('navigate services infrastructure')).toEqual({
kind: 'navigate',
resolution: { kind: 'route', routeId: 'services', fragment: 'infrastructure-network' },
targetKey: 'services infrastructure',
});
expect(parseCommand('navigate services platform')).toEqual({
kind: 'navigate',
resolution: { kind: 'route', routeId: 'services', fragment: 'platform-operations' },
targetKey: 'services platform',
});
expect(parseCommand('navigate cv')).toEqual({
kind: 'navigate',
resolution: { kind: 'cv' },
targetKey: 'cv',
});
});
it('suggests valid targets for incomplete navigate input', () => {
const parsed = parseCommand('navigate');
expect(parsed.kind).toBe('incomplete');
if (parsed.kind === 'incomplete') {
expect(parsed.suggestions).toEqual([...navigateTargetKeys()]);
}
const unknown = parseCommand('navigate nowhere');
expect(unknown.kind).toBe('unknown-target');
if (unknown.kind === 'unknown-target') {
expect(unknown.target).toBe('nowhere');
}
});
it('completes the current token against commands and navigate targets', () => {
expect(suggestCompletions('he')).toEqual(['help']);
expect(applyCompletion('he')).toEqual({ value: 'help', candidates: ['help'] });
expect(suggestCompletions('navigate p')).toEqual(['pitch', 'profil', 'projects', 'projekte']);
expect(applyCompletion('navigate pit')).toEqual({
value: 'navigate pitch',
candidates: ['pitch'],
});
expect(suggestCompletions('navigate services a')).toEqual(['services ai']);
});
it('rejects unsafe navigate targets without treating them as routes', () => {
const hostile = [
'navigate https://example.com',
'navigate ../secret',
'navigate /etc/passwd',
'navigate javascript:alert(1)',
];
for (const input of hostile) {
const target = input.slice('navigate '.length);
expect(isUnsafeNavigateTarget(target), input).toBe(true);
expect(parseCommand(input)).toEqual({
kind: 'unknown-target',
input,
target,
});
}
});
});