task-service.test.ts
1 import assert from 'node:assert/strict' 2 import { describe, it } from 'node:test' 3 4 import { computeTaskFingerprint } from '@/lib/task-dedupe' 5 import type { BoardTask } from '@/types' 6 7 import { applyTaskPatch, prepareTaskCreation } from '@/lib/server/tasks/task-service' 8 9 function makeTask(overrides: Partial<BoardTask> = {}): BoardTask { 10 return { 11 id: 'task-1', 12 title: 'Example Task', 13 description: 'Do the work', 14 status: 'backlog', 15 agentId: 'agent-1', 16 sessionId: null, 17 result: null, 18 error: null, 19 createdAt: 1, 20 updatedAt: 1, 21 queuedAt: null, 22 startedAt: null, 23 completedAt: null, 24 ...overrides, 25 } 26 } 27 28 describe('task service helpers', () => { 29 it('prepareTaskCreation derives a title and normalizes running to queued', () => { 30 const prepared = prepareTaskCreation({ 31 id: 'task-create', 32 input: { 33 description: 'Please create a new login page for the app.', 34 status: 'running', 35 agentId: 'agent-1', 36 }, 37 tasks: {}, 38 now: 50, 39 deriveTitleFromDescription: true, 40 requireMeaningfulTitle: true, 41 }) 42 43 assert.equal(prepared.ok, true) 44 if (!prepared.ok) return 45 assert.equal(prepared.duplicate, null) 46 assert.equal(prepared.task.title, 'a new login page for the app.') 47 assert.equal(prepared.task.status, 'queued') 48 assert.equal((prepared.task.fingerprint || '').length, 16) 49 }) 50 51 it('prepareTaskCreation returns an existing duplicate task instead of a new one', () => { 52 const existing = makeTask({ 53 id: 'existing-task', 54 title: 'Unique dedupe title', 55 agentId: 'agent-1', 56 fingerprint: computeTaskFingerprint('Unique dedupe title', 'agent-1'), 57 }) 58 const prepared = prepareTaskCreation({ 59 id: 'task-create', 60 input: { 61 title: 'Unique dedupe title', 62 description: 'Duplicate task', 63 agentId: 'agent-1', 64 }, 65 tasks: { 'existing-task': existing }, 66 now: 60, 67 }) 68 69 assert.equal(prepared.ok, true) 70 if (!prepared.ok) return 71 assert.equal(prepared.duplicate?.id, 'existing-task') 72 }) 73 74 it('applyTaskPatch strips invalid statuses and clears nullable project ids', () => { 75 const task = makeTask({ 76 status: 'backlog', 77 projectId: 'project-1', 78 }) 79 80 applyTaskPatch({ 81 task, 82 patch: { 83 status: 'bananas', 84 projectId: null, 85 }, 86 now: 75, 87 clearProjectIdWhenNull: true, 88 }) 89 90 assert.equal(task.status, 'backlog') 91 assert.equal('projectId' in task, false) 92 assert.equal(task.updatedAt, 75) 93 }) 94 95 it('applyTaskPatch normalizes running updates to queued', () => { 96 const task = makeTask({ 97 status: 'backlog', 98 }) 99 100 applyTaskPatch({ 101 task, 102 patch: { status: 'running' }, 103 now: 90, 104 }) 105 106 assert.equal(task.status, 'queued') 107 }) 108 })