Skip to main content
ouroborai maintains 419 TypeScript tests (38 files) and 115 Rust tests across the four Stylus contracts. This page documents the testing conventions and patterns used throughout the codebase.

TypeScript (Vitest)

The project uses Vitest v3 with globals enabled. All tests run through the workspace Vitest configuration.

Running Tests

Do NOT use bun test or npx vitest — version mismatches between Bun’s bundled test runner and the project’s Vitest installation cause failures. Always use ./node_modules/.bin/vitest run.

vi.hoisted for Mock Variables

When mock variables need to be referenced inside vi.mock() factory functions, use vi.hoisted() to ensure they are initialized before the mock factory runs:
vi.hoisted() lifts the callback above all vi.mock() calls in the module scope. Without it, mock variables would be undefined when the factory runs.

vi.clearAllMocks vs vi.restoreAllMocks

Use vi.clearAllMocks() in beforeEach — not vi.restoreAllMocks():
restoreAllMocks() removes mockImplementation callbacks, which breaks tests that rely on them. clearAllMocks() resets call counts and return values while preserving the mock structure.

Mocking with vi.mock

Factory-based mocking for module dependencies:

Globals Enabled

The Vitest config has globals: true, so describe, it, expect, beforeEach, vi, etc. are available without imports:

Testing Hono Routes

Use Hono’s built-in app.request() for route testing:

Rust (Stylus Contracts)

Stylus contracts use cargo test with the stylus-test feature flag for testing utilities.

Running Tests

TestVM Setup Pattern

Every test creates a TestVM and instantiates the contract from it:

Setting Sender

Use vm.set_sender() to simulate calls from different addresses:

Mocking External Calls

Use mock_call for state-changing calls and mock_static_call for view calls:
mock_static_call in stylus-test 0.10.0 always returns the LAST registered mock’s data when multiple mocks target the same contract. Register losing mocks first, winning mock last.

Required Imports

Stylus tests require specific imports that differ from the main code:

Verifying Events

Check emitted events via vm.get_emitted_logs():

Private Helpers

Private helper functions that take &mut parameters must live in a separate impl block (not #[public]). The Stylus SDK requires ABI-compatible types in all #[public] methods: