mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-30 06:32:24 +00:00
76 lines
2.9 KiB
TypeScript
76 lines
2.9 KiB
TypeScript
/**
|
|
* Unit tests for describeNode — the dynamic per-node card summary. Asserts the
|
|
* config-driven text for representative kinds plus the generic fallbacks when
|
|
* config isn't filled in.
|
|
*/
|
|
import { describe, expect, it } from 'vitest';
|
|
|
|
import { describeNode } from './nodeSummary';
|
|
|
|
describe('describeNode', () => {
|
|
it('describes a schedule trigger via its cron', () => {
|
|
expect(describeNode('trigger', { trigger_kind: 'schedule', schedule: '*/5 * * * 3' })).toBe(
|
|
'Every 5 minutes on Wed'
|
|
);
|
|
expect(describeNode('trigger', { trigger_kind: 'manual' })).toBe('Runs on demand');
|
|
});
|
|
|
|
it('describes a schedule trigger stored as a tagged `{kind:"every"}` schedule', () => {
|
|
// Regression: the engine writes `config.schedule` as a tagged object
|
|
// (`{kind:"every", every_ms}`), not a bare cron string — the summary must
|
|
// not fall through to "No schedule set" for that real, configured shape.
|
|
const summary = describeNode('trigger', {
|
|
trigger_kind: 'schedule',
|
|
schedule: { kind: 'every', every_ms: 86_400_000 },
|
|
});
|
|
expect(summary).not.toBe('No schedule set');
|
|
expect(summary).toContain('24h');
|
|
});
|
|
|
|
it('still shows "No schedule set" for a genuinely unconfigured schedule trigger', () => {
|
|
expect(describeNode('trigger', { trigger_kind: 'schedule' })).toBe('No schedule set');
|
|
});
|
|
|
|
it('describes an http_request from method + url', () => {
|
|
expect(describeNode('http_request', { method: 'POST', url: 'https://api.x.com/v1' })).toBe(
|
|
'POST https://api.x.com/v1'
|
|
);
|
|
expect(describeNode('http_request', {})).toBe('GET request (set a URL)');
|
|
});
|
|
|
|
it('describes an agent by model hint', () => {
|
|
expect(describeNode('agent', { model: 'hint:coding' })).toBe('Asks the coding');
|
|
expect(describeNode('agent', { prompt: 'Summarize the thread', model: '' })).toContain(
|
|
'Summarize the thread'
|
|
);
|
|
});
|
|
|
|
it('describes branch nodes and reflects output routes', () => {
|
|
expect(describeNode('condition', { field: 'status' })).toBe('If status → true / false');
|
|
expect(describeNode('switch', { expression: 'item.type' }, ['a', 'b', 'default'])).toBe(
|
|
'Routes by item.type (3 routes)'
|
|
);
|
|
});
|
|
|
|
it('falls back for tool_call / transform with empty config', () => {
|
|
expect(describeNode('tool_call', {})).toBe('Runs an app action (pick one)');
|
|
expect(describeNode('transform', { set: { a: '=1', b: '=2' } })).toBe(
|
|
'Sets 2 fields on each item'
|
|
);
|
|
});
|
|
|
|
it('returns empty string for an unknown kind', () => {
|
|
expect(describeNode('time_travel', {})).toBe('');
|
|
});
|
|
|
|
it('gives memory search its own summary, distinct from recall', () => {
|
|
expect(describeNode('memory', { operation: 'search', scope: 'user' })).toBe(
|
|
'Searches memory (user)'
|
|
);
|
|
expect(describeNode('memory', { operation: 'recall', scope: 'user' })).toBe(
|
|
'Recalls memory (user)'
|
|
);
|
|
expect(describeNode('memory', { operation: 'search' })).toBe('Searches memory');
|
|
});
|
|
});
|