From 783b9792df9a9068a7645443c29c242eebec18ff Mon Sep 17 00:00:00 2001 From: saravanakumardb1 Date: Mon, 16 Feb 2026 12:36:27 -0800 Subject: [PATCH] test(platform-service): add memory route-level tests --- .../src/modules/memory/routes.test.ts | 207 ++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 services/platform-service/src/modules/memory/routes.test.ts diff --git a/services/platform-service/src/modules/memory/routes.test.ts b/services/platform-service/src/modules/memory/routes.test.ts new file mode 100644 index 00000000..7e536da0 --- /dev/null +++ b/services/platform-service/src/modules/memory/routes.test.ts @@ -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); + }); +});