From 63fe612a61875a24170356916204978eba4b18e7 Mon Sep 17 00:00:00 2001 From: KS Jannette Date: Thu, 12 Feb 2026 07:09:57 -0500 Subject: [PATCH] mo tests --- backend/tests/Clustering.service.test.js | 90 ++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 backend/tests/Clustering.service.test.js diff --git a/backend/tests/Clustering.service.test.js b/backend/tests/Clustering.service.test.js new file mode 100644 index 0000000..34cc13a --- /dev/null +++ b/backend/tests/Clustering.service.test.js @@ -0,0 +1,90 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; + +const { createMock } = vi.hoisted(() => { + return { createMock: vi.fn() }; +}); + +vi.mock('@anthropic-ai/sdk', () => { + return { + default: class MockAnthropic { + constructor() { + this.messages = { create: createMock }; + } + }, + }; +}); + +vi.mock('../.secrets.js', () => ({ + anthropicApiKey: 'test-key-not-real', +})); + +import { clusterNotes } from '../services/clustering.service.js'; + +const MOCK_NOTES = [ + { id: 'note_001', text: 'Login is broken' }, + { id: 'note_002', text: 'Export fails' }, +]; + +const MOCK_CLUSTERS = [ + { label: 'Auth Issues', noteIds: ['note_001'] }, + { label: 'Export Issues', noteIds: ['note_002'] }, +]; + + +describe('clusterNotes service', () => { + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('should call Anthropic messages.create with the correct model', async () => { + createMock.mockResolvedValue({ + content: [{ text: JSON.stringify(MOCK_CLUSTERS) }], + }); + + await clusterNotes(MOCK_NOTES); + + expect(createMock).toHaveBeenCalledOnce(); + const callArgs = createMock.mock.calls[0][0]; + expect(callArgs.model).toBe('claude-sonnet-4-20250514'); + expect(callArgs.max_tokens).toBe(4096); + }); + + it('should include all note texts in prompt sent to the LLM API', async () => { + createMock.mockResolvedValue({ + content: [{ text: JSON.stringify(MOCK_CLUSTERS) }], + }); + + await clusterNotes(MOCK_NOTES); + + const prompt = createMock.mock.calls[0][0].messages[0].content; + expect(prompt).toContain('note_001'); + expect(prompt).toContain('Login is broken'); + expect(prompt).toContain('note_002'); + expect(prompt).toContain('Export fails'); + }); + + it('should parse and return the clustered JSON from the API response', async () => { + createMock.mockResolvedValue({ + content: [{ text: JSON.stringify(MOCK_CLUSTERS) }], + }); + + const result = await clusterNotes(MOCK_NOTES); + + expect(result).toEqual(MOCK_CLUSTERS); + }); + + it('should throw error when the API returns non-JSON', async () => { + createMock.mockResolvedValue({ + content: [{ text: 'An unknown error occured when generting structured response.' }], + }); + + await expect(clusterNotes(MOCK_NOTES)).rejects.toThrow(); + }); + + it('should throw error when Anthropic API authentication fails', async () => { + createMock.mockRejectedValue(new Error('401 Unauthorized')); + + await expect(clusterNotes(MOCK_NOTES)).rejects.toThrow('401 Unauthorized'); + }); +});