Skip to main content
The vtz runtime includes a built-in test runner powered by V8. No extra packages to install, no configuration required.
@vertz/test is a synthetic module provided automatically by the vtz runtime — like node:fs in Node.js. You do not need to run vtz add @vertz/test.

Quick start

Create a test file:
Run it:
That’s it. The runner discovers **/*.test.ts and **/*.test.tsx files automatically.

Writing tests

Structure

Use describe to group tests and it (or test) to define individual test cases:

Hooks

  • beforeEach(fn) — runs before each test in the current describe block
  • afterEach(fn) — runs after each test
  • beforeAll(fn) — runs once before all tests in the block
  • afterAll(fn) — runs once after all tests in the block
Hooks can be async. They compose hierarchically — parent beforeEach runs before child beforeEach.

Modifiers

Conditional skip

Parameterized tests

Assertions

The expect API is compatible with Vitest. Here are the most common matchers:

Asymmetric matchers

Use inside toEqual, toHaveBeenCalledWith, and other deep-equality matchers:
Available: expect.any(constructor), expect.anything(), expect.objectContaining(), expect.arrayContaining(), expect.stringContaining(), expect.stringMatching().

Mocking

Mock functions

Configure return values:
Available methods: mockReturnValue, mockReturnValueOnce, mockResolvedValue, mockResolvedValueOnce, mockRejectedValue, mockRejectedValueOnce, mockImplementation, mockImplementationOnce. Inspect calls via fn.mock.calls, fn.mock.results, and fn.mock.lastCall. Clean up with mockClear() (reset call history), mockReset() (clear + reset implementation), or mockRestore() (restore original for spies).

Spying on methods

vi namespace

For Vitest compatibility, the vi object provides the same utilities:

Fake timers

Available timer methods: useFakeTimers, useRealTimers, advanceTimersByTime, advanceTimersToNextTimer, runAllTimers, runOnlyPendingTimers, setSystemTime, getTimerCount, isFakeTimers.

Configuration

Configure the test runner in vertz.config.ts:
All fields are optional. Without a config file, vtz test uses sensible defaults.

CLI reference

Examples

Coming from Vitest or Jest

The @vertz/test API is intentionally compatible with Vitest. Your test logic stays the same — only the import path and runner change.

Key differences

  • No package to install. @vertz/test is provided by the vtz runtime automatically.
  • Runs in V8, not Node.js. The test runner uses the same V8 engine as vtz dev.
  • Snapshot testing (toMatchSnapshot, toMatchInlineSnapshot) is not currently supported.

Migrating from bun:test

The vtz migrate-tests command rewrites imports from bun:test to @vertz/test and adjusts API differences:

Troubleshooting

“Cannot find module ‘@vertz/test’” — You’re running tests with a different runner (Node, Bun, Vitest). Use vtz test instead — @vertz/test is only available inside the vtz runtime. Coverage outputvtz test --coverage generates a coverage.lcov file in the project root. Use any LCOV-compatible viewer to inspect results.

Next steps

Server Testing

Type-safe test client for entity CRUD, service actions, and raw HTTP.

E2E Testing

Browser-based tests with Playwright and authenticated users.