test(platform-service): add memory route-level tests
This commit is contained in:
parent
8576fe2e91
commit
783b9792df
207
services/platform-service/src/modules/memory/routes.test.ts
Normal file
207
services/platform-service/src/modules/memory/routes.test.ts
Normal 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);
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue
Block a user