Node.js Native Test Runner vs Vitest in OmniRoute: Key Differences Explained
TL;DR: OmniRoute uses Node.js native test runner for fast, deterministic unit and integration tests on pure logic, and Vitest for UI, MCP server, and browser-like environment tests requiring jsdom.
The OmniRoute repository employs a dual-test architecture that leverages each framework's strengths. Understanding when each test runner activates helps contributors write appropriate tests and debug failures faster.
Why OmniRoute Uses Two Test Runners
Splitting tests between Node.js native node:test and Vitest allows the project to optimize for speed on server-side logic and environment fidelity on client-side code. The ARCHITECTURE.md file explicitly documents this separation, ensuring consistency across the ~1,000+ test files in the codebase.
Node.js Native Test Runner: Core Logic Validation
The Node.js native test runner handles unit and integration tests targeting pure TypeScript/JavaScript logic without DOM dependencies.
Configuration and Command
Tests execute via:
npm run test:unit
This expands to node --import tsx/esm --test tests/unit/**/*.test.ts* as defined in package.json. The --import tsx/esm flag enables TypeScript support without transpilation overhead.
Key Characteristics
- Environment: Pure Node.js with no DOM simulation.
- Test API: Uses
node:testmodule functions —test(),describe(),it()— with Node's native assertion library orexpectfromnode:test. - Execution: Sequential by default for deterministic ordering; parallelization available via
--test-concurrencybut intentionally avoided in OmniRoute. - Coverage: Integrated with
npm run test:coveragefor the Node suite includingopen-sse/code.
Example: Encryption Test
From tests/unit/encryption.test.ts:
import { test, expect } from "node:test";
import { encrypt, decrypt } from "@/lib/crypto";
test("encryption round‑trip", () => {
const secret = "my‑secret";
const encrypted = encrypt(secret);
const decrypted = decrypt(encrypted);
expect(decrypted).toBe(secret);
});
This pattern validates database helpers, provider executors, policy engine rules, and request handlers without environment complexity.
Vitest: UI, MCP, and Browser Environment Tests
Vitest covers UI components, MCP server functionality, auto-combo routing, and caching behavior requiring DOM APIs or React component rendering.
Configuration and Command
Tests execute via:
npm run test:vitest
Vitest reads vitest.config.ts, which specifies:
// From vitest.config.ts
export default defineConfig({
test: {
environment: "jsdom",
pool: "threads",
maxWorkers: 20,
fileParallelism: true,
// include patterns for UI and service tests
},
});
Key Characteristics
- Environment: jsdom browser simulation enabling
document,window, and ReactTestingLibrary APIs. - Parallelism: Thread-pool execution with up to 20 workers and file-level parallelism for faster CI runs.
- Scope: UI tests in
src/app/**/__tests__/**/*.test.tsx, MCP tools inopen-sse/**/__tests__/**/*.test.ts. - Coverage: Separate from Node suite; reports merged manually per
COVERAGE_PLAN.md.
Example: React Component Test
From src/app/(dashboard)/dashboard/cache/__tests__/CachePage.test.tsx:
import { render, screen } from "@testing-library/react";
import { describe, it, expect } from "vitest";
import CachePage from "@/app/(dashboard)/dashboard/cache/CachePage";
describe("CachePage", () => {
it("displays the cache header", () => {
render(<CachePage />);
expect(screen.getByText(/Cache Overview/i)).toBeInTheDocument();
});
});
Head-to-Head Comparison
| Aspect | Node.js Native | Vitest |
|---|---|---|
| Primary use | Pure logic, DB modules, policies | UI components, MCP server, auto-combo |
| Environment | Node.js only | jsdom (browser simulation) |
| Test location | tests/unit/**/*.test.ts* |
src/**/__tests__/**/*.test.tsx, open-sse/**/__tests__/**/*.test.ts |
| Parallelism | Sequential (deterministic) | 20 worker threads, file-parallel |
| DOM access | None | Full document/window APIs |
| React support | No | Yes, with @testing-library/react |
| Coverage integration | Single Node suite report | Separate report (merging planned) |
Choosing the Right Test Runner
Follow these rules from the OmniRoute source code:
- Use Node.js native for utilities, encryption, database layers, and API route handlers in
src/lib/,src/db/,open-sse/services/(non-UI). - Use Vitest for dashboard pages, React hooks, MCP tool UIs, and any code importing
reactor browser globals. - Check existing patterns — mirror the test file location and imports of similar functionality.
Summary
- Node.js native test runner provides fast, deterministic validation of server-side logic in
tests/unit/with zero environment overhead. - Vitest delivers browser-faithful testing for UI and MCP features via jsdom, with aggressive parallelization for CI efficiency.
- Configuration files —
package.jsonfor commands,vitest.config.tsfor Vitest settings, andARCHITECTURE.mdfor architectural decisions — govern the split.
Frequently Asked Questions
Can I run both test suites together?
No — OmniRoute keeps them separate intentionally. Run npm run test:unit for Node tests and npm run test:vitest for Vitest tests. CI pipelines execute both commands sequentially.
Why not use Vitest for everything?
Vitest's jsdom environment adds overhead unsuitable for pure logic validation. The Node native runner starts faster and enforces platform-agnostic code by prohibiting accidental DOM dependencies.
How does coverage reporting work with two runners?
Per COVERAGE_PLAN.md, the Node suite coverage (npm run test:coverage) currently covers most business logic. Vitest produces its own coverage report, and merging these reports remains a documented future improvement.
What imports should I use in each test type?
Node tests import from node:test and node:assert (or expect from node:test). Vitest tests import from vitest and @testing-library/react for component tests.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →