diff --git a/packages/plugin-asterai/__tests__/actions/query.test.ts b/packages/plugin-asterai/__tests__/actions/query.test.ts new file mode 100644 index 00000000000..bd9745cfa8f --- /dev/null +++ b/packages/plugin-asterai/__tests__/actions/query.test.ts @@ -0,0 +1,110 @@ +const mockQuery = vi.fn(); + +vi.mock('@asterai/client', () => ({ + AsteraiClient: vi.fn(() => ({ + query: mockQuery + })) +})); + +vi.mock('../../src/index', () => ({ + getInitAsteraiClient: vi.fn(() => ({ + query: mockQuery + })) +})); + +import { vi, describe, it, expect, beforeEach } from 'vitest'; +import type { IAgentRuntime, Memory, State } from '@elizaos/core'; +import { queryAction } from '../../src/actions/query'; + +describe('queryAction', () => { + const mockRuntime: IAgentRuntime = { + getSetting: vi.fn(), + } as unknown as IAgentRuntime; + + const mockMessage: Memory = { + userId: 'test-user', + agentId: 'test-agent', + roomId: 'test-room', + content: { + text: 'test query' + } + } as Memory; + + const mockState: State = {}; + const mockCallback = vi.fn(); + + beforeEach(() => { + vi.clearAllMocks(); + vi.mocked(mockRuntime.getSetting).mockImplementation((key: string) => { + const settings = { + ASTERAI_AGENT_ID: 'test-agent-id', + ASTERAI_PUBLIC_QUERY_KEY: 'test-query-key' + }; + return settings[key as keyof typeof settings] || null; + }); + }); + + describe('validate', () => { + it('should validate with correct configuration', async () => { + const result = await queryAction.validate(mockRuntime, mockMessage); + expect(result).toBe(true); + }); + + it('should throw error with invalid configuration', async () => { + vi.mocked(mockRuntime.getSetting).mockReturnValue(null); + + await expect(queryAction.validate(mockRuntime, mockMessage)) + .rejects + .toThrow('Asterai plugin configuration validation failed'); + }); + }); + + describe('handler', () => { + it('should handle query and return response', async () => { + mockQuery.mockResolvedValueOnce({ text: () => Promise.resolve('mocked response') }); + + const result = await queryAction.handler( + mockRuntime, + mockMessage, + mockState, + {}, + mockCallback + ); + + expect(result).toBe(true); + expect(mockCallback).toHaveBeenCalledWith({ + text: 'mocked response' + }); + expect(mockQuery).toHaveBeenCalledWith({ + query: 'test query' + }); + }); + + it('should handle query errors gracefully', async () => { + mockQuery.mockRejectedValueOnce(new Error('Query failed')); + + await expect( + queryAction.handler(mockRuntime, mockMessage, mockState, {}, mockCallback) + ).rejects.toThrow('Query failed'); + }); + }); + + describe('metadata', () => { + it('should have correct name and similes', () => { + expect(queryAction.name).toBe('QUERY_ASTERAI_AGENT'); + expect(queryAction.similes).toContain('MESSAGE_ASTERAI_AGENT'); + expect(queryAction.similes).toContain('TALK_TO_ASTERAI_AGENT'); + }); + + it('should have valid examples', () => { + expect(Array.isArray(queryAction.examples)).toBe(true); + expect(queryAction.examples.length).toBeGreaterThan(0); + + queryAction.examples.forEach(example => { + expect(Array.isArray(example)).toBe(true); + expect(example.length).toBe(2); + expect(example[1].content.action).toBe('QUERY_ASTERAI_AGENT'); + }); + }); + }); +}); diff --git a/packages/plugin-asterai/__tests__/environment.test.ts b/packages/plugin-asterai/__tests__/environment.test.ts new file mode 100644 index 00000000000..2ff08992b1d --- /dev/null +++ b/packages/plugin-asterai/__tests__/environment.test.ts @@ -0,0 +1,58 @@ +import { describe, it, expect, vi } from 'vitest'; +import { validateAsteraiConfig } from '../src/environment'; +import type { IAgentRuntime } from '@elizaos/core'; + +describe('environment configuration', () => { + const mockRuntime: IAgentRuntime = { + getSetting: vi.fn(), + } as unknown as IAgentRuntime; + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('should validate correct configuration', async () => { + vi.mocked(mockRuntime.getSetting) + .mockImplementation((key: string) => { + const settings = { + ASTERAI_AGENT_ID: 'test-agent-id', + ASTERAI_PUBLIC_QUERY_KEY: 'test-query-key' + }; + return settings[key as keyof typeof settings] || null; + }); + + const config = await validateAsteraiConfig(mockRuntime); + expect(config).toEqual({ + ASTERAI_AGENT_ID: 'test-agent-id', + ASTERAI_PUBLIC_QUERY_KEY: 'test-query-key' + }); + }); + + it('should throw error for missing ASTERAI_AGENT_ID', async () => { + vi.mocked(mockRuntime.getSetting) + .mockImplementation((key: string) => { + const settings = { + ASTERAI_PUBLIC_QUERY_KEY: 'test-query-key' + }; + return settings[key as keyof typeof settings] || null; + }); + + await expect(validateAsteraiConfig(mockRuntime)) + .rejects + .toThrow('Asterai plugin configuration validation failed'); + }); + + it('should throw error for missing ASTERAI_PUBLIC_QUERY_KEY', async () => { + vi.mocked(mockRuntime.getSetting) + .mockImplementation((key: string) => { + const settings = { + ASTERAI_AGENT_ID: 'test-agent-id' + }; + return settings[key as keyof typeof settings] || null; + }); + + await expect(validateAsteraiConfig(mockRuntime)) + .rejects + .toThrow('Asterai plugin configuration validation failed'); + }); +}); diff --git a/packages/plugin-asterai/__tests__/providers/asterai.provider.test.ts b/packages/plugin-asterai/__tests__/providers/asterai.provider.test.ts new file mode 100644 index 00000000000..0f307bfaf4a --- /dev/null +++ b/packages/plugin-asterai/__tests__/providers/asterai.provider.test.ts @@ -0,0 +1,97 @@ +const mockFetchSummary = vi.fn(); + +vi.mock('@asterai/client', () => ({ + AsteraiClient: vi.fn(() => ({ + fetchSummary: mockFetchSummary + })) +})); + +vi.mock('../../src/index', () => ({ + getInitAsteraiClient: vi.fn(() => ({ + fetchSummary: mockFetchSummary + })) +})); + +import { vi, describe, it, expect, beforeEach } from 'vitest'; +import type { IAgentRuntime, Memory, State } from '@elizaos/core'; +import { asteraiProvider } from '../../src/providers/asterai.provider'; + +describe('asteraiProvider', () => { + const mockRuntime: IAgentRuntime = { + getSetting: vi.fn(), + knowledgeManager: { + getMemoryById: vi.fn(), + createMemory: vi.fn() + } + } as unknown as IAgentRuntime; + + const mockMessage: Memory = { + userId: 'test-user', + agentId: 'test-agent', + roomId: 'test-room', + content: { + text: 'test message' + } + } as Memory; + + const mockState: State = {}; + + beforeEach(() => { + vi.clearAllMocks(); + vi.mocked(mockRuntime.getSetting).mockImplementation((key: string) => { + const settings = { + ASTERAI_AGENT_ID: 'test-agent-id', + ASTERAI_PUBLIC_QUERY_KEY: 'test-query-key' + }; + return settings[key as keyof typeof settings] || null; + }); + }); + + describe('get', () => { + it('should return null if environment is not configured', async () => { + vi.mocked(mockRuntime.getSetting).mockReturnValue(null); + + const result = await asteraiProvider.get(mockRuntime, mockMessage, mockState); + expect(result).toBeNull(); + }); + + it('should return existing summary from knowledge manager', async () => { + const mockSummary = { + content: { text: 'existing summary' } + }; + vi.mocked(mockRuntime.knowledgeManager.getMemoryById).mockResolvedValue(mockSummary); + + const result = await asteraiProvider.get(mockRuntime, mockMessage, mockState); + expect(result).toBe('existing summary'); + }); + + it('should fetch and store new summary if none exists', async () => { + vi.mocked(mockRuntime.knowledgeManager.getMemoryById) + .mockResolvedValueOnce(null) + .mockResolvedValueOnce({ content: { text: 'new summary' } }); + + mockFetchSummary.mockResolvedValueOnce('new summary'); + vi.mocked(mockRuntime.knowledgeManager.createMemory).mockResolvedValueOnce(undefined); + + const result = await asteraiProvider.get(mockRuntime, mockMessage, mockState); + + expect(mockRuntime.knowledgeManager.createMemory).toHaveBeenCalledWith(expect.objectContaining({ + id: 'test-agent-id', + content: { text: 'new summary' } + })); + expect(result).toBe('new summary'); + }); + + it('should handle errors when fetching summary', async () => { + vi.mocked(mockRuntime.knowledgeManager.getMemoryById).mockResolvedValue(null); + mockFetchSummary.mockRejectedValue(new Error('Failed to fetch summary')); + + try { + await asteraiProvider.get(mockRuntime, mockMessage, mockState); + } catch (error) { + expect(error).toBeInstanceOf(Error); + expect(error.message).toBe('Failed to fetch summary'); + } + }); + }); +}); diff --git a/packages/plugin-asterai/package.json b/packages/plugin-asterai/package.json index 8b1916bbc1a..f8688c1fd82 100644 --- a/packages/plugin-asterai/package.json +++ b/packages/plugin-asterai/package.json @@ -32,12 +32,15 @@ "devDependencies": { "@types/elliptic": "6.4.18", "@types/uuid": "10.0.0", - "tsup": "8.3.5" + "tsup": "8.3.5", + "vitest": "^1.2.1" }, "scripts": { "lines": "find . \\( -name '*.cdc' -o -name '*.ts' \\) -not -path '*/node_modules/*' -not -path '*/tests/*' -not -path '*/deps/*' -not -path '*/dist/*' -not -path '*/imports*' | xargs wc -l", "build": "tsup --format esm --dts", - "dev": "tsup --format esm --dts --watch" + "dev": "tsup --format esm --dts --watch", + "test": "vitest run", + "test:watch": "vitest" }, "peerDependencies": { "whatwg-url": "7.1.0" diff --git a/packages/plugin-asterai/vitest.config.ts b/packages/plugin-asterai/vitest.config.ts new file mode 100644 index 00000000000..3b66182de91 --- /dev/null +++ b/packages/plugin-asterai/vitest.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + include: ['__tests__/**/*.test.ts'], + mockReset: true, + clearMocks: true, + restoreMocks: true, + reporters: ['default'], + testTimeout: 10000 + }, +});