![]() |
VOOZH | about |
uvu (short for ultimate velocity, unleashed) is considered to be one of the fastest and most lightweight test runners for Node.js and browsers. Its main features include individually executing test files, supporting asynchronous testing, supporting native ES modules, compatibility with browsers, outstanding lightweight size, familiar API, and remarkable performance. This blog post will cover the usage of uvu, its comparison with two other popular test runner libraries called Jest and AVA, and why and when to use it for testing.
๐ How to use uvu: A fast and lightweight test-runnerThe Replay is a weekly newsletter for dev and engineering leaders.
Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.
First of all, uvu supports asynchronous testing which is one of the common advantages that some testing libraries support. It assists in determining that the code which is being tested has completed the test process before it moves towards the next test. The prime objective of an asynchronous (async) function is just to clarify the syntax that is mandatory to consume promise based APIโs. In asynchronous testing, a method will be used like callback or promise which will determine the completion of a test process.
Another main feature is browser compatibility. At first, it was an issue that uvu was not compatible with the browsers but this was resolved by performing a little modification with the process file. You can find the discussion regarding the issue resolution here. So even if you are having any kind of issues with the browser compatibility you can check this link for a better understanding and sort out your problem.
Using uvu is simple and works like this:
// tests/demo.js
// Source: https://github.com/lukeed/uvu
import { test } from 'uvu';
import * as assert from 'uvu/assert';
test('Math.sqrt()', () => {
assert.is(Math.sqrt(4), 2);
assert.is(Math.sqrt(144), 12);
assert.is(Math.sqrt(2), Math.SQRT2);
});
test('JSON', () => {
const input = {
foo: 'hello',
bar: 'world'
};
const output = JSON.stringify(input);
assert.snapshot(output, `{"foo":"hello","bar":"world"}`);
assert.equal(JSON.parse(output), input, 'matches original');
});
test.run();
Now what you need to do is just to execute this test file:
# via `uvu` cli, for all `/tests/**` files $ uvu -r esm tests # via `node` directly, for file isolation $ node -r esm tests/demo.js
The point to be noted about the above command lines is that โr esm is only specified for legacy Node.js modules since the Ecmascript (ES) modules are deposited to Node.js versions >12.x. By default, .js and .cjs files are treated as Common.js, and .mjs file extensions are only the ones that would be served as Ecmascript Modules (ESM).
The above example can be considered as the simplest method through which Node.js will load ES modules and grant them to import any module when required. Also, you can load modules in some other ways as well that are shown below.
There are also other ways through which Node.js will load ES modules. These methods include type, module and esm package procedures. Here are the complete guides of these methods:
The main uvu module will assist regarding the tests or test suits(series of individual tests that are related to a certain functionality in the code) that are required for all the uvu tests. The users have the option available here whether to choose uvu.test or uvu.suite. Through uvu.suite one can grasp numerous additional perks like testing multiple files at once while one should choose uvu.test if thinking about testing a single file only (technically uvu.test is an unnamed test suite).
uvu.suite(name: string, context?:T)You can have as many suites as you want in the same file but itโs necessary to call suites run for each suite to be added to uvuโs queue. This just returns a suite along with creating a new suite. The name here corresponds to the name of the suite and is of type string. This will combine all console output together and will suffix the name of any test that fails. The context of the suite has an empty object as default value and is of any type. This will be passed to every test-block and hook inside the suite.
uvu.test (name: string, callback: function)If there is a requirement of testing only one file you can import this uvu.test. The name here obviously denotes the name of the test and is of type string and the callback here is consisted of the test code and is of type promise<any> or function<any>. The callback may be asynchronous and return values that are even though abandoned.
Each and every suite can be called and like this suite(name, callback).
In order to run a suite, one should add the suite to uvu test queue and use suite.run().
Skipping a suite can assist in missing an entire test block as suite.skip(name, callback).
For organizing an environment or establishing fixtures an ideal case would be to request the given callback before the beginning of the suit in the following way suite.before(callback).
Also for finishing an environment or fixture an ideal case would be to request the callback after the completion of the suite in the following way suite.after(callback).
Here is a sample code of the above description:
import { suite } from 'uvu';
import * as assert from 'uvu/assert';
import * as dates from '../src/dates';
const Now = suite('Date.now()');
let _Date;
Now.before(() => {
let count = 0;
_Date = global.Date;
global.Date = { now: () => 100 + count++ };
});
Now.after(() => {
global.Date = _Date;
});
// this is not run (skip)
Now.skip('should be a function', () => {
assert.type(Date.now, 'function');
});
// this is not run (only)
Now('should return a number', () => {
assert.type(Date.now(), 'number');
});
// this is run (only)
Now.only('should progress with time', () => {
assert.is(Date.now(), 100);
assert.is(Date.now(), 101);
assert.is(Date.now(), 102);
});
Now.run();
First, letโs take a look at a comparison of test runnersโ times. Below are the results of the sample test (achieved by testing the sample code which is present here) ran by few test runners with two timings. The first value is the total execution time of the whole process and the other value is the self-reported performance time only if it is known:
~> "ava" took 594ms ( ??? ) ~> "jest" took 962ms (356 ms) ~> "mocha" took 209ms (4 ms) ~> "tape" took 122ms ( ??? ) ~> "uvu" took 72ms (1.3ms)
Itโs obvious from the above result that uvu is the fastest option among its competitors.
Now let us talk a bit about the features comparison as well:
There has always been apprehension regarding the performance of test runners, but the features that uvu has provided have proved to be one of the finest ones. Itโs just like an all-in-one library for anyone worried about browser compatibility, high-speed testing, supporting native ES modules, asynchronous testing, and individually executing test files from a single library. So whenever you are anxious about all these things you just need to switch to one solution and thatโs uvu.
Install LogRocket via npm or script tag. LogRocket.init() must be called client-side, not
server-side
$ npm i --save logrocket
// Code:
import LogRocket from 'logrocket';
LogRocket.init('app/id');
// Add to your HTML:
<script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script>
<script>window.LogRocket && window.LogRocket.init('app/id');</script>
Learn how to use Gemini CLI subagents to delegate frontend, backend, testing, and docs tasks to specialized agents with guardrails and clear ownership.
Learn how next-browser gives AI agents runtime context for debugging Next.js apps, including React props, hydration, PPR, forms, and performance.
Build dynamic LLM routing in Next.js with OpenRouter, TanStack AI, task classification, model fallbacks, and cost-aware routing.
TSRX adds first-class control flow, conditional hooks, and scoped styles to React via a TypeScript compiler extension โ no new framework required.
Hey there, want to help make our blog better?
Join LogRocketโs Content Advisory Board. Youโll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up now