Skip to Content
🐺 Vovk.ts is released. Read the blog post →
Testing

Testing

Vovk.ts procedures expose an .fn method that calls the handler directly, skipping the HTTP round-trip. This makes unit testing straightforward — no server required.

Setup

Any test runner works (Vitest, Jest, Node.js test runner, etc.). Examples below use Vitest.

Testing with .fn

Given a controller:

src/modules/user/UserController.ts
import { z } from 'zod'; import { procedure, get, post, prefix } from 'vovk'; @prefix('users') export default class UserController { @get('{id}') static getUser = procedure({ params: z.object({ id: z.string() }), output: z.object({ id: z.string(), name: z.string() }), }).handle(async ({ vovk }) => { const { id } = vovk.params(); return { id, name: 'John' }; }); @post() static createUser = procedure({ body: z.object({ name: z.string() }), output: z.object({ id: z.string(), name: z.string() }), }).handle(async ({ vovk }) => { const { name } = await vovk.body(); return { id: 'new-id', name }; }); }

Test it directly:

src/modules/user/UserController.test.ts
import { describe, it, expect } from 'vitest'; import UserController from './UserController'; describe('UserController', () => { it('gets a user by ID', async () => { const user = await UserController.getUser.fn({ params: { id: '42' }, }); expect(user).toEqual({ id: '42', name: 'John' }); }); it('creates a user', async () => { const user = await UserController.createUser.fn({ body: { name: 'Alice' }, }); expect(user).toEqual({ id: 'new-id', name: 'Alice' }); }); });

The .fn method runs the full procedure pipeline including validation and decorators, but without HTTP overhead.

Testing Validation

Since procedures validate input, you can test that invalid data is rejected:

src/modules/user/UserController.test.ts
import { describe, it, expect } from 'vitest'; import { HttpException } from 'vovk'; import UserController from './UserController'; describe('UserController validation', () => { it('rejects invalid body', async () => { await expect( UserController.createUser.fn({ body: { name: 123 }, // invalid }) ).rejects.toThrow(HttpException); }); });

Integration Testing with RPC Modules

For end-to-end tests that go through the HTTP layer, use the generated RPC modules against a running dev server:

src/modules/user/UserController.e2e.test.ts
import { describe, it, expect } from 'vitest'; import { UserRPC } from 'vovk-client'; describe('UserController E2E', () => { it('gets a user via HTTP', async () => { const user = await UserRPC.getUser({ params: { id: '42' } }); expect(user).toEqual({ id: '42', name: 'John' }); }); });
Last updated on