Phase 1: Command palette (⌘K), editor autosave with quiet auto-saves, dashboard saved views from API + quick links + onboarding seed CTA, explicit task scan panel. Phase 2: Context pack formatter with YAML frontmatter, copy on note + workspace .md export. Phase 3: ADR for hybrid search without embeddings; POST /notes/search (lexical + ranked hybrid); search UI mode toggle. Phase 4: POST copilot + suggest-title; in-editor copilot actions; /chat retrieval answers with citations (backend chat.rag_enabled). Phase 5: Settings MCP snippet, offline queue note, API token deferral; DEEP_LINKS.md. Phase 6: Note shares + public GET; share page; POST onboarding-seed. Phase 7: note_versions on PATCH; version panel; create-note templates; PWA manifest. Flags: search.hybrid_enabled, copilot.enabled, chat.rag_enabled, onboarding.seed_enabled. Made-with: Cursor
65 lines
2.1 KiB
TypeScript
65 lines
2.1 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import { noteRoutes } from './routes.js';
|
|
|
|
const {
|
|
extractAuthMock,
|
|
listNotesMock,
|
|
getNoteMock,
|
|
createNoteMock,
|
|
updateNoteMock,
|
|
} = vi.hoisted(() => ({
|
|
extractAuthMock: vi.fn(async () => ({ sub: 'user_1' })),
|
|
listNotesMock: vi.fn(async () => ({ items: [], total: 0 })),
|
|
getNoteMock: vi.fn(async () => null),
|
|
createNoteMock: vi.fn(async (doc: unknown) => doc),
|
|
updateNoteMock: vi.fn(async () => null),
|
|
}));
|
|
|
|
vi.mock('../../lib/auth.js', () => ({ extractAuth: extractAuthMock, requireWriter: extractAuthMock }));
|
|
vi.mock('../../lib/product-config.js', () => ({ PRODUCT_ID: 'notelett' }));
|
|
vi.mock('../../lib/feature-flags.js', () => ({
|
|
isFeatureEnabled: vi.fn(() => true),
|
|
}));
|
|
vi.mock('../../lib/telemetry.js', () => ({ trackEvent: vi.fn() }));
|
|
vi.mock('../../lib/extraction-client.js', () => ({ extractFromText: vi.fn(async () => ({ summary: 'test' })) }));
|
|
vi.mock('../../lib/copilot-transform.js', () => ({
|
|
runCopilotTransform: vi.fn(async () => 'transformed'),
|
|
suggestTitleFromBody: vi.fn(async () => 'Suggested title'),
|
|
}));
|
|
vi.mock('../note-artifacts/repository.js', () => ({ createNoteArtifact: vi.fn(async (doc: unknown) => doc) }));
|
|
vi.mock('./repository.js', () => ({
|
|
listNotes: listNotesMock,
|
|
getNote: getNoteMock,
|
|
createNote: createNoteMock,
|
|
updateNote: updateNoteMock,
|
|
}));
|
|
vi.mock('../note-versions/repository.js', () => ({
|
|
appendNoteVersion: vi.fn(async () => ({})),
|
|
listNoteVersions: vi.fn(async () => ({ items: [], total: 0 })),
|
|
}));
|
|
vi.mock('../note-shares/repository.js', () => ({
|
|
createNoteShare: vi.fn(async () => ({})),
|
|
}));
|
|
|
|
describe('noteRoutes', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it('registers route handlers', async () => {
|
|
const app = {
|
|
get: vi.fn(),
|
|
post: vi.fn(),
|
|
patch: vi.fn(),
|
|
delete: vi.fn(),
|
|
};
|
|
|
|
await noteRoutes(app as never);
|
|
|
|
expect(app.get).toHaveBeenCalledTimes(5);
|
|
expect(app.post).toHaveBeenCalledTimes(9);
|
|
expect(app.patch).toHaveBeenCalledTimes(1);
|
|
expect(app.delete).toHaveBeenCalledTimes(1);
|
|
});
|
|
});
|