From 85a3d274e6ef657b8bd24f0840e2b6331c24c00e Mon Sep 17 00:00:00 2001 From: Anton Date: Wed, 4 Mar 2026 14:55:33 +0300 Subject: [PATCH] test: add Vitest config and test utils Made-with: Cursor --- tests/setup.ts | 5 ++++ tests/smoke.test.ts | 12 +++++++++ tests/test-utils.ts | 61 +++++++++++++++++++++++++++++++++++++++++++++ vitest.config.ts | 28 +++++++++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 tests/setup.ts create mode 100644 tests/smoke.test.ts create mode 100644 tests/test-utils.ts create mode 100644 vitest.config.ts diff --git a/tests/setup.ts b/tests/setup.ts new file mode 100644 index 0000000..a9fe784 --- /dev/null +++ b/tests/setup.ts @@ -0,0 +1,5 @@ +import { beforeAll, vi } from 'vitest'; + +beforeAll(() => { + vi.stubEnv('NODE_ENV', 'test'); +}); diff --git a/tests/smoke.test.ts b/tests/smoke.test.ts new file mode 100644 index 0000000..08fc400 --- /dev/null +++ b/tests/smoke.test.ts @@ -0,0 +1,12 @@ +import { describe, it, expect } from 'vitest'; +import { createMockDb } from './test-utils.js'; + +describe('test-utils', () => { + it('createMockDb returns mock with select, insert, update, delete', () => { + const db = createMockDb(); + expect(db.select).toBeDefined(); + expect(db.insert).toBeDefined(); + expect(db.update).toBeDefined(); + expect(db.delete).toBeDefined(); + }); +}); diff --git a/tests/test-utils.ts b/tests/test-utils.ts new file mode 100644 index 0000000..b411efb --- /dev/null +++ b/tests/test-utils.ts @@ -0,0 +1,61 @@ +import { vi } from 'vitest'; +import type { FastifyInstance } from 'fastify'; +import type { NodePgDatabase } from 'drizzle-orm/node-postgres'; +import type * as schema from '../src/db/schema/index.js'; + +export type MockDb = { + select: ReturnType['select']>; + insert: ReturnType['insert']>; + update: ReturnType['update']>; + delete: ReturnType['delete']>; +}; + +/** + * Create a chainable mock for Drizzle DB operations. + * Configure chain terminals (limit, returning) to resolve to desired values. + * Example: mockDb.select.mockReturnValue({ from: vi.fn().mockReturnValue({ where: vi.fn().mockReturnValue({ limit: vi.fn().mockResolvedValue([user]) }) }) }) + */ +export function createMockDb(): MockDb { + const chain = { + from: vi.fn().mockReturnThis(), + where: vi.fn().mockReturnThis(), + values: vi.fn().mockReturnThis(), + set: vi.fn().mockReturnThis(), + orderBy: vi.fn().mockReturnThis(), + limit: vi.fn().mockReturnThis(), + returning: vi.fn().mockReturnThis(), + }; + + return { + select: vi.fn().mockReturnValue(chain), + insert: vi.fn().mockReturnValue(chain), + update: vi.fn().mockReturnValue(chain), + delete: vi.fn().mockReturnValue(chain), + } as unknown as MockDb; +} + +/** + * Create a minimal mock Fastify app with db for route/integration tests. + * Use buildApp() from app.ts for full integration tests. + */ +export function createMockApp(): FastifyInstance & { db: MockDb } { + return { + db: createMockDb(), + log: { + child: () => ({ + debug: () => {}, + info: () => {}, + warn: () => {}, + error: () => {}, + trace: () => {}, + fatal: () => {}, + }), + debug: () => {}, + info: () => {}, + warn: () => {}, + error: () => {}, + trace: () => {}, + fatal: () => {}, + }, + } as FastifyInstance & { db: MockDb }; +} diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..6f73b43 --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,28 @@ +import { defineConfig } from 'vitest/config'; +import { resolve } from 'path'; + +export default defineConfig({ + test: { + globals: true, + environment: 'node', + include: ['tests/**/*.test.ts', 'tests/**/*.spec.ts'], + coverage: { + provider: 'v8', + reporter: ['text', 'json', 'lcov'], + include: ['src/services/**/*.ts'], + exclude: [ + 'src/services/**/*.d.ts', + '**/*.test.ts', + '**/*.spec.ts', + '**/index.ts', + ], + }, + setupFiles: ['tests/setup.ts'], + testTimeout: 10000, + }, + resolve: { + alias: { + '@': resolve(__dirname, 'src'), + }, + }, +});