test(mobile): add note-prompts API client and prompt-store tests (G14)
This commit is contained in:
parent
4fd6994fb0
commit
406153eeda
64
mobile/src/api/note-prompts.test.ts
Normal file
64
mobile/src/api/note-prompts.test.ts
Normal file
@ -0,0 +1,64 @@
|
||||
import { describe, expect, it, vi, beforeEach } from 'vitest';
|
||||
|
||||
const fetchMock = vi.fn();
|
||||
|
||||
vi.mock('./client', () => ({
|
||||
getApiClient: () => ({
|
||||
fetch: fetchMock,
|
||||
}),
|
||||
}));
|
||||
|
||||
import {
|
||||
listPromptTemplates,
|
||||
runPrompt,
|
||||
suggestTags,
|
||||
extractFromUrl,
|
||||
copilotTransform,
|
||||
getReadingTime,
|
||||
} from './note-prompts';
|
||||
|
||||
describe('note-prompts API client', () => {
|
||||
beforeEach(() => {
|
||||
fetchMock.mockReset();
|
||||
});
|
||||
|
||||
it('listPromptTemplates returns items', async () => {
|
||||
fetchMock.mockResolvedValue({ items: [{ id: 't1', slug: 'summarize' }] });
|
||||
const result = await listPromptTemplates();
|
||||
expect(result).toEqual([{ id: 't1', slug: 'summarize' }]);
|
||||
expect(fetchMock).toHaveBeenCalledWith('/note-prompts');
|
||||
});
|
||||
|
||||
it('runPrompt posts input', async () => {
|
||||
fetchMock.mockResolvedValue({ content: 'Summary', templateSlug: 'summarize' });
|
||||
const result = await runPrompt({ templateId: 'summarize', noteId: 'n1', workspaceId: 'ws1' });
|
||||
expect(result.content).toBe('Summary');
|
||||
expect(fetchMock).toHaveBeenCalledWith('/note-prompts/run', expect.objectContaining({ method: 'POST' }));
|
||||
});
|
||||
|
||||
it('suggestTags returns tag array', async () => {
|
||||
fetchMock.mockResolvedValue({ tags: ['tag1', 'tag2'] });
|
||||
const tags = await suggestTags('n1', 'ws1');
|
||||
expect(tags).toEqual(['tag1', 'tag2']);
|
||||
});
|
||||
|
||||
it('extractFromUrl sends url and workspaceId', async () => {
|
||||
fetchMock.mockResolvedValue({ title: 'Page', content: 'text', url: 'https://example.com', summarized: true });
|
||||
const result = await extractFromUrl('https://example.com', 'ws1');
|
||||
expect(result.title).toBe('Page');
|
||||
expect(fetchMock).toHaveBeenCalledWith('/note-prompts/url-extract', expect.objectContaining({ method: 'POST' }));
|
||||
});
|
||||
|
||||
it('copilotTransform sends action and text', async () => {
|
||||
fetchMock.mockResolvedValue({ text: 'Transformed' });
|
||||
const result = await copilotTransform('n1', 'ws1', 'shorten', 'Long text');
|
||||
expect(result).toBe('Transformed');
|
||||
});
|
||||
|
||||
it('getReadingTime returns word count and minutes', async () => {
|
||||
fetchMock.mockResolvedValue({ wordCount: 500, readingTimeMinutes: 3 });
|
||||
const result = await getReadingTime('n1', 'ws1');
|
||||
expect(result.wordCount).toBe(500);
|
||||
expect(result.readingTimeMinutes).toBe(3);
|
||||
});
|
||||
});
|
||||
113
mobile/src/store/prompt-store.test.ts
Normal file
113
mobile/src/store/prompt-store.test.ts
Normal file
@ -0,0 +1,113 @@
|
||||
import { describe, expect, it, vi, beforeEach } from 'vitest';
|
||||
|
||||
const listPromptTemplatesMock = vi.fn();
|
||||
const runPromptMock = vi.fn();
|
||||
|
||||
vi.mock('../api/note-prompts', () => ({
|
||||
listPromptTemplates: (...args: unknown[]) => listPromptTemplatesMock(...args),
|
||||
runPrompt: (...args: unknown[]) => runPromptMock(...args),
|
||||
}));
|
||||
|
||||
import { usePromptStore } from './prompt-store';
|
||||
|
||||
function resetStore() {
|
||||
usePromptStore.setState({
|
||||
templates: [],
|
||||
isLoading: false,
|
||||
isRunning: false,
|
||||
lastResult: null,
|
||||
error: null,
|
||||
});
|
||||
}
|
||||
|
||||
describe('prompt-store', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
resetStore();
|
||||
});
|
||||
|
||||
it('initial state is empty', () => {
|
||||
const state = usePromptStore.getState();
|
||||
expect(state.templates).toEqual([]);
|
||||
expect(state.isLoading).toBe(false);
|
||||
expect(state.isRunning).toBe(false);
|
||||
expect(state.lastResult).toBeNull();
|
||||
expect(state.error).toBeNull();
|
||||
});
|
||||
|
||||
it('fetchTemplates populates templates on success', async () => {
|
||||
listPromptTemplatesMock.mockResolvedValue([
|
||||
{ id: 't1', slug: 'summarize', name: 'Summarize' },
|
||||
]);
|
||||
|
||||
await usePromptStore.getState().fetchTemplates();
|
||||
|
||||
const state = usePromptStore.getState();
|
||||
expect(state.templates).toHaveLength(1);
|
||||
expect(state.templates[0].slug).toBe('summarize');
|
||||
expect(state.isLoading).toBe(false);
|
||||
});
|
||||
|
||||
it('fetchTemplates sets error on failure', async () => {
|
||||
listPromptTemplatesMock.mockRejectedValue(new Error('Network error'));
|
||||
|
||||
await usePromptStore.getState().fetchTemplates();
|
||||
|
||||
const state = usePromptStore.getState();
|
||||
expect(state.error).toBe('Network error');
|
||||
expect(state.isLoading).toBe(false);
|
||||
});
|
||||
|
||||
it('runPrompt stores result on success', async () => {
|
||||
runPromptMock.mockResolvedValue({
|
||||
content: 'Summary text',
|
||||
templateSlug: 'summarize',
|
||||
outputType: 'new_note',
|
||||
});
|
||||
|
||||
const result = await usePromptStore.getState().runPrompt({
|
||||
templateId: 'summarize',
|
||||
noteId: 'n1',
|
||||
workspaceId: 'ws1',
|
||||
});
|
||||
|
||||
expect(result).toBeTruthy();
|
||||
expect(result!.content).toBe('Summary text');
|
||||
const state = usePromptStore.getState();
|
||||
expect(state.lastResult!.content).toBe('Summary text');
|
||||
expect(state.isRunning).toBe(false);
|
||||
});
|
||||
|
||||
it('runPrompt sets error on failure', async () => {
|
||||
runPromptMock.mockRejectedValue(new Error('LLM timeout'));
|
||||
|
||||
const result = await usePromptStore.getState().runPrompt({
|
||||
templateId: 'summarize',
|
||||
noteId: 'n1',
|
||||
workspaceId: 'ws1',
|
||||
});
|
||||
|
||||
expect(result).toBeNull();
|
||||
const state = usePromptStore.getState();
|
||||
expect(state.error).toBe('LLM timeout');
|
||||
expect(state.isRunning).toBe(false);
|
||||
});
|
||||
|
||||
it('clearResult resets lastResult', async () => {
|
||||
runPromptMock.mockResolvedValue({ content: 'Result', templateSlug: 'x', outputType: 'new_note' });
|
||||
await usePromptStore.getState().runPrompt({ templateId: 'x', noteId: 'n1', workspaceId: 'ws1' });
|
||||
expect(usePromptStore.getState().lastResult).not.toBeNull();
|
||||
|
||||
usePromptStore.getState().clearResult();
|
||||
expect(usePromptStore.getState().lastResult).toBeNull();
|
||||
});
|
||||
|
||||
it('clearError resets error', async () => {
|
||||
runPromptMock.mockRejectedValue(new Error('fail'));
|
||||
await usePromptStore.getState().runPrompt({ templateId: 'x', noteId: 'n1', workspaceId: 'ws1' });
|
||||
expect(usePromptStore.getState().error).toBe('fail');
|
||||
|
||||
usePromptStore.getState().clearError();
|
||||
expect(usePromptStore.getState().error).toBeNull();
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user