Files
HartOMat/frontend/src/__tests__/api/workflows.test.ts
T

181 lines
5.6 KiB
TypeScript

import { describe, expect, test, vi } from 'vitest'
import {
createPresetWorkflowConfig,
createStarterWorkflowConfig,
normalizeWorkflowConfig,
getWorkflows,
} from '../../api/workflows'
import api from '../../api/client'
vi.mock('../../api/client', () => ({
default: {
get: vi.fn(),
},
}))
describe('workflow preset config builders', () => {
test('builds a non-legacy still graph preset', () => {
const config = createPresetWorkflowConfig('still_graph', {
render_engine: 'cycles',
samples: 128,
resolution: [1600, 900],
})
expect(config.ui?.preset).toBe('still_graph')
expect(config.ui?.execution_mode).toBe('graph')
expect(config.ui?.family).toBe('order_line')
expect(config.nodes.map(node => node.step)).toEqual([
'order_line_setup',
'resolve_template',
'auto_populate_materials',
'glb_bbox',
'material_map_resolve',
'blender_still',
'output_save',
'notify',
])
expect(config.nodes.find(node => node.step === 'blender_still')?.params).toMatchObject({
use_custom_render_settings: false,
render_engine: 'cycles',
samples: 128,
width: 1600,
height: 900,
})
})
test('builds family-specific starter configs', () => {
const cadStarter = createStarterWorkflowConfig('cad_file')
const orderStarter = createStarterWorkflowConfig('order_line')
expect(cadStarter.ui?.blueprint).toBe('starter_cad_intake')
expect(cadStarter.ui?.family).toBe('cad_file')
expect(cadStarter.nodes.map(node => node.step)).toEqual(['resolve_step_path'])
expect(orderStarter.ui?.blueprint).toBe('starter_order_rendering')
expect(orderStarter.ui?.family).toBe('order_line')
expect(orderStarter.nodes.map(node => node.step)).toEqual(['order_line_setup'])
})
test('preserves ui.family during normalization', () => {
const config = normalizeWorkflowConfig({
version: 1,
ui: {
preset: 'custom',
execution_mode: 'shadow',
family: 'order_line',
},
nodes: [
{ id: 'setup', step: 'order_line_setup', params: {} },
],
edges: [],
})
expect(config.ui?.family).toBe('order_line')
expect(config.ui?.execution_mode).toBe('shadow')
})
test('rebuilds canonical reference blueprints during normalization', () => {
const config = normalizeWorkflowConfig({
version: 1,
ui: {
preset: 'custom',
execution_mode: 'legacy',
blueprint: 'cad_intake',
},
nodes: [
{ id: 'resolve_step', step: 'resolve_step_path', params: {} },
],
edges: [],
})
expect(config.ui?.blueprint).toBe('cad_intake')
expect(config.ui?.family).toBe('cad_file')
expect(config.nodes.map(node => node.step)).toEqual([
'resolve_step_path',
'occ_object_extract',
'occ_glb_export',
'glb_bbox',
'stl_cache_generate',
'blender_render',
'threejs_render',
'thumbnail_save',
'thumbnail_save',
])
expect(config.edges).toEqual(
expect.arrayContaining([
{ from: 'export_glb', to: 'bbox' },
{ from: 'bbox', to: 'threejs_thumb' },
]),
)
})
test('rebuilds canonical starter blueprints during normalization', () => {
const config = normalizeWorkflowConfig({
version: 1,
ui: {
preset: 'custom',
execution_mode: 'legacy',
blueprint: 'starter_order_rendering',
},
nodes: [],
edges: [],
})
expect(config.ui?.blueprint).toBe('starter_order_rendering')
expect(config.ui?.family).toBe('order_line')
expect(config.nodes.map(node => node.step)).toEqual(['order_line_setup'])
})
test('normalizes workflow rollout summary from the API payload', async () => {
vi.mocked(api.get).mockResolvedValueOnce({
data: [
{
id: 'wf-1',
name: 'Still Graph',
output_type_id: null,
config: createPresetWorkflowConfig('still_graph'),
family: 'order_line',
supported_artifact_kinds: ['still_image'],
rollout_summary: {
linked_output_type_count: 2,
active_output_type_count: 1,
linked_output_type_names: ['Still Render', 'Still Render Shadow'],
rollout_modes: ['shadow'],
has_blocking_contracts: false,
blocking_reasons: [],
latest_run: {
workflow_run_id: 'run-1',
execution_mode: 'graph',
status: 'completed',
created_at: '2026-04-11T10:00:00Z',
completed_at: '2026-04-11T10:01:00Z',
},
latest_shadow_run: {
workflow_run_id: 'run-shadow-1',
execution_mode: 'shadow',
status: 'completed',
created_at: '2026-04-11T09:00:00Z',
completed_at: '2026-04-11T09:01:00Z',
},
latest_rollout_gate_verdict: 'pass',
latest_rollout_ready: true,
latest_rollout_status: 'ready_for_rollout',
latest_rollout_reasons: ['Observer output matches the authoritative legacy output byte-for-byte.'],
},
is_active: true,
created_at: '2026-04-11T08:00:00Z',
},
],
})
const [workflow] = await getWorkflows()
expect(workflow.rollout_summary.linked_output_type_count).toBe(2)
expect(workflow.rollout_summary.rollout_modes).toEqual(['shadow'])
expect(workflow.rollout_summary.latest_shadow_run?.execution_mode).toBe('shadow')
expect(workflow.rollout_summary.latest_rollout_gate_verdict).toBe('pass')
expect(workflow.rollout_summary.latest_rollout_ready).toBe(true)
})
})