test(platform-service): add memory route-level tests

This commit is contained in:
saravanakumardb1 2026-02-16 12:36:27 -08:00
parent 8576fe2e91
commit 783b9792df

View File

@ -0,0 +1,207 @@
/**
* Route-level tests for memory module Fastify inject.
*/
import Fastify from 'fastify';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
const repoMock = {
list: vi.fn(),
create: vi.fn(),
getById: vi.fn(),
replace: vi.fn(),
remove: vi.fn(),
};
vi.mock('./repository.js', () => repoMock);
vi.mock('../../lib/auth.js', () => ({
extractAuth: vi.fn(async () => ({ sub: 'user_1', role: 'user' })),
}));
vi.mock('../../lib/request-context.js', () => ({
getRequestProductId: () => 'lysnrai',
}));
const baseItem = {
id: 'mem_1',
productId: 'lysnrai',
userId: 'user_1',
sourceType: 'text',
captureSurface: 'app',
rawContent: 'Follow up with customer',
triageResult: {
contentType: 'task',
summary: 'Follow up with customer',
urgencyScore: 0.7,
emotionScore: 0,
confidenceScore: 0.8,
suggestedBrainId: 'work',
entities: [],
suggestedActions: [],
},
brainIds: ['work'],
actedOn: false,
actedOnAt: null,
nudgeCount: 1,
userCorrection: null,
isSensitive: false,
createdAt: '2026-02-16T00:00:00Z',
updatedAt: '2026-02-16T00:00:00Z',
};
describe('memoryRoutes', () => {
beforeEach(() => {
vi.clearAllMocks();
});
afterEach(() => {
vi.restoreAllMocks();
});
it('GET /memory-items returns list result', async () => {
repoMock.list.mockResolvedValue({ items: [baseItem], total: 1 });
const { memoryRoutes } = await import('./routes.js');
const app = Fastify({ logger: false });
await app.register(memoryRoutes, { prefix: '/api' });
const res = await app.inject({ method: 'GET', url: '/api/memory-items?limit=10&offset=0' });
expect(res.statusCode).toBe(200);
const data = JSON.parse(res.body);
expect(data.items).toHaveLength(1);
expect(data.limit).toBe(10);
});
it('GET /memory-items rejects invalid query', async () => {
const { memoryRoutes } = await import('./routes.js');
const app = Fastify({ logger: false });
await app.register(memoryRoutes, { prefix: '/api' });
const res = await app.inject({ method: 'GET', url: '/api/memory-items?limit=0' });
expect(res.statusCode).toBe(400);
});
it('POST /memory-items creates item', async () => {
repoMock.create.mockResolvedValue(baseItem);
const { memoryRoutes } = await import('./routes.js');
const app = Fastify({ logger: false });
await app.register(memoryRoutes, { prefix: '/api' });
const res = await app.inject({
method: 'POST',
url: '/api/memory-items',
payload: {
sourceType: 'text',
captureSurface: 'app',
rawContent: 'Follow up with customer',
},
});
expect(res.statusCode).toBe(201);
expect(repoMock.create).toHaveBeenCalled();
});
it('PUT /memory-items/:id/reassign updates brain assignment', async () => {
repoMock.getById.mockResolvedValue(baseItem);
repoMock.replace.mockResolvedValue({ ...baseItem, brainIds: ['home'], userCorrection: 'home' });
const { memoryRoutes } = await import('./routes.js');
const app = Fastify({ logger: false });
await app.register(memoryRoutes, { prefix: '/api' });
const res = await app.inject({
method: 'PUT',
url: '/api/memory-items/mem_1/reassign',
payload: { newBrainId: 'home' },
});
expect(res.statusCode).toBe(200);
const data = JSON.parse(res.body);
expect(data.brainIds).toEqual(['home']);
});
it('PUT /memory-items/:id/reassign returns 404 when item missing', async () => {
repoMock.getById.mockResolvedValue(null);
const { memoryRoutes } = await import('./routes.js');
const app = Fastify({ logger: false });
await app.register(memoryRoutes, { prefix: '/api' });
const res = await app.inject({
method: 'PUT',
url: '/api/memory-items/missing/reassign',
payload: { newBrainId: 'home' },
});
expect(res.statusCode).toBe(404);
});
it('PATCH /memory-items/:id mark_done sets actedOn', async () => {
repoMock.getById.mockResolvedValue(baseItem);
repoMock.replace.mockResolvedValue({ ...baseItem, actedOn: true, actedOnAt: '2026-02-16T01:00:00Z' });
const { memoryRoutes } = await import('./routes.js');
const app = Fastify({ logger: false });
await app.register(memoryRoutes, { prefix: '/api' });
const res = await app.inject({
method: 'PATCH',
url: '/api/memory-items/mem_1',
payload: { action: 'mark_done' },
});
expect(res.statusCode).toBe(200);
expect(repoMock.replace).toHaveBeenCalled();
});
it('PATCH /memory-items/:id set_reminder requires reminderAt', async () => {
repoMock.getById.mockResolvedValue(baseItem);
const { memoryRoutes } = await import('./routes.js');
const app = Fastify({ logger: false });
await app.register(memoryRoutes, { prefix: '/api' });
const res = await app.inject({
method: 'PATCH',
url: '/api/memory-items/mem_1',
payload: { action: 'set_reminder' },
});
expect(res.statusCode).toBe(400);
});
it('DELETE /memory-items/:id removes item', async () => {
repoMock.getById.mockResolvedValue(baseItem);
repoMock.remove.mockResolvedValue(undefined);
const { memoryRoutes } = await import('./routes.js');
const app = Fastify({ logger: false });
await app.register(memoryRoutes, { prefix: '/api' });
const res = await app.inject({
method: 'DELETE',
url: '/api/memory-items/mem_1',
});
expect(res.statusCode).toBe(200);
const data = JSON.parse(res.body);
expect(data.success).toBe(true);
});
it('DELETE /memory-items/:id returns 404 when missing', async () => {
repoMock.getById.mockResolvedValue(null);
const { memoryRoutes } = await import('./routes.js');
const app = Fastify({ logger: false });
await app.register(memoryRoutes, { prefix: '/api' });
const res = await app.inject({
method: 'DELETE',
url: '/api/memory-items/missing',
});
expect(res.statusCode).toBe(404);
});
});