test(btmsg): add regression tests for named column access and camelCase serialization
Covers the CRITICAL status vs system_prompt bug (positional index 7), JOIN alias disambiguation, serde camelCase serialization, TypeScript bridge IPC commands, and plantuml hex encoding algorithm. 49 new tests: 8 btmsg.rs + 7 bttask.rs + 8 sidecar + 17 btmsg-bridge.ts + 10 bttask-bridge.ts + 7 plantuml-encode.ts
This commit is contained in:
parent
a12f2bec7b
commit
e41d237745
6 changed files with 1012 additions and 0 deletions
150
v2/src/lib/adapters/bttask-bridge.test.ts
Normal file
150
v2/src/lib/adapters/bttask-bridge.test.ts
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
|
||||
const { mockInvoke } = vi.hoisted(() => ({
|
||||
mockInvoke: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@tauri-apps/api/core', () => ({
|
||||
invoke: mockInvoke,
|
||||
}));
|
||||
|
||||
import {
|
||||
listTasks,
|
||||
getTaskComments,
|
||||
updateTaskStatus,
|
||||
addTaskComment,
|
||||
createTask,
|
||||
deleteTask,
|
||||
type Task,
|
||||
type TaskComment,
|
||||
} from './bttask-bridge';
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('bttask-bridge', () => {
|
||||
// ---- REGRESSION: camelCase field names ----
|
||||
|
||||
describe('Task camelCase fields', () => {
|
||||
it('receives camelCase fields from Rust backend', async () => {
|
||||
const task: Task = {
|
||||
id: 't1',
|
||||
title: 'Fix bug',
|
||||
description: 'Critical fix',
|
||||
status: 'progress',
|
||||
priority: 'high',
|
||||
assignedTo: 'a1', // was: assigned_to
|
||||
createdBy: 'admin', // was: created_by
|
||||
groupId: 'g1', // was: group_id
|
||||
parentTaskId: null, // was: parent_task_id
|
||||
sortOrder: 1, // was: sort_order
|
||||
createdAt: '2026-01-01', // was: created_at
|
||||
updatedAt: '2026-01-01', // was: updated_at
|
||||
};
|
||||
mockInvoke.mockResolvedValue([task]);
|
||||
|
||||
const result = await listTasks('g1');
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].assignedTo).toBe('a1');
|
||||
expect(result[0].createdBy).toBe('admin');
|
||||
expect(result[0].groupId).toBe('g1');
|
||||
expect(result[0].parentTaskId).toBeNull();
|
||||
expect(result[0].sortOrder).toBe(1);
|
||||
// Verify no snake_case leaks
|
||||
expect((result[0] as Record<string, unknown>)['assigned_to']).toBeUndefined();
|
||||
expect((result[0] as Record<string, unknown>)['created_by']).toBeUndefined();
|
||||
expect((result[0] as Record<string, unknown>)['group_id']).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('TaskComment camelCase fields', () => {
|
||||
it('receives camelCase fields from Rust backend', async () => {
|
||||
const comment: TaskComment = {
|
||||
id: 'c1',
|
||||
taskId: 't1', // was: task_id
|
||||
agentId: 'a1', // was: agent_id
|
||||
content: 'Working on it',
|
||||
createdAt: '2026-01-01',
|
||||
};
|
||||
mockInvoke.mockResolvedValue([comment]);
|
||||
|
||||
const result = await getTaskComments('t1');
|
||||
|
||||
expect(result[0].taskId).toBe('t1');
|
||||
expect(result[0].agentId).toBe('a1');
|
||||
expect((result[0] as Record<string, unknown>)['task_id']).toBeUndefined();
|
||||
expect((result[0] as Record<string, unknown>)['agent_id']).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
// ---- IPC command name tests ----
|
||||
|
||||
describe('IPC commands', () => {
|
||||
it('listTasks invokes bttask_list', async () => {
|
||||
mockInvoke.mockResolvedValue([]);
|
||||
await listTasks('g1');
|
||||
expect(mockInvoke).toHaveBeenCalledWith('bttask_list', { groupId: 'g1' });
|
||||
});
|
||||
|
||||
it('getTaskComments invokes bttask_comments', async () => {
|
||||
mockInvoke.mockResolvedValue([]);
|
||||
await getTaskComments('t1');
|
||||
expect(mockInvoke).toHaveBeenCalledWith('bttask_comments', { taskId: 't1' });
|
||||
});
|
||||
|
||||
it('updateTaskStatus invokes bttask_update_status', async () => {
|
||||
mockInvoke.mockResolvedValue(undefined);
|
||||
await updateTaskStatus('t1', 'done');
|
||||
expect(mockInvoke).toHaveBeenCalledWith('bttask_update_status', { taskId: 't1', status: 'done' });
|
||||
});
|
||||
|
||||
it('addTaskComment invokes bttask_add_comment', async () => {
|
||||
mockInvoke.mockResolvedValue('c-id');
|
||||
const result = await addTaskComment('t1', 'a1', 'Done!');
|
||||
expect(result).toBe('c-id');
|
||||
expect(mockInvoke).toHaveBeenCalledWith('bttask_add_comment', { taskId: 't1', agentId: 'a1', content: 'Done!' });
|
||||
});
|
||||
|
||||
it('createTask invokes bttask_create with all fields', async () => {
|
||||
mockInvoke.mockResolvedValue('t-id');
|
||||
const result = await createTask('Fix bug', 'desc', 'high', 'g1', 'admin', 'a1');
|
||||
expect(result).toBe('t-id');
|
||||
expect(mockInvoke).toHaveBeenCalledWith('bttask_create', {
|
||||
title: 'Fix bug',
|
||||
description: 'desc',
|
||||
priority: 'high',
|
||||
groupId: 'g1',
|
||||
createdBy: 'admin',
|
||||
assignedTo: 'a1',
|
||||
});
|
||||
});
|
||||
|
||||
it('createTask invokes bttask_create without assignedTo', async () => {
|
||||
mockInvoke.mockResolvedValue('t-id');
|
||||
await createTask('Add tests', '', 'medium', 'g1', 'a1');
|
||||
expect(mockInvoke).toHaveBeenCalledWith('bttask_create', {
|
||||
title: 'Add tests',
|
||||
description: '',
|
||||
priority: 'medium',
|
||||
groupId: 'g1',
|
||||
createdBy: 'a1',
|
||||
assignedTo: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it('deleteTask invokes bttask_delete', async () => {
|
||||
mockInvoke.mockResolvedValue(undefined);
|
||||
await deleteTask('t1');
|
||||
expect(mockInvoke).toHaveBeenCalledWith('bttask_delete', { taskId: 't1' });
|
||||
});
|
||||
});
|
||||
|
||||
describe('error propagation', () => {
|
||||
it('propagates invoke errors', async () => {
|
||||
mockInvoke.mockRejectedValue(new Error('btmsg database not found'));
|
||||
await expect(listTasks('g1')).rejects.toThrow('btmsg database not found');
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue